diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 77c580350..cf9f3e78e 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1257,7 +1257,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord check.set_min_projection (options.min_projection); check.set_max_projection (options.max_projection); - edge2edge_check_negative_or_positive edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded); + edge2edge_check_negative_or_positive edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded, true /*symmetric edge pairs*/); poly2poly_check poly_check (edge_check); do { diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index c2864fcff..77cdd68d6 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1494,7 +1494,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) { - edge2edge_check_negative_or_positive edge_check (check, result, options.negative, false, false, options.shielded); + edge2edge_check_negative_or_positive edge_check (check, result, options.negative, false /*does not require different polygons*/, false /*does not require different layers*/, options.shielded, true /*symmetric edge pairs*/); poly2poly_check poly_check (edge_check); db::Polygon poly; diff --git a/src/db/db/dbEdgePair.h b/src/db/db/dbEdgePair.h index ef1978557..805fb8cbe 100644 --- a/src/db/db/dbEdgePair.h +++ b/src/db/db/dbEdgePair.h @@ -39,6 +39,16 @@ namespace db { +/** + * @brief A pair of edges + * + * An edge pair is a pair of edges which usually is used to mark a DRC violation. It flags the relationship of two edges. + * It's a compoisition of two edges: first and second. + * + * By default, an edge pair is directed: first and second are not commutable and indicate a relationship ("from first towards second"). + * The edge pair carries a flag which allows indicating symmetric mode: in this mode, the first and second edge are commutable. + * As a consequence, when the symmetric flag is used, edge_pair(e1, e2, true) == edge_pair(e2, e1, true). + */ template class DB_PUBLIC_TEMPLATE edge_pair { @@ -61,7 +71,7 @@ public: * The default constructor creates an edge pair with two default edges. */ edge_pair () - : m_first (), m_second () + : m_first (), m_second (), m_symmetric (false) { // .. nothing else .. } @@ -71,10 +81,11 @@ public: * * @param first The first edge * @param second The second edge + * @param symmetric True, if the edge pair is symmetric */ template - edge_pair (const db::edge &first, const db::edge &second) - : m_first (first), m_second (second) + edge_pair (const db::edge &first, const db::edge &second, bool symmetric = false) + : m_first (first), m_second (second), m_symmetric (symmetric) { // .. nothing else .. } @@ -84,11 +95,27 @@ public: */ template edge_pair (const edge_pair &e) - : m_first (e.first ()), m_second (e.second ()) + : m_first (e.first ()), m_second (e.second ()), m_symmetric (e.is_symmetric ()) { // .. nothing else .. } + /** + * @brief Gets the symmetric flag + */ + bool is_symmetric () const + { + return m_symmetric; + } + + /** + * @brief Sets the symmetric flag + */ + void set_symmetric (bool s) + { + m_symmetric = s; + } + /** * @brief The (dummy) translation operator */ @@ -112,7 +139,15 @@ public: */ bool operator< (const edge_pair &b) const { - return m_first < b.m_first || (m_first == b.m_first && m_second < b.m_second); + if (m_symmetric != b.m_symmetric) { + return m_symmetric < b.m_symmetric; + } + + const edge_type &l = lesser (); + const edge_type &g = greater (); + const edge_type &bl = b.lesser (); + const edge_type &bg = b.greater (); + return l < bl || (l == bl && g < bg); } /** @@ -120,7 +155,10 @@ public: */ bool operator== (const edge_pair &b) const { - return m_first == b.m_first && m_second == b.m_second; + if (m_symmetric != b.m_symmetric) { + return false; + } + return lesser () == b.lesser () && greater () == b.greater (); } /** @@ -136,7 +174,15 @@ public: */ bool less (const edge_pair &b) const { - return m_first.less (b.m_first) || (m_first.equal (b.m_first) && m_second.less (b.m_second)); + if (m_symmetric != b.m_symmetric) { + return m_symmetric < b.m_symmetric; + } + + const edge_type &l = lesser (); + const edge_type &g = greater (); + const edge_type &bl = b.lesser (); + const edge_type &bg = b.greater (); + return l.less (bl) || (l.equal (bl) && g.less (bg)); } /** @@ -144,7 +190,10 @@ public: */ bool equal (const edge_pair &b) const { - return m_first.equal (b.m_first) && m_second.equal (b.m_second); + if (m_symmetric != b.m_symmetric) { + return false; + } + return lesser ().equal (b.lesser ()) && greater ().equal (b.greater ()); } /** @@ -160,7 +209,7 @@ public: */ edge_pair scaled (double s) const { - return edge_pair (edge_type (first () * s), edge_type (second () * s)); + return edge_pair (edge_type (first () * s), edge_type (second () * s), m_symmetric); } /** @@ -193,7 +242,7 @@ public: template edge_pair &transform (const Tr &t) { - *this = edge_pair (t * m_first, t * m_second); + *this = edge_pair (t * m_first, t * m_second, m_symmetric); return *this; } @@ -210,7 +259,7 @@ public: template edge_pair transformed (const Tr &t) const { - return edge_pair (t * m_first, t * m_second); + return edge_pair (t * m_first, t * m_second, m_symmetric); } /** @@ -278,6 +327,32 @@ public: return m_second; } + /** + * @brief The "lesser" edge. + * This feature is used for comparing symmetric edge pairs. + */ + const edge_type &lesser () const + { + if (m_symmetric) { + return m_first < m_second ? m_first : m_second; + } else { + return m_first; + } + } + + /** + * @brief The "greater" edge. + * This feature is used for comparing symmetric edge pairs. + */ + const edge_type &greater () const + { + if (m_symmetric) { + return m_second < m_first ? m_first : m_second; + } else { + return m_second; + } + } + /** * @brief returns the bounding box */ @@ -310,7 +385,7 @@ public: */ std::string to_string (double dbu) const { - return m_first.to_string (dbu) + "/" + m_second.to_string (dbu); + return lesser ().to_string (dbu) + (m_symmetric ? "|" : "/") + greater ().to_string (dbu); } /** @@ -466,6 +541,7 @@ public: private: edge_type m_first, m_second; + bool m_symmetric; }; /** diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index 38f4fb11d..47b9f78ed 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -89,6 +89,9 @@ public: void process(const EdgePair &ep, std::vector &res) const { res.push_back (ep.first ()); + if (ep.is_symmetric ()) { + res.push_back (ep.second ()); + } } }; @@ -102,7 +105,9 @@ public: void process(const EdgePair &ep, std::vector &res) const { - res.push_back (ep.second ()); + if (! ep.is_symmetric ()) { + res.push_back (ep.second ()); + } } }; diff --git a/src/db/db/dbHash.h b/src/db/db/dbHash.h index de5e2359d..fe6f6b452 100644 --- a/src/db/db/dbHash.h +++ b/src/db/db/dbHash.h @@ -141,7 +141,7 @@ namespace std { size_t operator() (const db::edge_pair &o) const { - return hfunc (o.first (), hfunc (o.second ())); + return hfunc (o.lesser (), hfunc (o.greater (), hfunc (int (o.is_symmetric ())))); } }; diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 68bc38156..b079a60c1 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -723,10 +723,12 @@ shape_interactions::intruder_shape (unsigned int id) const // explicit instantiations template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; -template class DB_PUBLIC shape_interactions; -template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index c75205b1d..e3f360bab 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -89,17 +89,27 @@ void local_operation::compute_local (db::Layout *layout, const shape // explicit instantiations template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; +template class DB_PUBLIC local_operation; // --------------------------------------------------------------------------------------------- // BoolAndOrNotLocalOperation implementation diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index 24307a99b..0b5f68c42 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -202,7 +202,10 @@ check_local_operation::do_compute_local (db::Layout *layout, const shape tl_assert (results.size () == 1); std::unordered_set result, intra_polygon_result; - edge2edge_check_negative_or_positive > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded); + // NOTE: the rectangle and opposite filters are unsymmetric + bool symmetric_edge_pairs = ! m_has_other && m_options.opposite_filter == db::NoOppositeFilter && m_options.rect_filter == RectFilter::NoSideAllowed; + + edge2edge_check_negative_or_positive > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded, symmetric_edge_pairs); poly2poly_check poly_check (edge_check); std::list heap; @@ -302,7 +305,6 @@ check_local_operation::do_compute_local (db::Layout *layout, const shape scanner.process (poly_check, m_check.distance (), db::box_convert ()); } while (edge_check.prepare_next_pass ()); - // detect and remove parts of the result which have or do not have results "opposite" // ("opposite" is defined by the projection of edges "through" the subject shape) if (m_options.opposite_filter != db::NoOppositeFilter && (! result.empty () || ! intra_polygon_result.empty ())) { @@ -313,6 +315,8 @@ check_local_operation::do_compute_local (db::Layout *layout, const shape if (m_has_other) { + tl_assert (intra_polygon_result.empty ()); + // filter out opposite edges: this is the case of two-layer checks where we can maintain the edge pairs but // strip them of the filtered-out part. diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 31f2ccc18..a1eacf9f7 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -32,9 +32,14 @@ namespace db // ------------------------------------------------------------------------------------- // Edge2EdgeCheckBase implementation -Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding) +Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges) : mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), - m_first_pseudo (std::numeric_limits::max ()), m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0) + m_first_pseudo (std::numeric_limits::max ()), + m_with_shielding (with_shielding), + m_symmetric_edges (symmetric_edges), + m_has_edge_pair_output (true), + m_has_negative_edge_output (false), + m_pass (0) { m_distance = check.distance (); } @@ -159,13 +164,42 @@ Edge2EdgeCheckBase::feed_pseudo_edges (db::box_scanner &scanne } } +inline bool edges_considered (bool requires_different_polygons, bool requires_different_layers, size_t p1, size_t p2) +{ + if (p1 == p2) { + if (requires_different_polygons) { + return false; + } else if ((p1 & size_t (1)) != 0) { + // edges from the same polygon are only considered on first layer. + // Reasoning: this case happens when "intruder" polygons are put on layer 1 + // while "subject" polygons are put on layer 0. We don't want "intruders" + // to generate intra-polygon markers. + return false; + } + } + + if (((p1 ^ p2) & size_t (1)) == 0) { + if (requires_different_layers) { + return false; + } else if ((p1 & size_t (1)) != 0) { + // edges on the same layer are only considered on first layer. + // Reasoning: this case happens when "intruder" polygons are put on layer 1 + // while "subject" polygons are put on layer 0. We don't want "intruders" + // to generate inter-polygon markers between them. + return false; + } + } + + return true; +} + void Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2) { if (m_pass == 0) { // Overlap or inside checks require input from different layers - if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) { + if (edges_considered (m_different_polygons, m_requires_different_layers, p1, p2)) { // ensure that the first check argument is of layer 1 and the second of // layer 2 (unless both are of the same layer) @@ -180,6 +214,8 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size db::EdgePair ep; if (mp_check->check (*o1, *o2, &ep)) { + ep.set_symmetric (m_symmetric_edges); + // found a violation: store inside the local buffer for now. In the second // pass we will eliminate those which are shielded completely (with shielding) // and/or compute the negative edges. @@ -266,7 +302,7 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size (m_pseudo_edges.find (std::make_pair (*o1, p1)) != m_pseudo_edges.end ()) != (m_pseudo_edges.find (std::make_pair (*o2, p2)) != m_pseudo_edges.end ())) { // Overlap or inside checks require input from different layers - if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) { + if (edges_considered (m_different_polygons, m_requires_different_layers, p1, p2)) { // ensure that the first check argument is of layer 1 and the second of // layer 2 (unless both are of the same layer) @@ -756,7 +792,7 @@ SinglePolygonCheck::process (const db::Polygon &polygon, std::vector > edge_check (check, result, m_options.negative, false /*=same polygons*/, false /*=same layers*/, m_options.shielded); + edge2edge_check_negative_or_positive > edge_check (check, result, m_options.negative, false /*=same polygons*/, false /*=same layers*/, m_options.shielded, true /*=symmetric*/); poly2poly_check poly_check (edge_check); do { diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index a05727604..28ce19f67 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -544,7 +544,7 @@ class DB_PUBLIC Edge2EdgeCheckBase : public db::box_scanner_receiver { public: - Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding); + Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges); /** * @brief Call this to initiate a new pass until the return value is false @@ -630,6 +630,7 @@ private: size_t m_first_pseudo; std::vector m_ep_discarded, m_ep_intra_polygon; bool m_with_shielding; + bool m_symmetric_edges; bool m_has_edge_pair_output; bool m_has_negative_edge_output; unsigned int m_pass; @@ -645,14 +646,14 @@ class DB_PUBLIC_TEMPLATE edge2edge_check : public Edge2EdgeCheckBase { public: - edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), mp_output_inter (&output), mp_output_intra (0) + edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges) + : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output), mp_output_intra (0) { // .. nothing yet .. } - edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding) - : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), mp_output_inter (&output_inter), mp_output_intra (&output_intra) + edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges) + : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output_inter), mp_output_intra (&output_intra) { // .. nothing yet .. } @@ -683,16 +684,16 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_with_negative_output : public edge2edge_check { public: - edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : edge2edge_check (check, output, different_polygons, requires_different_layers, with_shielding), + edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges) + : edge2edge_check (check, output, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_l1_negative_output (&l1_negative_output), mp_l2_negative_output (&l2_negative_output) { edge2edge_check::set_has_negative_edge_output (true); } - edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : edge2edge_check (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding), + edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges) + : edge2edge_check (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_l1_negative_output (&l1_negative_output), mp_l2_negative_output (&l2_negative_output) { @@ -726,7 +727,7 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_negative { public: edge2edge_check_negative (const EdgeRelationFilter &check, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), + : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, false), mp_l1_negative_output (&l1_negative_output), mp_l2_negative_output (&l2_negative_output) { @@ -761,15 +762,15 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_negative_or_positive : public edge2edge_check { public: - edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : edge2edge_check (check, output, different_polygons, requires_different_layers, with_shielding) + edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric) + : edge2edge_check (check, output, different_polygons, requires_different_layers, with_shielding, symmetric) { edge2edge_check::set_has_negative_edge_output (negative_output); edge2edge_check::set_has_edge_pair_output (! negative_output); } - edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding) - : edge2edge_check (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding) + edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric) + : edge2edge_check (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric) { edge2edge_check::set_has_negative_edge_output (negative_output); edge2edge_check::set_has_edge_pair_output (! negative_output); diff --git a/src/db/db/gsiDeclDbEdgePair.cc b/src/db/db/gsiDeclDbEdgePair.cc index 127b2d7a8..4f72cfe4c 100644 --- a/src/db/db/gsiDeclDbEdgePair.cc +++ b/src/db/db/gsiDeclDbEdgePair.cc @@ -54,9 +54,9 @@ struct edge_pair_defs return new C (); } - static C *new_ee (const edge_type &first, const edge_type &second) + static C *new_ee (const edge_type &first, const edge_type &second, bool symmetric) { - return new C (first, second); + return new C (first, second, symmetric); } static size_t hash_value (const C *ep) @@ -72,10 +72,11 @@ struct edge_pair_defs "\n" "This constructor creates an default edge pair.\n" ) + - constructor ("new", &new_ee, + constructor ("new", &new_ee, gsi::arg ("first"), gsi::arg ("second"), gsi::arg ("symmetric", false), "@brief Constructor from two edges\n" "\n" "This constructor creates an edge pair from the two edges given.\n" + "See \\symmetric? for a description of this attribute." ) + method ("first", (const edge_type &(C::*) () const) &C::first, "@brief Gets the first edge\n" @@ -89,7 +90,34 @@ struct edge_pair_defs method ("second=", &C::set_second, gsi::arg ("edge"), "@brief Sets the second edge\n" ) + - method ("normalized", &C::normalized, + method ("symmetric?", &C::is_symmetric, + "@brief Returns a value indicating whether the edge pair is symmetric\n" + "For symmetric edge pairs, the edges are commutable. Specifically, a symmetric edge pair with (e1,e2) is identical to (e2,e1). " + "Symmetric edge pairs are generated by some checks for which there is no directed error marker (width, space, notch, isolated).\n" + "\n" + "Symmetric edge pairs have been introduced in version 0.27.\n" + ) + + method ("symmetric=", &C::set_symmetric, + "@brief Sets a value indicating whether the edge pair is symmetric\n" + "See \\symmetric? for a description of this attribute.\n" + "\n" + "Symmetric edge pairs have been introduced in version 0.27.\n" + ) + + method ("lesser", (const edge_type &(C::*) () const) &C::lesser, + "@brief Gets the 'lesser' edge for symmetric edge pairs\n" + "As first and second edges are commutable for symmetric edge pairs (see \\symmetric?), this accessor allows " + "retrieving a 'first' edge in a way independent on the actual assignment.\n" + "\n" + "This read-only attribute has been introduced in version 0.27.\n" + ) + + method ("greater", (const edge_type &(C::*) () const) &C::greater, + "@brief Gets the 'greater' edge for symmetric edge pairs\n" + "As first and second edges are commutable for symmetric edge pairs (see \\symmetric?), this accessor allows " + "retrieving a 'second' edge in a way independent on the actual assignment.\n" + "\n" + "This read-only attribute has been introduced in version 0.27.\n" + ) + + method ("normalized", &C::normalized, "@brief Normalizes the edge pair\n" "This method normalized the edge pair such that when connecting the edges at their \n" "start and end points a closed loop is formed which is oriented clockwise. To " diff --git a/src/db/unit_tests/dbEdgePairTests.cc b/src/db/unit_tests/dbEdgePairTests.cc index 85663a2bf..251bc15be 100644 --- a/src/db/unit_tests/dbEdgePairTests.cc +++ b/src/db/unit_tests/dbEdgePairTests.cc @@ -23,8 +23,12 @@ #include "dbEdgePair.h" +#include "dbHash.h" #include "tlUnitTest.h" +#include +#include + TEST(1) { db::EdgePair ep; @@ -147,3 +151,56 @@ TEST(2) EXPECT_EQ (ep.normalized ().to_polygon (1).to_string (), "(1,-1;-1,19;-1,31;1,11)"); } +TEST(3_symmetric) +{ + db::Edge e1 (db::Point (0, 0), db::Point (0, 100)); + db::Edge e2 (db::Point (200, 100), db::Point (200, 0)); + + EXPECT_EQ (db::EdgePair (e1, e2, false) == db::EdgePair (e1, e2, false), true); + EXPECT_EQ (db::EdgePair (e1, e2, false) == db::EdgePair (e2, e1, false), false); + EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e1, e2, false), false); + EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e1, e2, true), true); + EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e2, e1, true), true); + + EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e1, e2, false), false); + EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e2, e1, false), true); + EXPECT_EQ (db::EdgePair (e2, e1, false) < db::EdgePair (e2, e1, false), false); + EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e1, e2, true), true); + EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e1, e2, false), false); + EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e1, e2, true), false); + EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e2, e1, true), false); + + std::set es; + + es.clear (); + es.insert (db::EdgePair (e1, e2, false)); + es.insert (db::EdgePair (e1, e2, true)); + EXPECT_EQ (int (es.size ()), 2); + + es.clear (); + es.insert (db::EdgePair (e1, e2, false)); + es.insert (db::EdgePair (e2, e1, false)); + EXPECT_EQ (int (es.size ()), 2); + + es.clear (); + es.insert (db::EdgePair (e1, e2, true)); + es.insert (db::EdgePair (e2, e1, true)); + EXPECT_EQ (int (es.size ()), 1); + + std::unordered_set eh; + + eh.clear (); + eh.insert (db::EdgePair (e1, e2, false)); + eh.insert (db::EdgePair (e1, e2, true)); + EXPECT_EQ (int (eh.size ()), 2); + + eh.clear (); + eh.insert (db::EdgePair (e1, e2, false)); + eh.insert (db::EdgePair (e2, e1, false)); + EXPECT_EQ (int (eh.size ()), 2); + + eh.clear (); + eh.insert (db::EdgePair (e1, e2, true)); + eh.insert (db::EdgePair (e2, e1, true)); + EXPECT_EQ (int (eh.size ()), 1); +} diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 4df6ad260..8c4a7dd43 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -505,14 +505,14 @@ TEST(15a) db::Box bb[3] = { db::Box (db::Point (0, 0), db::Point (10, 10)), db::Box (), db::Box (db::Point (20, 20), db::Point (40, 50)) }; db::Region r (bb + 0, bb + 3); - EXPECT_EQ (r.width_check (15).to_string (), "(0,0;0,10)/(10,10;10,0);(0,10;10,10)/(10,0;0,0)"); + EXPECT_EQ (r.width_check (15).to_string (), "(0,0;0,10)|(10,10;10,0);(10,0;0,0)|(0,10;10,10)"); EXPECT_EQ (r.width_check (5).to_string (), ""); - EXPECT_EQ (r.width_check (5, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(0,5;0,10)/(0,10;5,10);(0,0;0,5)/(5,0;0,0);(5,10;10,10)/(10,10;10,5);(10,5;10,0)/(10,0;5,0);(20,45;20,50)/(20,50;25,50);(20,20;20,25)/(25,20;20,20);(35,50;40,50)/(40,50;40,45);(40,25;40,20)/(40,20;35,20)"); - EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(20,20;20,21)/(9,10;10,10);(20,20;20,21)/(10,10;10,9);(21,20;20,20)/(9,10;10,10);(21,20;20,20)/(10,10;10,9)"); - EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square, 91)).to_string (), "(20,20;20,25)/(5,10;10,10);(20,20;20,25)/(10,10;10,5);(25,20;20,20)/(5,10;10,10);(25,20;20,20)/(10,10;10,5)"); - EXPECT_EQ (r.space_check (15).to_string (), "(20,20;20,21)/(10,10;10,9);(21,20;20,20)/(9,10;10,10)"); - EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (true)).to_string (), "(20,20;20,50)/(10,10;10,0);(40,20;20,20)/(0,10;10,10)"); - EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square)).to_string (), "(20,20;20,25)/(10,10;10,5);(25,20;20,20)/(5,10;10,10)"); + EXPECT_EQ (r.width_check (5, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(0,5;0,10)|(0,10;5,10);(0,0;0,5)|(5,0;0,0);(5,10;10,10)|(10,10;10,5);(10,0;5,0)|(10,5;10,0);(20,45;20,50)|(20,50;25,50);(20,20;20,25)|(25,20;20,20);(35,50;40,50)|(40,50;40,45);(40,20;35,20)|(40,25;40,20)"); + EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(9,10;10,10)|(20,20;20,21);(10,10;10,9)|(20,20;20,21);(9,10;10,10)|(21,20;20,20);(10,10;10,9)|(21,20;20,20)"); + EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square, 91)).to_string (), "(5,10;10,10)|(20,20;20,25);(10,10;10,5)|(20,20;20,25);(5,10;10,10)|(25,20;20,20);(10,10;10,5)|(25,20;20,20)"); + EXPECT_EQ (r.space_check (15).to_string (), "(10,10;10,9)|(20,20;20,21);(9,10;10,10)|(21,20;20,20)"); + EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (true)).to_string (), "(10,10;10,0)|(20,20;20,50);(0,10;10,10)|(40,20;20,20)"); + EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square)).to_string (), "(10,10;10,5)|(20,20;20,25);(5,10;10,10)|(25,20;20,20)"); r.clear (); db::Point pts[] = { @@ -533,7 +533,7 @@ TEST(15a) poly.assign_hull(pts + 0, pts + sizeof(pts)/sizeof(pts[0])); r.insert (poly); - EXPECT_EQ (r.width_check (70000).to_string (), "(20550000,-18950000;20550000,-18920000)/(20570000,-18880000;20570000,-18890000);(20550000,-18920000;20530000,-18920000)/(20550000,-18880000;20570000,-18880000);(20550000,-18920000;20530000,-18920000)/(20570000,-18890000;20613246,-18890000);(20530000,-18920000;20530000,-18910000)/(20550000,-18850000;20550000,-18880000);(20530000,-18920000;20530000,-18910000)/(20570000,-18880000;20570000,-18890000);(20530000,-18910000;20450000,-18910000)/(20450000,-18850000;20550000,-18850000);(20530000,-18910000;20486754,-18910000)/(20550000,-18880000;20570000,-18880000);(20530000,-18910000;20502918,-18910000)/(20570000,-18890000;20597082,-18890000);(20570000,-18890000;20650000,-18890000)/(20650000,-18950000;20550000,-18950000)"); + EXPECT_EQ (r.width_check (70000).to_string (), "(20550000,-18950000;20550000,-18920000)|(20570000,-18880000;20570000,-18890000);(20550000,-18920000;20530000,-18920000)|(20550000,-18880000;20570000,-18880000);(20550000,-18920000;20530000,-18920000)|(20570000,-18890000;20613246,-18890000);(20530000,-18920000;20530000,-18910000)|(20550000,-18850000;20550000,-18880000);(20530000,-18920000;20530000,-18910000)|(20570000,-18880000;20570000,-18890000);(20530000,-18910000;20450000,-18910000)|(20450000,-18850000;20550000,-18850000);(20530000,-18910000;20486754,-18910000)|(20550000,-18880000;20570000,-18880000);(20530000,-18910000;20502918,-18910000)|(20570000,-18890000;20597082,-18890000);(20650000,-18950000;20550000,-18950000)|(20570000,-18890000;20650000,-18890000)"); } TEST(15b) @@ -544,10 +544,10 @@ TEST(15b) r.insert (db::Box (db::Point (300, 300), db::Point (500, 500))); r.insert (db::Box (db::Point (400, 200), db::Point (500, 300))); - EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)/(500,300;500,200)"); - EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)/(200,200;200,0);(300,300;300,500)/(200,500;200,300);(300,200;400,200)/(400,300;300,300)"); - EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)/(400,300;300,300)"); - EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(200,200;200,0)/(300,0;300,200);(200,500;200,300)/(300,300;300,500)"); + EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)|(500,300;500,200)"); + EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300)"); + EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)|(400,300;300,300)"); + EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300)"); } TEST(15c) @@ -562,10 +562,10 @@ TEST(15c) r.insert (db::Box (db::Point (400, 200), db::Point (500, 250))); r.insert (db::Box (db::Point (400, 250), db::Point (500, 300))); - EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)/(500,300;500,200)"); - EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)/(200,200;200,0);(300,300;300,500)/(200,500;200,300);(300,200;400,200)/(400,300;300,300)"); - EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)/(400,300;300,300)"); - EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(200,200;200,0)/(300,0;300,200);(200,500;200,300)/(300,300;300,500)"); + EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)|(500,300;500,200)"); + EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300)"); + EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)|(400,300;300,300)"); + EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300)"); } TEST(15d) @@ -581,12 +581,12 @@ TEST(15d) r.insert (db::Box (db::Point (0, 140), db::Point (350, 160))); EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), - "(100,140;0,140)/(0,100;100,100);" - "(350,140;300,140)/(300,100;350,100);" - "(100,200;0,200)/(0,160;100,160);" - "(400,200;300,200)/(300,100;400,100);" - "(350,200;300,200)/(300,160;350,160);" - "(700,200;600,200)/(600,100;700,100)" + "(300,100;350,100)|(350,140;300,140);" + "(0,100;100,100)|(100,140;0,140);" + "(0,160;100,160)|(100,200;0,200);" + "(300,160;350,160)|(350,200;300,200);" + "(300,100;400,100)|(400,200;300,200);" + "(600,100;700,100)|(700,200;600,200)" ); } @@ -635,7 +635,7 @@ TEST(15e) r.insert (poly); } - EXPECT_EQ (r.space_check (1000).to_string (), "(20857,3600;20857,66000)/(19957,66000;19957,3600)"); + EXPECT_EQ (r.space_check (1000).to_string (), "(20857,3600;20857,66000)|(19957,66000;19957,3600)"); } TEST(15g) @@ -1235,14 +1235,14 @@ TEST(20) { db::Region r1 (db::RecursiveShapeIterator (ly, ly.cell (top), l2)); - EXPECT_EQ (r1.width_check (20).to_string (), "(60,10;60,20)/(70,20;70,10);(60,20;70,20)/(70,10;60,10)"); - EXPECT_EQ (r1.width_check (50).to_string (), "(60,10;60,20)/(70,20;70,10);(60,20;70,20)/(70,10;60,10);(10,10;10,40)/(40,40;40,10);(10,40;40,40)/(40,10;10,10);(80,70;140,70)/(140,40;80,40)"); + EXPECT_EQ (r1.width_check (20).to_string (), "(60,10;60,20)|(70,20;70,10);(70,10;60,10)|(60,20;70,20)"); + EXPECT_EQ (r1.width_check (50).to_string (), "(60,10;60,20)|(70,20;70,10);(70,10;60,10)|(60,20;70,20);(10,10;10,40)|(40,40;40,10);(40,10;10,10)|(10,40;40,40);(140,40;80,40)|(80,70;140,70)"); } { db::Region r1 (db::RecursiveShapeIterator (ly, ly.cell (top), l2)); EXPECT_EQ (r1.has_valid_polygons (), false); - EXPECT_EQ (r1.space_check (30).to_string (), "(40,40;40,10)/(60,10;60,20);(80,40;80,48)/(70,20;70,12);(92,40;80,40)/(60,20;70,20)"); + EXPECT_EQ (r1.space_check (30).to_string (), "(60,10;60,20)|(40,40;40,10);(70,20;70,12)|(80,40;80,48);(60,20;70,20)|(92,40;80,40)"); EXPECT_EQ (r1.space_check (2).to_string (), ""); } diff --git a/src/db/unit_tests/dbRegionUtilsTests.cc b/src/db/unit_tests/dbRegionUtilsTests.cc index cffd08e2c..5e161b272 100644 --- a/src/db/unit_tests/dbRegionUtilsTests.cc +++ b/src/db/unit_tests/dbRegionUtilsTests.cc @@ -70,7 +70,40 @@ TEST(1_SimpleLShape) db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, true); + + db::Point pts[] = { + db::Point (0, 0), + db::Point (0, 2000), + db::Point (2000, 2000), + db::Point (2000, 1000), + db::Point (1000, 1000), + db::Point (1000, 0) + }; + + db::Polygon poly; + poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0])); + + db::poly2poly_check poly_check (e2e); + + do { + // single polygon check + poly_check.enter (poly, 0); + } while (e2e.prepare_next_pass ()); + + EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0),(2000,1000;1000,1000)|(1000,2000;2000,2000)"); + EXPECT_EQ (tl::to_string (ee1), ""); + EXPECT_EQ (tl::to_string (ee2), ""); +} + +TEST(1s_SimpleLShape) +{ + std::set ep; + std::set ee1, ee2; + + db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection); + + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, false); db::Point pts[] = { db::Point (0, 0), @@ -103,7 +136,7 @@ TEST(2_SimpleLWithBigPart) db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, true); db::Point pts[] = { db::Point (0, 0), @@ -124,7 +157,7 @@ TEST(2_SimpleLWithBigPart) poly_check.enter (poly, 0); } while (e2e.prepare_next_pass ()); - EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0)"); + EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0)"); EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(0,2500;2000,2500),(2000,2500;2000,1000)"); EXPECT_EQ (tl::to_string (ee2), ""); } @@ -136,7 +169,7 @@ TEST(3_SimpleTWithBigPart) db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, true); db::Point pts[] = { db::Point (0, 0), @@ -159,7 +192,7 @@ TEST(3_SimpleTWithBigPart) poly_check.enter (poly, 0); } while (e2e.prepare_next_pass ()); - EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0),(0,2500;0,3500)/(1000,3500;1000,2500)"); + EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0),(0,2500;0,3500)|(1000,3500;1000,2500)"); EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(1000,2500;2000,2500),(2000,2500;2000,1000)"); EXPECT_EQ (tl::to_string (ee2), ""); } @@ -171,7 +204,7 @@ TEST(4_SimpleNotch) db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, true); db::Point pts[] = { db::Point (0, 0), @@ -194,7 +227,7 @@ TEST(4_SimpleNotch) poly_check.enter (poly, 0); } while (e2e.prepare_next_pass ()); - EXPECT_EQ (tl::to_string (ep), "(2000,2000;1000,2000)/(1000,1000;2000,1000)"); + EXPECT_EQ (tl::to_string (ep), "(1000,1000;2000,1000)|(2000,2000;1000,2000)"); EXPECT_EQ (tl::to_string (ee1), "(0,0;0,3000),(2000,0;0,0),(2000,1000;2000,0),(0,3000;2000,3000),(2000,3000;2000,2000)"); EXPECT_EQ (tl::to_string (ee2), ""); } @@ -206,7 +239,7 @@ TEST(5_LShapeNotch) db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, false, false, true); db::Point pts[] = { db::Point (0, 0), @@ -231,7 +264,7 @@ TEST(5_LShapeNotch) poly_check.enter (poly, 0); } while (e2e.prepare_next_pass ()); - EXPECT_EQ (tl::to_string (ep), "(1500,1500;1500,2500)/(500,2500;500,1500),(2000,1500;1500,1500)/(1500,500;2000,500)"); + EXPECT_EQ (tl::to_string (ep), "(1500,500;2000,500)|(2000,1500;1500,1500),(1500,1500;1500,2500)|(500,2500;500,1500)"); EXPECT_EQ (tl::to_string (ee1), "(0,0;0,3000),(2000,0;0,0),(2000,500;2000,0),(0,3000;2000,3000),(2000,3000;2000,1500)"); EXPECT_EQ (tl::to_string (ee2), ""); } @@ -243,7 +276,7 @@ TEST(6_SeparationLvsBox) db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection); - db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, true /*different layers*/, false); + db::edge2edge_check_with_negative_output, std::set > e2e (er, ep, ee1, ee2, false, true /*different layers*/, false, false); db::Point pts1[] = { db::Point (0, 0), diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 59a9046e4..1c8419bbe 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -1112,6 +1112,9 @@ CODE # # This method acts on edge pair expressions and returns the first edges of the # edge pairs delivered by the expression. + # + # Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the + # edges are commutable. "first_edges" will deliver both edges for such edge pairs. # %DRC% # @name second_edges @@ -1120,6 +1123,10 @@ CODE # # This method acts on edge pair expressions and returns the second edges of the # edge pairs delivered by the expression. + # + # Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the + # edges are commutable. "second_edges" will not deliver edges for such edge pairs. + # Instead, "first_edges" will deliver both. def first_edges DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_first_edges, "first_edges") diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index d0e9e5d3e..0f1363f61 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -2755,6 +2755,9 @@ CODE # # Applies to edge pair collections only. # Returns the first edges of the edge pairs in the collection. + # + # Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the + # edges are commutable. "first_edges" will deliver both edges for such edge pairs. # %DRC% # @name second_edges @@ -2763,6 +2766,10 @@ CODE # # Applies to edge pair collections only. # Returns the second edges of the edge pairs in the collection. + # + # Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the + # edges are commutable. "second_edges" will not deliver edges for such edge pairs. + # Instead, "first_edges" will deliver both. %w(first_edges second_edges).each do |f| eval <<"CODE" diff --git a/src/lay/lay/doc/about/drc_ref_drc.xml b/src/lay/lay/doc/about/drc_ref_drc.xml index f2bddd69f..16683f7cb 100644 --- a/src/lay/lay/doc/about/drc_ref_drc.xml +++ b/src/lay/lay/doc/about/drc_ref_drc.xml @@ -553,6 +553,9 @@ The plain function is equivalent to "primary.extents".

This method acts on edge pair expressions and returns the first edges of the edge pairs delivered by the expression. +

+Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the +edges are commutable. "first_edges" will deliver both edges for such edge pairs.

"holes" - Selects all holes from the input polygons

@@ -860,6 +863,10 @@ The plain function is equivalent to "primary.rounded_corners".

This method acts on edge pair expressions and returns the second edges of the edge pairs delivered by the expression. +

+Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the +edges are commutable. "second_edges" will not deliver edges for such edge pairs. +Instead, "first_edges" will deliver both.

"sized" - Returns the sized version of the input

diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml index b82899503..f0964154e 100644 --- a/src/lay/lay/doc/about/drc_ref_layer.xml +++ b/src/lay/lay/doc/about/drc_ref_layer.xml @@ -1032,6 +1032,9 @@ The following images show the effect of the extents method:

Applies to edge pair collections only. Returns the first edges of the edge pairs in the collection. +

+Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the +edges are commutable. "first_edges" will deliver both edges for such edge pairs.

"flatten" - Flattens the layer

@@ -2178,6 +2181,10 @@ The following images shows the effect of the "scaled" method:

Applies to edge pair collections only. Returns the second edges of the edge pairs in the collection. +

+Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the +edges are commutable. "second_edges" will not deliver edges for such edge pairs. +Instead, "first_edges" will deliver both.

"select" - Selects edges, edge pairs or polygons based on evaluation of a block

diff --git a/testdata/drc/drcGenericTests_9.drc b/testdata/drc/drcGenericTests_9.drc index 78dd5cb5c..20f4924d9 100644 --- a/testdata/drc/drcGenericTests_9.drc +++ b/testdata/drc/drcGenericTests_9.drc @@ -20,6 +20,8 @@ l1.drc((space(projection) < 1.0).polygons).output(100, 0) l1.drc((space(projection) < 1.0).edges).output(101, 0) l1.drc((space(projection) < 1.0).first_edges).output(102, 0) l1.drc((space(projection) < 1.0).second_edges).output(103, 0) +l1.drc((sep(l2, projection) < 1.0).first_edges).output(104, 0) +l1.drc((sep(l2, projection) < 1.0).second_edges).output(105, 0) l2.drc(primary.edges).output(110, 0) l2.drc(primary.edges.extended_in(0.1)).output(111, 0) diff --git a/testdata/drc/drcGenericTests_au17.gds b/testdata/drc/drcGenericTests_au17.gds index 9e868c17a..f0bc2aedc 100644 Binary files a/testdata/drc/drcGenericTests_au17.gds and b/testdata/drc/drcGenericTests_au17.gds differ diff --git a/testdata/drc/drcGenericTests_au17d.gds b/testdata/drc/drcGenericTests_au17d.gds index 9f9b40744..fe85657e5 100644 Binary files a/testdata/drc/drcGenericTests_au17d.gds and b/testdata/drc/drcGenericTests_au17d.gds differ diff --git a/testdata/drc/drcGenericTests_au3d.gds b/testdata/drc/drcGenericTests_au3d.gds index 170651e20..64a67ad63 100644 Binary files a/testdata/drc/drcGenericTests_au3d.gds and b/testdata/drc/drcGenericTests_au3d.gds differ diff --git a/testdata/drc/drcGenericTests_au9.gds b/testdata/drc/drcGenericTests_au9.gds index f3ee703d2..7b1f2589e 100644 Binary files a/testdata/drc/drcGenericTests_au9.gds and b/testdata/drc/drcGenericTests_au9.gds differ diff --git a/testdata/drc/drcGenericTests_au9d.gds b/testdata/drc/drcGenericTests_au9d.gds index 0c417e794..3c102c9ee 100644 Binary files a/testdata/drc/drcGenericTests_au9d.gds and b/testdata/drc/drcGenericTests_au9d.gds differ diff --git a/testdata/drc/drcSimpleTests_au27.gds b/testdata/drc/drcSimpleTests_au27.gds index e36adc82a..69bd49a82 100644 Binary files a/testdata/drc/drcSimpleTests_au27.gds and b/testdata/drc/drcSimpleTests_au27.gds differ diff --git a/testdata/drc/drcSimpleTests_au27d.gds b/testdata/drc/drcSimpleTests_au27d.gds index c1d38d1eb..7e8b363d1 100644 Binary files a/testdata/drc/drcSimpleTests_au27d.gds and b/testdata/drc/drcSimpleTests_au27d.gds differ diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index f8915df92..ef395210f 100644 Binary files a/testdata/drc/drcSuiteTests_au1.oas and b/testdata/drc/drcSuiteTests_au1.oas differ diff --git a/testdata/drc/drcSuiteTests_au3.oas b/testdata/drc/drcSuiteTests_au3.oas index 003fd6382..4f5221a28 100644 Binary files a/testdata/drc/drcSuiteTests_au3.oas and b/testdata/drc/drcSuiteTests_au3.oas differ diff --git a/testdata/ruby/dbEdgePairTest.rb b/testdata/ruby/dbEdgePairTest.rb index 405cea188..e6f496281 100644 --- a/testdata/ruby/dbEdgePairTest.rb +++ b/testdata/ruby/dbEdgePairTest.rb @@ -163,6 +163,53 @@ class DBEdgePair_TestClass < TestBase end + # Symmetric edge pairs + def test_5 + + b1 = RBA::DEdgePair::new(RBA::DEdge::new(1, 2, 3, 4), RBA::DEdge::new(11, 12, 13, 14), false) + b1x = RBA::DEdgePair::new(RBA::DEdge::new(11, 12, 13, 14), RBA::DEdge::new(1, 2, 3, 4), false) + b2a = RBA::DEdgePair::new(RBA::DEdge::new(1, 2, 3, 4), RBA::DEdge::new(11, 12, 13, 14), true) + b2b = RBA::DEdgePair::new(RBA::DEdge::new(11, 12, 13, 14), RBA::DEdge::new(1, 2, 3, 4), true) + + assert_equal(b1.hash == b1x.hash, false) + assert_equal(b1.hash == b2a.hash, false) + assert_equal(b1.hash == b2b.hash, false) + assert_equal(b2a.hash == b2b.hash, true) + + assert_equal(b1 < b1x, true) + assert_equal(b1 == b1x, false) + assert_equal(b1 < b2a, true) + assert_equal(b1 == b2a, false) + assert_equal(b1 < b2b, true) + assert_equal(b2a < b2b, false) + assert_equal(b2a == b2b, true) + assert_equal(b2b < b2a, false) + + assert_equal(b1.to_s, "(1,2;3,4)/(11,12;13,14)") + assert_equal(b1x.to_s, "(11,12;13,14)/(1,2;3,4)") + assert_equal(b2a.to_s, "(1,2;3,4)|(11,12;13,14)") + assert_equal(b2b.to_s, "(1,2;3,4)|(11,12;13,14)") + + h = {} + h[b1] = 1 + h[b1x] = 2 + assert_equal(h.size, 2) + assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)/(11,12;13,14),(11,12;13,14)/(1,2;3,4)") + + h = {} + h[b1] = 1 + h[b2a] = 2 + assert_equal(h.size, 2) + assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)/(11,12;13,14),(1,2;3,4)|(11,12;13,14)") + + h = {} + h[b2a] = 1 + h[b2b] = 2 + assert_equal(h.size, 1) + assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)|(11,12;13,14)") + + end + end load("test_epilogue.rb") diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 9069a7f65..33554fac3 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -478,38 +478,38 @@ class DBRegion_TestClass < TestBase assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "") assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)") - assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)/(100,395;100,5)") - assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(100,380;100,20)") - assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Square, nil, nil, nil).to_s, "(120,20;120,380)/(100,400;100,0)") - assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)/(100,395;100,5)") - assert_equal((r1 | r2).merged.isolated_check(25, true, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)/(100,400;100,0)") + assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)|(100,395;100,5)") + assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,380;100,20)") + assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Square, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0)") + assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)|(100,395;100,5)") + assert_equal((r1 | r2).merged.isolated_check(25, true, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0)") assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, 0.0, nil, nil).to_s, "") assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 0, 300).to_s, "") - assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, 500).to_s, "(120,20;120,380)/(100,395;100,5)") - assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, nil).to_s, "(120,20;120,380)/(100,395;100,5)") + assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, 500).to_s, "(120,20;120,380)|(100,395;100,5)") + assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, nil).to_s, "(120,20;120,380)|(100,395;100,5)") - assert_equal((r1 | r2).merged.notch_check(25).to_s, "(0,200;50,200)/(50,220;10,220)") - assert_equal((r1 | r2).merged.notch_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)/(50,220;10,220)") - assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.notch_check(25).to_s, "(0,200;50,200)|(50,220;10,220)") + assert_equal((r1 | r2).merged.notch_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)|(50,220;10,220)") + assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)|(50,220;10,220)") assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "") - assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, nil).to_s, "(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, nil).to_s, "(0,200;50,200)|(50,220;10,220)") assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "") - assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)|(50,220;10,220)") assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, 40).to_s, "") - assert_equal((r1 | r2).merged.space_check(25).to_s, "(100,395;100,5)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)") - assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(100,380;100,20)/(120,20;120,380);(10,200;50,200)/(50,220;10,220)") - assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(100,400;100,0)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25).to_s, "(120,20;120,380)|(100,395;100,5);(0,200;50,200)|(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,380;100,20);(10,200;50,200)|(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0);(0,200;50,200)|(50,220;10,220)") assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "") - assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(100,400;100,0)/(120,20;120,380)") - assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)|(100,400;100,0)") + assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)|(50,220;10,220)") - assert_equal((r1 | r2).merged.width_check(60).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,253;100,167)") - assert_equal((r1 | r2).merged.width_check(60, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,220;100,200)") - assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,400;100,0)") + assert_equal((r1 | r2).merged.width_check(60).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,253;100,167)") + assert_equal((r1 | r2).merged.width_check(60, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,220;100,200)") + assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,400;100,0)") assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "") - assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)/(130,380;130,20)") - assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, 50).to_s, "(50,200;50,220)/(100,400;100,0)") + assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)|(130,380;130,20)") + assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, 50).to_s, "(50,200;50,220)|(100,400;100,0)") end