From 30ab1a13ca690b912af72792d2cbfb1693e9ad6a Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sat, 12 Nov 2022 18:16:57 +0100
Subject: [PATCH] Added tests, documentation, doc bug fixes for angle-class
edge selectors
---
src/db/db/gsiDeclDbEdgePairs.cc | 58 +++++++++++++++++++++--
src/db/db/gsiDeclDbEdges.cc | 4 +-
src/doc/doc/about/drc_ref_layer.xml | 31 ++++++++++--
src/drc/drc/built-in-macros/_drc_layer.rb | 4 ++
testdata/ruby/dbEdgePairsTest.rb | 21 ++++++++
testdata/ruby/dbEdgesTest.rb | 13 +++++
6 files changed, 120 insertions(+), 11 deletions(-)
diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc
index da526ed66..d374dd526 100644
--- a/src/db/db/gsiDeclDbEdgePairs.cc
+++ b/src/db/db/gsiDeclDbEdgePairs.cc
@@ -676,7 +676,15 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"This will filter edge pairs with at least one horizontal edge:\n"
"\n"
"@code\n"
- "horizontal = edge_pairs.with_orientation(0, false)\n"
+ "horizontal = edge_pairs.with_angle(0, false)\n"
+ "@/code\n"
+ "\n"
+ "Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle(0, false)\n"
+ "others = edge_pairs.with_angle_both(0, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
@@ -690,6 +698,14 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
"\n"
+ "Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle(0, 45, false)\n"
+ "others = edge_pairs.with_angle_both(0, 45, true)\n"
+ "@/code\n"
+ "\n"
"This method has been added in version 0.27.1.\n"
) +
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
@@ -699,7 +715,15 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"edge pairs not fulfilling this criterion are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
- "and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEgdes or \\Edges#OrthoDiagonalEdges types.\n"
+ "and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEdges or \\Edges#OrthoDiagonalEdges types.\n"
+ "\n"
+ "Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle(RBA::Edges::Ortho, false)\n"
+ "others = edge_pairs.with_angle_both(RBA::Edges::Ortho, true)\n"
+ "@/code\n"
"\n"
"This method has been added in version 0.28.\n"
) +
@@ -712,7 +736,15 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"This will filter edge pairs with at least one horizontal edge:\n"
"\n"
"@code\n"
- "horizontal = edge_pairs.with_orientation(0, false)\n"
+ "horizontal = edge_pairs.with_angle_both(0, false)\n"
+ "@/code\n"
+ "\n"
+ "Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle_both(0, false)\n"
+ "others = edge_pairs.with_angle(0, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
@@ -726,16 +758,32 @@ Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
"\n"
+ "Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle_both(0, 45, false)\n"
+ "others = edge_pairs.with_angle(0, 45, true)\n"
+ "@/code\n"
+ "\n"
"This method has been added in version 0.27.1.\n"
) +
method_ext ("with_angle_both", with_angle_both3, gsi::arg ("type"), gsi::arg ("inverse"),
"@brief Filter the edge pairs by orientation of their edges\n"
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
"edge pairs with both edges having an angle of the given type are returned. If \"inverse\" is true, "
- "edge pairs not fulfilling this criterion are returned.\n"
+ "edge pairs not fulfilling this criterion for both edges are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
- "and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEgdes or \\Edges#OrthoDiagonalEdges types.\n"
+ "and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEdges or \\Edges#OrthoDiagonalEdges types.\n"
+ "\n"
+ "Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
+ "I.e\n"
+ "\n"
+ "@code\n"
+ "result = edge_pairs.with_angle_both(RBA::Edges::Ortho, false)\n"
+ "others = edge_pairs.with_angle(RBA::Edges::Ortho, true)\n"
+ "@/code\n"
"\n"
"This method has been added in version 0.28.\n"
) +
diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc
index f2ded4b5c..e2977296f 100644
--- a/src/db/db/gsiDeclDbEdges.cc
+++ b/src/db/db/gsiDeclDbEdges.cc
@@ -639,7 +639,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"This will select horizontal edges:\n"
"\n"
"@code\n"
- "horizontal = edges.with_orientation(0, false)\n"
+ "horizontal = edges.with_angle(0, false)\n"
"@/code\n"
) +
method_ext ("with_angle", with_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
@@ -661,7 +661,7 @@ Class decl_Edges (decl_dbShapeCollection, "db", "Edges",
"edges which do not conform to this criterion are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
- "and are specified using one of the \\OrthoEdges, \\DiagonalEgdes or \\OrthoDiagonalEdges types.\n"
+ "and are specified using one of the \\OrthoEdges, \\DiagonalEdges or \\OrthoDiagonalEdges types.\n"
"\n"
"This method has been added in version 0.28.\n"
) +
diff --git a/src/doc/doc/about/drc_ref_layer.xml b/src/doc/doc/about/drc_ref_layer.xml
index 4cc344d45..323b77638 100644
--- a/src/doc/doc/about/drc_ref_layer.xml
+++ b/src/doc/doc/about/drc_ref_layer.xml
@@ -3290,7 +3290,10 @@ Shielding is enabled by default, but can be switched off with the "transparent"
layer.with_angle(min .. max)
layer.with_angle(value)
layer.with_angle(min, max)
-edge_pair_layer.with_angle(min, max [, both])
+layer.with_angle(ortho)
+layer.with_angle(diagonal)
+layer.with_angle(diagonal_only)
+edge_pair_layer.with_angle(... [, both])
When called on an edge layer, the method selects edges by their angle,
@@ -3303,7 +3306,7 @@ an angle of 90 degee. The angle range is from -90 (exclusive) to 90 degree (incl
The first version of this method selects
edges with a angle larger or equal to min and less than max (but not equal).
The second version selects edges with exactly the given angle. The third
-version is identical to the first one.
+version is identical to the first one.
When called on an edge pair layer, this method selects edge pairs with one or both edges
meeting the angle criterion. In this case an additional argument is accepted which can be
@@ -3320,6 +3323,10 @@ ep2 = edge_pairs.with_angle(90, both)
A method delivering all objects not matching the angle criterion is without_angle.
+Note that for edge pairs, in order to get the inverse result, you have to add or drop "both"
+on without_angle. This is because without_angle without both returns edge pairs where
+one edge does not match the criterion. The logical opposite of "one edge matches" however is
+"both edges do not match".
The following images demonstrate some use cases of with_angle and without_angle:
@@ -3334,6 +3341,17 @@ The following images demonstrate some use cases of with_an
+Specifying "ortho", "diagonal" or "diagonal_only" instead of the angle values will select
+0 and 90 degree edges (ortho), -45 and 45 degree edges (diagonal_only) and both types (diagonal).
+This simplifies the implementation of selectors for manhattan or half-manhattan features:
+
+
+ortho_edges = edges.with_angle(ortho)
+
+# which is equivalent to, but more efficient as:
+ortho_edges = edges.with_angle(0) + edges.with_angle(90)
+
+
Note that in former versions, with_angle could be used on polygon layers selecting corners with specific angles.
This feature has been deprecated. Use corners instead.
@@ -3663,12 +3681,17 @@ This method is available for polygon layers only.
layer.without_angle(min .. max)
layer.without_angle(value)
layer.without_angle(min, max)
-edge_pair_layer.without_angle(min, max [, both])
+layer.without_angle(ortho)
+layer.without_angle(diagonal)
+layer.without_angle(diagonal_only)
+edge_pair_layer.without_angle(... [, both])
The method basically is the inverse of with_angle. It selects all edges
of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
-is not inside the given interval (first and third form). When called on edge pairs, it selects
+is not inside the given interval (first and third form) or of the given type (other forms).
+
+When called on edge pairs, it selects
edge pairs by the angles of their edges.
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index 0b1b41634..8e3c13d69 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -896,6 +896,10 @@ CODE
# @/code
#
# A method delivering all objects not matching the angle criterion is \without_angle.
+ # Note that for edge pairs, in order to get the inverse result, you have to add or drop "both"
+ # on \without_angle. This is because \without_angle without both returns edge pairs where
+ # one edge does not match the criterion. The logical opposite of "one edge matches" however is
+ # "both edges do not match".
#
# The following images demonstrate some use cases of \with_angle and \without_angle:
#
diff --git a/testdata/ruby/dbEdgePairsTest.rb b/testdata/ruby/dbEdgePairsTest.rb
index db5570d45..d44b25977 100644
--- a/testdata/ruby/dbEdgePairsTest.rb
+++ b/testdata/ruby/dbEdgePairsTest.rb
@@ -303,6 +303,27 @@ class DBEdgePairs_TestClass < TestBase
assert_equal(r1.with_internal_angle(0, 45, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,10;30,0)")
assert_equal(r1.with_internal_angle(0, 45, true, true, true).to_s, "")
+ ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 20, 0))
+ ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 20, 10))
+ ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 20), RBA::Edge::new(10, 20, 10, 0))
+ ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 15, 10))
+
+ r = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ])
+
+ assert_equal(r.with_angle(RBA::Edges::OrthoEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoEdges, true).to_s, "(0,0;0,10)/(10,0;20,10);(0,0;0,10)/(10,0;15,10)")
+ assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,10)")
+ assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;15,10)")
+
+ assert_equal(r.with_angle_both(RBA::Edges::OrthoEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,20)/(10,20;10,0)")
+ assert_equal(r.with_angle_both(RBA::Edges::OrthoEdges, true).to_s, "")
+ assert_equal(r.with_angle_both(RBA::Edges::DiagonalEdges, false).to_s, "")
+ assert_equal(r.with_angle_both(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
+ assert_equal(r.with_angle_both(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0)")
+ assert_equal(r.with_angle_both(RBA::Edges::OrthoDiagonalEdges, true).to_s, "")
+
end
end
diff --git a/testdata/ruby/dbEdgesTest.rb b/testdata/ruby/dbEdgesTest.rb
index c199c0c10..680a60568 100644
--- a/testdata/ruby/dbEdgesTest.rb
+++ b/testdata/ruby/dbEdgesTest.rb
@@ -474,6 +474,19 @@ class DBEdges_TestClass < TestBase
assert_equal(r.with_length(100, 200, true).to_s, "(100,0;100,50)")
assert_equal(r.with_length(nil, 100, false).to_s, "(100,0;100,50)")
+ r = RBA::Edges::new
+ r.insert(RBA::Edge::new(0, 0, 100, 0))
+ r.insert(RBA::Edge::new(100, 0, 100, 50))
+ r.insert(RBA::Edge::new(0, 0, 100, 100))
+ r.insert(RBA::Edge::new(0, 0, 100, -100))
+ r.insert(RBA::Edge::new(0, 0, 100, 120))
+ assert_equal(r.with_angle(RBA::Edges::OrthoEdges, false).to_s, "(0,0;100,0);(100,0;100,50)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoEdges, true).to_s, "(0,0;100,100);(0,0;100,-100);(0,0;100,120)")
+ assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, false).to_s, "(0,0;100,100);(0,0;100,-100)")
+ assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;100,0);(100,0;100,50);(0,0;100,120)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;100,0);(100,0;100,50);(0,0;100,100);(0,0;100,-100)")
+ assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, true).to_s, "(0,0;100,120)")
+
end
# interact