diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 6ba256ae1..717ef2935 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -701,11 +701,12 @@ namespace * * If will perform a edge by edge check using the provided EdgeRelationFilter */ -class Edge2EdgeCheck +template +class edge2edge_check_for_edges : public db::box_scanner_receiver { public: - Edge2EdgeCheck (const EdgeRelationFilter &check, EdgePairs &output, bool requires_different_layers) + edge2edge_check_for_edges (const EdgeRelationFilter &check, Output &output, bool requires_different_layers) : mp_check (&check), mp_output (&output) { m_requires_different_layers = requires_different_layers; @@ -731,7 +732,7 @@ public: private: const EdgeRelationFilter *mp_check; - EdgePairs *mp_output; + Output *mp_output; bool m_requires_different_layers; }; @@ -771,7 +772,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co check.set_min_projection (min_projection); check.set_max_projection (max_projection); - Edge2EdgeCheck edge_check (check, result, other != 0); + edge2edge_check_for_edges edge_check (check, result, other != 0); scanner.process (edge_check, d, db::box_convert ()); return result; diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 989993c71..5445550ec 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -595,271 +595,6 @@ AsIfFlatRegion::strange_polygon_check () const return new_region.release (); } - -namespace { - -/** - * @brief A helper class for the DRC functionality which acts as an edge pair receiver - */ -class Edge2EdgeCheck - : public db::box_scanner_receiver -{ -public: - Edge2EdgeCheck (const EdgeRelationFilter &check, EdgePairs &output, bool different_polygons, bool requires_different_layers) - : mp_check (&check), mp_output (&output), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), - m_pass (0) - { - m_distance = check.distance (); - } - - bool prepare_next_pass () - { - ++m_pass; - - if (m_pass == 1) { - - if (! 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) { - mp_output->insert (*ep); - } - ++d; - ++ep; - } - - } - - return false; - } - - void 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)) { - - // ensure that the first check argument is of layer 1 and the second of - // layer 2 (unless both are of the same layer) - int l1 = int (p1 & size_t (1)); - int l2 = int (p2 & size_t (1)); - - db::EdgePair ep; - 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. - size_t n = m_ep.size (); - m_ep.push_back (ep); - m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n)); - m_e2ep.insert (std::make_pair (std::make_pair (*o2, p2), n)); - - } - - } - - } 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. - - // 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. - - 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); - - } - - for (unsigned int p = 0; p < 2; ++p) { - - 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 (db::Edge (ep.first ().p1 (), ep.second ().p2 ()).intersect (*o2) && - db::Edge (ep.second ().p1 (), ep.first ().p2 ()).intersect (*o2)) { - m_ep_discarded [*i] = true; - } - } - } - - std::swap (o1, o2); - std::swap (p1, p2); - n1.swap (n2); - - } - - } - - } - - /** - * @brief Gets a value indicating whether the check requires different layers - */ - bool requires_different_layers () const - { - return m_requires_different_layers; - } - - /** - * @brief Sets a value indicating whether the check requires different layers - */ - void set_requires_different_layers (bool f) - { - m_requires_different_layers = f; - } - - /** - * @brief Gets a value indicating whether the check requires different layers - */ - bool different_polygons () const - { - return m_different_polygons; - } - - /** - * @brief Sets a value indicating whether the check requires different layers - */ - void set_different_polygons (bool f) - { - m_different_polygons = f; - } - - /** - * @brief Gets the distance value - */ - EdgeRelationFilter::distance_type distance () const - { - return m_distance; - } - -private: - const EdgeRelationFilter *mp_check; - EdgePairs *mp_output; - bool m_requires_different_layers; - bool m_different_polygons; - EdgeRelationFilter::distance_type m_distance; - std::vector m_ep; - std::multimap, size_t> m_e2ep; - std::vector m_ep_discarded; - unsigned int m_pass; -}; - -/** - * @brief A helper class for the DRC functionality which acts as an edge pair receiver - */ -class Poly2PolyCheck - : public db::box_scanner_receiver -{ -public: - Poly2PolyCheck (Edge2EdgeCheck &output) - : mp_output (&output) - { - // .. nothing yet .. - } - - void finish (const db::Polygon *o, size_t p) - { - enter (*o, p); - } - - void enter (const db::Polygon &o, size_t p) - { - if (! mp_output->requires_different_layers () && ! mp_output->different_polygons ()) { - - // finally we check the polygons vs. itself for checks involving intra-polygon interactions - - m_scanner.clear (); - m_scanner.reserve (o.vertices ()); - - m_edges.clear (); - m_edges.reserve (o.vertices ()); - - for (db::Polygon::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) { - m_edges.push_back (*e); - m_scanner.insert (& m_edges.back (), p); - } - - tl_assert (m_edges.size () == o.vertices ()); - - m_scanner.process (*mp_output, mp_output->distance (), db::box_convert ()); - - } - } - - void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2) - { - enter (*o1, p1, *o2, p2); - } - - void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2) - { - if ((! mp_output->different_polygons () || p1 != p2) && (! mp_output->requires_different_layers () || ((p1 ^ p2) & 1) != 0)) { - - m_scanner.clear (); - m_scanner.reserve (o1.vertices () + o2.vertices ()); - - m_edges.clear (); - m_edges.reserve (o1.vertices () + o2.vertices ()); - - for (db::Polygon::polygon_edge_iterator e = o1.begin_edge (); ! e.at_end (); ++e) { - m_edges.push_back (*e); - m_scanner.insert (& m_edges.back (), p1); - } - - for (db::Polygon::polygon_edge_iterator e = o2.begin_edge (); ! e.at_end (); ++e) { - m_edges.push_back (*e); - m_scanner.insert (& m_edges.back (), p2); - } - - tl_assert (m_edges.size () == o1.vertices () + o2.vertices ()); - - // temporarily disable intra-polygon check in that step .. we do that later in finish() - // if required (#650). - bool no_intra = mp_output->different_polygons (); - mp_output->set_different_polygons (true); - - m_scanner.process (*mp_output, mp_output->distance (), db::box_convert ()); - - mp_output->set_different_polygons (no_intra); - - } - } - -private: - db::box_scanner m_scanner; - Edge2EdgeCheck *mp_output; - std::vector m_edges; -}; - -} - EdgePairs AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const { @@ -897,8 +632,8 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, check.set_min_projection (min_projection); check.set_max_projection (max_projection); - Edge2EdgeCheck edge_check (check, result, different_polygons, other != 0); - Poly2PolyCheck poly_check (edge_check); + edge2edge_check edge_check (check, result, different_polygons, other != 0); + poly2poly_check poly_check (edge_check); do { scanner.process (poly_check, d, db::box_convert ()); @@ -918,8 +653,8 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord check.set_min_projection (min_projection); check.set_max_projection (max_projection); - Edge2EdgeCheck edge_check (check, result, false, false); - Poly2PolyCheck poly_check (edge_check); + edge2edge_check edge_check (check, result, false, false); + poly2poly_check poly_check (edge_check); do { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 7b504287f..f3dfec779 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -30,11 +30,274 @@ #include "dbPolygon.h" #include "dbEdge.h" #include "dbBoxScanner.h" +#include "dbEdgePairRelations.h" #include namespace db { +/** + * @brief A helper class for the DRC functionality which acts as an edge pair receiver + */ +template +class edge2edge_check + : public db::box_scanner_receiver +{ +public: + edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers) + : mp_check (&check), mp_output (&output), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), + m_pass (0) + { + m_distance = check.distance (); + } + + bool prepare_next_pass () + { + ++m_pass; + + if (m_pass == 1) { + + if (! 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) { + mp_output->insert (*ep); + } + ++d; + ++ep; + } + + } + + return false; + } + + void 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)) { + + // ensure that the first check argument is of layer 1 and the second of + // layer 2 (unless both are of the same layer) + int l1 = int (p1 & size_t (1)); + int l2 = int (p2 & size_t (1)); + + db::EdgePair ep; + 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. + size_t n = m_ep.size (); + m_ep.push_back (ep); + m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n)); + m_e2ep.insert (std::make_pair (std::make_pair (*o2, p2), n)); + + } + + } + + } 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. + + // 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. + + 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); + + } + + for (unsigned int p = 0; p < 2; ++p) { + + 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 (db::Edge (ep.first ().p1 (), ep.second ().p2 ()).intersect (*o2) && + db::Edge (ep.second ().p1 (), ep.first ().p2 ()).intersect (*o2)) { + m_ep_discarded [*i] = true; + } + } + } + + std::swap (o1, o2); + std::swap (p1, p2); + n1.swap (n2); + + } + + } + + } + + /** + * @brief Gets a value indicating whether the check requires different layers + */ + bool requires_different_layers () const + { + return m_requires_different_layers; + } + + /** + * @brief Sets a value indicating whether the check requires different layers + */ + void set_requires_different_layers (bool f) + { + m_requires_different_layers = f; + } + + /** + * @brief Gets a value indicating whether the check requires different layers + */ + bool different_polygons () const + { + return m_different_polygons; + } + + /** + * @brief Sets a value indicating whether the check requires different layers + */ + void set_different_polygons (bool f) + { + m_different_polygons = f; + } + + /** + * @brief Gets the distance value + */ + EdgeRelationFilter::distance_type distance () const + { + return m_distance; + } + +private: + const EdgeRelationFilter *mp_check; + Output *mp_output; + bool m_requires_different_layers; + bool m_different_polygons; + EdgeRelationFilter::distance_type m_distance; + std::vector m_ep; + std::multimap, size_t> m_e2ep; + std::vector m_ep_discarded; + unsigned int m_pass; +}; + +/** + * @brief A helper class for the DRC functionality which acts as an edge pair receiver + */ +template +class poly2poly_check + : public db::box_scanner_receiver +{ +public: + poly2poly_check (edge2edge_check &output) + : mp_output (&output) + { + // .. nothing yet .. + } + + void finish (const db::Polygon *o, size_t p) + { + enter (*o, p); + } + + void enter (const db::Polygon &o, size_t p) + { + if (! mp_output->requires_different_layers () && ! mp_output->different_polygons ()) { + + // finally we check the polygons vs. itself for checks involving intra-polygon interactions + + m_scanner.clear (); + m_scanner.reserve (o.vertices ()); + + m_edges.clear (); + m_edges.reserve (o.vertices ()); + + for (db::Polygon::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) { + m_edges.push_back (*e); + m_scanner.insert (& m_edges.back (), p); + } + + tl_assert (m_edges.size () == o.vertices ()); + + m_scanner.process (*mp_output, mp_output->distance (), db::box_convert ()); + + } + } + + void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2) + { + enter (*o1, p1, *o2, p2); + } + + void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2) + { + if ((! mp_output->different_polygons () || p1 != p2) && (! mp_output->requires_different_layers () || ((p1 ^ p2) & 1) != 0)) { + + m_scanner.clear (); + m_scanner.reserve (o1.vertices () + o2.vertices ()); + + m_edges.clear (); + m_edges.reserve (o1.vertices () + o2.vertices ()); + + for (db::Polygon::polygon_edge_iterator e = o1.begin_edge (); ! e.at_end (); ++e) { + m_edges.push_back (*e); + m_scanner.insert (& m_edges.back (), p1); + } + + for (db::Polygon::polygon_edge_iterator e = o2.begin_edge (); ! e.at_end (); ++e) { + m_edges.push_back (*e); + m_scanner.insert (& m_edges.back (), p2); + } + + tl_assert (m_edges.size () == o1.vertices () + o2.vertices ()); + + // temporarily disable intra-polygon check in that step .. we do that later in finish() + // if required (#650). + bool no_intra = mp_output->different_polygons (); + mp_output->set_different_polygons (true); + + m_scanner.process (*mp_output, mp_output->distance (), db::box_convert ()); + + mp_output->set_different_polygons (no_intra); + + } + } + +private: + db::box_scanner m_scanner; + edge2edge_check *mp_output; + std::vector m_edges; +}; + /** * @brief A helper class for the region to edge interaction functionality */ diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 53b97f918..457252481 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -26,6 +26,7 @@ #include "dbEmptyRegion.h" #include "dbRegion.h" #include "dbDeepEdges.h" +#include "dbDeepEdgePairs.h" #include "dbShapeProcessor.h" #include "dbFlatRegion.h" #include "dbHierProcessor.h" @@ -1233,18 +1234,142 @@ DeepRegion::smoothed (coord_type d) const return res.release (); } +namespace +{ + +class CheckLocalOperation + : public local_operation +{ +public: + CheckLocalOperation (const EdgeRelationFilter &check, bool different_polygons) + : m_check (check), m_different_polygons (different_polygons) + { + // .. nothing yet .. + } + + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + edge2edge_check > edge_check (m_check, result, false, false); + poly2poly_check > poly_check (edge_check); + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + size_t n = 0; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) { + const db::PolygonRef &subject = interactions.subject_shape (i->first); + db::Polygon poly = subject.obj ().transformed (subject.trans ()); + poly_check.enter (poly, n); + n += 2; + } + + n = 1; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + db::Polygon poly = o->obj ().transformed (o->trans ()); + poly_check.enter (poly, n); + n += 2; + } + + db::box_scanner scanner; + + do { + scanner.process (poly_check, m_check.distance (), db::box_convert ()); + } while (edge_check.prepare_next_pass ()); + } + + virtual db::Coord dist () const + { + // TODO: will the distance be sufficient? Or should be take somewhat more? + return m_check.distance (); + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + return m_different_polygons ? Drop : Ignore; + } + + virtual std::string description () const + { + return tl::to_string (tr ("Generic DRC check")); + } + +private: + EdgeRelationFilter m_check; + bool m_different_polygons; +}; + +} + EdgePairs DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const { - // TODO: implement hierarchically - return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + const db::DeepRegion *other_deep = dynamic_cast (other->delegate ()); + if (! other_deep) { + return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + ensure_merged_polygons_valid (); + + EdgeRelationFilter check (rel, d, metrics); + check.set_whole_edges (whole_edges); + check.set_ignore_angle (ignore_angle); + check.set_min_projection (min_projection); + check.set_max_projection (max_projection); + + DeepLayer dl_out (m_deep_layer.derived ()); + std::auto_ptr res (new db::DeepEdgePairs (m_merged_polygons.derived ())); + + db::CheckLocalOperation op (check, different_polygons); + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); + + proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + return db::EdgePairs (res.release ()); } EdgePairs DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const { - // TODO: implement hierarchically - return db::AsIfFlatRegion::run_single_polygon_check (rel, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + ensure_merged_polygons_valid (); + + EdgeRelationFilter check (rel, d, metrics); + check.set_whole_edges (whole_edges); + check.set_ignore_angle (ignore_angle); + check.set_min_projection (min_projection); + check.set_max_projection (max_projection); + + db::Layout &layout = m_merged_polygons.layout (); + + std::auto_ptr res (new db::DeepEdgePairs (m_merged_polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const db::Shapes &shapes = c->shapes (m_merged_polygons.layer ()); + db::Shapes &result = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) { + + edge2edge_check edge_check (check, result, false, false); + poly2poly_check poly_check (edge_check); + + db::Polygon poly; + s->polygon (poly); + + do { + poly_check.enter (poly, 0); + } while (edge_check.prepare_next_pass ()); + + } + + } + + return db::EdgePairs (res.release ()); } namespace