diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 3ac6682e7..1980af561 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -26,6 +26,7 @@ #include "dbFlatEdgePairs.h" #include "dbEmptyRegion.h" #include "dbRegion.h" +#include "dbRegionUtils.h" #include "dbShapeProcessor.h" #include "dbBoxConvert.h" #include "dbBoxScanner.h" @@ -92,60 +93,6 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const return edges; } -RegionDelegate * -AsIfFlatRegion::hulls () const -{ - std::auto_ptr new_region (new FlatRegion (false)); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - db::Polygon h; - h.assign_hull (p->begin_hull (), p->end_hull ()); - new_region->insert (h); - } - - return new_region.release (); -} - -RegionDelegate * -AsIfFlatRegion::holes () const -{ - std::auto_ptr new_region (new FlatRegion (false)); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - for (size_t i = 0; i < p->holes (); ++i) { - db::Polygon h; - h.assign_hull (p->begin_hole ((unsigned int) i), p->end_hole ((unsigned int) i)); - new_region->insert (h); - } - } - - return new_region.release (); -} - -RegionDelegate * -AsIfFlatRegion::rounded_corners (double rinner, double router, unsigned int n) const -{ - std::auto_ptr new_region (new FlatRegion (false)); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - new_region->insert (db::compute_rounded (*p, rinner, router, n)); - } - - return new_region.release (); -} - -RegionDelegate * -AsIfFlatRegion::smoothed (coord_type d) const -{ - std::auto_ptr new_region (new FlatRegion (false)); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - new_region->insert (db::smooth (*p, d)); - } - - return new_region.release (); -} - RegionDelegate * AsIfFlatRegion::in (const Region &other, bool invert) const { @@ -301,6 +248,25 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const return new_region.release (); } +RegionDelegate * +AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const +{ + std::auto_ptr new_region (new FlatRegion ()); + std::vector poly_res; + + for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { + + poly_res.clear (); + filter.process (*p, poly_res); + for (std::vector::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) { + new_region->insert (*pr); + } + + } + + return new_region.release (); +} + RegionDelegate * AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const { @@ -593,41 +559,6 @@ AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) return new_region.release (); } -/** - * @brief A helper class to implement the strange polygon detector - */ -struct DB_PUBLIC StrangePolygonInsideFunc -{ - inline bool operator() (int wc) const - { - return wc < 0 || wc > 1; - } -}; - -void -AsIfFlatRegion::produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes) -{ - EdgeProcessor ep; - ep.insert (poly); - - StrangePolygonInsideFunc inside; - db::GenericMerge op (inside); - db::ShapeGenerator pc (shapes, false); - db::PolygonGenerator pg (pc, false, false); - ep.process (pg, op); -} - -RegionDelegate * -AsIfFlatRegion::strange_polygon_check () const -{ - std::auto_ptr new_region (new FlatRegion (merged_semantics ())); - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - produce_shape_for_strange_polygon (*p, new_region->raw_polygons ()); - } - - return new_region.release (); -} - 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 { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index c414dafa0..21ad83c0f 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -36,329 +36,6 @@ 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 - */ -template -class DB_PUBLIC region_to_edge_interaction_filter - : public db::box_scanner_receiver2 -{ -public: - region_to_edge_interaction_filter (OutputContainer &output, bool inverse) - : mp_output (&output), m_inverse (inverse) - { - // .. nothing yet .. - } - - void preset (const db::Polygon *poly) - { - m_seen.insert (poly); - } - - void add (const db::Polygon *p, size_t, const db::Edge *e, size_t) - { - if ((m_seen.find (p) == m_seen.end ()) != m_inverse) { - - // A polygon and an edge interact if the edge is either inside completely - // of at least one edge of the polygon intersects with the edge - bool interacts = false; - if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) { - interacts = true; - } else { - for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) { - if ((*pe).intersect (*e)) { - interacts = true; - } - } - } - - if (interacts) { - if (m_inverse) { - m_seen.erase (p); - } else { - m_seen.insert (p); - mp_output->insert (*p); - } - } - - } - } - - void fill_output () - { - for (std::set::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) { - mp_output->insert (**p); - } - } - -private: - OutputContainer *mp_output; - std::set m_seen; - bool m_inverse; -}; - /** * @brief Provides default flat implementations */ @@ -430,6 +107,13 @@ public: virtual Edges edges (const EdgeFilterBase *) const; + virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) + { + return processed (filter); + } + + virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const; + virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) { return filtered (filter); @@ -454,8 +138,6 @@ public: virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; - virtual RegionDelegate *strange_polygon_check () const; - virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; @@ -521,11 +203,7 @@ public: return selected_interacting_generic (other, 0, false, true); } - virtual RegionDelegate *holes () const; - virtual RegionDelegate *hulls () const; virtual RegionDelegate *in (const Region &other, bool invert) const; - virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const; - virtual RegionDelegate *smoothed (coord_type d) const; virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; @@ -541,7 +219,6 @@ protected: RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; - static void produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes); template static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes); template diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 013b1d2e2..c6adaea0e 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -25,6 +25,7 @@ #include "dbDeepShapeStore.h" #include "dbEmptyRegion.h" #include "dbRegion.h" +#include "dbRegionUtils.h" #include "dbDeepEdges.h" #include "dbDeepEdgePairs.h" #include "dbShapeProcessor.h" @@ -902,6 +903,83 @@ DeepRegion::edges (const EdgeFilterBase *filter) const return db::Edges (res.release ()); } +RegionDelegate * +DeepRegion::process_in_place (const PolygonProcessorBase &filter) +{ + // TODO: implement to be really in-place + return processed (filter); +} + +RegionDelegate * +DeepRegion::processed (const PolygonProcessorBase &filter) const +{ + ensure_merged_polygons_valid (); + + std::auto_ptr vars; + if (filter.vars ()) { + + vars.reset (new db::VariantsCollectorBase (filter.vars ())); + + vars->collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); + + // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? + const_cast (m_merged_polygons).separate_variants (*vars); + + } + + db::Layout &layout = m_merged_polygons.layout (); + + std::vector poly_res; + + std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + if (vars.get ()) { + + const std::map &v = vars->variants (c->cell_index ()); + tl_assert (v.size () == size_t (1)); + const db::ICplxTrans &tr = v.begin ()->first; + db::ICplxTrans trinv = tr.inverted (); + + const db::Shapes &s = c->shapes (filter.requires_raw_input () ? m_deep_layer.layer () : m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + db::Polygon poly; + si->polygon (poly); + poly.transform (tr); + poly_res.clear (); + filter.process (poly, poly_res); + for (std::vector::const_iterator p = poly_res.begin (); p != poly_res.end (); ++p) { + st.insert (p->transformed (trinv)); + } + } + + } else { + + const db::Shapes &s = c->shapes (filter.requires_raw_input () ? m_deep_layer.layer () : m_merged_polygons.layer ()); + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + db::Polygon poly; + si->polygon (poly); + poly_res.clear (); + filter.process (poly, poly_res); + for (std::vector::const_iterator p = poly_res.begin (); p != poly_res.end (); ++p) { + st.insert (*p); + } + } + + } + + } + + if (filter.result_is_merged ()) { + res->set_is_merged (true); + } + return res.release (); +} + RegionDelegate * DeepRegion::filter_in_place (const PolygonFilterBase &filter) { @@ -1043,12 +1121,6 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const return res; } -RegionDelegate * -DeepRegion::strange_polygon_check () const -{ - throw tl::Exception (tl::to_string (tr ("A strange polygon check does not make sense on a processed region - polygons are already normalized"))); -} - RegionDelegate * DeepRegion::sized (coord_type d, unsigned int mode) const { @@ -1173,72 +1245,6 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const return res.release (); } -RegionDelegate * -DeepRegion::holes () const -{ - ensure_merged_polygons_valid (); - - db::Layout &layout = m_merged_polygons.layout (); - - std::vector pts; - - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - - const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); - db::PolygonRefToShapesGenerator pr (&layout, &st); - - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - for (size_t i = 0; i < si->holes (); ++i) { - db::Polygon h; - pts.clear (); - for (db::Shape::point_iterator p = si->begin_hole ((unsigned int) i); p != si->end_hole ((unsigned int) i); ++p) { - pts.push_back (*p); - } - h.assign_hull (pts.begin (), pts.end ()); - pr.put (h); - } - } - - } - - res->set_is_merged (true); - return res.release (); -} - -RegionDelegate * -DeepRegion::hulls () const -{ - ensure_merged_polygons_valid (); - - db::Layout &layout = m_merged_polygons.layout (); - - std::vector pts; - - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - - const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); - db::PolygonRefToShapesGenerator pr (&layout, &st); - - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - db::Polygon h; - pts.clear (); - for (db::Shape::point_iterator p = si->begin_hull (); p != si->end_hull (); ++p) { - pts.push_back (*p); - } - h.assign_hull (pts.begin (), pts.end ()); - pr.put (h); - } - - } - - res->set_is_merged (true); - return res.release (); -} - RegionDelegate * DeepRegion::in (const Region &other, bool invert) const { @@ -1246,79 +1252,6 @@ DeepRegion::in (const Region &other, bool invert) const return db::AsIfFlatRegion::in (other, invert); } -RegionDelegate * -DeepRegion::rounded_corners (double rinner, double router, unsigned int n) const -{ - ensure_merged_polygons_valid (); - - db::cell_variants_collector vars; - vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); - - // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? - const_cast (m_merged_polygons).separate_variants (vars); - - db::Layout &layout = m_merged_polygons.layout (); - - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - - const std::map &v = vars.variants (c->cell_index ()); - tl_assert (v.size () == size_t (1)); - double mag = v.begin ()->first.mag (); - db::Coord rinner_with_mag = db::coord_traits::rounded (rinner / mag); - db::Coord router_with_mag = db::coord_traits::rounded (router / mag); - - const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); - db::PolygonRefToShapesGenerator pr (&layout, &st); - - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - db::Polygon poly; - si->polygon (poly); - pr.put (db::compute_rounded (poly, rinner_with_mag, router_with_mag, n)); - } - - } - - return res.release (); -} - -RegionDelegate * -DeepRegion::smoothed (coord_type d) const -{ - ensure_merged_polygons_valid (); - - db::cell_variants_collector vars; - vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ()); - - // NOTE: m_merged_polygons is mutable, so why is the const_cast needed? - const_cast (m_merged_polygons).separate_variants (vars); - - db::Layout &layout = m_merged_polygons.layout (); - - std::auto_ptr res (new db::DeepRegion (m_merged_polygons.derived ())); - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - - const std::map &v = vars.variants (c->cell_index ()); - tl_assert (v.size () == size_t (1)); - double mag = v.begin ()->first.mag (); - db::Coord d_with_mag = db::coord_traits::rounded (d / mag); - - const db::Shapes &s = c->shapes (m_merged_polygons.layer ()); - db::Shapes &st = c->shapes (res->deep_layer ().layer ()); - db::PolygonRefToShapesGenerator pr (&layout, &st); - - for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - db::Polygon poly; - si->polygon (poly); - pr.put (db::smooth (poly, d_with_mag)); - } - - } - - return res.release (); -} - namespace { diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 153820931..83dee241a 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -138,6 +138,8 @@ public: virtual Edges edges (const EdgeFilterBase *) const; + virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter); + virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const; virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter); virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const; @@ -147,8 +149,6 @@ public: virtual RegionDelegate *merged () const; virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; - virtual RegionDelegate *strange_polygon_check () const; - virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; @@ -202,11 +202,7 @@ public: return selected_interacting_generic (other, 0, false, true); } - virtual RegionDelegate *holes () const; - virtual RegionDelegate *hulls () const; virtual RegionDelegate *in (const Region &other, bool invert) const; - virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const; - virtual RegionDelegate *smoothed (coord_type d) const; virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index ca8688d96..e6393a0a8 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -41,6 +41,7 @@ class EmptyEdgePairs; class Edges; class Region; class DeepShapeStore; +class TransformationReducer; /** * @brief An edge pair set iterator @@ -213,6 +214,7 @@ public: virtual ~EdgePairFilterBase () { } virtual bool selected (const db::EdgePair &edge) const = 0; + virtual const TransformationReducer *vars () const = 0; }; /** diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index ddde91409..78cfceffb 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -73,11 +73,11 @@ public: virtual RegionDelegate *snapped_in_place (db::Coord, db::Coord) { return this; } virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); } - virtual RegionDelegate *strange_polygon_check () const { return new EmptyRegion (); } - virtual Edges edges (const EdgeFilterBase *) const { return db::Edges (); } virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; } virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); } + virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; } + virtual RegionDelegate *processed (const PolygonProcessorBase &) const { return new EmptyRegion (); } virtual RegionDelegate *merged_in_place () { return this; } virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; } @@ -104,12 +104,7 @@ public: virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); } - - virtual RegionDelegate *holes () const { return new EmptyRegion (); } - virtual RegionDelegate *hulls () const { return new EmptyRegion (); } virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); } - virtual RegionDelegate *rounded_corners (double, double, unsigned int) const { return new EmptyRegion (); } - virtual RegionDelegate *smoothed (coord_type) const { return new EmptyRegion (); } virtual bool has_valid_polygons () const { return true; } virtual bool has_valid_merged_polygons () const { return true; } diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index c4c8d51b3..fe1979706 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -205,6 +205,34 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) return this; } +RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter) +{ + std::vector poly_res; + + polygon_iterator_type pw = m_polygons.get_layer ().begin (); + for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { + + poly_res.clear (); + filter.process (*p, poly_res); + + for (std::vector::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) { + if (pw == m_polygons.get_layer ().end ()) { + m_polygons.get_layer ().insert (*pr); + pw = m_polygons.get_layer ().end (); + } else { + m_polygons.get_layer ().replace (pw++, *pr); + } + } + + } + + m_polygons.get_layer ().erase (pw, m_polygons.get_layer ().end ()); + m_merged_polygons.clear (); + m_is_merged = filter.result_is_merged () && merged_semantics (); + + return this; +} + RegionDelegate *FlatRegion::merged_in_place () { if (! m_is_merged) { diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index 6ad08639d..5fe5e50ec 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -119,6 +119,7 @@ public: return db::AsIfFlatRegion::merged (min_coherence, min_wc); } + virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter); virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter); virtual RegionDelegate *add_in_place (const Region &other); diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 01b5392d9..c81df5f28 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -26,10 +26,144 @@ #include "dbEmptyRegion.h" #include "dbFlatRegion.h" #include "dbDeepRegion.h" +#include "dbPolygonTools.h" namespace db { +namespace +{ + +// ------------------------------------------------------------------------------------------------------------- +// Strange polygon processor + +/** + * @brief A helper class to implement the strange polygon detector + */ +struct DB_PUBLIC StrangePolygonInsideFunc +{ + inline bool operator() (int wc) const + { + return wc < 0 || wc > 1; + } +}; + +class StrangePolygonCheckProcessor + : public PolygonProcessorBase +{ +public: + StrangePolygonCheckProcessor () { } + + virtual void process (const db::Polygon &poly, std::vector &res) const + { + EdgeProcessor ep; + ep.insert (poly); + + StrangePolygonInsideFunc inside; + db::GenericMerge op (inside); + db::PolygonContainer pc (res, false); + db::PolygonGenerator pg (pc, false, false); + ep.process (pg, op); + } + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return false; } + virtual bool requires_raw_input () const { return true; } +}; + +// ------------------------------------------------------------------------------------------------------------- +// Smoothing processor + +class SmoothingProcessor + : public PolygonProcessorBase +{ +public: + SmoothingProcessor (db::Coord d) : m_d (d) { } + + virtual void process (const db::Polygon &poly, std::vector &res) const + { + res.push_back (db::smooth (poly, m_d)); + } + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return false; } + virtual bool requires_raw_input () const { return false; } + +private: + db::Coord m_d; + db::MagnificationReducer m_vars; +}; + +// ------------------------------------------------------------------------------------------------------------- +// Rounded corners processor + +class RoundedCornersProcessor + : public PolygonProcessorBase +{ +public: + RoundedCornersProcessor (double rinner, double router, unsigned int n) + : m_rinner (rinner), m_router (router), m_n (n) + { } + + virtual void process (const db::Polygon &poly, std::vector &res) const + { + res.push_back (db::compute_rounded (poly, m_rinner, m_router, m_n)); + } + + virtual const TransformationReducer *vars () const { return &m_vars; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } + +private: + double m_rinner, m_router; + unsigned int m_n; + db::MagnificationReducer m_vars; +}; + +// ------------------------------------------------------------------------------------------------------------- +// Holes decomposition processor + +class HolesExtractionProcessor + : public PolygonProcessorBase +{ +public: + HolesExtractionProcessor () { } + + virtual void process (const db::Polygon &poly, std::vector &res) const + { + for (size_t i = 0; i < poly.holes (); ++i) { + res.push_back (db::Polygon ()); + res.back ().assign_hull (poly.begin_hole ((unsigned int) i), poly.end_hole ((unsigned int) i)); + } + } + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } +}; + +// ------------------------------------------------------------------------------------------------------------- +// Hull extraction processor + +class HullExtractionProcessor + : public PolygonProcessorBase +{ +public: + HullExtractionProcessor () { } + + virtual void process (const db::Polygon &poly, std::vector &res) const + { + res.push_back (db::Polygon ()); + res.back ().assign_hull (poly.begin_hull (), poly.end_hull ()); + } + + virtual const TransformationReducer *vars () const { return 0; } + virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool requires_raw_input () const { return false; } +}; + +} + // ------------------------------------------------------------------------------------------------------------- // Region implementation @@ -174,6 +308,86 @@ Region::flat_region () return region; } +Region & +Region::size (coord_type d, unsigned int mode) +{ + set_delegate (mp_delegate->sized (d, mode)); + return *this; +} + +Region & +Region::size (coord_type dx, coord_type dy, unsigned int mode) +{ + set_delegate (mp_delegate->sized (dx, dy, mode)); + return *this; +} + +Region +Region::sized (coord_type d, unsigned int mode) const +{ + return Region (mp_delegate->sized (d, mode)); +} + +Region +Region::sized (coord_type dx, coord_type dy, unsigned int mode) const +{ + return Region (mp_delegate->sized (dx, dy, mode)); +} + +void +Region::round_corners (double rinner, double router, unsigned int n) +{ + process (RoundedCornersProcessor (rinner, router, n)); +} + +Region +Region::rounded_corners (double rinner, double router, unsigned int n) const +{ + return processed (RoundedCornersProcessor (rinner, router, n)); +} + +void +Region::smooth (coord_type d) +{ + process (SmoothingProcessor (d)); +} + +Region +Region::smoothed (coord_type d) const +{ + return processed (SmoothingProcessor (d)); +} + +void +Region::snap (db::Coord gx, db::Coord gy) +{ + set_delegate (mp_delegate->snapped_in_place (gx, gy)); +} + +Region +Region::snapped (db::Coord gx, db::Coord gy) const +{ + return Region (mp_delegate->snapped (gx, gy)); +} + +Region +Region::strange_polygon_check () const +{ + return Region (processed (StrangePolygonCheckProcessor ())); +} + +Region +Region::holes () const +{ + return Region (processed (HolesExtractionProcessor ())); +} + +Region +Region::hulls () const +{ + return Region (processed (HullExtractionProcessor ())); +} + } namespace tl diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 1bc381d95..a7bcb771e 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -42,19 +42,6 @@ class EmptyRegion; class DeepShapeStore; class TransformationReducer; -/** - * @brief A base class for polygon filters - */ -class DB_PUBLIC PolygonFilterBase -{ -public: - PolygonFilterBase () { } - virtual ~PolygonFilterBase () { } - - virtual bool selected (const db::Polygon &polygon) const = 0; - virtual const TransformationReducer *vars () const = 0; -}; - /** * @brief A region iterator * @@ -640,6 +627,39 @@ public: return Region (mp_delegate->filtered (filter)); } + /** + * @brief Processes the (merged) polygons + * + * This method will keep all polygons for which the processing filter returns true. + * The processing filter can apply modifications too. These modifications will be + * kept in the output region. + * + * Merged semantics applies. In merged semantics, the filter will run over + * all merged polygons. + */ + Region &process (const PolygonProcessorBase &filter) + { + set_delegate (mp_delegate->process_in_place (filter)); + return *this; + } + + /** + * @brief Returns the processed polygons + * + * This method will keep all polygons for which the processing filter returns true. + * The processing filter can apply modifications too. These modifications will be + * kept in the output region. + * + * Merged semantics applies. In merged semantics, the filter will run over + * all merged polygons. + * + * This method will return a new region with the modified and filtered polygons. + */ + Region processed (const PolygonProcessorBase &filter) const + { + return Region (mp_delegate->processed (filter)); + } + /** * @brief Applies a width check and returns EdgePairs which correspond to violation markers * @@ -844,18 +864,12 @@ public: * Snaps the vertices of the polygons to the specified grid. * different grids can be specified int x and y direction. */ - void snap (db::Coord gx, db::Coord gy) - { - set_delegate (mp_delegate->snapped_in_place (gx, gy)); - } + void snap (db::Coord gx, db::Coord gy); /** * @brief Returns the snapped region */ - Region snapped (db::Coord gx, db::Coord gy) const - { - return Region (mp_delegate->snapped (gx, gy)); - } + Region snapped (db::Coord gx, db::Coord gy) const; /** * @brief Performs a check for "strange" polygons @@ -865,10 +879,7 @@ public: * * Naturally this method will ignore the merged_semantics setting. */ - Region strange_polygon_check () const - { - return Region (mp_delegate->strange_polygon_check ()); - } + Region strange_polygon_check () const; /** * @brief Swap with the other region @@ -948,11 +959,7 @@ public: * @param mode The sizing mode (see EdgeProcessor) for a description of the sizing mode which controls the miter distance. * @return A reference to self */ - Region &size (coord_type d, unsigned int mode = 2) - { - set_delegate (mp_delegate->sized (d, mode)); - return *this; - } + Region &size (coord_type d, unsigned int mode = 2); /** * @brief Anisotropic sizing @@ -966,11 +973,7 @@ public: * @param dy The vertical sizing * @param mode The sizing mode (see EdgeProcessor) for a description of the sizing mode which controls the miter distance. */ - Region &size (coord_type dx, coord_type dy, unsigned int mode = 2) - { - set_delegate (mp_delegate->sized (dx, dy, mode)); - return *this; - } + Region &size (coord_type dx, coord_type dy, unsigned int mode = 2); /** * @brief Returns the sized region @@ -980,10 +983,7 @@ public: * * Merged semantics applies. */ - Region sized (coord_type d, unsigned int mode = 2) const - { - return Region (mp_delegate->sized (d, mode)); - } + Region sized (coord_type d, unsigned int mode = 2) const; /** * @brief Returns the sized region @@ -993,10 +993,7 @@ public: * * Merged semantics applies. */ - Region sized (coord_type dx, coord_type dy, unsigned int mode = 2) const - { - return Region (mp_delegate->sized (dx, dy, mode)); - } + Region sized (coord_type dx, coord_type dy, unsigned int mode = 2) const; /** * @brief Boolean AND operator @@ -1333,10 +1330,7 @@ public: * * Merged semantics applies. */ - Region holes () const - { - return Region (mp_delegate->holes ()); - } + Region holes () const; /** * @brief Returns the hulls @@ -1346,10 +1340,7 @@ public: * * Merged semantics applies. */ - Region hulls () const - { - return Region (mp_delegate->hulls ()); - } + Region hulls () const; /** * @brief Returns all polygons which are in the other region @@ -1374,36 +1365,24 @@ public: * @param router The outer radius in DBU units * @param n The number of points to use per circle */ - void round_corners (double rinner, double router, unsigned int n) - { - set_delegate (mp_delegate->rounded_corners (rinner, router, n)); - } + void round_corners (double rinner, double router, unsigned int n); /** * @brief Returns a new region with rounded corners (out of place) */ - Region rounded_corners (double rinner, double router, unsigned int n) const - { - return Region (mp_delegate->rounded_corners (rinner, router, n)); - } + Region rounded_corners (double rinner, double router, unsigned int n) const; /** * @brief Smoothes the region (in-place) */ - void smooth (coord_type d) - { - set_delegate (mp_delegate->smoothed (d)); - } + void smooth (coord_type d); /** * @brief Returns the smoothed region * * @param d The smoothing accuracy */ - Region smoothed (coord_type d) const - { - return Region (mp_delegate->smoothed (d)); - } + Region smoothed (coord_type d) const; /** * @brief Returns the nth polygon diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index fe1ffcb25..ed52b56d9 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -37,7 +37,34 @@ namespace db { class RecursiveShapeIterator; class EdgeFilterBase; -class PolygonFilterBase; + +/** + * @brief A base class for polygon filters + */ +class DB_PUBLIC PolygonFilterBase +{ +public: + PolygonFilterBase () { } + virtual ~PolygonFilterBase () { } + + virtual bool selected (const db::Polygon &polygon) const = 0; + virtual const TransformationReducer *vars () const = 0; +}; + +/** + * @brief A base class for polygon processors + */ +class DB_PUBLIC PolygonProcessorBase +{ +public: + PolygonProcessorBase () { } + virtual ~PolygonProcessorBase () { } + + virtual void process (const db::Polygon &polygon, std::vector &res) const = 0; + virtual const TransformationReducer *vars () const = 0; + virtual bool result_is_merged () const = 0; + virtual bool requires_raw_input () const = 0; +}; /** * @brief The region iterator delegate @@ -141,14 +168,14 @@ public: virtual Edges edges (const EdgeFilterBase *filter) const = 0; virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0; virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const = 0; + virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) = 0; + virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const = 0; virtual RegionDelegate *merged_in_place () = 0; virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) = 0; virtual RegionDelegate *merged () const = 0; virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const = 0; - virtual RegionDelegate *strange_polygon_check () const = 0; - virtual RegionDelegate *sized (coord_type d, unsigned int mode) const = 0; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const = 0; @@ -169,12 +196,7 @@ public: virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0; virtual RegionDelegate *selected_overlapping (const Region &other) const = 0; virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0; - - virtual RegionDelegate *holes () const = 0; - virtual RegionDelegate *hulls () const = 0; virtual RegionDelegate *in (const Region &other, bool invert) const = 0; - virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const = 0; - virtual RegionDelegate *smoothed (coord_type d) const = 0; virtual const db::Polygon *nth (size_t n) const = 0; virtual bool has_valid_polygons () const = 0; diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 7b3af0289..eb1114e1a 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -23,9 +23,306 @@ #include "dbRegionUtils.h" -namespace db { +namespace db +{ - // .. nothing yet .. +// ------------------------------------------------------------------------------------- +// Edge2EdgeCheckBase implementation + +Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers) + : mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), + m_pass (0) +{ + m_distance = check.distance (); +} + +bool +Edge2EdgeCheckBase::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) { + put (*ep); + } + ++d; + ++ep; + } + + } + + return false; +} + +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)) { + + // 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 +Edge2EdgeCheckBase::requires_different_layers () const +{ + return m_requires_different_layers; +} + +/** + * @brief Sets a value indicating whether the check requires different layers + */ +void +Edge2EdgeCheckBase::set_requires_different_layers (bool f) +{ + m_requires_different_layers = f; +} + +/** + * @brief Gets a value indicating whether the check requires different layers + */ +bool +Edge2EdgeCheckBase::different_polygons () const +{ + return m_different_polygons; +} + +/** + * @brief Sets a value indicating whether the check requires different layers + */ +void +Edge2EdgeCheckBase::set_different_polygons (bool f) +{ + m_different_polygons = f; +} + +/** + * @brief Gets the distance value + */ +EdgeRelationFilter::distance_type +Edge2EdgeCheckBase::distance () const +{ + return m_distance; +} + +// ------------------------------------------------------------------------------------- +// Poly2PolyCheckBase implementation + +Poly2PolyCheckBase::Poly2PolyCheckBase (Edge2EdgeCheckBase &output) + : mp_output (& output) +{ + // .. nothing yet .. +} + +void +Poly2PolyCheckBase::finish (const db::Polygon *o, size_t p) +{ + enter (*o, p); +} + +void +Poly2PolyCheckBase::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 +Poly2PolyCheckBase::add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2) +{ + enter (*o1, p1, *o2, p2); +} + +void +Poly2PolyCheckBase::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); + + } +} + +// ------------------------------------------------------------------------------------- +// RegionToEdgeInteractionFilterBase implementation + +RegionToEdgeInteractionFilterBase::RegionToEdgeInteractionFilterBase (bool inverse) + : m_inverse (inverse) +{ + // .. nothing yet .. +} + +void +RegionToEdgeInteractionFilterBase::preset (const db::Polygon *poly) +{ + m_seen.insert (poly); +} + +void +RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db::Edge *e, size_t) +{ + if ((m_seen.find (p) == m_seen.end ()) != m_inverse) { + + // A polygon and an edge interact if the edge is either inside completely + // of at least one edge of the polygon intersects with the edge + bool interacts = false; + if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) { + interacts = true; + } else { + for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) { + if ((*pe).intersect (*e)) { + interacts = true; + } + } + } + + if (interacts) { + if (m_inverse) { + m_seen.erase (p); + } else { + m_seen.insert (p); + put (*p); + } + } + + } +} + +void +RegionToEdgeInteractionFilterBase::fill_output () +{ + for (std::set::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) { + put (**p); + } +} } diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index e1eef0578..32d9b58b4 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbRegion.h" #include "dbCellVariants.h" +#include "dbBoxScanner.h" namespace db { @@ -310,6 +311,168 @@ private: db::MagnificationAndOrientationReducer m_anisotropic_vars; }; +/** + * @brief A helper class for the DRC functionality which acts as an edge pair receiver + */ +class Edge2EdgeCheckBase + : public db::box_scanner_receiver +{ +public: + Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers); + + /** + * @brief Call this to initiate a new pass until the return value is false + */ + bool prepare_next_pass (); + + /** + * @brief Reimplementation of the box_scanner_receiver interface + */ + void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2); + + /** + * @brief Gets a value indicating whether the check requires different layers + */ + bool requires_different_layers () const; + + /** + * @brief Sets a value indicating whether the check requires different layers + */ + void set_requires_different_layers (bool f); + + /** + * @brief Gets a value indicating whether the check requires different layers + */ + bool different_polygons () const; + + /** + * @brief Sets a value indicating whether the check requires different layers + */ + void set_different_polygons (bool f); + + /** + * @brief Gets the distance value + */ + EdgeRelationFilter::distance_type distance () const; + +protected: + virtual void put (const db::EdgePair &edge) const = 0; + +private: + const EdgeRelationFilter *mp_check; + 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 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) + { + // .. nothing yet .. + } + +protected: + void put (const db::EdgePair &edge) const + { + mp_output->insert (edge); + } + +private: + Output *mp_output; +}; + +/** + * @brief A helper class for the DRC functionality which acts as an edge pair receiver + */ +class Poly2PolyCheckBase + : public db::box_scanner_receiver +{ +public: + Poly2PolyCheckBase (Edge2EdgeCheckBase &output); + + void finish (const db::Polygon *o, size_t p); + void enter (const db::Polygon &o, size_t p); + void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2); + void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2); + +private: + db::Edge2EdgeCheckBase *mp_output; + db::box_scanner m_scanner; + std::vector m_edges; +}; + +/** + * @brief A helper class for the DRC functionality which acts as an edge pair receiver + */ +template +class poly2poly_check + : public Poly2PolyCheckBase +{ +public: + poly2poly_check (edge2edge_check &output) + : Poly2PolyCheckBase (output) + { + // .. nothing yet .. + } +}; + +/** + * @brief A helper class for the region to edge interaction functionality + */ +class DB_PUBLIC RegionToEdgeInteractionFilterBase + : public db::box_scanner_receiver2 +{ +public: + RegionToEdgeInteractionFilterBase (bool inverse); + + void preset (const db::Polygon *poly); + void add (const db::Polygon *p, size_t, const db::Edge *e, size_t); + void fill_output (); + +protected: + virtual void put (const db::Polygon &poly) const = 0; + +private: + std::set m_seen; + bool m_inverse; +}; + +/** + * @brief A helper class for the region to edge interaction functionality + */ +template +class DB_PUBLIC region_to_edge_interaction_filter + : public RegionToEdgeInteractionFilterBase +{ +public: + region_to_edge_interaction_filter (OutputContainer &output, bool inverse) + : RegionToEdgeInteractionFilterBase (inverse), mp_output (&output) + { + // .. nothing yet .. + } + +protected: + virtual void put (const db::Polygon &poly) const + { + mp_output->insert (poly); + } + +private: + OutputContainer *mp_output; +}; + } // namespace db #endif diff --git a/src/db/unit_tests/dbEdgePairs.cc b/src/db/unit_tests/dbEdgePairs.cc index 7b889d4a1..07583a268 100644 --- a/src/db/unit_tests/dbEdgePairs.cc +++ b/src/db/unit_tests/dbEdgePairs.cc @@ -112,6 +112,14 @@ struct EPTestFilter { return ep.first ().double_length () < 50; } + + const db::TransformationReducer *vars () const + { + return &m_vars; + } + +private: + db::MagnificationReducer m_vars; }; TEST(3) diff --git a/testdata/algo/deep_region_au11.gds b/testdata/algo/deep_region_au11.gds index 978dd07ad..764182714 100644 Binary files a/testdata/algo/deep_region_au11.gds and b/testdata/algo/deep_region_au11.gds differ