diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc
index 47e54c130..127409275 100644
--- a/src/db/db/dbAsIfFlatEdgePairs.cc
+++ b/src/db/db/dbAsIfFlatEdgePairs.cc
@@ -46,7 +46,17 @@ AsIfFlatEdgePairs::AsIfFlatEdgePairs ()
AsIfFlatEdgePairs::AsIfFlatEdgePairs (const AsIfFlatEdgePairs &other)
: EdgePairsDelegate (other), m_bbox_valid (other.m_bbox_valid), m_bbox (other.m_bbox)
{
- // .. nothing yet ..
+ operator= (other);
+}
+
+AsIfFlatEdgePairs &
+AsIfFlatEdgePairs::operator= (const AsIfFlatEdgePairs &other)
+{
+ if (this != &other) {
+ m_bbox_valid = other.m_bbox_valid;
+ m_bbox = other.m_bbox;
+ }
+ return *this;
}
AsIfFlatEdgePairs::~AsIfFlatEdgePairs ()
diff --git a/src/db/db/dbAsIfFlatEdgePairs.h b/src/db/db/dbAsIfFlatEdgePairs.h
index 5fe1e3f1d..938beaeea 100644
--- a/src/db/db/dbAsIfFlatEdgePairs.h
+++ b/src/db/db/dbAsIfFlatEdgePairs.h
@@ -81,6 +81,8 @@ protected:
void invalidate_bbox ();
private:
+ friend class DeepEdgePairs;
+
AsIfFlatEdgePairs &operator= (const AsIfFlatEdgePairs &other);
mutable bool m_bbox_valid;
diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc
index 07d422b45..9f59c5da6 100644
--- a/src/db/db/dbDeepEdgePairs.cc
+++ b/src/db/db/dbDeepEdgePairs.cc
@@ -532,4 +532,14 @@ void DeepEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
}
+DeepEdgePairs &DeepEdgePairs::operator= (const DeepEdgePairs &other)
+{
+ if (this != &other) {
+ AsIfFlatEdgePairs::operator= (other);
+ DeepShapeCollectionDelegateBase::operator= (other);
+ }
+
+ return *this;
+}
+
}
diff --git a/src/db/db/dbEdge.h b/src/db/db/dbEdge.h
index 27ed72d3f..39ddf359f 100644
--- a/src/db/db/dbEdge.h
+++ b/src/db/db/dbEdge.h
@@ -856,6 +856,9 @@ public:
* line through the edge. If the edge is degenerated, the distance
* is not defined.
*
+ * The distance is through as a distance of the point from the line
+ * through the edge.
+ *
* @param p The point to test.
*
* @return The distance
@@ -877,6 +880,27 @@ public:
}
}
+ /**
+ * @brief Gets the distance of the point from the edge.
+ *
+ * The distance is computed as the minimum distance of the point to any of the edge's
+ * points.
+ *
+ * @param p The point whose distance is to be computed
+ *
+ * @return The distance
+ */
+ distance_type euclidian_distance (const db::point &p)
+ {
+ if (db::sprod_sign (p - p1 (), d ()) < 0) {
+ return p1 ().distance (p);
+ } else if (db::sprod_sign (p - p2 (), d ()) > 0) {
+ return p2 ().distance (p);
+ } else {
+ return std::abs (distance (p));
+ }
+ }
+
/**
* @brief Side of the point
*
diff --git a/src/db/db/dbEdgePair.h b/src/db/db/dbEdgePair.h
index 805fb8cbe..0b6209725 100644
--- a/src/db/db/dbEdgePair.h
+++ b/src/db/db/dbEdgePair.h
@@ -204,6 +204,24 @@ public:
return !equal (b);
}
+ /**
+ * @brief Computes the distance of the edges in the edge pair
+ *
+ * The distance is the minimum distance of any of the points from
+ * each edge.
+ */
+ distance_type distance () const
+ {
+ db::edge e1 = first (), e2 = second ();
+ if (! e1.intersect (e2)) {
+ distance_type d12 = std::min (e2.euclidian_distance (e1.p1 ()), e2.euclidian_distance (e1.p2 ()));
+ distance_type d21 = std::min (e1.euclidian_distance (e2.p1 ()), e1.euclidian_distance (e2.p2 ()));
+ return std::min (d12, d21);
+ } else {
+ return 0;
+ }
+ }
+
/**
* @brief A method binding of operator* (mainly for automation purposes)
*/
diff --git a/src/db/db/dbEdgePairFilters.cc b/src/db/db/dbEdgePairFilters.cc
index 170b3ce8c..541f33731 100644
--- a/src/db/db/dbEdgePairFilters.cc
+++ b/src/db/db/dbEdgePairFilters.cc
@@ -71,28 +71,9 @@ EdgePairFilterByDistance::EdgePairFilterByDistance (distance_type min_distance,
// .. nothing yet ..
}
-static db::coord_traits::distance_type
-distance_of_point_from_edge (const db::Edge &e, const db::Point &p)
-{
- if (db::sprod_sign (p - e.p1 (), e.d ()) < 0) {
- return e.p1 ().distance (p);
- } else if (db::sprod_sign (p - e.p2 (), e.d ()) > 0) {
- return e.p2 ().distance (p);
- } else {
- return e.distance (p);
- }
-}
-
bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const
{
- distance_type dist = 0;
- db::Edge e1 = edge_pair.first (), e2 = edge_pair.second ();
- if (! e1.intersect (e2)) {
- distance_type d12 = std::min (distance_of_point_from_edge (e2, e1.p1 ()), distance_of_point_from_edge (e2, e1.p2 ()));
- distance_type d21 = std::min (distance_of_point_from_edge (e1, e2.p1 ()), distance_of_point_from_edge (e1, e2.p2 ()));
- dist = std::min (d12, d21);
- }
-
+ distance_type dist = edge_pair.distance ();
bool sel = (dist >= m_min_distance && dist < m_max_distance);
return m_inverted ? !sel : sel;
}
diff --git a/src/db/unit_tests/dbEdgePairTests.cc b/src/db/unit_tests/dbEdgePairTests.cc
index cd24fc074..9a27fa8f0 100644
--- a/src/db/unit_tests/dbEdgePairTests.cc
+++ b/src/db/unit_tests/dbEdgePairTests.cc
@@ -202,3 +202,17 @@ TEST(3_symmetric)
eh.insert (db::EdgePair (e2, e1, true));
EXPECT_EQ (int (eh.size ()), 1);
}
+
+TEST(4_distance)
+{
+ db::Edge e1 (db::Point (0, 0), db::Point (0, 100));
+ db::Edge e2 (db::Point (200, 100), db::Point (200, 0));
+ db::Edge e3 (db::Point (0, 0), db::Point (100, 0));
+ db::Edge e4 (db::Point (200, 0), db::Point (300, 0));
+ db::Edge e5 (db::Point (200, 100), db::Point (300, 100));
+
+ EXPECT_EQ (db::EdgePair (e1, e1).distance (), 0);
+ EXPECT_EQ (db::EdgePair (e1, e2).distance (), 200);
+ EXPECT_EQ (db::EdgePair (e3, e2).distance (), 100);
+ EXPECT_EQ (db::EdgePair (e3, e5).distance (), 141);
+}
diff --git a/src/db/unit_tests/dbEdgeTests.cc b/src/db/unit_tests/dbEdgeTests.cc
index a64880a86..d47932ced 100644
--- a/src/db/unit_tests/dbEdgeTests.cc
+++ b/src/db/unit_tests/dbEdgeTests.cc
@@ -106,6 +106,17 @@ TEST(2)
EXPECT_EQ (db::Edge (10,20,110,222).distance_abs (db::Point (100, 200)), db::Edge::distance_type (1));
EXPECT_EQ (db::Edge (10,20,110,222).contains (db::Point (0, 0)), false);
EXPECT_EQ (db::Edge (10,20,110,222).contains (db::Point (100, 200)), false);
+
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (100, 120)), 100);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (100, -80)), 100);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, 120)), 141);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, -80)), 141);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (210, 120)), 141);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (210, -80)), 141);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, 20)), 100);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (10, 20)), 0);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (50, 20)), 0);
+ EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (110, 20)), 0);
}
TEST(3)
diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb
index 71585d76a..511c1622f 100644
--- a/src/drc/drc/built-in-macros/_drc_layer.rb
+++ b/src/drc/drc/built-in-macros/_drc_layer.rb
@@ -706,12 +706,21 @@ CODE
# version is similar to the first one, but allows specification of nil for min or
# max indicating that there is no lower or upper limit.
#
+ # This method is available for edge and edge pair layers.
+ #
# When called on an edge pair layer, this method will select edge pairs if one
# or both of the edges meet the length criterion. Use the additional argument
# and pass "both" (plain word) to specify that both edges need to be within the given interval.
# By default, it's sufficient for one edge to meet the criterion.
+ #
+ # Here are examples for "with_length" on edge pair layers:
#
- # This method is available for edge and edge pair layers.
+ # @code
+ # # at least one edge needs to have a length of 1.0 <= l < 2.0
+ # ep1 = edge_pairs.with_length(1.um .. 2.um)
+ # # both edges need to have a length of exactly 2 um
+ # ep2 = edge_pairs.with_length(2.um, both)
+ # @/code
# %DRC%
# @name without_length
@@ -725,6 +734,15 @@ CODE
# not inside the given interval (first and third form).
#
# This method is available for edge and edge pair layers.
+ #
+ # A note on the "both" modifier (without_length called on edge pairs): "both" means that
+ # both edges need to be "without_length". For example
+ #
+ # @code
+ # # both edges are not exactly 1 um in length, or:
+ # # the edge pair is skipped if one edge has a length of exactly 1 um
+ # ep = edge_pairs.without_length(1.um, both)
+ # @/code
%w(length).each do |f|
[true, false].each do |inv|
@@ -862,6 +880,15 @@ CODE
# either "both" (plain word) to indicate that both edges have to be within the given interval.
# Without this argument, it is sufficient for one edge to meet the criterion.
#
+ # Here are examples for "with_angle" on edge pair layers:
+ #
+ # @code
+ # # at least one edge needs to be horizontal
+ # ep1 = edge_pairs.with_angle(0)
+ # # both edges need to vertical
+ # ep2 = edge_pairs.with_angle(90, both)
+ # @/code
+ #
# A method delivering all objects not matching the angle criterion is \without_angle.
#
# The following images demonstrate some use cases of \with_angle and \without_angle:
@@ -888,6 +915,16 @@ CODE
# 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).
+ #
+ # A note on the "both" modifier (without_angle called on edge pairs): "both" means that
+ # both edges need to be "without_angle". For example
+ #
+ # @code
+ # # both edges are not horizontal or:
+ # # the edge pair is skipped if one edge is horizontal
+ # ep = edge_pairs.without_angle(0, both)
+ # @/code
+ #
%w(angle).each do |f|
[true, false].each do |inv|
diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml
index 776eec007..a8cbdb35f 100644
--- a/src/lay/lay/doc/about/drc_ref_layer.xml
+++ b/src/lay/lay/doc/about/drc_ref_layer.xml
@@ -3182,6 +3182,15 @@ meeting the angle criterion. In this case an additional argument is accepted whi
either "both" (plain word) to indicate that both edges have to be within the given interval.
Without this argument, it is sufficient for one edge to meet the criterion.
+Here are examples for "with_angle" on edge pair layers:
+
+
+# at least one edge needs to be horizontal
+ep1 = edge_pairs.with_angle(0)
+# both edges need to vertical
+ep2 = edge_pairs.with_angle(90, both)
+
+
A method delivering all objects not matching the angle criterion is without_angle.
The following images demonstrate some use cases of with_angle and without_angle:
@@ -3424,12 +3433,21 @@ The second version selects edges with exactly the given length. The third
version is similar to the first one, but allows specification of nil for min or
max indicating that there is no lower or upper limit.
+This method is available for edge and edge pair layers.
+
When called on an edge pair layer, this method will select edge pairs if one
or both of the edges meet the length criterion. Use the additional argument
and pass "both" (plain word) to specify that both edges need to be within the given interval.
By default, it's sufficient for one edge to meet the criterion.
-This method is available for edge and edge pair layers.
+Here are examples for "with_length" on edge pair layers:
+
+
+# at least one edge needs to have a length of 1.0 <= l < 2.0
+ep1 = edge_pairs.with_length(1.um .. 2.um)
+# both edges need to have a length of exactly 2 um
+ep2 = edge_pairs.with_length(2.um, both)
+
"with_perimeter" - Selects polygons by perimeter
@@ -3480,6 +3498,15 @@ This method is available for polygon layers only.
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).
+
+A note on the "both" modifier (without_angle called on edge pairs): "both" means that
+both edges need to be "without_angle". For example
+
+
+# both edges are not horizontal or:
+# the edge pair is skipped if one edge is horizontal
+ep = edge_pairs.without_angle(0, both)
+
"without_area" - Selects polygons by area
@@ -3622,6 +3649,15 @@ of the edge layer which do not have the given length (second form) or are
not inside the given interval (first and third form).
This method is available for edge and edge pair layers.
+
+A note on the "both" modifier (without_length called on edge pairs): "both" means that
+both edges need to be "without_length". For example
+
+
+# both edges are not exactly 1 um in length, or:
+# the edge pair is skipped if one edge has a length of exactly 1 um
+ep = edge_pairs.without_length(1.um, both)
+
"without_perimeter" - Selects polygons by perimeter