From 476a2b3f091fdc67f0b4baf995e7dcfb8156c78a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 2 Nov 2019 22:33:28 +0100 Subject: [PATCH] WIP: preparations for an extended width/space concept --- src/db/db/dbRegionUtils.cc | 150 +++++++++++++++++++++++++++---------- src/db/db/dbRegionUtils.h | 120 +++++++++++++++++++++++++++-- 2 files changed, 225 insertions(+), 45 deletions(-) diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 3214fa747..43e50b28c 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -22,6 +22,7 @@ #include "dbRegionUtils.h" +#include "dbEdgeBoolean.h" #include "tlSelect.h" namespace db @@ -30,9 +31,9 @@ namespace db // ------------------------------------------------------------------------------------- // Edge2EdgeCheckBase implementation -Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers) +Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding) : mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), - m_pass (0) + m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0) { m_distance = check.distance (); } @@ -44,22 +45,29 @@ Edge2EdgeCheckBase::prepare_next_pass () if (m_pass == 1) { - if (! m_ep.empty ()) { + if (m_with_shielding && ! m_ep.empty ()) { m_ep_discarded.resize (m_ep.size (), false); return true; } } else if (m_pass == 2) { - std::vector::const_iterator d = m_ep_discarded.begin (); - std::vector::const_iterator ep = m_ep.begin (); - while (ep != m_ep.end ()) { - tl_assert (d != m_ep_discarded.end ()); - if (! *d) { - put (*ep); + if (m_has_edge_pair_output) { + + std::vector::const_iterator d = m_ep_discarded.begin (); + std::vector::const_iterator ep = m_ep.begin (); + while (ep != m_ep.end ()) { + bool use_result = true; + if (d != m_ep_discarded.end ()) { + use_result = ! *d; + ++d; + } + if (use_result) { + put (*ep); + } + ++ep; } - ++d; - ++ep; + } } @@ -82,6 +90,18 @@ static inline bool shields (const db::EdgePair &ep, const db::Edge &q) } } +void +Edge2EdgeCheckBase::finish (const Edge *o, const size_t &p) +{ + if (m_has_negative_edge_output && m_pass == 1) { + + // no interaction at all: create a single-edged edge pair + int l = int (p & size_t (1)); + put_negative (*o, l); + + } +} + void Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2) { @@ -99,7 +119,8 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size if (mp_check->check (l1 <= l2 ? *o1 : *o2, l1 <= l2 ? *o2 : *o1, &ep)) { // found a violation: store inside the local buffer for now. In the second - // pass we will eliminate those which are shielded completely. + // pass we will eliminate those which are shielded completely (with shielding) + // and/or compute the negative edges. size_t n = m_ep.size (); m_ep.push_back (ep); m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n)); @@ -111,48 +132,97 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size } else { - // a simple (complete) shielding implementation which is based on the - // assumption that shielding is relevant as soon as a foreign edge cuts through - // both of the edge pair's connecting edges. + // set the discarded flags for shielded output + if (m_with_shielding) { - // TODO: this implementation does not take into account the nature of the - // EdgePair - because of "whole_edge" it may not reflect the part actually - // violating the distance. + // a simple (complete) shielding implementation which is based on the + // assumption that shielding is relevant as soon as a foreign edge cuts through + // both of the edge pair's connecting edges. - std::vector n1, n2; + // TODO: this implementation does not take into account the nature of the + // EdgePair - because of "whole_edge" it may not reflect the part actually + // violating the distance. - for (unsigned int p = 0; p < 2; ++p) { + std::vector n1, n2; + + for (unsigned int p = 0; p < 2; ++p) { + + std::pair k (*o1, p1); + for (std::multimap, size_t>::const_iterator i = m_e2ep.find (k); i != m_e2ep.end () && i->first == k; ++i) { + n1.push_back (i->second); + } + + std::sort (n1.begin (), n1.end ()); + + std::swap (o1, o2); + std::swap (p1, p2); + n1.swap (n2); - std::pair k (*o1, p1); - for (std::multimap, size_t>::const_iterator i = m_e2ep.find (k); i != m_e2ep.end () && i->first == k; ++i) { - n1.push_back (i->second); } - std::sort (n1.begin (), n1.end ()); + for (unsigned int p = 0; p < 2; ++p) { - std::swap (o1, o2); - std::swap (p1, p2); - n1.swap (n2); + std::vector nn; + std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn)); + + for (std::vector::const_iterator i = nn.begin (); i != nn.end (); ++i) { + if (! m_ep_discarded [*i]) { + db::EdgePair ep = m_ep [*i].normalized (); + if (shields (ep, *o2)) { + m_ep_discarded [*i] = true; + } + } + } + + std::swap (o1, o2); + std::swap (p1, p2); + n1.swap (n2); + + } } - for (unsigned int p = 0; p < 2; ++p) { + // prepare the negative edge output + if (m_has_negative_edge_output) { - std::vector nn; - std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn)); + // Overlap or inside checks require input from different layers + if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) { - for (std::vector::const_iterator i = nn.begin (); i != nn.end (); ++i) { - if (! m_ep_discarded [*i]) { - db::EdgePair ep = m_ep [*i].normalized (); - if (shields (ep, *o2)) { - m_ep_discarded [*i] = true; + for (int p = 0; p < 2; ++p) { + + std::pair k (*o1, p1); + std::multimap, size_t>::const_iterator i0 = m_e2ep.find (k); + + bool fully_removed = false; + for (std::multimap, size_t>::const_iterator i = i0; ! fully_removed && i != m_e2ep.end () && i->first == k; ++i) { + fully_removed = (m_ep [i->second].first () == *o1); } - } - } - std::swap (o1, o2); - std::swap (p1, p2); - n1.swap (n2); + if (! fully_removed) { + + std::set partial_edges; + + db::EdgeBooleanCluster > ec (&partial_edges, db::EdgeNot); + ec.add (o1, 0); + + for (std::multimap, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) { + ec.add (&m_ep [i->second].first (), 1); + } + + ec.finish (); + + for (std::set::const_iterator e = partial_edges.begin (); e != partial_edges.end (); ++e) { + put_negative (*e, p); + } + + std::swap (o1, o2); + std::swap (p1, p2); + + } + + } + + } } diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 46ef4d9cc..f80b9efe5 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -368,7 +368,7 @@ class DB_PUBLIC Edge2EdgeCheckBase : public db::box_scanner_receiver { public: - Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers); + Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding); /** * @brief Call this to initiate a new pass until the return value is false @@ -380,6 +380,11 @@ public: */ void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2); + /** + * @brief Reimplementation of the box_scanner_receiver interface + */ + void finish (const Edge *o, const size_t &); + /** * @brief Gets a value indicating whether the check requires different layers */ @@ -400,13 +405,37 @@ public: */ void set_different_polygons (bool f); + /** + * @brief Sets a flag indicating that this class wants negative edge output + */ + void set_has_negative_edge_output (bool f) + { + m_has_negative_edge_output = f; + } + + /** + * @brief Sets a flag indicating that this class wants normal edge pair output + */ + void set_has_edge_pair_output (bool f) + { + m_has_edge_pair_output = f; + } + /** * @brief Gets the distance value */ EdgeRelationFilter::distance_type distance () const; protected: - virtual void put (const db::EdgePair &edge) const = 0; + /** + * @brief Normal edge pair output (violations) + */ + virtual void put (const db::EdgePair & /*edge*/) const { } + + /** + * @brief Negative edge output + */ + virtual void put_negative (const db::Edge & /*edge*/, int /*layer*/) const { } private: const EdgeRelationFilter *mp_check; @@ -416,19 +445,24 @@ private: std::vector m_ep; std::multimap, size_t> m_e2ep; std::vector m_ep_discarded; + bool m_with_shielding; + bool m_has_edge_pair_output; + bool m_has_negative_edge_output; unsigned int m_pass; }; /** - * @brief A helper class for the DRC functionality which acts as an edge pair receiver + * @brief A helper class for the DRC functionality + * + * This class implements the edge-to-edge part of the polygon DRC. */ template class DB_PUBLIC_TEMPLATE edge2edge_check : public Edge2EdgeCheckBase { public: - edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers) - : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers), mp_output (&output) + 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 (&output) { // .. nothing yet .. } @@ -443,6 +477,82 @@ private: Output *mp_output; }; +/** + * @brief A helper class for the DRC functionality + * + * This class implements the edge-to-edge part of the polygon DRC. + * This version allows delivery of the negative edges. + */ +template +class DB_PUBLIC_TEMPLATE edge2edge_check_with_negative_output + : public Edge2EdgeCheckBase +{ +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) + : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), + mp_output (&output), + mp_l1_negative_output (&l1_negative_output), + mp_l2_negative_output (&l2_negative_output) + { + set_has_negative_edge_output (true); + } + +protected: + void put (const db::EdgePair &ep) const + { + mp_output->insert (ep); + } + + void put_negative (const db::Edge &edge, int layer) const + { + if (layer == 0) { + mp_l1_negative_output->insert (edge); + } + if (layer == 1) { + mp_l2_negative_output->insert (edge); + } + } + +private: + Output *mp_output; + NegativeEdgeOutput *mp_l1_negative_output, *mp_l2_negative_output; +}; + +/** + * @brief A helper class for the DRC functionality + * + * This class implements the edge-to-edge part of the polygon DRC. + * This version has only negative edge output. + */ +template +class DB_PUBLIC_TEMPLATE edge2edge_check_negative + : public Edge2EdgeCheckBase +{ +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), + mp_l1_negative_output (&l1_negative_output), + mp_l2_negative_output (&l2_negative_output) + { + set_has_negative_edge_output (true); + set_has_edge_pair_output (false); + } + +protected: + void put_negative (const db::Edge &edge, int layer) const + { + if (layer == 0) { + mp_l1_negative_output->insert (edge); + } + if (layer == 1) { + mp_l2_negative_output->insert (edge); + } + } + +private: + NegativeEdgeOutput *mp_l1_negative_output, *mp_l2_negative_output; +}; + /** * @brief A helper class for the DRC functionality which acts as an edge pair receiver */