From 8107e1bb516efea2de3e792c19c17921f9395b68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 7 Nov 2018 22:17:51 +0100 Subject: [PATCH] Refactoring: separated sources for db::Region --- src/db/db/db.pro | 14 +- src/db/db/dbAsIfFlatRegion.cc | 1492 +++++++++ src/db/db/dbAsIfFlatRegion.h | 226 ++ src/db/db/dbEdges.cc | 1 + src/db/db/dbEmptyRegion.cc | 98 + src/db/db/dbEmptyRegion.h | 130 + src/db/db/dbFlatRegion.cc | 432 +++ src/db/db/dbFlatRegion.h | 197 ++ src/db/db/dbOriginalLayerRegion.cc | 274 ++ src/db/db/dbOriginalLayerRegion.h | 83 + src/db/db/dbRegion.cc | 3909 +----------------------- src/db/db/dbRegion.h | 1877 +----------- src/db/db/dbRegionDelegate.cc | 91 + src/db/db/dbRegionDelegate.h | 206 ++ src/db/unit_tests/dbTilingProcessor.cc | 1 + 15 files changed, 3310 insertions(+), 5721 deletions(-) create mode 100644 src/db/db/dbAsIfFlatRegion.cc create mode 100644 src/db/db/dbAsIfFlatRegion.h create mode 100644 src/db/db/dbEmptyRegion.cc create mode 100644 src/db/db/dbEmptyRegion.h create mode 100644 src/db/db/dbFlatRegion.cc create mode 100644 src/db/db/dbFlatRegion.h create mode 100644 src/db/db/dbOriginalLayerRegion.cc create mode 100644 src/db/db/dbOriginalLayerRegion.h create mode 100644 src/db/db/dbRegionDelegate.cc create mode 100644 src/db/db/dbRegionDelegate.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 8c0a4e558..788335b11 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -119,7 +119,12 @@ SOURCES = \ gsiDeclDbVector.cc \ gsiDeclDbLayoutDiff.cc \ gsiDeclDbGlyphs.cc \ - dbConverters.cc + dbConverters.cc \ + dbAsIfFlatRegion.cc \ + dbEmptyRegion.cc \ + dbFlatRegion.cc \ + dbOriginalLayerRegion.cc \ + dbRegionDelegate.cc HEADERS = \ dbArray.h \ @@ -208,7 +213,12 @@ HEADERS = \ dbForceLink.h \ dbPlugin.h \ dbInit.h \ - dbConverters.h + dbConverters.h \ + dbAsIfFlatRegion.h \ + dbEmptyRegion.h \ + dbFlatRegion.h \ + dbOriginalLayerRegion.h \ + dbRegionDelegate.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc new file mode 100644 index 000000000..3f4b41003 --- /dev/null +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -0,0 +1,1492 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbAsIfFlatRegion.h" +#include "dbFlatRegion.h" +#include "dbEmptyRegion.h" +#include "dbRegion.h" +#include "dbShapeProcessor.h" +#include "dbBoxConvert.h" +#include "dbBoxScanner.h" +#include "dbClip.h" +#include "dbPolygonTools.h" + +#include + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// AsIfFlagRegion implementation + +AsIfFlatRegion::AsIfFlatRegion () + : RegionDelegate (), m_bbox_valid (false) +{ + // .. nothing yet .. +} + +AsIfFlatRegion::~AsIfFlatRegion () +{ + // .. nothing yet .. +} + +std::string +AsIfFlatRegion::to_string (size_t nmax) const +{ + std::ostringstream os; + RegionIterator p (begin ()); + bool first = true; + for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) { + if (! first) { + os << ";"; + } + first = false; + os << p->to_string (); + } + if (! p.at_end ()) { + os << "..."; + } + return os.str (); +} + +Edges +AsIfFlatRegion::edges (const EdgeFilterBase *filter) const +{ + Edges edges; + + size_t n = 0; + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + edges.reserve (n); + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { + if (! filter || filter->selected (*e)) { + edges.insert (*e); + } + } + } + + 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 +{ + std::set op; + for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) { + op.insert (*o); + } + + std::auto_ptr new_region (new FlatRegion (false)); + + for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) { + if ((op.find (*o) == op.end ()) == invert) { + new_region->insert (*o); + } + } + + return new_region.release (); +} + +size_t +AsIfFlatRegion::size () const +{ + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + ++n; + } + return n; +} + +bool +AsIfFlatRegion::is_box () const +{ + RegionIterator p (begin ()); + if (p.at_end ()) { + return false; + } else { + const db::Polygon &poly = *p; + ++p; + if (! p.at_end ()) { + return false; + } else { + return poly.is_box (); + } + } +} + +AsIfFlatRegion::area_type +AsIfFlatRegion::area (const db::Box &box) const +{ + area_type a = 0; + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + if (box.empty () || p->box ().inside (box)) { + a += p->area (); + } else { + std::vector clipped; + clip_poly (*p, box, clipped); + for (std::vector::const_iterator c = clipped.begin (); c != clipped.end (); ++c) { + a += c->area (); + } + } + } + + return a; +} + +AsIfFlatRegion::perimeter_type +AsIfFlatRegion::perimeter (const db::Box &box) const +{ + perimeter_type d = 0; + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + + if (box.empty () || p->box ().inside (box)) { + d += p->perimeter (); + } else { + + for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { + + if (box.empty ()) { + d += (*e).length (); + } else { + + std::pair ce = (*e).clipped (box); + if (ce.first) { + + db::Coord dx = ce.second.dx (); + db::Coord dy = ce.second.dy (); + db::Coord x = ce.second.p1 ().x (); + db::Coord y = ce.second.p1 ().y (); + if ((dx == 0 && x == box.left () && dy < 0) || + (dx == 0 && x == box.right () && dy > 0) || + (dy == 0 && y == box.top () && dx < 0) || + (dy == 0 && y == box.bottom () && dx > 0)) { + // not counted -> box is at outside side of the edge + } else { + d += ce.second.length (); + } + + } + + } + + } + + } + + } + + return d; +} + +Box AsIfFlatRegion::bbox () const +{ + if (! m_bbox_valid) { + m_bbox = compute_bbox (); + m_bbox_valid = true; + } + return m_bbox; +} + +Box AsIfFlatRegion::compute_bbox () const +{ + db::Box b; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + b += p->box (); + } + return b; +} + +void AsIfFlatRegion::update_bbox (const db::Box &b) +{ + m_bbox = b; + m_bbox_valid = true; +} + +void AsIfFlatRegion::invalidate_bbox () +{ + m_bbox_valid = false; +} + +RegionDelegate * +AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const +{ + std::auto_ptr new_region (new FlatRegion ()); + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + if (filter.selected (*p)) { + new_region->insert (*p); + } + } + + return new_region.release (); +} + +namespace +{ + +/** + * @brief A helper class for the region to edge interaction functionality + * + * Note: This special scanner uses pointers to two different objects: edges and polygons. + * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate + * pointers to edges. + * + * There is a special box converter which is able to sort that out as well. + */ +template +class region_to_edge_interaction_filter + : public db::box_scanner_receiver +{ +public: + region_to_edge_interaction_filter (OutputContainer &output) + : mp_output (&output), m_inverse (false) + { + // .. nothing yet .. + } + + region_to_edge_interaction_filter (OutputContainer &output, const db::RegionIterator &polygons) + : mp_output (&output), m_inverse (true) + { + for (db::RegionIterator p = polygons; ! p.at_end (); ++p) { + m_seen.insert (&*p); + } + } + + void add (const char *o1, size_t p1, const char *o2, size_t p2) + { + const db::Edge *e = 0; + const db::Polygon *p = 0; + + // Note: edges have property 0 and have even-valued pointers. + // Polygons have property 1 and odd-valued pointers. + if (p1 == 0 && p2 == 1) { + e = reinterpret_cast (o1); + p = reinterpret_cast (o2 - 1); + } else if (p1 == 1 && p2 == 0) { + e = reinterpret_cast (o2); + p = reinterpret_cast (o1 - 1); + } + + if (e && p && (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 A special box converter that splits the pointers into polygon and edge pointers + */ +struct EdgeOrRegionBoxConverter +{ + typedef db::Box box_type; + + db::Box operator() (const char &c) const + { + // Note: edges have property 0 and have even-valued pointers. + // Polygons have property 1 and odd-valued pointers. + const char *cp = &c; + if ((size_t (cp) & 1) == 1) { + // it's a polygon + return (reinterpret_cast (cp - 1))->box (); + } else { + // it's an edge + const db::Edge *e = reinterpret_cast (cp); + return db::Box (e->p1 (), e->p2 ()); + } + } +}; + +} + +RegionDelegate * +AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const +{ + if (other.empty ()) { + if (! inverse) { + return new EmptyRegion (); + } else { + return clone (); + } + } else if (empty ()) { + return clone (); + } + + db::box_scanner scanner (report_progress (), progress_desc ()); + scanner.reserve (size () + other.size ()); + + AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert ((char *) p.operator-> () + 1, 1); + } + + other.ensure_valid_merged_edges (); + for (Edges::const_iterator e = other.begin (); ! e.at_end (); ++e) { + scanner.insert ((char *) &*e, 0); + } + + std::auto_ptr output (new FlatRegion (false)); + EdgeOrRegionBoxConverter bc; + + if (! inverse) { + region_to_edge_interaction_filter filter (output->raw_polygons ()); + scanner.process (filter, 1, bc); + } else { + region_to_edge_interaction_filter filter (output->raw_polygons (), RegionIterator (begin_merged ())); + scanner.process (filter, 1, bc); + filter.fill_output (); + } + + return output.release (); +} + +RegionDelegate * +AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const +{ + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // shortcut + if (empty ()) { + return clone (); + } else if (other.empty ()) { + // clear, if b is empty and + // * mode is inside or interacting and inverse is false ("inside" or "interacting") + // * mode is outside and inverse is true ("not outside") + if ((mode <= 0) != inverse) { + return new EmptyRegion (); + } else { + return clone (); + } + } + + for (RegionIterator p = other.begin (); ! p.at_end (); ++p) { + if (p->box ().touches (bbox ())) { + ep.insert (*p, 0); + } + } + + size_t n = 1; + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { + if (mode > 0 || p->box ().touches (other.bbox ())) { + ep.insert (*p, n); + } + } + + db::InteractionDetector id (mode, 0); + id.set_include_touching (touching); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + std::auto_ptr output (new FlatRegion (false)); + + n = 0; + std::set selected; + for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { + ++n; + selected.insert (i->second); + } + + output->reserve (n); + + n = 1; + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { + if ((selected.find (n) == selected.end ()) == inverse) { + output->raw_polygons ().insert (*p); + } + } + + return output.release (); +} + +EdgePairs +AsIfFlatRegion::grid_check (db::Coord gx, db::Coord gy) const +{ + EdgePairs out; + + gx = std::max (db::Coord (1), gx); + gy = std::max (db::Coord (1), gy); + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + + for (size_t i = 0; i < p->holes () + 1; ++i) { + + db::Polygon::polygon_contour_iterator b, e; + + if (i == 0) { + b = p->begin_hull (); + e = p->end_hull (); + } else { + b = p->begin_hole ((unsigned int) (i - 1)); + e = p->end_hole ((unsigned int) (i - 1)); + } + + for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { + if (((*pt).x () % gx) != 0 || ((*pt).y () % gy) != 0) { + out.insert (EdgePair (db::Edge (*pt, *pt), db::Edge (*pt, *pt))); + } + } + + } + + } + + return out; +} + +static bool ac_less (double cos_a, bool gt180_a, double cos_b, bool gt180_b) +{ + if (gt180_a != gt180_b) { + return gt180_a < gt180_b; + } else { + if (gt180_a) { + return cos_a < cos_b - 1e-10; + } else { + return cos_a > cos_b + 1e-10; + } + } +} + +EdgePairs +AsIfFlatRegion::angle_check (double min, double max, bool inverse) const +{ + EdgePairs out; + + double cos_min = cos (std::max (0.0, std::min (360.0, min)) / 180.0 * M_PI); + double cos_max = cos (std::max (0.0, std::min (360.0, max)) / 180.0 * M_PI); + bool gt180_min = min > 180.0; + bool gt180_max = max > 180.0; + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + + for (size_t i = 0; i < p->holes () + 1; ++i) { + + const db::Polygon::contour_type *h = 0; + if (i == 0) { + h = &p->hull (); + } else { + h = &p->hole ((unsigned int) (i - 1)); + } + + size_t np = h->size (); + + for (size_t j = 0; j < np; ++j) { + + db::Edge e ((*h) [j], (*h) [(j + 1) % np]); + db::Edge ee (e.p2 (), (*h) [(j + 2) % np]); + double le = e.double_length (); + double lee = ee.double_length (); + + double cos_a = -db::sprod (e, ee) / (le * lee); + bool gt180_a = db::vprod_sign (e, ee) > 0; + + if ((ac_less (cos_a, gt180_a, cos_max, gt180_max) && !ac_less (cos_a, gt180_a, cos_min, gt180_min)) == !inverse) { + out.insert (EdgePair (e, ee)); + } + + } + + } + + } + + return out; +} + +static inline db::Coord snap_to_grid (db::Coord c, db::Coord g) +{ + // This form of snapping always snaps g/2 to right/top. + if (c < 0) { + c = -g * ((-c + (g - 1) / 2) / g); + } else { + c = g * ((c + g / 2) / g); + } + return c; +} + +RegionDelegate * +AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) +{ + std::auto_ptr new_region (new FlatRegion (merged_semantics ())); + + gx = std::max (db::Coord (1), gx); + gy = std::max (db::Coord (1), gy); + + std::vector pts; + + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + + db::Polygon pnew; + + for (size_t i = 0; i < p->holes () + 1; ++i) { + + pts.clear (); + + db::Polygon::polygon_contour_iterator b, e; + + if (i == 0) { + b = p->begin_hull (); + e = p->end_hull (); + } else { + b = p->begin_hole ((unsigned int) (i - 1)); + e = p->end_hole ((unsigned int) (i - 1)); + } + + for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { + pts.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy))); + } + + if (i == 0) { + pnew.assign_hull (pts.begin (), pts.end ()); + } else { + pnew.insert_hole (pts.begin (), pts.end ()); + } + + } + + new_region->raw_polygons ().insert (pnew); + + } + + return new_region.release (); +} + +namespace +{ + /** + * @brief A helper class to implement the strange polygon detector + */ + struct StrangePolygonInsideFunc + { + inline bool operator() (int wc) const + { + return wc < 0 || wc > 1; + } + }; +} + +RegionDelegate * +AsIfFlatRegion::strange_polygon_check () const +{ + EdgeProcessor ep; + std::auto_ptr new_region (new FlatRegion (merged_semantics ())); + + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + + ep.clear (); + ep.insert (*p); + + StrangePolygonInsideFunc inside; + db::GenericMerge op (inside); + db::ShapeGenerator pc (new_region->raw_polygons (), false); + db::PolygonGenerator pg (pc, false, false); + ep.process (pg, op); + } + + 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 +{ + EdgePairs result; + + db::box_scanner scanner (report_progress (), progress_desc ()); + scanner.reserve (size () + (other ? other->size () : 0)); + + AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); + + size_t n = 0; + for ( ; ! p.at_end (); ++p) { + scanner.insert (p.operator-> (), n); + n += 2; + } + + AddressablePolygonDelivery po; + + if (other) { + + po = other->addressable_merged_polygons (); + + n = 1; + for ( ; ! po.at_end (); ++po) { + scanner.insert (po.operator-> (), n); + n += 2; + } + + } + + EdgeRelationFilter check (rel, d, metrics); + check.set_include_zero (other != 0); + check.set_whole_edges (whole_edges); + check.set_ignore_angle (ignore_angle); + 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); + + do { + scanner.process (poly_check, d, db::box_convert ()); + } while (edge_check.prepare_next_pass ()); + + return result; +} + +EdgePairs +AsIfFlatRegion::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 +{ + EdgePairs result; + + 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); + + Edge2EdgeCheck edge_check (check, result, false, false); + Poly2PolyCheck poly_check (edge_check); + + do { + + size_t n = 0; + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + poly_check.enter (*p, n); + n += 2; + } + + } while (edge_check.prepare_next_pass ()); + + return result; +} + +RegionDelegate * +AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const +{ + if (empty ()) { + + return new EmptyRegion (); + + } else if (is_box ()) { + + // take box only if min_wc == 0, otherwise clear + if (min_wc > 0) { + return new EmptyRegion (); + } else { + return clone (); + } + + } else { + + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (true)); + + // and run the merge step + db::MergeOp op (min_wc); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::region_from_box (const db::Box &b) +{ + if (! b.empty () && b.width () > 0 && b.height () > 0) { + FlatRegion *new_region = new FlatRegion (); + new_region->insert (b); + return new_region; + } else { + return new EmptyRegion (); + } +} + +RegionDelegate * +AsIfFlatRegion::sized (coord_type d, unsigned int mode) const +{ + return sized (d, d, mode); +} + +RegionDelegate * +AsIfFlatRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const +{ + if (empty ()) { + + // ignore empty + return new EmptyRegion (); + + } else if (is_box () && mode >= 2) { + + // simplified handling for a box + db::Box b = bbox ().enlarged (db::Vector (dx, dy)); + return region_from_box (b); + + } else if (! merged_semantics ()) { + + // Generic case + std::auto_ptr new_region (new FlatRegion (false /*output isn't merged*/)); + + db::ShapeGenerator pc (new_region->raw_polygons (), false); + db::PolygonGenerator pg (pc, false, true); + db::SizingPolygonFilter sf (pg, dx, dy, mode); + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + sf.put (*p); + } + + return new_region.release (); + + } else { + + // Generic case - the size operation will merge first + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (false /*output isn't merged*/)); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/); + db::SizingPolygonFilter siz (pg2, dx, dy, mode); + db::PolygonGenerator pg (siz, false /*don't resolve holes*/, false /*min. coherence*/); + db::BooleanOp op (db::BooleanOp::Or); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::and_with (const Region &other) const +{ + if (empty () || other.empty ()) { + + // Nothing to do + return new EmptyRegion (); + + } else if (is_box () && other.is_box ()) { + + // Simplified handling for boxes + db::Box b = bbox (); + b &= other.bbox (); + return region_from_box (b); + + } else if (is_box () && ! other.strict_handling ()) { + + // map AND with box to clip .. + db::Box b = bbox (); + std::auto_ptr new_region (new FlatRegion (false)); + + std::vector clipped; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + clipped.clear (); + clip_poly (*p, b, clipped); + new_region->raw_polygons ().insert (clipped.begin (), clipped.end ()); + } + + return new_region.release (); + + } else if (other.is_box () && ! strict_handling ()) { + + // map AND with box to clip .. + db::Box b = other.bbox (); + std::auto_ptr new_region (new FlatRegion (false)); + + std::vector clipped; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + clipped.clear (); + clip_poly (*p, b, clipped); + new_region->raw_polygons ().insert (clipped.begin (), clipped.end ()); + } + + return new_region.release (); + + } else if (! bbox ().overlaps (other.bbox ())) { + + // Result will be nothing + return new EmptyRegion (); + + } else { + + // Generic case + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + n = 1; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (true)); + db::BooleanOp op (db::BooleanOp::And); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::not_with (const Region &other) const +{ + if (empty ()) { + + // Nothing to do + return new EmptyRegion (); + + } else if (other.empty () && ! strict_handling ()) { + + // Nothing to do + return clone (); + + } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling ()) { + + // Nothing to do + return clone (); + + } else { + + // Generic case + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + n = 1; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (true)); + db::BooleanOp op (db::BooleanOp::ANotB); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::xor_with (const Region &other) const +{ + if (empty () && ! other.strict_handling ()) { + + return other.delegate ()->clone (); + + } else if (other.empty () && ! strict_handling ()) { + + return clone (); + + } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling () && ! other.strict_handling ()) { + + // Simplified handling for disjunct case + return or_with (other); + + } else { + + // Generic case + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + n = 1; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (true)); + db::BooleanOp op (db::BooleanOp::Xor); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::or_with (const Region &other) const +{ + if (empty () && ! other.strict_handling ()) { + + return other.delegate ()->clone (); + + } else if (other.empty () && ! strict_handling ()) { + + // Nothing to do + return clone (); + + } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling () && ! other.strict_handling ()) { + + // Simplified handling for disjunct case + return add (other); + + } else { + + // Generic case + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + n = 1; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + + std::auto_ptr new_region (new FlatRegion (true)); + db::BooleanOp op (db::BooleanOp::Or); + db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + return new_region.release (); + + } +} + +RegionDelegate * +AsIfFlatRegion::add (const Region &other) const +{ + FlatRegion *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + std::auto_ptr new_region (new FlatRegion (*other_flat)); + new_region->set_is_merged (false); + new_region->invalidate_cache (); + + size_t n = new_region->raw_polygons ().size () + size (); + + new_region->reserve (n); + + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + new_region->raw_polygons ().insert (*p); + } + + return new_region.release (); + + } else { + + std::auto_ptr new_region (new FlatRegion (false /*not merged*/)); + + size_t n = size () + other.size (); + + new_region->reserve (n); + + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + new_region->raw_polygons ().insert (*p); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + new_region->raw_polygons ().insert (*p); + } + + return new_region.release (); + + } +} + +bool +AsIfFlatRegion::equals (const Region &other) const +{ + if (empty () != other.empty ()) { + return false; + } + if (size () != other.size ()) { + return false; + } + RegionIterator o1 (begin ()); + RegionIterator o2 (other.begin ()); + while (! o1.at_end () && ! o2.at_end ()) { + if (*o1 != *o2) { + return false; + } + ++o1; + ++o2; + } + return true; +} + +bool +AsIfFlatRegion::less (const Region &other) const +{ + if (empty () != other.empty ()) { + return empty () < other.empty (); + } + if (size () != other.size ()) { + return (size () < other.size ()); + } + RegionIterator o1 (begin ()); + RegionIterator o2 (other.begin ()); + while (! o1.at_end () && ! o2.at_end ()) { + if (*o1 != *o2) { + return *o1 < *o2; + } + ++o1; + ++o2; + } + return false; +} + +} + diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h new file mode 100644 index 000000000..e9cedaaa8 --- /dev/null +++ b/src/db/db/dbAsIfFlatRegion.h @@ -0,0 +1,226 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbAsIfFlatRegion +#define HDR_dbAsIfFlatRegion + +#include "dbCommon.h" + +#include "dbRegionDelegate.h" + +namespace db { + +/** + * @brief Provides default flat implementations + */ +class DB_PUBLIC AsIfFlatRegion + : public RegionDelegate +{ +public: + AsIfFlatRegion (); + virtual ~AsIfFlatRegion (); + + virtual bool is_box () const; + virtual size_t size () const; + + virtual area_type area (const db::Box &box) const; + virtual perimeter_type perimeter (const db::Box &box) const; + virtual Box bbox () const; + + virtual std::string to_string (size_t nmax) const; + + EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_single_polygon_check (db::WidthRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::SpaceRelation, false, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs isolated_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::SpaceRelation, true, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs notch_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_single_polygon_check (db::SpaceRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs enclosing_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::OverlapRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs overlap_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::WidthRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs separation_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::SpaceRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + EdgePairs inside_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::InsideRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs grid_check (db::Coord gx, db::Coord gy) const; + virtual EdgePairs angle_check (double min, double max, bool inverse) const; + + virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) + { + return snapped (gx, gy); + } + + virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy); + + virtual Edges edges (const EdgeFilterBase *) const; + + virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) + { + return filtered (filter); + } + + virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const; + + virtual RegionDelegate *merged_in_place () + { + return merged (); + } + + virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) + { + return merged (min_coherence, min_wc); + } + + virtual RegionDelegate *merged () const + { + return merged (min_coherence (), 0); + } + + 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; + + virtual RegionDelegate *and_with (const Region &other) const; + virtual RegionDelegate *not_with (const Region &other) const; + virtual RegionDelegate *xor_with (const Region &other) const; + virtual RegionDelegate *or_with (const Region &other) const; + + virtual RegionDelegate *add_in_place (const Region &other) + { + return add (other); + } + + virtual RegionDelegate *add (const Region &other) const; + + virtual RegionDelegate *selected_outside (const Region &other) const + { + return selected_interacting_generic (other, 1, false, false); + } + + virtual RegionDelegate *selected_not_outside (const Region &other) const + { + return selected_interacting_generic (other, 1, false, true); + } + + virtual RegionDelegate *selected_inside (const Region &other) const + { + return selected_interacting_generic (other, -1, true, false); + } + + virtual RegionDelegate *selected_not_inside (const Region &other) const + { + return selected_interacting_generic (other, -1, true, true); + } + + virtual RegionDelegate *selected_interacting (const Region &other) const + { + return selected_interacting_generic (other, 0, true, false); + } + + virtual RegionDelegate *selected_not_interacting (const Region &other) const + { + return selected_interacting_generic (other, 0, true, true); + } + + virtual RegionDelegate *selected_interacting (const Edges &other) const + { + return selected_interacting_generic (other, false); + } + + virtual RegionDelegate *selected_not_interacting (const Edges &other) const + { + return selected_interacting_generic (other, true); + } + + virtual RegionDelegate *selected_overlapping (const Region &other) const + { + return selected_interacting_generic (other, 0, false, false); + } + + virtual RegionDelegate *selected_not_overlapping (const Region &other) const + { + 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; + +protected: + void update_bbox (const db::Box &box); + void invalidate_bbox (); + +private: + AsIfFlatRegion &operator= (const AsIfFlatRegion &other); + + mutable bool m_bbox_valid; + mutable db::Box m_bbox; + + virtual db::Box compute_bbox () const; + static RegionDelegate *region_from_box (const db::Box &b); + + EdgePairs 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; + EdgePairs 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; + RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; + RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; +}; + +} + +#endif + diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index 42f770aff..7ef4b2ffd 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -28,6 +28,7 @@ #include "dbBoxConvert.h" #include "dbBoxScanner.h" #include "dbPolygonTools.h" +#include "dbShapeProcessor.h" #include "tlIntervalMap.h" #include "tlVariant.h" diff --git a/src/db/db/dbEmptyRegion.cc b/src/db/db/dbEmptyRegion.cc new file mode 100644 index 000000000..6389faa51 --- /dev/null +++ b/src/db/db/dbEmptyRegion.cc @@ -0,0 +1,98 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbEmptyRegion.h" +#include "dbRegion.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// EmptyRegion implementation + +EmptyRegion::EmptyRegion () +{ + // .. nothing yet .. +} + +EmptyRegion::~EmptyRegion () +{ + // .. nothing yet .. +} + +EmptyRegion::EmptyRegion (const EmptyRegion &other) + : RegionDelegate (other) +{ + // .. nothing yet .. +} + +RegionDelegate * +EmptyRegion::clone () const +{ + return new EmptyRegion (*this); +} + +RegionDelegate * +EmptyRegion::add_in_place (const Region &other) +{ + return add (other); +} + +RegionDelegate * +EmptyRegion::add (const Region &other) const +{ + return other.delegate ()->clone (); +} + +RegionDelegate * +EmptyRegion::xor_with (const Region &other) const +{ + return or_with (other); +} + +RegionDelegate * +EmptyRegion::or_with (const Region &other) const +{ + if (other.empty ()) { + return new EmptyRegion (); + } else if (! other.strict_handling ()) { + return other.delegate ()->clone (); + } else { + return other.delegate ()->merged (); + } +} + +bool +EmptyRegion::equals (const Region &other) const +{ + return other.empty (); +} + +bool +EmptyRegion::less (const Region &other) const +{ + return other.empty () ? false : true; +} + +} + diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h new file mode 100644 index 000000000..696853af1 --- /dev/null +++ b/src/db/db/dbEmptyRegion.h @@ -0,0 +1,130 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbEmptyRegion +#define HDR_dbEmptyRegion + +#include "dbCommon.h" +#include "dbRegionDelegate.h" + +namespace db { + +/** + * @brief An empty Region + */ +class DB_PUBLIC EmptyRegion + : public RegionDelegate +{ +public: + EmptyRegion (); + virtual ~EmptyRegion (); + + EmptyRegion (const EmptyRegion &other); + RegionDelegate *clone () const; + + virtual RegionIteratorDelegate *begin () const { return 0; } + virtual RegionIteratorDelegate *begin_merged () const { return 0; } + + virtual std::pair begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } + virtual std::pair begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } + + virtual bool empty () const { return true; } + virtual size_t size () const { return 0; } + virtual std::string to_string (size_t) const { return std::string (); } + + virtual bool is_box () const { return false; } + virtual bool is_merged () const { return true; } + virtual area_type area (const db::Box &) const { return 0; } + virtual perimeter_type perimeter (const db::Box &) const { return 0; } + + virtual Box bbox () const { return Box (); } + + virtual EdgePairs width_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs space_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs isolated_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs notch_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs enclosing_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs overlap_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs separation_check (const Region &, db::Coord, bool , metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs inside_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } + virtual EdgePairs grid_check (db::Coord, db::Coord) const { return EdgePairs (); } + virtual EdgePairs angle_check (double, double, bool) const { return EdgePairs (); } + + 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 *merged_in_place () { return this; } + virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; } + virtual RegionDelegate *merged () const { return new EmptyRegion (); } + virtual RegionDelegate *merged (bool, unsigned int) const { return new EmptyRegion (); } + + virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); } + virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); } + + virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *xor_with (const Region &other) const; + virtual RegionDelegate *or_with (const Region &other) const; + virtual RegionDelegate *add_in_place (const Region &other); + virtual RegionDelegate *add (const Region &other) const; + + virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_interacting (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); } + 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; } + virtual const db::Polygon *nth (size_t) const { tl_assert (false); } + + virtual const db::RecursiveShapeIterator *iter () const { return 0; } + + virtual bool equals (const Region &other) const; + virtual bool less (const Region &other) const; + +private: + EmptyRegion &operator= (const EmptyRegion &other); +}; + +} // namespace db + +#endif + diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc new file mode 100644 index 000000000..411dff8e5 --- /dev/null +++ b/src/db/db/dbFlatRegion.cc @@ -0,0 +1,432 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbFlatRegion.h" +#include "dbEmptyRegion.h" +#include "dbRegion.h" +#include "dbShapeProcessor.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// FlatRegion implementation + +FlatRegion::FlatRegion () + : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) +{ + init (); +} + +FlatRegion::~FlatRegion () +{ + // .. nothing yet .. +} + +FlatRegion::FlatRegion (const FlatRegion &other) + : AsIfFlatRegion (other), m_polygons (false), m_merged_polygons (false) +{ + init (); + + m_is_merged = other.m_is_merged; + m_polygons = other.m_polygons; + m_merged_polygons = other.m_merged_polygons; + m_merged_polygons_valid = other.m_merged_polygons_valid; +} + +FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) + : AsIfFlatRegion (), m_polygons (polygons), m_merged_polygons (false) +{ + init (); + + m_is_merged = is_merged; +} + +FlatRegion::FlatRegion (bool is_merged) + : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) +{ + init (); + + m_is_merged = is_merged; +} + +void FlatRegion::set_is_merged (bool m) +{ + m_is_merged = m; +} + +void FlatRegion::invalidate_cache () +{ + invalidate_bbox (); + m_merged_polygons.clear (); + m_merged_polygons_valid = false; +} + +void FlatRegion::init () +{ + m_is_merged = true; + m_merged_polygons_valid = false; +} + +void FlatRegion::merged_semantics_changed () +{ + m_merged_polygons.clear (); + m_merged_polygons_valid = false; +} + +void FlatRegion::reserve (size_t n) +{ + m_polygons.reserve (db::Polygon::tag (), n); +} + +void +FlatRegion::ensure_merged_polygons_valid () const +{ + if (! m_merged_polygons_valid) { + + m_merged_polygons.clear (); + + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + // and run the merge step + db::MergeOp op (0); + db::ShapeGenerator pc (m_merged_polygons); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + m_merged_polygons_valid = true; + + } +} + +RegionIteratorDelegate *FlatRegion::begin () const +{ + return new FlatRegionIterator (m_polygons.get_layer ().begin (), m_polygons.get_layer ().end ()); +} + +RegionIteratorDelegate *FlatRegion::begin_merged () const +{ + if (! merged_semantics () || m_is_merged) { + return begin (); + } else { + ensure_merged_polygons_valid (); + return new FlatRegionIterator (m_merged_polygons.get_layer ().begin (), m_merged_polygons.get_layer ().end ()); + } +} + +std::pair FlatRegion::begin_iter () const +{ + return std::make_pair (db::RecursiveShapeIterator (m_polygons), db::ICplxTrans ()); +} + +std::pair FlatRegion::begin_merged_iter () const +{ + if (! merged_semantics () || m_is_merged) { + return begin_iter (); + } else { + ensure_merged_polygons_valid (); + return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); + } +} + +bool FlatRegion::empty () const +{ + return m_polygons.empty (); +} + +size_t FlatRegion::size () const +{ + return m_polygons.size (); +} + +bool FlatRegion::is_merged () const +{ + return m_is_merged; +} + +Box FlatRegion::compute_bbox () const +{ + m_polygons.update_bbox (); + return m_polygons.bbox (); +} + +RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) +{ + polygon_iterator_type pw = m_polygons.get_layer ().begin (); + for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { + if (filter.selected (*p)) { + if (pw == m_polygons.get_layer ().end ()) { + m_polygons.get_layer ().insert (*p); + pw = m_polygons.get_layer ().end (); + } else { + m_polygons.get_layer ().replace (pw++, *p); + } + } + } + + m_polygons.get_layer ().erase (pw, m_polygons.get_layer ().end ()); + m_merged_polygons.clear (); + m_is_merged = merged_semantics (); + + return this; +} + +RegionDelegate *FlatRegion::merged_in_place () +{ + if (! m_is_merged) { + + if (m_merged_polygons_valid) { + + m_polygons.swap (m_merged_polygons); + m_merged_polygons.clear (); + m_is_merged = true; + return this; + + } else { + return merged_in_place (min_coherence (), 0); + } + + } else { + return this; + } +} + +RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc) +{ + if (empty ()) { + + // ignore empty + return new EmptyRegion (); + + } else if (is_box ()) { + + // take box only if min_wc == 0, otherwise clear + if (min_wc > 0) { + return new EmptyRegion (); + } + + } else { + + invalidate_cache (); + + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + // and run the merge step + db::MergeOp op (min_wc); + db::ShapeGenerator pc (m_polygons, true /*clear*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); + ep.process (pg, op); + + m_is_merged = true; + + } + + return this; +} + +RegionDelegate *FlatRegion::merged () const +{ + if (! m_is_merged) { + + if (m_merged_polygons_valid) { + return new FlatRegion (m_merged_polygons, true); + } else { + return AsIfFlatRegion::merged (min_coherence (), 0); + } + + } else { + return clone (); + } +} + +RegionDelegate *FlatRegion::add (const Region &other) const +{ + std::auto_ptr new_region (new FlatRegion (*this)); + new_region->invalidate_cache (); + new_region->set_is_merged (false); + + FlatRegion *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + new_region->raw_polygons ().insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); + + } else { + + size_t n = new_region->raw_polygons ().size (); + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + ++n; + } + + new_region->raw_polygons ().reserve (db::Polygon::tag (), n); + + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + new_region->raw_polygons ().insert (*p); + } + + } + + return new_region.release (); +} + +RegionDelegate *FlatRegion::add_in_place (const Region &other) +{ + invalidate_cache (); + m_is_merged = false; + + FlatRegion *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + m_polygons.insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); + + } else { + + size_t n = m_polygons.size (); + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + ++n; + } + + m_polygons.reserve (db::Polygon::tag (), n); + + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + m_polygons.insert (*p); + } + + } + + return this; +} + +const db::Polygon *FlatRegion::nth (size_t n) const +{ + return n < m_polygons.size () ? &m_polygons.get_layer ().begin () [n] : 0; +} + +bool FlatRegion::has_valid_polygons () const +{ + return true; +} + +bool FlatRegion::has_valid_merged_polygons () const +{ + return true; +} + +const db::RecursiveShapeIterator *FlatRegion::iter () const +{ + return 0; +} + +void +FlatRegion::insert (const db::Box &box) +{ + if (! box.empty () && box.width () > 0 && box.height () > 0) { + + if (empty ()) { + + m_polygons.insert (db::Polygon (box)); + m_is_merged = true; + update_bbox (box); + + } else { + + m_polygons.insert (db::Polygon (box)); + m_is_merged = false; + invalidate_cache (); + + } + + } +} + +void +FlatRegion::insert (const db::Path &path) +{ + if (path.points () > 0) { + m_polygons.insert (path.polygon ()); + m_is_merged = false; + invalidate_cache (); + } +} + +void +FlatRegion::insert (const db::Polygon &polygon) +{ + if (polygon.holes () > 0 || polygon.vertices () > 0) { + m_polygons.insert (polygon); + m_is_merged = false; + invalidate_cache (); + } +} + +void +FlatRegion::insert (const db::SimplePolygon &polygon) +{ + if (polygon.vertices () > 0) { + db::Polygon poly; + poly.assign_hull (polygon.begin_hull (), polygon.end_hull ()); + m_polygons.insert (poly); + m_is_merged = false; + invalidate_cache (); + } +} + +void +FlatRegion::insert (const db::Shape &shape) +{ + if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { + db::Polygon poly; + shape.polygon (poly); + m_polygons.insert (poly); + m_is_merged = false; + invalidate_cache (); + } +} + +} + diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h new file mode 100644 index 000000000..72e712a6d --- /dev/null +++ b/src/db/db/dbFlatRegion.h @@ -0,0 +1,197 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbFlatRegion +#define HDR_dbFlatRegion + +#include "dbCommon.h" + +#include "dbAsIfFlatRegion.h" +#include "dbShapes.h" +#include "dbShapes2.h" + +namespace db { + +/** + * @brief An iterator delegate for the flat region + */ +class DB_PUBLIC FlatRegionIterator + : public RegionIteratorDelegate +{ +public: + typedef db::layer polygon_layer_type; + typedef polygon_layer_type::iterator iterator_type; + + FlatRegionIterator (iterator_type from, iterator_type to) + : m_from (from), m_to (to) + { + // .. nothing yet .. + } + + virtual bool at_end () const + { + return m_from == m_to; + } + + virtual void increment () + { + ++m_from; + } + + virtual const value_type *get () const + { + return m_from.operator-> (); + } + + virtual RegionIteratorDelegate *clone () const + { + return new FlatRegionIterator (*this); + } + +private: + friend class Region; + + iterator_type m_from, m_to; +}; + +/** + * @brief A flat, polygon-set delegate + */ +class DB_PUBLIC FlatRegion + : public AsIfFlatRegion +{ +public: + typedef db::layer polygon_layer_type; + typedef polygon_layer_type::iterator polygon_iterator_type; + + FlatRegion (); + FlatRegion (const db::Shapes &polygons, bool is_merged); + FlatRegion (bool is_merged); + + FlatRegion (const FlatRegion &other); + + virtual ~FlatRegion (); + + RegionDelegate *clone () const + { + return new FlatRegion (*this); + } + + void reserve (size_t); + + virtual RegionIteratorDelegate *begin () const; + virtual RegionIteratorDelegate *begin_merged () const; + + virtual std::pair begin_iter () const; + virtual std::pair begin_merged_iter () const; + + virtual bool empty () const; + virtual size_t size () const; + virtual bool is_merged () const; + + virtual RegionDelegate *merged_in_place (); + virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); + virtual RegionDelegate *merged () const; + + virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter); + + virtual RegionDelegate *add_in_place (const Region &other); + virtual RegionDelegate *add (const Region &other) const; + + virtual const db::Polygon *nth (size_t n) const; + virtual bool has_valid_polygons () const; + virtual bool has_valid_merged_polygons () const; + + virtual const db::RecursiveShapeIterator *iter () const; + + void insert (const db::Box &box); + void insert (const db::Path &path); + void insert (const db::SimplePolygon &polygon); + void insert (const db::Polygon &polygon); + void insert (const db::Shape &shape); + + template + void insert (const db::Shape &shape, const T &trans) + { + if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { + db::Polygon poly; + shape.polygon (poly); + poly.transform (trans); + insert (poly); + } + } + + template + void insert (const Iter &b, const Iter &e) + { + reserve (size () + (e - b)); + for (Iter i = b; i != e; ++i) { + insert (*i); + } + } + + template + void insert_seq (const Iter &seq) + { + for (Iter i = seq; ! i.at_end (); ++i) { + insert (*i); + } + } + + template + void transform (const Trans &trans) + { + if (! trans.is_unity ()) { + for (polygon_iterator_type p = m_polygons.get_layer ().begin (); p != m_polygons.get_layer ().end (); ++p) { + m_polygons.get_layer ().replace (p, p->transformed (trans)); + } + invalidate_cache (); + } + } + +protected: + virtual void merged_semantics_changed (); + virtual Box compute_bbox () const; + void invalidate_cache (); + void set_is_merged (bool m); + +private: + friend class AsIfFlatRegion; + + db::Shapes &raw_polygons () { return m_polygons; } + + FlatRegion &operator= (const FlatRegion &other); + + bool m_is_merged; + mutable db::Shapes m_polygons; + mutable db::Shapes m_merged_polygons; + mutable bool m_merged_polygons_valid; + + void init (); + void ensure_merged_polygons_valid () const; +}; + +} + +#endif + diff --git a/src/db/db/dbOriginalLayerRegion.cc b/src/db/db/dbOriginalLayerRegion.cc new file mode 100644 index 000000000..7fbc11839 --- /dev/null +++ b/src/db/db/dbOriginalLayerRegion.cc @@ -0,0 +1,274 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbOriginalLayerRegion.h" +#include "dbFlatRegion.h" +#include "dbRegion.h" +#include "dbShapeProcessor.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// OriginalLayerRegion implementation + +namespace +{ + + class OriginalLayerRegionIterator + : public RegionIteratorDelegate + { + public: + OriginalLayerRegionIterator (const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans) + : m_rec_iter (iter), m_iter_trans (trans) + { + set (); + } + + virtual bool at_end () const + { + return m_rec_iter.at_end (); + } + + virtual void increment () + { + inc (); + set (); + } + + virtual const value_type *get () const + { + return &m_polygon; + } + + virtual RegionIteratorDelegate *clone () const + { + return new OriginalLayerRegionIterator (*this); + } + + private: + friend class Region; + + db::RecursiveShapeIterator m_rec_iter; + db::ICplxTrans m_iter_trans; + db::Polygon m_polygon; + + void set () + { + while (! m_rec_iter.at_end () && ! (m_rec_iter.shape ().is_polygon () || m_rec_iter.shape ().is_path () || m_rec_iter.shape ().is_box ())) { + ++m_rec_iter; + } + if (! m_rec_iter.at_end ()) { + m_rec_iter.shape ().polygon (m_polygon); + m_polygon.transform (m_iter_trans * m_rec_iter.trans (), false); + } + } + + void inc () + { + if (! m_rec_iter.at_end ()) { + ++m_rec_iter; + } + } + }; + +} + +OriginalLayerRegion::OriginalLayerRegion () + : AsIfFlatRegion (), m_merged_polygons (false) +{ + init (); +} + +OriginalLayerRegion::OriginalLayerRegion (const OriginalLayerRegion &other) + : AsIfFlatRegion (other), + m_is_merged (other.m_is_merged), + m_merged_polygons (other.m_merged_polygons), + m_merged_polygons_valid (other.m_merged_polygons_valid), + m_iter (other.m_iter), + m_iter_trans (other.m_iter_trans) +{ + // .. nothing yet .. +} + +OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged) + : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si) +{ + init (); + + m_is_merged = is_merged; +} + +OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) + : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si), m_iter_trans (trans) +{ + init (); + + m_is_merged = is_merged; + set_merged_semantics (merged_semantics); +} + +OriginalLayerRegion::~OriginalLayerRegion () +{ + // .. nothing yet .. +} + +RegionDelegate * +OriginalLayerRegion::clone () const +{ + return new OriginalLayerRegion (*this); +} + +RegionIteratorDelegate * +OriginalLayerRegion::begin () const +{ + return new OriginalLayerRegionIterator (m_iter, m_iter_trans); +} + +RegionIteratorDelegate * +OriginalLayerRegion::begin_merged () const +{ + if (! merged_semantics () || m_is_merged) { + return begin (); + } else { + ensure_merged_polygons_valid (); + return new FlatRegionIterator (m_merged_polygons.get_layer ().begin (), m_merged_polygons.get_layer ().end ()); + } +} + +std::pair +OriginalLayerRegion::begin_iter () const +{ + return std::make_pair (m_iter, m_iter_trans); +} + +std::pair +OriginalLayerRegion::begin_merged_iter () const +{ + if (! merged_semantics () || m_is_merged) { + return begin_iter (); + } else { + ensure_merged_polygons_valid (); + return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); + } +} + +bool +OriginalLayerRegion::empty () const +{ + return m_iter.at_end (); +} + +bool +OriginalLayerRegion::is_merged () const +{ + return m_is_merged; +} + +const db::Polygon * +OriginalLayerRegion::nth (size_t) const +{ + tl_assert (false); +} + +bool +OriginalLayerRegion::has_valid_polygons () const +{ + return false; +} + +bool +OriginalLayerRegion::has_valid_merged_polygons () const +{ + return merged_semantics () && ! m_is_merged; +} + +const db::RecursiveShapeIterator * +OriginalLayerRegion::iter () const +{ + return &m_iter; +} + +bool +OriginalLayerRegion::equals (const Region &other) const +{ + const OriginalLayerRegion *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { + return true; + } else { + return AsIfFlatRegion::equals (other); + } +} + +bool +OriginalLayerRegion::less (const Region &other) const +{ + const OriginalLayerRegion *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { + return false; + } else { + return AsIfFlatRegion::less (other); + } +} + +void +OriginalLayerRegion::init () +{ + m_is_merged = true; + m_merged_polygons_valid = false; +} + +void +OriginalLayerRegion::ensure_merged_polygons_valid () const +{ + if (! m_merged_polygons_valid) { + + m_merged_polygons.clear (); + + db::EdgeProcessor ep (report_progress (), progress_desc ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { + ep.insert (*p, n); + } + + // and run the merge step + db::MergeOp op (0); + db::ShapeGenerator pc (m_merged_polygons); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); + ep.process (pg, op); + + m_merged_polygons_valid = true; + + } +} + +} diff --git a/src/db/db/dbOriginalLayerRegion.h b/src/db/db/dbOriginalLayerRegion.h new file mode 100644 index 000000000..2584dda7b --- /dev/null +++ b/src/db/db/dbOriginalLayerRegion.h @@ -0,0 +1,83 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbOriginalLayerRegion +#define HDR_dbOriginalLayerRegion + +#include "dbCommon.h" + +#include "dbAsIfFlatRegion.h" + +namespace db { + +/** + * @brief An original layerregion based on a RecursiveShapeIterator + */ +class DB_PUBLIC OriginalLayerRegion + : public AsIfFlatRegion +{ +public: + OriginalLayerRegion (); + OriginalLayerRegion (const OriginalLayerRegion &other); + OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged = false); + OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false); + virtual ~OriginalLayerRegion (); + + RegionDelegate *clone () const; + + virtual RegionIteratorDelegate *begin () const; + virtual RegionIteratorDelegate *begin_merged () const; + + virtual std::pair begin_iter () const; + virtual std::pair begin_merged_iter () const; + + virtual bool empty () const; + + virtual bool is_merged () const; + + virtual const db::Polygon *nth (size_t n) const; + virtual bool has_valid_polygons () const; + virtual bool has_valid_merged_polygons () const; + + virtual const db::RecursiveShapeIterator *iter () const; + + virtual bool equals (const Region &other) const; + virtual bool less (const Region &other) const; + +private: + OriginalLayerRegion &operator= (const OriginalLayerRegion &other); + + bool m_is_merged; + mutable db::Shapes m_merged_polygons; + mutable bool m_merged_polygons_valid; + mutable db::RecursiveShapeIterator m_iter; + db::ICplxTrans m_iter_trans; + + void init (); + void ensure_merged_polygons_valid () const; +}; + +} + +#endif + diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 439772415..9dfff7aca 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -22,2290 +22,13 @@ #include "dbRegion.h" -#include "dbLayoutUtils.h" -#include "dbEdgeProcessor.h" -#include "dbEdgePairRelations.h" -#include "dbEdges.h" -#include "dbEdgePairs.h" -#include "dbBoxConvert.h" -#include "dbBoxScanner.h" -#include "dbClip.h" -#include "dbPolygonTools.h" - -#include "tlVariant.h" - -#include -#include +#include "dbOriginalLayerRegion.h" +#include "dbEmptyRegion.h" +#include "dbFlatRegion.h" namespace db { -// ------------------------------------------------------------------------------------------------------------- - -RegionDelegate::RegionDelegate () -{ - m_report_progress = false; - m_merged_semantics = true; - m_strict_handling = false; - m_merge_min_coherence = false; -} - -RegionDelegate::RegionDelegate (const RegionDelegate &other) -{ - operator= (other); -} - -RegionDelegate & -RegionDelegate::operator= (const RegionDelegate &other) -{ - if (this != &other) { - m_report_progress = other.m_report_progress; - m_merged_semantics = other.m_merged_semantics; - m_strict_handling = other.m_strict_handling; - m_merge_min_coherence = other.m_merge_min_coherence; - } - return *this; -} - -RegionDelegate::~RegionDelegate () -{ - // .. nothing yet .. -} - -void RegionDelegate::enable_progress (const std::string &progress_desc) -{ - m_report_progress = true; - m_progress_desc = progress_desc; -} - -void RegionDelegate::disable_progress () -{ - m_report_progress = false; -} - -void RegionDelegate::set_min_coherence (bool f) -{ - m_merge_min_coherence = f; -} - -void RegionDelegate::set_merged_semantics (bool f) -{ - if (f != m_merged_semantics) { - m_merged_semantics = f; - merged_semantics_changed (); - } -} - -void RegionDelegate::set_strict_handling (bool f) -{ - m_strict_handling = f; -} - -// ------------------------------------------------------------------------------------------------------------- -// EmptyRegion implementation - -EmptyRegion::EmptyRegion () -{ - // .. nothing yet .. -} - -EmptyRegion::~EmptyRegion () -{ - // .. nothing yet .. -} - -EmptyRegion::EmptyRegion (const EmptyRegion &other) - : RegionDelegate (other) -{ - // .. nothing yet .. -} - -RegionDelegate * -EmptyRegion::clone () const -{ - return new EmptyRegion (*this); -} - -RegionDelegate * -EmptyRegion::add_in_place (const Region &other) -{ - return add (other); -} - -RegionDelegate * -EmptyRegion::add (const Region &other) const -{ - return other.delegate ()->clone (); -} - -RegionDelegate * -EmptyRegion::xor_with (const Region &other) const -{ - return or_with (other); -} - -RegionDelegate * -EmptyRegion::or_with (const Region &other) const -{ - if (other.empty ()) { - return new EmptyRegion (); - } else if (! other.strict_handling ()) { - return other.delegate ()->clone (); - } else { - return other.delegate ()->merged (); - } -} - -bool -EmptyRegion::equals (const Region &other) const -{ - return other.empty (); -} - -bool -EmptyRegion::less (const Region &other) const -{ - return other.empty () ? false : true; -} - -// ------------------------------------------------------------------------------------------------------------- -// AsIfFlagRegion implementation - -AsIfFlatRegion::AsIfFlatRegion () - : RegionDelegate (), m_bbox_valid (false) -{ - // .. nothing yet .. -} - -AsIfFlatRegion::~AsIfFlatRegion () -{ - // .. nothing yet .. -} - -std::string -AsIfFlatRegion::to_string (size_t nmax) const -{ - std::ostringstream os; - RegionIterator p (begin ()); - bool first = true; - for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) { - if (! first) { - os << ";"; - } - first = false; - os << p->to_string (); - } - if (! p.at_end ()) { - os << "..."; - } - return os.str (); -} - -Edges -AsIfFlatRegion::edges (const EdgeFilterBase *filter) const -{ - Edges edges; - - size_t n = 0; - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - edges.reserve (n); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - if (! filter || filter->selected (*e)) { - edges.insert (*e); - } - } - } - - 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 -{ - std::set op; - for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) { - op.insert (*o); - } - - std::auto_ptr new_region (new FlatRegion (false)); - - for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) { - if ((op.find (*o) == op.end ()) == invert) { - new_region->insert (*o); - } - } - - return new_region.release (); -} - -size_t -AsIfFlatRegion::size () const -{ - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - ++n; - } - return n; -} - -bool -AsIfFlatRegion::is_box () const -{ - RegionIterator p (begin ()); - if (p.at_end ()) { - return false; - } else { - const db::Polygon &poly = *p; - ++p; - if (! p.at_end ()) { - return false; - } else { - return poly.is_box (); - } - } -} - -AsIfFlatRegion::area_type -AsIfFlatRegion::area (const db::Box &box) const -{ - area_type a = 0; - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (box.empty () || p->box ().inside (box)) { - a += p->area (); - } else { - std::vector clipped; - clip_poly (*p, box, clipped); - for (std::vector::const_iterator c = clipped.begin (); c != clipped.end (); ++c) { - a += c->area (); - } - } - } - - return a; -} - -AsIfFlatRegion::perimeter_type -AsIfFlatRegion::perimeter (const db::Box &box) const -{ - perimeter_type d = 0; - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - - if (box.empty () || p->box ().inside (box)) { - d += p->perimeter (); - } else { - - for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - - if (box.empty ()) { - d += (*e).length (); - } else { - - std::pair ce = (*e).clipped (box); - if (ce.first) { - - db::Coord dx = ce.second.dx (); - db::Coord dy = ce.second.dy (); - db::Coord x = ce.second.p1 ().x (); - db::Coord y = ce.second.p1 ().y (); - if ((dx == 0 && x == box.left () && dy < 0) || - (dx == 0 && x == box.right () && dy > 0) || - (dy == 0 && y == box.top () && dx < 0) || - (dy == 0 && y == box.bottom () && dx > 0)) { - // not counted -> box is at outside side of the edge - } else { - d += ce.second.length (); - } - - } - - } - - } - - } - - } - - return d; -} - -Box AsIfFlatRegion::bbox () const -{ - if (! m_bbox_valid) { - m_bbox = compute_bbox (); - m_bbox_valid = true; - } - return m_bbox; -} - -Box AsIfFlatRegion::compute_bbox () const -{ - db::Box b; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - b += p->box (); - } - return b; -} - -void AsIfFlatRegion::update_bbox (const db::Box &b) -{ - m_bbox = b; - m_bbox_valid = true; -} - -void AsIfFlatRegion::invalidate_bbox () -{ - m_bbox_valid = false; -} - -RegionDelegate * -AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const -{ - std::auto_ptr new_region (new FlatRegion ()); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { - new_region->insert (*p); - } - } - - return new_region.release (); -} - -namespace -{ - -/** - * @brief A helper class for the region to edge interaction functionality - * - * Note: This special scanner uses pointers to two different objects: edges and polygons. - * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate - * pointers to edges. - * - * There is a special box converter which is able to sort that out as well. - */ -template -class region_to_edge_interaction_filter - : public db::box_scanner_receiver -{ -public: - region_to_edge_interaction_filter (OutputContainer &output) - : mp_output (&output), m_inverse (false) - { - // .. nothing yet .. - } - - region_to_edge_interaction_filter (OutputContainer &output, const db::RegionIterator &polygons) - : mp_output (&output), m_inverse (true) - { - for (db::RegionIterator p = polygons; ! p.at_end (); ++p) { - m_seen.insert (&*p); - } - } - - void add (const char *o1, size_t p1, const char *o2, size_t p2) - { - const db::Edge *e = 0; - const db::Polygon *p = 0; - - // Note: edges have property 0 and have even-valued pointers. - // Polygons have property 1 and odd-valued pointers. - if (p1 == 0 && p2 == 1) { - e = reinterpret_cast (o1); - p = reinterpret_cast (o2 - 1); - } else if (p1 == 1 && p2 == 0) { - e = reinterpret_cast (o2); - p = reinterpret_cast (o1 - 1); - } - - if (e && p && (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 A special box converter that splits the pointers into polygon and edge pointers - */ -struct EdgeOrRegionBoxConverter -{ - typedef db::Box box_type; - - db::Box operator() (const char &c) const - { - // Note: edges have property 0 and have even-valued pointers. - // Polygons have property 1 and odd-valued pointers. - const char *cp = &c; - if ((size_t (cp) & 1) == 1) { - // it's a polygon - return (reinterpret_cast (cp - 1))->box (); - } else { - // it's an edge - const db::Edge *e = reinterpret_cast (cp); - return db::Box (e->p1 (), e->p2 ()); - } - } -}; - -} - -RegionDelegate * -AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const -{ - if (other.empty ()) { - if (! inverse) { - return new EmptyRegion (); - } else { - return clone (); - } - } else if (empty ()) { - return clone (); - } - - db::box_scanner scanner (report_progress (), progress_desc ()); - scanner.reserve (size () + other.size ()); - - AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); - - for ( ; ! p.at_end (); ++p) { - scanner.insert ((char *) p.operator-> () + 1, 1); - } - - other.ensure_valid_merged_edges (); - for (Edges::const_iterator e = other.begin (); ! e.at_end (); ++e) { - scanner.insert ((char *) &*e, 0); - } - - std::auto_ptr output (new FlatRegion (false)); - EdgeOrRegionBoxConverter bc; - - if (! inverse) { - region_to_edge_interaction_filter filter (output->raw_polygons ()); - scanner.process (filter, 1, bc); - } else { - region_to_edge_interaction_filter filter (output->raw_polygons (), RegionIterator (begin_merged ())); - scanner.process (filter, 1, bc); - filter.fill_output (); - } - - return output.release (); -} - -RegionDelegate * -AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const -{ - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // shortcut - if (empty ()) { - return clone (); - } else if (other.empty ()) { - // clear, if b is empty and - // * mode is inside or interacting and inverse is false ("inside" or "interacting") - // * mode is outside and inverse is true ("not outside") - if ((mode <= 0) != inverse) { - return new EmptyRegion (); - } else { - return clone (); - } - } - - for (RegionIterator p = other.begin (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, 0); - } - } - - size_t n = 1; - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { - if (mode > 0 || p->box ().touches (other.bbox ())) { - ep.insert (*p, n); - } - } - - db::InteractionDetector id (mode, 0); - id.set_include_touching (touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - std::auto_ptr output (new FlatRegion (false)); - - n = 0; - std::set selected; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { - ++n; - selected.insert (i->second); - } - - output->reserve (n); - - n = 1; - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { - if ((selected.find (n) == selected.end ()) == inverse) { - output->raw_polygons ().insert (*p); - } - } - - return output.release (); -} - -EdgePairs -AsIfFlatRegion::grid_check (db::Coord gx, db::Coord gy) const -{ - EdgePairs out; - - gx = std::max (db::Coord (1), gx); - gy = std::max (db::Coord (1), gy); - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - db::Polygon::polygon_contour_iterator b, e; - - if (i == 0) { - b = p->begin_hull (); - e = p->end_hull (); - } else { - b = p->begin_hole ((unsigned int) (i - 1)); - e = p->end_hole ((unsigned int) (i - 1)); - } - - for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { - if (((*pt).x () % gx) != 0 || ((*pt).y () % gy) != 0) { - out.insert (EdgePair (db::Edge (*pt, *pt), db::Edge (*pt, *pt))); - } - } - - } - - } - - return out; -} - -static bool ac_less (double cos_a, bool gt180_a, double cos_b, bool gt180_b) -{ - if (gt180_a != gt180_b) { - return gt180_a < gt180_b; - } else { - if (gt180_a) { - return cos_a < cos_b - 1e-10; - } else { - return cos_a > cos_b + 1e-10; - } - } -} - -EdgePairs -AsIfFlatRegion::angle_check (double min, double max, bool inverse) const -{ - EdgePairs out; - - double cos_min = cos (std::max (0.0, std::min (360.0, min)) / 180.0 * M_PI); - double cos_max = cos (std::max (0.0, std::min (360.0, max)) / 180.0 * M_PI); - bool gt180_min = min > 180.0; - bool gt180_max = max > 180.0; - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - const db::Polygon::contour_type *h = 0; - if (i == 0) { - h = &p->hull (); - } else { - h = &p->hole ((unsigned int) (i - 1)); - } - - size_t np = h->size (); - - for (size_t j = 0; j < np; ++j) { - - db::Edge e ((*h) [j], (*h) [(j + 1) % np]); - db::Edge ee (e.p2 (), (*h) [(j + 2) % np]); - double le = e.double_length (); - double lee = ee.double_length (); - - double cos_a = -db::sprod (e, ee) / (le * lee); - bool gt180_a = db::vprod_sign (e, ee) > 0; - - if ((ac_less (cos_a, gt180_a, cos_max, gt180_max) && !ac_less (cos_a, gt180_a, cos_min, gt180_min)) == !inverse) { - out.insert (EdgePair (e, ee)); - } - - } - - } - - } - - return out; -} - -static inline db::Coord snap_to_grid (db::Coord c, db::Coord g) -{ - // This form of snapping always snaps g/2 to right/top. - if (c < 0) { - c = -g * ((-c + (g - 1) / 2) / g); - } else { - c = g * ((c + g / 2) / g); - } - return c; -} - -RegionDelegate * -AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy) -{ - std::auto_ptr new_region (new FlatRegion (merged_semantics ())); - - gx = std::max (db::Coord (1), gx); - gy = std::max (db::Coord (1), gy); - - std::vector pts; - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - - db::Polygon pnew; - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - pts.clear (); - - db::Polygon::polygon_contour_iterator b, e; - - if (i == 0) { - b = p->begin_hull (); - e = p->end_hull (); - } else { - b = p->begin_hole ((unsigned int) (i - 1)); - e = p->end_hole ((unsigned int) (i - 1)); - } - - for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { - pts.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy))); - } - - if (i == 0) { - pnew.assign_hull (pts.begin (), pts.end ()); - } else { - pnew.insert_hole (pts.begin (), pts.end ()); - } - - } - - new_region->raw_polygons ().insert (pnew); - - } - - return new_region.release (); -} - -namespace -{ - /** - * @brief A helper class to implement the strange polygon detector - */ - struct StrangePolygonInsideFunc - { - inline bool operator() (int wc) const - { - return wc < 0 || wc > 1; - } - }; -} - -RegionDelegate * -AsIfFlatRegion::strange_polygon_check () const -{ - EdgeProcessor ep; - std::auto_ptr new_region (new FlatRegion (merged_semantics ())); - - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - - ep.clear (); - ep.insert (*p); - - StrangePolygonInsideFunc inside; - db::GenericMerge op (inside); - db::ShapeGenerator pc (new_region->raw_polygons (), false); - db::PolygonGenerator pg (pc, false, false); - ep.process (pg, op); - } - - 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 -{ - EdgePairs result; - - db::box_scanner scanner (report_progress (), progress_desc ()); - scanner.reserve (size () + (other ? other->size () : 0)); - - AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); - - size_t n = 0; - for ( ; ! p.at_end (); ++p) { - scanner.insert (p.operator-> (), n); - n += 2; - } - - AddressablePolygonDelivery po; - - if (other) { - - po = other->addressable_merged_polygons (); - - n = 1; - for ( ; ! po.at_end (); ++po) { - scanner.insert (po.operator-> (), n); - n += 2; - } - - } - - EdgeRelationFilter check (rel, d, metrics); - check.set_include_zero (other != 0); - check.set_whole_edges (whole_edges); - check.set_ignore_angle (ignore_angle); - 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); - - do { - scanner.process (poly_check, d, db::box_convert ()); - } while (edge_check.prepare_next_pass ()); - - return result; -} - -EdgePairs -AsIfFlatRegion::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 -{ - EdgePairs result; - - 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); - - Edge2EdgeCheck edge_check (check, result, false, false); - Poly2PolyCheck poly_check (edge_check); - - do { - - size_t n = 0; - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - poly_check.enter (*p, n); - n += 2; - } - - } while (edge_check.prepare_next_pass ()); - - return result; -} - -RegionDelegate * -AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const -{ - if (empty ()) { - - return new EmptyRegion (); - - } else if (is_box ()) { - - // take box only if min_wc == 0, otherwise clear - if (min_wc > 0) { - return new EmptyRegion (); - } else { - return clone (); - } - - } else { - - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (true)); - - // and run the merge step - db::MergeOp op (min_wc); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::region_from_box (const db::Box &b) -{ - if (! b.empty () && b.width () > 0 && b.height () > 0) { - FlatRegion *new_region = new FlatRegion (); - new_region->insert (b); - return new_region; - } else { - return new EmptyRegion (); - } -} - -RegionDelegate * -AsIfFlatRegion::sized (coord_type d, unsigned int mode) const -{ - return sized (d, d, mode); -} - -RegionDelegate * -AsIfFlatRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const -{ - if (empty ()) { - - // ignore empty - return new EmptyRegion (); - - } else if (is_box () && mode >= 2) { - - // simplified handling for a box - db::Box b = bbox ().enlarged (db::Vector (dx, dy)); - return region_from_box (b); - - } else if (! merged_semantics ()) { - - // Generic case - std::auto_ptr new_region (new FlatRegion (false /*output isn't merged*/)); - - db::ShapeGenerator pc (new_region->raw_polygons (), false); - db::PolygonGenerator pg (pc, false, true); - db::SizingPolygonFilter sf (pg, dx, dy, mode); - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - sf.put (*p); - } - - return new_region.release (); - - } else { - - // Generic case - the size operation will merge first - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (false /*output isn't merged*/)); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/); - db::SizingPolygonFilter siz (pg2, dx, dy, mode); - db::PolygonGenerator pg (siz, false /*don't resolve holes*/, false /*min. coherence*/); - db::BooleanOp op (db::BooleanOp::Or); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::and_with (const Region &other) const -{ - if (empty () || other.empty ()) { - - // Nothing to do - return new EmptyRegion (); - - } else if (is_box () && other.is_box ()) { - - // Simplified handling for boxes - db::Box b = bbox (); - b &= other.bbox (); - return region_from_box (b); - - } else if (is_box () && ! other.strict_handling ()) { - - // map AND with box to clip .. - db::Box b = bbox (); - std::auto_ptr new_region (new FlatRegion (false)); - - std::vector clipped; - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - clipped.clear (); - clip_poly (*p, b, clipped); - new_region->raw_polygons ().insert (clipped.begin (), clipped.end ()); - } - - return new_region.release (); - - } else if (other.is_box () && ! strict_handling ()) { - - // map AND with box to clip .. - db::Box b = other.bbox (); - std::auto_ptr new_region (new FlatRegion (false)); - - std::vector clipped; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - clipped.clear (); - clip_poly (*p, b, clipped); - new_region->raw_polygons ().insert (clipped.begin (), clipped.end ()); - } - - return new_region.release (); - - } else if (! bbox ().overlaps (other.bbox ())) { - - // Result will be nothing - return new EmptyRegion (); - - } else { - - // Generic case - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (true)); - db::BooleanOp op (db::BooleanOp::And); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::not_with (const Region &other) const -{ - if (empty ()) { - - // Nothing to do - return new EmptyRegion (); - - } else if (other.empty () && ! strict_handling ()) { - - // Nothing to do - return clone (); - - } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling ()) { - - // Nothing to do - return clone (); - - } else { - - // Generic case - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (true)); - db::BooleanOp op (db::BooleanOp::ANotB); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::xor_with (const Region &other) const -{ - if (empty () && ! other.strict_handling ()) { - - return other.delegate ()->clone (); - - } else if (other.empty () && ! strict_handling ()) { - - return clone (); - - } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling () && ! other.strict_handling ()) { - - // Simplified handling for disjunct case - return or_with (other); - - } else { - - // Generic case - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (true)); - db::BooleanOp op (db::BooleanOp::Xor); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::or_with (const Region &other) const -{ - if (empty () && ! other.strict_handling ()) { - - return other.delegate ()->clone (); - - } else if (other.empty () && ! strict_handling ()) { - - // Nothing to do - return clone (); - - } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling () && ! other.strict_handling ()) { - - // Simplified handling for disjunct case - return add (other); - - } else { - - // Generic case - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - std::auto_ptr new_region (new FlatRegion (true)); - db::BooleanOp op (db::BooleanOp::Or); - db::ShapeGenerator pc (new_region->raw_polygons (), true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - return new_region.release (); - - } -} - -RegionDelegate * -AsIfFlatRegion::add (const Region &other) const -{ - FlatRegion *other_flat = dynamic_cast (other.delegate ()); - if (other_flat) { - - std::auto_ptr new_region (new FlatRegion (*other_flat)); - new_region->set_is_merged (false); - new_region->invalidate_cache (); - - size_t n = new_region->raw_polygons ().size () + size (); - - new_region->reserve (n); - - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - new_region->raw_polygons ().insert (*p); - } - - return new_region.release (); - - } else { - - std::auto_ptr new_region (new FlatRegion (false /*not merged*/)); - - size_t n = size () + other.size (); - - new_region->reserve (n); - - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - new_region->raw_polygons ().insert (*p); - } - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - new_region->raw_polygons ().insert (*p); - } - - return new_region.release (); - - } -} - -bool -AsIfFlatRegion::equals (const Region &other) const -{ - if (empty () != other.empty ()) { - return false; - } - if (size () != other.size ()) { - return false; - } - RegionIterator o1 (begin ()); - RegionIterator o2 (other.begin ()); - while (! o1.at_end () && ! o2.at_end ()) { - if (*o1 != *o2) { - return false; - } - ++o1; - ++o2; - } - return true; -} - -bool -AsIfFlatRegion::less (const Region &other) const -{ - if (empty () != other.empty ()) { - return empty () < other.empty (); - } - if (size () != other.size ()) { - return (size () < other.size ()); - } - RegionIterator o1 (begin ()); - RegionIterator o2 (other.begin ()); - while (! o1.at_end () && ! o2.at_end ()) { - if (*o1 != *o2) { - return *o1 < *o2; - } - ++o1; - ++o2; - } - return false; -} - -// ------------------------------------------------------------------------------------------------------------- -// FlatRegion implementation - -namespace -{ - - class FlatRegionIterator - : public RegionIteratorDelegate - { - public: - typedef db::layer polygon_layer_type; - typedef polygon_layer_type::iterator iterator_type; - - FlatRegionIterator (iterator_type from, iterator_type to) - : m_from (from), m_to (to) - { - // .. nothing yet .. - } - - virtual bool at_end () const - { - return m_from == m_to; - } - - virtual void increment () - { - ++m_from; - } - - virtual const value_type *get () const - { - return m_from.operator-> (); - } - - virtual RegionIteratorDelegate *clone () const - { - return new FlatRegionIterator (*this); - } - - private: - friend class Region; - - iterator_type m_from, m_to; - }; - -} - - -FlatRegion::FlatRegion () - : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) -{ - init (); -} - -FlatRegion::~FlatRegion () -{ - // .. nothing yet .. -} - -FlatRegion::FlatRegion (const FlatRegion &other) - : AsIfFlatRegion (other), m_polygons (false), m_merged_polygons (false) -{ - init (); - - m_is_merged = other.m_is_merged; - m_polygons = other.m_polygons; - m_merged_polygons = other.m_merged_polygons; - m_merged_polygons_valid = other.m_merged_polygons_valid; -} - -FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged) - : AsIfFlatRegion (), m_polygons (polygons), m_merged_polygons (false) -{ - init (); - - m_is_merged = is_merged; -} - -FlatRegion::FlatRegion (bool is_merged) - : AsIfFlatRegion (), m_polygons (false), m_merged_polygons (false) -{ - init (); - - m_is_merged = is_merged; -} - -void FlatRegion::set_is_merged (bool m) -{ - m_is_merged = m; -} - -void FlatRegion::invalidate_cache () -{ - invalidate_bbox (); - m_merged_polygons.clear (); - m_merged_polygons_valid = false; -} - -void FlatRegion::init () -{ - m_is_merged = true; - m_merged_polygons_valid = false; -} - -void FlatRegion::merged_semantics_changed () -{ - m_merged_polygons.clear (); - m_merged_polygons_valid = false; -} - -void FlatRegion::reserve (size_t n) -{ - m_polygons.reserve (db::Polygon::tag (), n); -} - -void -FlatRegion::ensure_merged_polygons_valid () const -{ - if (! m_merged_polygons_valid) { - - m_merged_polygons.clear (); - - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - // and run the merge step - db::MergeOp op (0); - db::ShapeGenerator pc (m_merged_polygons); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - m_merged_polygons_valid = true; - - } -} - -RegionIteratorDelegate *FlatRegion::begin () const -{ - return new FlatRegionIterator (m_polygons.get_layer ().begin (), m_polygons.get_layer ().end ()); -} - -RegionIteratorDelegate *FlatRegion::begin_merged () const -{ - if (! merged_semantics () || m_is_merged) { - return begin (); - } else { - ensure_merged_polygons_valid (); - return new FlatRegionIterator (m_merged_polygons.get_layer ().begin (), m_merged_polygons.get_layer ().end ()); - } -} - -std::pair FlatRegion::begin_iter () const -{ - return std::make_pair (db::RecursiveShapeIterator (m_polygons), db::ICplxTrans ()); -} - -std::pair FlatRegion::begin_merged_iter () const -{ - if (! merged_semantics () || m_is_merged) { - return begin_iter (); - } else { - ensure_merged_polygons_valid (); - return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); - } -} - -bool FlatRegion::empty () const -{ - return m_polygons.empty (); -} - -size_t FlatRegion::size () const -{ - return m_polygons.size (); -} - -bool FlatRegion::is_merged () const -{ - return m_is_merged; -} - -Box FlatRegion::compute_bbox () const -{ - m_polygons.update_bbox (); - return m_polygons.bbox (); -} - -RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) -{ - polygon_iterator_type pw = m_polygons.get_layer ().begin (); - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { - if (pw == m_polygons.get_layer ().end ()) { - m_polygons.get_layer ().insert (*p); - pw = m_polygons.get_layer ().end (); - } else { - m_polygons.get_layer ().replace (pw++, *p); - } - } - } - - m_polygons.get_layer ().erase (pw, m_polygons.get_layer ().end ()); - m_merged_polygons.clear (); - m_is_merged = merged_semantics (); - - return this; -} - -RegionDelegate *FlatRegion::merged_in_place () -{ - if (! m_is_merged) { - - if (m_merged_polygons_valid) { - - m_polygons.swap (m_merged_polygons); - m_merged_polygons.clear (); - m_is_merged = true; - return this; - - } else { - return merged_in_place (min_coherence (), 0); - } - - } else { - return this; - } -} - -RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc) -{ - if (empty ()) { - - // ignore empty - return new EmptyRegion (); - - } else if (is_box ()) { - - // take box only if min_wc == 0, otherwise clear - if (min_wc > 0) { - return new EmptyRegion (); - } - - } else { - - invalidate_cache (); - - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - // and run the merge step - db::MergeOp op (min_wc); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); - ep.process (pg, op); - - m_is_merged = true; - - } - - return this; -} - -RegionDelegate *FlatRegion::merged () const -{ - if (! m_is_merged) { - - if (m_merged_polygons_valid) { - return new FlatRegion (m_merged_polygons, true); - } else { - return AsIfFlatRegion::merged (min_coherence (), 0); - } - - } else { - return clone (); - } -} - -RegionDelegate *FlatRegion::add (const Region &other) const -{ - std::auto_ptr new_region (new FlatRegion (*this)); - new_region->invalidate_cache (); - new_region->set_is_merged (false); - - FlatRegion *other_flat = dynamic_cast (other.delegate ()); - if (other_flat) { - - new_region->raw_polygons ().insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); - - } else { - - size_t n = new_region->raw_polygons ().size (); - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - ++n; - } - - new_region->raw_polygons ().reserve (db::Polygon::tag (), n); - - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - new_region->raw_polygons ().insert (*p); - } - - } - - return new_region.release (); -} - -RegionDelegate *FlatRegion::add_in_place (const Region &other) -{ - invalidate_cache (); - m_is_merged = false; - - FlatRegion *other_flat = dynamic_cast (other.delegate ()); - if (other_flat) { - - m_polygons.insert (other_flat->raw_polygons ().get_layer ().begin (), other_flat->raw_polygons ().get_layer ().end ()); - - } else { - - size_t n = m_polygons.size (); - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - ++n; - } - - m_polygons.reserve (db::Polygon::tag (), n); - - for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { - m_polygons.insert (*p); - } - - } - - return this; -} - -const db::Polygon *FlatRegion::nth (size_t n) const -{ - return n < m_polygons.size () ? &m_polygons.get_layer ().begin () [n] : 0; -} - -bool FlatRegion::has_valid_polygons () const -{ - return true; -} - -bool FlatRegion::has_valid_merged_polygons () const -{ - return true; -} - -const db::RecursiveShapeIterator *FlatRegion::iter () const -{ - return 0; -} - -void -FlatRegion::insert (const db::Box &box) -{ - if (! box.empty () && box.width () > 0 && box.height () > 0) { - - if (empty ()) { - - m_polygons.insert (db::Polygon (box)); - m_is_merged = true; - update_bbox (box); - - } else { - - m_polygons.insert (db::Polygon (box)); - m_is_merged = false; - invalidate_cache (); - - } - - } -} - -void -FlatRegion::insert (const db::Path &path) -{ - if (path.points () > 0) { - m_polygons.insert (path.polygon ()); - m_is_merged = false; - invalidate_cache (); - } -} - -void -FlatRegion::insert (const db::Polygon &polygon) -{ - if (polygon.holes () > 0 || polygon.vertices () > 0) { - m_polygons.insert (polygon); - m_is_merged = false; - invalidate_cache (); - } -} - -void -FlatRegion::insert (const db::SimplePolygon &polygon) -{ - if (polygon.vertices () > 0) { - db::Polygon poly; - poly.assign_hull (polygon.begin_hull (), polygon.end_hull ()); - m_polygons.insert (poly); - m_is_merged = false; - invalidate_cache (); - } -} - -void -FlatRegion::insert (const db::Shape &shape) -{ - if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { - db::Polygon poly; - shape.polygon (poly); - m_polygons.insert (poly); - m_is_merged = false; - invalidate_cache (); - } -} - -// ------------------------------------------------------------------------------------------------------------- -// OriginalLayerRegion implementation - -namespace -{ - - class OriginalLayerRegionIterator - : public RegionIteratorDelegate - { - public: - OriginalLayerRegionIterator (const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans) - : m_rec_iter (iter), m_iter_trans (trans) - { - set (); - } - - virtual bool at_end () const - { - return m_rec_iter.at_end (); - } - - virtual void increment () - { - inc (); - set (); - } - - virtual const value_type *get () const - { - return &m_polygon; - } - - virtual RegionIteratorDelegate *clone () const - { - return new OriginalLayerRegionIterator (*this); - } - - private: - friend class Region; - - db::RecursiveShapeIterator m_rec_iter; - db::ICplxTrans m_iter_trans; - db::Polygon m_polygon; - - void set () - { - while (! m_rec_iter.at_end () && ! (m_rec_iter.shape ().is_polygon () || m_rec_iter.shape ().is_path () || m_rec_iter.shape ().is_box ())) { - ++m_rec_iter; - } - if (! m_rec_iter.at_end ()) { - m_rec_iter.shape ().polygon (m_polygon); - m_polygon.transform (m_iter_trans * m_rec_iter.trans (), false); - } - } - - void inc () - { - if (! m_rec_iter.at_end ()) { - ++m_rec_iter; - } - } - }; - -} - -OriginalLayerRegion::OriginalLayerRegion () - : AsIfFlatRegion (), m_merged_polygons (false) -{ - init (); -} - -OriginalLayerRegion::OriginalLayerRegion (const OriginalLayerRegion &other) - : AsIfFlatRegion (other), - m_is_merged (other.m_is_merged), - m_merged_polygons (other.m_merged_polygons), - m_merged_polygons_valid (other.m_merged_polygons_valid), - m_iter (other.m_iter), - m_iter_trans (other.m_iter_trans) -{ - // .. nothing yet .. -} - -OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged) - : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si) -{ - init (); - - m_is_merged = is_merged; -} - -OriginalLayerRegion::OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged) - : AsIfFlatRegion (), m_merged_polygons (false), m_iter (si), m_iter_trans (trans) -{ - init (); - - m_is_merged = is_merged; - set_merged_semantics (merged_semantics); -} - -OriginalLayerRegion::~OriginalLayerRegion () -{ - // .. nothing yet .. -} - -RegionDelegate * -OriginalLayerRegion::clone () const -{ - return new OriginalLayerRegion (*this); -} - -RegionIteratorDelegate * -OriginalLayerRegion::begin () const -{ - return new OriginalLayerRegionIterator (m_iter, m_iter_trans); -} - -RegionIteratorDelegate * -OriginalLayerRegion::begin_merged () const -{ - if (! merged_semantics () || m_is_merged) { - return begin (); - } else { - ensure_merged_polygons_valid (); - return new FlatRegionIterator (m_merged_polygons.get_layer ().begin (), m_merged_polygons.get_layer ().end ()); - } -} - -std::pair -OriginalLayerRegion::begin_iter () const -{ - return std::make_pair (m_iter, m_iter_trans); -} - -std::pair -OriginalLayerRegion::begin_merged_iter () const -{ - if (! merged_semantics () || m_is_merged) { - return begin_iter (); - } else { - ensure_merged_polygons_valid (); - return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); - } -} - -bool -OriginalLayerRegion::empty () const -{ - return m_iter.at_end (); -} - -bool -OriginalLayerRegion::is_merged () const -{ - return m_is_merged; -} - -const db::Polygon * -OriginalLayerRegion::nth (size_t) const -{ - tl_assert (false); -} - -bool -OriginalLayerRegion::has_valid_polygons () const -{ - return false; -} - -bool -OriginalLayerRegion::has_valid_merged_polygons () const -{ - return merged_semantics () && ! m_is_merged; -} - -const db::RecursiveShapeIterator * -OriginalLayerRegion::iter () const -{ - return &m_iter; -} - -bool -OriginalLayerRegion::equals (const Region &other) const -{ - const OriginalLayerRegion *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { - return true; - } else { - return AsIfFlatRegion::equals (other); - } -} - -bool -OriginalLayerRegion::less (const Region &other) const -{ - const OriginalLayerRegion *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { - return false; - } else { - return AsIfFlatRegion::less (other); - } -} - -void -OriginalLayerRegion::init () -{ - m_is_merged = true; - m_merged_polygons_valid = false; -} - -void -OriginalLayerRegion::ensure_merged_polygons_valid () const -{ - if (! m_merged_polygons_valid) { - - m_merged_polygons.clear (); - - db::EdgeProcessor ep (report_progress (), progress_desc ()); - - // count edges and reserve memory - size_t n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - // and run the merge step - db::MergeOp op (0); - db::ShapeGenerator pc (m_merged_polygons); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence ()); - ep.process (pg, op); - - m_merged_polygons_valid = true; - - } -} - // ------------------------------------------------------------------------------------------------------------- // Region implementation @@ -2368,6 +91,54 @@ Region::set_delegate (RegionDelegate *delegate) } } +void +Region::clear () +{ + set_delegate (new EmptyRegion ()); +} + +void +Region::reserve (size_t n) +{ + flat_region ()->reserve (n); +} + +template +Region &Region::transform (const T &trans) +{ + flat_region ()->transform (trans); + return *this; +} + +// explicit instantiations +template <> Region &Region::transform (const db::ICplxTrans &); +template <> Region &Region::transform (const db::Trans &); + +template +void Region::insert (const Sh &shape) +{ + flat_region ()->insert (shape); +} + +template void Region::insert (const db::Box &); +template void Region::insert (const db::SimplePolygon &); +template void Region::insert (const db::Polygon &); +template void Region::insert (const db::Path &); + +void Region::insert (const db::Shape &shape) +{ + flat_region ()->insert (shape); +} + +template +void Region::insert (const db::Shape &shape, const T &trans) +{ + flat_region ()->insert (shape, trans); +} + +template void Region::insert (const db::Shape &, const db::ICplxTrans &); +template void Region::insert (const db::Shape &, const db::Trans &); + FlatRegion * Region::flat_region () { @@ -2382,1584 +153,6 @@ Region::flat_region () return region; } -// ------------------------------------------------------------------------------------------------------------- - -#if 0 -@@@@ original - -Region::Region (const RecursiveShapeIterator &si) - : m_polygons (false), m_merged_polygons (false), m_iter (si) -{ - init (); - // Make sure we restart the iterator and late-initialize it (this makes sure - // it refers to the configuration present then) - m_iter.reset (); - m_bbox_valid = false; - m_is_merged = false; -} - -Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics) - : m_polygons (false), m_merged_polygons (false), m_iter (si), m_iter_trans (trans) -{ - init (); - // Make sure we restart the iterator and late-initialize it (this makes sure - // it refers to the configuration present then) - m_iter.reset (); - m_bbox_valid = false; - m_is_merged = false; - m_merged_semantics = merged_semantics; -} - -bool -Region::operator== (const db::Region &other) const -{ - if (empty () != other.empty ()) { - return false; - } - if (size () != other.size ()) { - return false; - } - db::Region::const_iterator o1 = begin (); - db::Region::const_iterator o2 = other.begin (); - while (! o1.at_end () && ! o2.at_end ()) { - if (*o1 != *o2) { - return false; - } - ++o1; - ++o2; - } - return true; -} - -bool -Region::operator< (const db::Region &other) const -{ - if (empty () != other.empty ()) { - return empty () < other.empty (); - } - if (size () != other.size ()) { - return (size () < other.size ()); - } - db::Region::const_iterator o1 = begin (); - db::Region::const_iterator o2 = other.begin (); - while (! o1.at_end () && ! o2.at_end ()) { - if (*o1 != *o2) { - return *o1 < *o2; - } - ++o1; - ++o2; - } - return false; -} - -size_t -Region::size () const -{ - if (! has_valid_polygons ()) { - // If we have an iterator, we have to do it the hard way .. - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - ++n; - } - return n; - } else { - return m_polygons.size (); - } -} - -void -Region::set_strict_handling (bool f) -{ - m_strict_handling = f; -} - -void -Region::set_merged_semantics (bool f) -{ - if (f != m_merged_semantics) { - m_merged_semantics = f; - m_merged_polygons.clear (); - m_merged_polygons_valid = false; - } -} - -std::string -Region::to_string (size_t nmax) const -{ - std::ostringstream os; - const_iterator p = begin (); - bool first = true; - for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) { - if (! first) { - os << ";"; - } - first = false; - os << p->to_string (); - } - if (! p.at_end ()) { - os << "..."; - } - return os.str (); -} - -Region::area_type -Region::area (const db::Box &box) const -{ - area_type a = 0; - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - if (box.empty () || p->box ().inside (box)) { - a += p->area (); - } else { - std::vector clipped; - clip_poly (*p, box, clipped); - for (std::vector::const_iterator c = clipped.begin (); c != clipped.end (); ++c) { - a += c->area (); - } - } - } - - return a; -} - -Region::perimeter_type -Region::perimeter (const db::Box &box) const -{ - perimeter_type d = 0; - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - - if (box.empty () || p->box ().inside (box)) { - d += p->perimeter (); - } else { - - for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - - if (box.empty ()) { - d += (*e).length (); - } else { - - std::pair ce = (*e).clipped (box); - if (ce.first) { - - db::Coord dx = ce.second.dx (); - db::Coord dy = ce.second.dy (); - db::Coord x = ce.second.p1 ().x (); - db::Coord y = ce.second.p1 ().y (); - if ((dx == 0 && x == box.left () && dy < 0) || - (dx == 0 && x == box.right () && dy > 0) || - (dy == 0 && y == box.top () && dx < 0) || - (dy == 0 && y == box.bottom () && dx > 0)) { - // not counted -> box is at outside side of the edge - } else { - d += ce.second.length (); - } - - } - - } - - } - - } - - } - - return d; -} - -Region -Region::hulls () const -{ - Region region; - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - db::Polygon h; - h.assign_hull (p->begin_hull (), p->end_hull ()); - region.insert (h); - } - - return region; -} - -Region -Region::holes () const -{ - Region region; - - for (const_iterator 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)); - region.insert (h); - } - } - - return region; -} - -Region -Region::rounded_corners (double rinner, double router, unsigned int n) const -{ - Region r; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - r.insert (db::compute_rounded (*p, rinner, router, n)); - } - return r; -} - -Region -Region::smoothed (coord_type d) const -{ - Region r; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - r.insert (db::smooth (*p, d)); - } - return r; -} - -Region -Region::in (const Region &other, bool invert) const -{ - std::set op; - for (const_iterator o = other.begin_merged (); ! o.at_end (); ++o) { - op.insert (*o); - } - - Region r; - for (const_iterator o = begin_merged (); ! o.at_end (); ++o) { - if ((op.find (*o) == op.end ()) == invert) { - r.insert (*o); - } - } - - return r; -} - -Edges -Region::edges () const -{ - Edges edges; - - size_t n = 0; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - n += p->vertices (); - } - edges.reserve (n); - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - edges.insert (*e); - } - } - - return edges; -} - -bool -Region::is_box () const -{ - const_iterator p = begin (); - if (p.at_end ()) { - return false; - } else { - const db::Polygon &poly = *p; - ++p; - if (! p.at_end ()) { - return false; - } else { - return poly.is_box (); - } - } -} - -void -Region::swap (Region &other) -{ - std::swap (m_is_merged, other.m_is_merged); - std::swap (m_merged_semantics, other.m_merged_semantics); - std::swap (m_strict_handling, other.m_strict_handling); - std::swap (m_merge_min_coherence, other.m_merge_min_coherence); - m_polygons.swap (other.m_polygons); - m_merged_polygons.swap (other.m_merged_polygons); - std::swap (m_bbox, other.m_bbox); - std::swap (m_bbox_valid, other.m_bbox_valid); - std::swap (m_merged_polygons_valid, other.m_merged_polygons_valid); - std::swap (m_iter, other.m_iter); - std::swap (m_iter_trans, other.m_iter_trans); -} - -Region & -Region::merge () -{ - if (! m_is_merged) { - - if (m_merged_polygons_valid) { - - m_polygons.swap (m_merged_polygons); - m_merged_polygons.clear (); - m_is_merged = true; - - } else { - - merge (m_merge_min_coherence, 0); - - } - - } - - return *this; -} - -Region & -Region::merge (bool min_coherence, unsigned int min_wc) -{ - if (empty ()) { - - // ignore empty - - } else if (is_box ()) { - - // take box only if min_wc == 0, otherwise clear - if (min_wc > 0) { - clear (); - } - - } else { - - invalidate_cache (); - - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - // and run the merge step - db::MergeOp op (min_wc); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = true; - - } - - return *this; -} - -Region & -Region::size (Region::coord_type dx, Region::coord_type dy, unsigned int mode) -{ - if (empty ()) { - - // ignore empty - - } else if (is_box () && mode >= 2) { - - // simplified handling for a box - db::Box b = bbox ().enlarged (db::Vector (dx, dy)); - m_polygons.clear (); - if (! b.empty () && b.width () > 0 && b.height () > 0) { - m_polygons.insert (db::Polygon (b)); - } else { - b = db::Box (); - } - - m_is_merged = true; - m_bbox = b; - m_bbox_valid = true; - - m_merged_polygons.clear (); - m_merged_polygons_valid = false; - set_valid_polygons (); - - } else if (! m_merged_semantics) { - - invalidate_cache (); - - // Generic case - db::Shapes output (false); - - db::ShapeGenerator pc (output, false); - db::PolygonGenerator pg (pc, false, true); - db::SizingPolygonFilter sf (pg, dx, dy, mode); - for (const_iterator p = begin (); ! p.at_end (); ++p) { - sf.put (*p); - } - - output.swap (m_polygons); - set_valid_polygons (); - - m_is_merged = false; - - } else { - - invalidate_cache (); - - // Generic case - the size operation will merge first - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/); - db::SizingPolygonFilter siz (pg2, dx, dy, mode); - db::PolygonGenerator pg (siz, false /*don't resolve holes*/, false /*min. coherence*/); - db::BooleanOp op (db::BooleanOp::Or); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = false; - - } - - return *this; -} - -Region & -Region::operator&= (const Region &other) -{ - if (empty ()) { - - // Nothing to do - - } else if (other.empty ()) { - - clear (); - - } else if (is_box () && other.is_box ()) { - - // Simplified handling for boxes - db::Box b = bbox (); - b &= other.bbox (); - m_polygons.clear (); - if (! b.empty () && b.width () > 0 && b.height () > 0 ) { - m_polygons.insert (db::Polygon (b)); - } - - m_is_merged = true; - m_bbox = b; - m_bbox_valid = true; - - m_merged_polygons.clear (); - m_merged_polygons_valid = false; - set_valid_polygons (); - - } else if (is_box () && ! other.strict_handling ()) { - - // map AND with box to clip .. - db::Box b = bbox (); - m_polygons.clear (); - - std::vector clipped; - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - clipped.clear (); - clip_poly (*p, b, clipped); - m_polygons.insert (clipped.begin (), clipped.end ()); - } - - m_is_merged = false; - invalidate_cache (); - set_valid_polygons (); - - } else if (other.is_box () && ! m_strict_handling) { - - // map AND with box to clip .. - db::Box b = other.bbox (); - db::Shapes polygons (false); - - std::vector clipped; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - clipped.clear (); - clip_poly (*p, b, clipped); - polygons.insert (clipped.begin (), clipped.end ()); - } - - m_polygons.swap (polygons); - m_is_merged = false; - invalidate_cache (); - set_valid_polygons (); - - } else if (! bbox ().overlaps (other.bbox ())) { - - // Result will be nothing - clear (); - - } else { - - invalidate_cache (); - - // Generic case - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (const_iterator p = other.begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - db::BooleanOp op (db::BooleanOp::And); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, m_merge_min_coherence); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = true; - - } - - return *this; -} - -Region & -Region::operator-= (const Region &other) -{ - if (empty ()) { - - // Nothing to do - - } else if (other.empty () && ! m_strict_handling) { - - // Nothing to do - - } else if (! bbox ().overlaps (other.bbox ()) && ! m_strict_handling) { - - // Nothing to do - - } else { - - invalidate_cache (); - - // Generic case - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (const_iterator p = other.begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - db::BooleanOp op (db::BooleanOp::ANotB); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, m_merge_min_coherence); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = true; - - } - - return *this; -} - -Region & -Region::operator^= (const Region &other) -{ - if (empty () && ! other.strict_handling ()) { - - *this = other; - - } else if (other.empty () && ! m_strict_handling) { - - // Nothing to do - - } else if (! bbox ().overlaps (other.bbox ()) && ! m_strict_handling && ! other.strict_handling ()) { - - // Simplified handling for disjunct case - *this |= other; - - } else { - - invalidate_cache (); - - // Generic case - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (const_iterator p = other.begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - db::BooleanOp op (db::BooleanOp::Xor); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, m_merge_min_coherence); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = true; - - } - - return *this; -} - -Region & -Region::operator|= (const Region &other) -{ - if (empty () && ! other.strict_handling ()) { - - *this = other; - - } else if (other.empty () && ! m_strict_handling) { - - // Nothing to do - - } else if (! bbox ().overlaps (other.bbox ()) && ! m_strict_handling && ! other.strict_handling ()) { - - // Simplified handling for disjunct case - *this += other; - - } else { - - invalidate_cache (); - - // Generic case - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - n = 1; - for (const_iterator p = other.begin (); ! p.at_end (); ++p, n += 2) { - ep.insert (*p, n); - } - - db::BooleanOp op (db::BooleanOp::Or); - db::ShapeGenerator pc (m_polygons, true /*clear*/); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, m_merge_min_coherence); - ep.process (pg, op); - - set_valid_polygons (); - - m_is_merged = true; - - } - - return *this; -} - -Region & -Region::operator+= (const Region &other) -{ - invalidate_cache (); - - if (! has_valid_polygons ()) { - - m_polygons.clear (); - - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - ++n; - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - ++n; - } - - m_polygons.reserve (db::Polygon::tag (), n); - - for (const_iterator p = begin (); ! p.at_end (); ++p) { - m_polygons.insert (*p); - } - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - m_polygons.insert (*p); - } - - set_valid_polygons (); - - } else if (! other.has_valid_polygons ()) { - - size_t n = m_polygons.size (); - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - ++n; - } - - m_polygons.reserve (db::Polygon::tag (), n); - - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - m_polygons.insert (*p); - } - - } else { - m_polygons.insert (other.m_polygons.get_layer ().begin (), other.m_polygons.get_layer ().end ()); - } - - m_is_merged = false; - return *this; -} - -Region -Region::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const -{ - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // shortcut - if (empty ()) { - return *this; - } else if (other.empty ()) { - // clear, if b is empty and - // * mode is inside or interacting and inverse is false ("inside" or "interacting") - // * mode is outside and inverse is true ("not outside") - if ((mode <= 0) != inverse) { - return Region (); - } else { - return *this; - } - } - - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, 0); - } - } - - size_t n = 1; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p, ++n) { - if (mode > 0 || p->box ().touches (other.bbox ())) { - ep.insert (*p, n); - } - } - - db::InteractionDetector id (mode, 0); - id.set_include_touching (touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - Region out; - n = 0; - std::set selected; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { - ++n; - selected.insert (i->second); - } - - out.reserve (n); - - n = 1; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p, ++n) { - if ((selected.find (n) == selected.end ()) == inverse) { - out.insert (*p); - } - } - - return out; -} - -void -Region::select_interacting_generic (const Region &other, int mode, bool touching, bool inverse) -{ - // shortcut - if (empty ()) { - return; - } else if (other.empty ()) { - // clear, if b is empty and - // * mode is inside or interacting and inverse is false ("inside" or "interacting") - // * mode is outside and inverse is true ("not outside") - if ((mode <= 0) != inverse) { - clear (); - } - return; - } - - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - for (const_iterator p = other.begin (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, 0); - } - } - - size_t n = 1; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p, ++n) { - if (mode > 0 || p->box ().touches (other.bbox ())) { - ep.insert (*p, n); - } - } - - invalidate_cache (); - - db::InteractionDetector id (mode, 0); - id.set_include_touching (touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - db::Shapes out (false); - std::set selected; - n = 0; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () && i->first == 0; ++i) { - selected.insert (i->second); - ++n; - } - - out.reserve (db::Polygon::tag (), n); - n = 1; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p, ++n) { - if ((selected.find (n) == selected.end ()) == inverse) { - out.insert (*p); - } - } - - m_polygons.swap (out); - set_valid_polygons (); -} - -namespace -{ - -/** - * @brief A helper class for the region to edge interaction functionality - * - * Note: This special scanner uses pointers to two different objects: edges and polygons. - * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate - * pointers to edges. - * - * There is a special box converter which is able to sort that out as well. - */ -template -class region_to_edge_interaction_filter - : public db::box_scanner_receiver -{ -public: - region_to_edge_interaction_filter (OutputContainer &output) - : mp_output (&output), m_inverse (false) - { - // .. nothing yet .. - } - - region_to_edge_interaction_filter (OutputContainer &output, const db::Region ®ion) - : mp_output (&output), m_inverse (true) - { - for (db::Region::const_iterator p = region.begin_merged (); ! p.at_end (); ++p) { - m_seen.insert (&*p); - } - } - - void add (const char *o1, size_t p1, const char *o2, size_t p2) - { - const db::Edge *e = 0; - const db::Polygon *p = 0; - - // Note: edges have property 0 and have even-valued pointers. - // Polygons have property 1 and odd-valued pointers. - if (p1 == 0 && p2 == 1) { - e = reinterpret_cast (o1); - p = reinterpret_cast (o2 - 1); - } else if (p1 == 1 && p2 == 0) { - e = reinterpret_cast (o2); - p = reinterpret_cast (o1 - 1); - } - - if (e && p && (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 A special box converter that splits the pointers into polygon and edge pointers - */ -struct EdgeOrRegionBoxConverter -{ - typedef db::Box box_type; - - db::Box operator() (const char &c) const - { - // Note: edges have property 0 and have even-valued pointers. - // Polygons have property 1 and odd-valued pointers. - const char *cp = &c; - if ((size_t (cp) & 1) == 1) { - // it's a polygon - return (reinterpret_cast (cp - 1))->box (); - } else { - // it's an edge - const db::Edge *e = reinterpret_cast (cp); - return db::Box (e->p1 (), e->p2 ()); - } - } -}; - -} - -Region -Region::selected_interacting_generic (const Edges &other, bool inverse) const -{ - if (other.empty ()) { - if (! inverse) { - return Region (); - } else { - return *this; - } - } else if (empty ()) { - return *this; - } - - db::box_scanner scanner (m_report_progress, m_progress_desc); - scanner.reserve (size () + other.size ()); - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - scanner.insert ((char *) &*p + 1, 1); - } - - other.ensure_valid_merged_edges (); - for (Edges::const_iterator e = other.begin (); ! e.at_end (); ++e) { - scanner.insert ((char *) &*e, 0); - } - - Region output; - EdgeOrRegionBoxConverter bc; - - if (! inverse) { - region_to_edge_interaction_filter filter (output); - scanner.process (filter, 1, bc); - } else { - region_to_edge_interaction_filter filter (output, *this); - scanner.process (filter, 1, bc); - filter.fill_output (); - } - - return output; -} - -void -Region::select_interacting_generic (const Edges &other, bool inverse) -{ - // shortcut - if (other.empty ()) { - if (! inverse) { - clear (); - } - return; - } else if (empty ()) { - return; - } - - db::box_scanner scanner (m_report_progress, m_progress_desc); - scanner.reserve (size () + other.size ()); - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - scanner.insert ((char *) &*p + 1, 1); - } - - other.ensure_valid_merged_edges (); - for (Edges::const_iterator e = other.begin (); ! e.at_end (); ++e) { - scanner.insert ((char *) &*e, 0); - } - - db::Shapes output (false); - EdgeOrRegionBoxConverter bc; - - if (! inverse) { - region_to_edge_interaction_filter filter (output); - scanner.process (filter, 1, bc); - } else { - region_to_edge_interaction_filter filter (output, *this); - scanner.process (filter, 1, bc); - filter.fill_output (); - } - - m_polygons.swap (output); - set_valid_polygons (); -} - -EdgePairs -Region::grid_check (db::Coord gx, db::Coord gy) const -{ - EdgePairs out; - - gx = std::max (db::Coord (1), gx); - gy = std::max (db::Coord (1), gy); - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - db::Polygon::polygon_contour_iterator b, e; - - if (i == 0) { - b = p->begin_hull (); - e = p->end_hull (); - } else { - b = p->begin_hole ((unsigned int) (i - 1)); - e = p->end_hole ((unsigned int) (i - 1)); - } - - for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { - if (((*pt).x () % gx) != 0 || ((*pt).y () % gy) != 0) { - out.insert (EdgePair (db::Edge (*pt, *pt), db::Edge (*pt, *pt))); - } - } - - } - - } - - return out; -} - -static bool ac_less (double cos_a, bool gt180_a, double cos_b, bool gt180_b) -{ - if (gt180_a != gt180_b) { - return gt180_a < gt180_b; - } else { - if (gt180_a) { - return cos_a < cos_b - 1e-10; - } else { - return cos_a > cos_b + 1e-10; - } - } -} - -EdgePairs -Region::angle_check (double min, double max, bool inverse) const -{ - EdgePairs out; - - double cos_min = cos (std::max (0.0, std::min (360.0, min)) / 180.0 * M_PI); - double cos_max = cos (std::max (0.0, std::min (360.0, max)) / 180.0 * M_PI); - bool gt180_min = min > 180.0; - bool gt180_max = max > 180.0; - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - const db::Polygon::contour_type *h = 0; - if (i == 0) { - h = &p->hull (); - } else { - h = &p->hole ((unsigned int) (i - 1)); - } - - size_t np = h->size (); - - for (size_t j = 0; j < np; ++j) { - - db::Edge e ((*h) [j], (*h) [(j + 1) % np]); - db::Edge ee (e.p2 (), (*h) [(j + 2) % np]); - double le = e.double_length (); - double lee = ee.double_length (); - - double cos_a = -db::sprod (e, ee) / (le * lee); - bool gt180_a = db::vprod_sign (e, ee) > 0; - - if ((ac_less (cos_a, gt180_a, cos_max, gt180_max) && !ac_less (cos_a, gt180_a, cos_min, gt180_min)) == !inverse) { - out.insert (EdgePair (e, ee)); - } - - } - - } - - } - - return out; -} - -static inline db::Coord snap_to_grid (db::Coord c, db::Coord g) -{ - // This form of snapping always snaps g/2 to right/top. - if (c < 0) { - c = -g * ((-c + (g - 1) / 2) / g); - } else { - c = g * ((c + g / 2) / g); - } - return c; -} - -void -Region::snap (db::Coord gx, db::Coord gy) -{ - db::Shapes polygons (false); - - gx = std::max (db::Coord (1), gx); - gy = std::max (db::Coord (1), gy); - - std::vector pts; - - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - - db::Polygon pnew; - - for (size_t i = 0; i < p->holes () + 1; ++i) { - - pts.clear (); - - db::Polygon::polygon_contour_iterator b, e; - - if (i == 0) { - b = p->begin_hull (); - e = p->end_hull (); - } else { - b = p->begin_hole ((unsigned int) (i - 1)); - e = p->end_hole ((unsigned int) (i - 1)); - } - - for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) { - pts.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy))); - } - - if (i == 0) { - pnew.assign_hull (pts.begin (), pts.end ()); - } else { - pnew.insert_hole (pts.begin (), pts.end ()); - } - - } - - polygons.insert (pnew); - - } - - m_polygons.swap (polygons); - - bool was_merged = m_merged_semantics; - invalidate_cache (); - m_is_merged = was_merged; - set_valid_polygons (); -} - -/** - * @brief A helper class to implement the strange polygon detector - */ -struct StrangePolygonInsideFunc -{ - inline bool operator() (int wc) const - { - return wc < 0 || wc > 1; - } -}; - -Region -Region::strange_polygon_check () const -{ - EdgeProcessor ep; - Region out; - - for (const_iterator p = begin (); ! p.at_end (); ++p) { - - ep.clear (); - ep.insert (*p); - - StrangePolygonInsideFunc inside; - db::GenericMerge op (inside); - RegionPolygonSink pc (out); - db::PolygonGenerator pg (pc, false, false); - ep.process (pg, op); - } - - return out; -} - -void -Region::init () -{ - m_report_progress = false; - m_bbox_valid = true; - m_is_merged = true; - m_merged_semantics = true; - m_strict_handling = false; - m_merge_min_coherence = false; - m_merged_polygons_valid = false; -} - -void -Region::disable_progress () -{ - m_report_progress = false; -} - -void -Region::enable_progress (const std::string &progress_desc) -{ - m_report_progress = true; - m_progress_desc = progress_desc; -} - -void -Region::invalidate_cache () -{ - m_bbox_valid = false; - m_merged_polygons.clear (); - m_merged_polygons_valid = false; -} - -void -Region::ensure_valid_merged_polygons () const -{ - // If no merged semantics applies or we will deliver the original - // polygons as merged ones, we need to make sure those are valid - // ones (with a unique memory address) - if (! m_merged_semantics || m_is_merged) { - ensure_valid_polygons (); - } else { - ensure_merged_polygons_valid (); - } -} - -void -Region::ensure_valid_polygons () const -{ - if (! has_valid_polygons ()) { - - m_polygons.clear (); - - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - ++n; - } - m_polygons.reserve (db::Polygon::tag (), n); - - for (const_iterator p = begin (); ! p.at_end (); ++p) { - m_polygons.insert (*p); - } - - // set valid polygons - m_iter = db::RecursiveShapeIterator (); - - } -} - -void -Region::set_valid_polygons () -{ - m_iter = db::RecursiveShapeIterator (); -} - -void -Region::ensure_bbox_valid () const -{ - if (! m_bbox_valid) { - m_bbox = db::Box (); - for (const_iterator p = begin (); ! p.at_end (); ++p) { - m_bbox += p->box (); - } - m_bbox_valid = true; - } -} - -Region::const_iterator -Region::begin_merged () const -{ - if (! m_merged_semantics || m_is_merged) { - return begin (); - } else { - ensure_merged_polygons_valid (); - return db::RegionIterator (m_merged_polygons.get_layer ().begin (), m_merged_polygons.get_layer ().end ()); - } -} - -std::pair -Region::begin_iter () const -{ - if (has_valid_polygons ()) { - return std::make_pair (db::RecursiveShapeIterator (m_polygons), db::ICplxTrans ()); - } else { - return std::make_pair (m_iter, m_iter_trans); - } -} - -std::pair -Region::begin_merged_iter () const -{ - if (! m_merged_semantics || m_is_merged) { - return begin_iter (); - } else { - ensure_merged_polygons_valid (); - return std::make_pair (db::RecursiveShapeIterator (m_merged_polygons), db::ICplxTrans ()); - } -} - -void -Region::ensure_merged_polygons_valid () const -{ - if (! m_merged_polygons_valid) { - - m_merged_polygons.clear (); - - db::EdgeProcessor ep (m_report_progress, m_progress_desc); - - // count edges and reserve memory - size_t n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p) { - n += p->vertices (); - } - ep.reserve (n); - - // insert the polygons into the processor - n = 0; - for (const_iterator p = begin (); ! p.at_end (); ++p, ++n) { - ep.insert (*p, n); - } - - // and run the merge step - db::MergeOp op (0); - db::ShapeGenerator pc (m_merged_polygons); - db::PolygonGenerator pg (pc, false /*don't resolve holes*/, m_merge_min_coherence); - ep.process (pg, op); - - m_merged_polygons_valid = true; - - } -} - -void -Region::insert (const db::Box &box) -{ - if (! box.empty () && box.width () > 0 && box.height () > 0) { - ensure_valid_polygons (); - m_polygons.insert (db::Polygon (box)); - m_is_merged = false; - invalidate_cache (); - } -} - -void -Region::insert (const db::Path &path) -{ - if (path.points () > 0) { - ensure_valid_polygons (); - m_polygons.insert (path.polygon ()); - m_is_merged = false; - invalidate_cache (); - } -} - -void -Region::insert (const db::Polygon &polygon) -{ - if (polygon.holes () > 0 || polygon.vertices () > 0) { - ensure_valid_polygons (); - m_polygons.insert (polygon); - m_is_merged = false; - invalidate_cache (); - } -} - -void -Region::insert (const db::SimplePolygon &polygon) -{ - if (polygon.vertices () > 0) { - ensure_valid_polygons (); - db::Polygon poly; - poly.assign_hull (polygon.begin_hull (), polygon.end_hull ()); - m_polygons.insert (poly); - m_is_merged = false; - invalidate_cache (); - } -} - -void -Region::insert (const db::Shape &shape) -{ - if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { - ensure_valid_polygons (); - db::Polygon poly; - shape.polygon (poly); - m_polygons.insert (poly); - m_is_merged = false; - invalidate_cache (); - } -} - -void -Region::clear () -{ - m_polygons.clear (); - m_bbox = db::Box (); - m_bbox_valid = true; - m_is_merged = true; - m_merged_polygons.clear (); - m_merged_polygons_valid = true; - m_iter = db::RecursiveShapeIterator (); - m_iter_trans = db::ICplxTrans (); -} - -EdgePairs -Region::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 -{ - EdgePairs result; - - db::box_scanner scanner (m_report_progress, m_progress_desc); - scanner.reserve (size () + (other ? other->size () : 0)); - - ensure_valid_merged_polygons (); - size_t n = 0; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - scanner.insert (&*p, n); - n += 2; - } - - if (other) { - other->ensure_valid_merged_polygons (); - n = 1; - for (const_iterator p = other->begin_merged (); ! p.at_end (); ++p) { - scanner.insert (&*p, n); - n += 2; - } - } - - EdgeRelationFilter check (rel, d, metrics); - check.set_include_zero (other != 0); - check.set_whole_edges (whole_edges); - check.set_ignore_angle (ignore_angle); - 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); - - do { - scanner.process (poly_check, d, db::box_convert ()); - } while (edge_check.prepare_next_pass ()); - - return result; -} - -EdgePairs -Region::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 -{ - EdgePairs result; - - 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); - - Edge2EdgeCheck edge_check (check, result, false, false); - Poly2PolyCheck poly_check (edge_check); - - do { - size_t n = 0; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - poly_check.finish (&*p, n); - n += 2; - } - } while (edge_check.prepare_next_pass ()); - - return result; -} - -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@q -#endif - } namespace tl diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 1ab534af0..a8b08eee0 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -25,20 +25,10 @@ #define HDR_dbRegion #include "dbCommon.h" - -#include "dbTypes.h" -#include "dbPolygon.h" -#include "dbPath.h" -#include "dbTrans.h" -#include "dbShape.h" -#include "dbShapes.h" -#include "dbShapes2.h" -#include "dbEdgePairRelations.h" -#include "dbShapeProcessor.h" -#include "dbEdges.h" +#include "dbRegionDelegate.h" #include "dbRecursiveShapeIterator.h" -#include "dbEdgePairs.h" -#include "tlString.h" +#include "dbPolygonGenerators.h" + #include "gsiObject.h" #include @@ -46,6 +36,8 @@ namespace db { class EdgeFilterBase; +class FlatRegion; +class EmptyRegion; /** * @brief A base class for polygon filters @@ -291,23 +283,6 @@ private: parameter_type m_parameter; }; -/** - * @brief The region iterator delegate - */ -class DB_PUBLIC RegionIteratorDelegate -{ -public: - RegionIteratorDelegate () { } - virtual ~RegionIteratorDelegate () { } - - typedef db::Polygon value_type; - - virtual bool at_end () const = 0; - virtual void increment () = 0; - virtual const value_type *get () const = 0; - virtual RegionIteratorDelegate *clone () const = 0; -}; - /** * @brief A region iterator * @@ -412,599 +387,6 @@ private: RegionIteratorDelegate *mp_delegate; }; -/** - * @brief The delegate for the actual region implementation - */ -class DB_PUBLIC RegionDelegate -{ -public: - typedef db::Coord coord_type; - typedef db::coord_traits coord_traits; - typedef db::Polygon polygon_type; - typedef db::Vector vector_type; - typedef db::Point point_type; - typedef db::Box box_type; - typedef coord_traits::distance_type distance_type; - typedef coord_traits::perimeter_type perimeter_type; - typedef coord_traits::area_type area_type; - - RegionDelegate (); - virtual ~RegionDelegate (); - - RegionDelegate (const RegionDelegate &other); - RegionDelegate &operator= (const RegionDelegate &other); - - virtual RegionDelegate *clone () const = 0; - - void enable_progress (const std::string &progress_desc); - void disable_progress (); - - void set_min_coherence (bool f); - bool min_coherence () const - { - return m_merge_min_coherence; - } - - void set_merged_semantics (bool f); - bool merged_semantics () const - { - return m_merged_semantics; - } - - void set_strict_handling (bool f); - bool strict_handling () const - { - return m_strict_handling; - } - - virtual std::string to_string (size_t nmax) const = 0; - - virtual RegionIteratorDelegate *begin () const = 0; - virtual RegionIteratorDelegate *begin_merged () const = 0; - - virtual std::pair begin_iter () const = 0; - virtual std::pair begin_merged_iter () const = 0; - - virtual bool empty () const = 0; - virtual bool is_box () const = 0; - virtual bool is_merged () const = 0; - virtual size_t size () const = 0; - - virtual area_type area (const db::Box &box) const = 0; - virtual perimeter_type perimeter (const db::Box &box) const = 0; - virtual Box bbox () const = 0; - - virtual EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs isolated_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs notch_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs enclosing_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs overlap_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs separation_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs inside_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; - virtual EdgePairs grid_check (db::Coord gx, db::Coord gy) const = 0; - virtual EdgePairs angle_check (double min, double max, bool inverse) const = 0; - - virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) = 0; - virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy) = 0; - - 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 *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; - - virtual RegionDelegate *and_with (const Region &other) const = 0; - virtual RegionDelegate *not_with (const Region &other) const = 0; - virtual RegionDelegate *xor_with (const Region &other) const = 0; - virtual RegionDelegate *or_with (const Region &other) const = 0; - virtual RegionDelegate *add_in_place (const Region &other) = 0; - virtual RegionDelegate *add (const Region &other) const = 0; - - virtual RegionDelegate *selected_outside (const Region &other) const = 0; - virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; - virtual RegionDelegate *selected_inside (const Region &other) const = 0; - virtual RegionDelegate *selected_not_inside (const Region &other) const = 0; - virtual RegionDelegate *selected_interacting (const Region &other) const = 0; - virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0; - virtual RegionDelegate *selected_interacting (const Edges &other) const = 0; - 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; - virtual bool has_valid_merged_polygons () const = 0; - - virtual const db::RecursiveShapeIterator *iter () const = 0; - - virtual bool equals (const Region &other) const = 0; - virtual bool less (const Region &other) const = 0; - -protected: - const std::string &progress_desc () const - { - return m_progress_desc; - } - - bool report_progress () const - { - return m_report_progress; - } - - virtual void merged_semantics_changed () { } - -private: - bool m_merged_semantics; - bool m_strict_handling; - bool m_merge_min_coherence; - bool m_report_progress; - std::string m_progress_desc; -}; - -/** - * @brief An empty Region - */ -class DB_PUBLIC EmptyRegion - : public RegionDelegate -{ -public: - EmptyRegion (); - virtual ~EmptyRegion (); - - EmptyRegion (const EmptyRegion &other); - RegionDelegate *clone () const; - - virtual RegionIteratorDelegate *begin () const { return 0; } - virtual RegionIteratorDelegate *begin_merged () const { return 0; } - - virtual std::pair begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } - virtual std::pair begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } - - virtual bool empty () const { return true; } - virtual size_t size () const { return 0; } - virtual std::string to_string (size_t) const { return std::string (); } - - virtual bool is_box () const { return false; } - virtual bool is_merged () const { return true; } - virtual area_type area (const db::Box &) const { return 0; } - virtual perimeter_type perimeter (const db::Box &) const { return 0; } - - virtual Box bbox () const { return Box (); } - - virtual EdgePairs width_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs space_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs isolated_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs notch_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs enclosing_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs overlap_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs separation_check (const Region &, db::Coord, bool , metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs inside_check (const Region &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); } - virtual EdgePairs grid_check (db::Coord, db::Coord) const { return EdgePairs (); } - virtual EdgePairs angle_check (double, double, bool) const { return EdgePairs (); } - - 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 *merged_in_place () { return this; } - virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; } - virtual RegionDelegate *merged () const { return new EmptyRegion (); } - virtual RegionDelegate *merged (bool, unsigned int) const { return new EmptyRegion (); } - - virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); } - virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); } - - virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *xor_with (const Region &other) const; - virtual RegionDelegate *or_with (const Region &other) const; - virtual RegionDelegate *add_in_place (const Region &other); - virtual RegionDelegate *add (const Region &other) const; - - virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_interacting (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); } - virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); } - 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; } - virtual const db::Polygon *nth (size_t) const { tl_assert (false); } - - virtual const db::RecursiveShapeIterator *iter () const { return 0; } - - virtual bool equals (const Region &other) const; - virtual bool less (const Region &other) const; - -private: - EmptyRegion &operator= (const EmptyRegion &other); -}; - -/** - * @brief Provides default flat implementations - */ -class DB_PUBLIC AsIfFlatRegion - : public RegionDelegate -{ -public: - AsIfFlatRegion (); - virtual ~AsIfFlatRegion (); - - virtual bool is_box () const; - virtual size_t size () const; - - virtual area_type area (const db::Box &box) const; - virtual perimeter_type perimeter (const db::Box &box) const; - virtual Box bbox () const; - - virtual std::string to_string (size_t nmax) const; - - EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_single_polygon_check (db::WidthRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::SpaceRelation, false, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs isolated_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::SpaceRelation, true, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs notch_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_single_polygon_check (db::SpaceRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs enclosing_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::OverlapRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs overlap_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::WidthRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs separation_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::SpaceRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - EdgePairs inside_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const - { - return run_check (db::InsideRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - virtual EdgePairs grid_check (db::Coord gx, db::Coord gy) const; - virtual EdgePairs angle_check (double min, double max, bool inverse) const; - - virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) - { - return snapped (gx, gy); - } - - virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy); - - virtual Edges edges (const EdgeFilterBase *) const; - - virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) - { - return filtered (filter); - } - - virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const; - - virtual RegionDelegate *merged_in_place () - { - return merged (); - } - - virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) - { - return merged (min_coherence, min_wc); - } - - virtual RegionDelegate *merged () const - { - return merged (min_coherence (), 0); - } - - 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; - - virtual RegionDelegate *and_with (const Region &other) const; - virtual RegionDelegate *not_with (const Region &other) const; - virtual RegionDelegate *xor_with (const Region &other) const; - virtual RegionDelegate *or_with (const Region &other) const; - - virtual RegionDelegate *add_in_place (const Region &other) - { - return add (other); - } - - virtual RegionDelegate *add (const Region &other) const; - - virtual RegionDelegate *selected_outside (const Region &other) const - { - return selected_interacting_generic (other, 1, false, false); - } - - virtual RegionDelegate *selected_not_outside (const Region &other) const - { - return selected_interacting_generic (other, 1, false, true); - } - - virtual RegionDelegate *selected_inside (const Region &other) const - { - return selected_interacting_generic (other, -1, true, false); - } - - virtual RegionDelegate *selected_not_inside (const Region &other) const - { - return selected_interacting_generic (other, -1, true, true); - } - - virtual RegionDelegate *selected_interacting (const Region &other) const - { - return selected_interacting_generic (other, 0, true, false); - } - - virtual RegionDelegate *selected_not_interacting (const Region &other) const - { - return selected_interacting_generic (other, 0, true, true); - } - - virtual RegionDelegate *selected_interacting (const Edges &other) const - { - return selected_interacting_generic (other, false); - } - - virtual RegionDelegate *selected_not_interacting (const Edges &other) const - { - return selected_interacting_generic (other, true); - } - - virtual RegionDelegate *selected_overlapping (const Region &other) const - { - return selected_interacting_generic (other, 0, false, false); - } - - virtual RegionDelegate *selected_not_overlapping (const Region &other) const - { - 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; - -protected: - void update_bbox (const db::Box &box); - void invalidate_bbox (); - -private: - AsIfFlatRegion &operator= (const AsIfFlatRegion &other); - - mutable bool m_bbox_valid; - mutable db::Box m_bbox; - - virtual db::Box compute_bbox () const; - static RegionDelegate *region_from_box (const db::Box &b); - - EdgePairs 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; - EdgePairs 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; - RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; - RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; -}; - -/** - * @brief A flat, polygon-set delegate - */ -class DB_PUBLIC FlatRegion - : public AsIfFlatRegion -{ -public: - typedef db::layer polygon_layer_type; - typedef polygon_layer_type::iterator polygon_iterator_type; - - FlatRegion (); - FlatRegion (const db::Shapes &polygons, bool is_merged); - FlatRegion (bool is_merged); - - FlatRegion (const FlatRegion &other); - - virtual ~FlatRegion (); - - RegionDelegate *clone () const - { - return new FlatRegion (*this); - } - - void reserve (size_t); - - virtual RegionIteratorDelegate *begin () const; - virtual RegionIteratorDelegate *begin_merged () const; - - virtual std::pair begin_iter () const; - virtual std::pair begin_merged_iter () const; - - virtual bool empty () const; - virtual size_t size () const; - virtual bool is_merged () const; - - virtual RegionDelegate *merged_in_place (); - virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); - virtual RegionDelegate *merged () const; - - virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter); - - virtual RegionDelegate *add_in_place (const Region &other); - virtual RegionDelegate *add (const Region &other) const; - - virtual const db::Polygon *nth (size_t n) const; - virtual bool has_valid_polygons () const; - virtual bool has_valid_merged_polygons () const; - - virtual const db::RecursiveShapeIterator *iter () const; - - void insert (const db::Box &box); - void insert (const db::Path &path); - void insert (const db::SimplePolygon &polygon); - void insert (const db::Polygon &polygon); - void insert (const db::Shape &shape); - - template - void insert (const db::Shape &shape, const T &trans) - { - if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { - db::Polygon poly; - shape.polygon (poly); - poly.transform (trans); - insert (poly); - } - } - - template - void insert (const Iter &b, const Iter &e) - { - reserve (size () + (e - b)); - for (Iter i = b; i != e; ++i) { - insert (*i); - } - } - - template - void insert_seq (const Iter &seq) - { - for (Iter i = seq; ! i.at_end (); ++i) { - insert (*i); - } - } - - template - void transform (const Trans &trans) - { - if (! trans.is_unity ()) { - for (polygon_iterator_type p = m_polygons.get_layer ().begin (); p != m_polygons.get_layer ().end (); ++p) { - m_polygons.get_layer ().replace (p, p->transformed (trans)); - } - invalidate_cache (); - } - } - -protected: - virtual void merged_semantics_changed (); - virtual Box compute_bbox () const; - void invalidate_cache (); - void set_is_merged (bool m); - -private: - friend class AsIfFlatRegion; - - db::Shapes &raw_polygons () { return m_polygons; } - - FlatRegion &operator= (const FlatRegion &other); - - bool m_is_merged; - mutable db::Shapes m_polygons; - mutable db::Shapes m_merged_polygons; - mutable bool m_merged_polygons_valid; - - void init (); - void ensure_merged_polygons_valid () const; -}; - -/** - * @brief An original layerregion based on a RecursiveShapeIterator - */ -class DB_PUBLIC OriginalLayerRegion - : public AsIfFlatRegion -{ -public: - OriginalLayerRegion (); - OriginalLayerRegion (const OriginalLayerRegion &other); - OriginalLayerRegion (const RecursiveShapeIterator &si, bool is_merged = false); - OriginalLayerRegion (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false); - virtual ~OriginalLayerRegion (); - - RegionDelegate *clone () const; - - virtual RegionIteratorDelegate *begin () const; - virtual RegionIteratorDelegate *begin_merged () const; - - virtual std::pair begin_iter () const; - virtual std::pair begin_merged_iter () const; - - virtual bool empty () const; - - virtual bool is_merged () const; - - virtual const db::Polygon *nth (size_t n) const; - virtual bool has_valid_polygons () const; - virtual bool has_valid_merged_polygons () const; - - virtual const db::RecursiveShapeIterator *iter () const; - - virtual bool equals (const Region &other) const; - virtual bool less (const Region &other) const; - -private: - FlatRegion &operator= (const FlatRegion &other); - - bool m_is_merged; - mutable db::Shapes m_merged_polygons; - mutable bool m_merged_polygons_valid; - mutable db::RecursiveShapeIterator m_iter; - db::ICplxTrans m_iter_trans; - - void init (); - void ensure_merged_polygons_valid () const; -}; - /** * @brief A helper class allowing delivery of addressable polygons * @@ -1126,9 +508,7 @@ public: template Region (const Sh &s) { - FlatRegion *delegate = new FlatRegion (); - mp_delegate = delegate; - delegate->insert (s); + insert (s); } /** @@ -1141,9 +521,10 @@ public: template Region (const Iter &b, const Iter &e) { - FlatRegion *delegate = new FlatRegion (); - mp_delegate = delegate; - delegate->insert (b, e); + reserve (e - b); + for (Iter i = b; i != e; ++i) { + insert (*i); + } } /** @@ -1230,27 +611,18 @@ public: * @brief Inserts the given shape (working object) into the region */ template - void insert (const Sh &shape) - { - flat_region ()->insert (shape); - } + void insert (const Sh &shape); /** * @brief Insert a shape reference into the region */ - void insert (const db::Shape &shape) - { - flat_region ()->insert (shape); - } + void insert (const db::Shape &shape); /** * @brief Insert a transformed shape into the region */ template - void insert (const db::Shape &shape, const T &trans) - { - flat_region ()->insert (shape, trans); - } + void insert (const db::Shape &shape, const T &trans); /** * @brief Returns true if the region is empty @@ -1281,18 +653,12 @@ public: /** * @brief Clear the region */ - void clear () - { - set_delegate (new EmptyRegion ()); - } + void clear (); /** * @brief Reserve memory for the given number of polygons */ - void reserve (size_t n) - { - flat_region ()->reserve (n); - } + void reserve (size_t n); /** * @brief Sets the minimum-coherence flag @@ -1602,11 +968,7 @@ public: * @brief Transform the region */ template - Region &transform (const T &trans) - { - flat_region ()->transform (trans); - return *this; - } + Region &transform (const T &trans); /** * @brief Returns the transformed region @@ -2301,1213 +1663,6 @@ private: FlatRegion *flat_region (); }; - -// ...................................................................................................... - -#if 0 // ORIGINAL -/** - * @brief A region - * - * A region basically is a set of polygons. It supports a variety of operations, i.e. - * boolean operations with other regions, sizing etc. - * - * Regions can have different states. Specifically a region can be merged (no overlapping - * polygons are present, touching polygons are merged, self-intersections of polygons are - * removed) or non-merged (polygons may overlap or polygons may be self-intersecting). In - * merged state, the wrap count at every point is either zero or 1, in non-merged state - * it can be every value. - * - * Polygons inside the region may contain holes if the region is merged. - */ -class DB_PUBLIC Region - : public gsi::ObjectBase -{ -public: - typedef db::Coord coord_type; - typedef db::coord_traits coord_traits; - typedef db::Polygon polygon_type; - typedef db::Vector vector_type; - typedef db::Point point_type; - typedef db::Box box_type; - typedef coord_traits::distance_type distance_type; - typedef coord_traits::perimeter_type perimeter_type; - typedef coord_traits::area_type area_type; - typedef RegionIterator const_iterator; - - /** - * @brief Default constructor - * - * Creates an empty region. - */ - Region () - : m_polygons (false), m_merged_polygons (false) - { - init (); - } - - /** - * @brief Constructor from an object - * - * Creates a region representing a single instance of that object - */ - template - Region (const Sh &s) - : m_polygons (false), m_merged_polygons (false) - { - init (); - insert (s); - } - - /** - * @brief Sequence constructor - * - * Creates a region from a sequence of objects. The objects can be boxes, - * polygons, paths or shapes. This version accepts iterators of the begin ... end - * style. - */ - template - Region (const Iter &b, const Iter &e) - : m_polygons (false), m_merged_polygons (false) - { - init (); - reserve (e - b); - for (Iter i = b; i != e; ++i) { - insert (*i); - } - } - - /** - * @brief Constructor from a RecursiveShapeIterator - * - * Creates a region from a recursive shape iterator. This allows to feed a region - * from a hierarchy of cells. - */ - Region (const RecursiveShapeIterator &si); - - /** - * @brief Constructor from a RecursiveShapeIterator with a transformation - * - * Creates a region from a recursive shape iterator. This allows to feed a region - * from a hierarchy of cells. The transformation is useful to scale to a specific - * DBU for example. - */ - Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true); - - /** - * @brief Enable progress reporting - * - * @param progress_text The description text of the progress object - */ - void enable_progress (const std::string &progress_desc = std::string ()); - - /** - * @brief Disable progress reporting - */ - void disable_progress (); - - /** - * @brief Iterator of the region - * - * The iterator delivers the polygons of the region. - * It follows the at_end semantics. - */ - const_iterator begin () const - { - if (has_valid_polygons ()) { - return const_iterator (m_polygons.get_layer ().begin (), m_polygons.get_layer ().end ()); - } else { - return const_iterator (m_iter, m_iter_trans); - } - } - - /** - * @brief Returns the merged polygons if merge semantics applies - * - * If merge semantics is not enabled, this iterator delivers the individual polygons. - */ - const_iterator begin_merged () const; - - /** - * @brief Delivers a RecursiveShapeIterator pointing to the polygons plus the necessary transformation - */ - std::pair begin_iter () const; - - /** - * @brief Delivers a RecursiveShapeIterator pointing to the merged polygons plus the necessary transformation - */ - std::pair begin_merged_iter () const; - - /** - * @brief Insert a box into the region - */ - void insert (const db::Box &box); - - /** - * @brief Insert a path into the region - */ - void insert (const db::Path &path); - - /** - * @brief Insert a simple polygon into the region - */ - void insert (const db::SimplePolygon &polygon); - - /** - * @brief Insert a polygon into the region - */ - void insert (const db::Polygon &polygon); - - /** - * @brief Insert a shape into the region - */ - void insert (const db::Shape &shape); - - /** - * @brief Insert a transformed shape into the region - */ - template - void insert (const db::Shape &shape, const T &trans) - { - if (shape.is_polygon () || shape.is_path () || shape.is_box ()) { - ensure_valid_polygons (); - db::Polygon poly; - shape.polygon (poly); - poly.transform (trans); - m_polygons.insert (poly); - m_is_merged = false; - invalidate_cache (); - } - } - - /** - * @brief Returns true if the region is empty - */ - bool empty () const - { - return has_valid_polygons () && m_polygons.empty (); - } - - /** - * @brief Returns the number of polygons in the region - */ - size_t size () const; - - /** - * @brief Returns a string representing the region - * - * nmax specifies how many polygons are included (set to std::numeric_limits::max() for "all". - */ - std::string to_string (size_t nmax = 10) const; - - /** - * @brief Clear the region - */ - void clear (); - - /** - * @brief Reserve memory for the given number of polygons - */ - void reserve (size_t n) - { - m_polygons.reserve (db::Polygon::tag (), n); - } - - /** - * @brief Sets the minimum-coherence flag - * - * If minimum coherence is set, the merge operations (explicit merge with \merge or - * implicit merge through merged_semantics) are performed using minimum coherence mode. - * The coherence mode determines how kissing-corner situations are resolved. If - * minimum coherence is selected, they are resolved such that multiple polygons are - * created which touch at a corner). - */ - void set_min_coherence (bool f) - { - if (m_merge_min_coherence != f) { - m_merge_min_coherence = f; - invalidate_cache (); - } - } - - /** - * @brief Gets the minimum coherence flag - */ - bool min_coherence () const - { - return m_merge_min_coherence; - } - - /** - * @brief Sets the merged-semantics flag - * - * If merged semantics is enabled (the default), coherent polygons will be considered - * as single regions and artificial edges such as cut-lines will not be considered. - * Merged semantics thus is equivalent to considering coherent areas rather than - * single polygons. - */ - void set_merged_semantics (bool f); - - /** - * @brief Gets the merged-semantics flag - */ - bool merged_semantics () const - { - return m_merged_semantics; - } - - /** - * @brief Enables or disables strict handling - * - * Strict handling means to leave away some optimizations. Specifically the - * output of boolean operations will be merged even if one input is empty. - * Without strict handling, the operation will be optimized and output - * won't be merged. - * - * Strict handling is disabled by default. - */ - void set_strict_handling (bool f); - - /** - * @brief Gets a valid indicating whether strict handling is enabled - */ - bool strict_handling () const - { - return m_strict_handling; - } - - /** - * @brief Returns true if the region is a single box - * - * If the region is not merged, this method may return false even - * if the merged region would be a box. - */ - bool is_box () const; - - /** - * @brief Returns true if the region is merged - */ - bool is_merged () const - { - return m_is_merged; - } - - /** - * @brief Returns the area of the region - * - * This method returns the area sum over all polygons. - * Merged semantics applies. In merged semantics, the area is the correct area covered by the - * polygons. Without merged semantics, overlapping parts are counted twice. - * - * If a box is given, the computation is restricted to that box. - */ - area_type area (const db::Box &box = db::Box ()) const; - - /** - * @brief Returns the perimeter sum of the region - * - * This method returns the perimeter sum over all polygons. - * Merged semantics applies. In merged semantics, the perimeter is the true perimeter. - * Without merged semantics, inner edges contribute to the perimeter. - * - * If a box is given, the computation is restricted to that box. - * Edges coincident with the box edges are counted only if the form outer edges at the box edge. - */ - perimeter_type perimeter (const db::Box &box = db::Box ()) const; - - /** - * @brief Returns the bounding box of the region - */ - Box bbox () const - { - ensure_bbox_valid (); - return m_bbox; - } - - /** - * @brief Filters the polygons - * - * This method will keep all polygons for which the filter returns true. - * Merged semantics applies. In merged semantics, the filter will run over - * all merged polygons. - */ - template - Region &filter (F &filter) - { - polygon_iterator_type pw = m_polygons.get_layer ().begin (); - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - if (filter (*p)) { - if (pw == m_polygons.get_layer ().end ()) { - m_polygons.get_layer ().insert (*p); - pw = m_polygons.get_layer ().end (); - } else { - m_polygons.get_layer ().replace (pw++, *p); - } - } - } - m_polygons.get_layer ().erase (pw, m_polygons.get_layer ().end ()); - m_merged_polygons.clear (); - m_is_merged = m_merged_semantics; - m_iter = db::RecursiveShapeIterator (); - return *this; - } - - /** - * @brief Returns the filtered polygons - * - * This method will return a new region with only those polygons which - * conform to the filter criterion. - */ - template - Region filtered (F &filter) const - { - Region d; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - if (filter (*p)) { - d.insert (*p); - } - } - return d; - } - - /** - * @brief Applies a width check and returns EdgePairs which correspond to violation markers - * - * The width check will create a edge pairs if the width of the area between the - * edges is less than the specified threshold d. Without "whole_edges", the parts of - * the edges are returned which violate the condition. If "whole_edges" is true, the - * result will contain the complete edges participating in the result. - * - * The metrics parameter specifies which metrics to use. "Euclidian", "Square" and "Projected" - * metrics are available. - * - * ingore_angle allows specification of a maximum angle that connected edges can have to not participate - * in the check. By choosing 90 degree, edges with angles of 90 degree and larger are not checked, - * but acute corners are for example. - * - * With min_projection and max_projection it is possible to specify how edges must be related - * to each other. If the length of the projection of either edge on the other is >= min_projection - * or < max_projection, the edges are considered for the check. - * - * The order of the edges in the resulting edge pairs is undefined. - * - * Merged semantics applies. - */ - EdgePairs width_check (db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_single_polygon_check (db::WidthRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a space check and returns EdgePairs which correspond to violation markers - * - * For the parameters see \width_check. The space check reports edges for which the space is - * less than the specified threshold d. - * - * Merged semantics applies. - */ - EdgePairs space_check (db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::SpaceRelation, false, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a isolation check (space of polygon vs. other polygons) and returns EdgePairs which correspond to violation markers - * - * For the parameters see \width_check. The space check reports edges for which the notch space is - * less than the specified threshold d. - * - * Merged semantics applies. - */ - EdgePairs isolated_check (db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::SpaceRelation, true, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a notch check (space in polygon vs. itself) and returns EdgePairs which correspond to violation markers - * - * For the parameters see \width_check. The space check reports edges for which the notch space is - * less than the specified threshold d. - * - * Merged semantics applies. - */ - EdgePairs notch_check (db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_single_polygon_check (db::SpaceRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a enclosed check and returns EdgePairs which correspond to violation markers - * - * The check will return true, where this region is enclosing the polygons of the other - * region by less than the specified threshold d. - * - * The first edges of the edge pairs will be the ones from "this", the second edges will be those of "other". - * - * For the other parameters see \width_check. - * - * Merged semantics applies. - */ - EdgePairs enclosing_check (const Region &other, db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::OverlapRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a overlap check and returns EdgePairs which correspond to violation markers - * - * The check will return true, where this region overlaps the polygons of the other - * region by less than the specified threshold d. - * - * The first edges of the edge pairs will be the ones from "this", the second edges will be those of "other". - * - * For the other parameters see \width_check. - * - * Merged semantics applies. - */ - EdgePairs overlap_check (const Region &other, db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::WidthRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a separation check and returns EdgePairs which correspond to violation markers - * - * The check will return true, where this region is separated by polygons of the other - * region by less than the specified threshold d. - * - * The first edges of the edge pairs will be the ones from "this", the second edges will be those of "other". - * - * For the other parameters see \width_check. - * - * Merged semantics applies. - */ - EdgePairs separation_check (const Region &other, db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::SpaceRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Applies a inside check and returns EdgePairs which correspond to violation markers - * - * The check will return true, where this region is inside by less than the threshold d inside the polygons of the other - * region. - * - * The first edges of the edge pairs will be the ones from "this", the second edges will be those of "other". - * - * For the other parameters see \width_check. - * - * Merged semantics applies. - */ - EdgePairs inside_check (const Region &other, db::Coord d, bool whole_edges = false, metrics_type metrics = db::Euclidian, double ignore_angle = 90, distance_type min_projection = 0, distance_type max_projection = std::numeric_limits::max ()) const - { - return run_check (db::InsideRelation, true, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); - } - - /** - * @brief Returns an edge set containing all edges of the polygons in this region - * - * Merged semantics applies. In merged semantics, only full, outer edges are delivered. - */ - Edges edges () const; - - /** - * @brief Returns an edge set containing all edges of the polygons in this region - * - * This version allows to specify a filter by which the edges are filtered before they are - * returned. - * - * Merged semantics applies. In merged semantics, only full, outer edges are delivered. - */ - template - Edges edges (F &filter) const - { - Edges edges; - for (const_iterator p = begin_merged (); ! p.at_end (); ++p) { - for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - if (filter (*e)) { - edges.insert (*e); - } - } - } - return edges; - } - - /** - * @brief Transform the region - */ - template - Region &transform (const T &trans) - { - if (! trans.is_unity ()) { - ensure_valid_polygons (); - for (polygon_iterator_type p = m_polygons.get_layer ().begin (); p != m_polygons.get_layer ().end (); ++p) { - m_polygons.get_layer ().replace (p, p->transformed (trans)); - } - m_iter_trans = db::ICplxTrans (trans) * m_iter_trans; - m_bbox_valid = false; - } - return *this; - } - - /** - * @brief Returns the transformed region - */ - template - Region transformed (const T &trans) const - { - Region d (*this); - d.transform (trans); - return d; - } - - /** - * @brief Performs an off-grid check on the polygons inside the region - * - * The method returns single-point edge pairs for each vertex found off-grid. - * The grid can be specified differently in x and y direction. - */ - EdgePairs grid_check (db::Coord gx, db::Coord gy) const; - - /** - * @brief Performs an angle check - * - * The method returns edge pairs for each connected edges having - * an angle between min and max (exclusive max, in degree) or - * not between min and max (if inverse is true). - */ - EdgePairs angle_check (double min, double max, bool inverse) const; - - /** - * @brief Grid-snaps the region - * - * 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); - - /** - * @brief Returns the snapped region - */ - Region snapped (db::Coord gx, db::Coord gy) const - { - Region d (*this); - d.snap (gx, gy); - return d; - } - - /** - * @brief Performs a check for "strange" polygons - * - * This check will return a region with all self-overlapping or - * non-orientable parts of polygons. - * - * Naturally this method will ignore the merged_semantics setting. - */ - Region strange_polygon_check () const; - - /** - * @brief Swap with the other region - */ - void swap (db::Region &other); - - /** - * @brief Merge the region - * - * This method merges the polygons of the region if they are not merged already. - * It returns a reference to this region. - * An out-of-place merge version is "merged". - */ - Region &merge (); - - /* - * @brief Returns the merged region - * - * This is the out-of-place merge. It returns a new region but does not modify - * the region it is called on. An in-place version is "merge". - */ - Region merged () const - { - Region d (*this); - d.merge (); - return d; - } - - /** - * @brief Merge the region with options - * - * This will merge the region and provides some options while doing so. - * - * A result is generated if the wrap count (wc) - * of a point is larger than the given min_wrapcount value. - * A min_wrapcount of 1 will produce output where at least two polygons overlap. - * - * This method will always execute the merge, even if the region is already merged. - * - * @param min_coherence Set this parameter to true to get minimum polygons (kissing corner problem) - * @param min_wrapcount See the description above - * @return A reference to this region - */ - Region &merge (bool min_coherence, unsigned int min_wc = 0); - - /** - * @brief Returns the merged region with options - * - * This is the out-of-place version of "merge" with options (see there). - */ - Region merged (bool min_coherence, unsigned int min_wc = 0) const - { - Region d (*this); - d.merge (min_coherence, min_wc); - return d; - } - - /** - * @brief Size the region - * - * This method applies a sizing to the region. Before the sizing is done, the - * region is merged if this is not the case already. - * - * The result is a set of polygons which may be overlapping, but are not self- - * intersecting. - * - * Merged semantics applies. - * - * @param d The (isotropic) sizing value - * @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) - { - return size (d, d, mode); - } - - /** - * @brief Anisotropic sizing - * - * This version provides anisotropic sizing by allowing to specify a distance int x and y - * direction. - * - * Merged semantics applies. - * - * @param dx The horizontal sizing - * @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); - - /** - * @brief Returns the sized region - * - * This is an out-of-place version of the size method with isotropic sizing - * "merged polygon" semantics applies if merged_polygon_semantics is true (see set_auto_merge). - * - * Merged semantics applies. - */ - Region sized (coord_type d, unsigned int mode = 2) const - { - Region r (*this); - r.size (d, mode); - return r; - } - - /** - * @brief Returns the sized region - * - * This is an out-of-place version of the size method with anisotropic sizing - * "merged polygon" semantics applies if merged_polygon_semantics is true (see set_auto_merge). - * - * Merged semantics applies. - */ - Region sized (coord_type dx, coord_type dy, unsigned int mode = 2) const - { - Region r (*this); - r.size (dx, dy, mode); - return r; - } - - /** - * @brief Boolean AND operator - */ - Region operator& (const Region &other) const - { - Region d (*this); - d &= other; - return d; - } - - /** - * @brief In-place boolean AND operator - * - * This method does not necessarily merge the region. To ensure the region - * is merged, call merge afterwards. - */ - Region &operator&= (const Region &other); - - /** - * @brief Boolean NOT operator - */ - Region operator- (const Region &other) const - { - Region d (*this); - d -= other; - return d; - } - - /** - * @brief In-place boolean NOT operator - * - * This method does not necessarily merge the region. To ensure the region - * is merged, call merge afterwards. - */ - Region &operator-= (const Region &other); - - /** - * @brief Boolean XOR operator - */ - Region operator^ (const Region &other) const - { - Region d (*this); - d ^= other; - return d; - } - - /** - * @brief In-place boolean XOR operator - * - * This method does not necessarily merge the region. To ensure the region - * is merged, call merge afterwards. - */ - Region &operator^= (const Region &other); - - /** - * @brief Boolean OR operator - * - * This method merges the polygons of both regions. - */ - Region operator| (const Region &other) const - { - Region d (*this); - d |= other; - return d; - } - - /** - * @brief In-place boolean OR operator - */ - Region &operator|= (const Region &other); - - /** - * @brief Joining of regions - * - * This method joins the regions but does not merge them afterwards. - */ - Region operator+ (const Region &other) const - { - Region d (*this); - d += other; - return d; - } - - /** - * @brief In-place region joining - */ - Region &operator+= (const Region &other); - - /** - * @brief Selects all polygons of this region which are completly outside polygons from the other region - * - * Merged semantics applies. - */ - Region &select_outside (const Region &other) - { - select_interacting_generic (other, 1, false, false); - return *this; - } - - /** - * @brief Selects all polygons of this region which are not completly outside polygons from the other region - * - * Merged semantics applies. - */ - Region &select_not_outside (const Region &other) - { - select_interacting_generic (other, 1, false, true); - return *this; - } - - /** - * @brief Returns all polygons of this which are completly outside polygons from the other region - * - * This method is an out-of-place version of select_outside. - * - * Merged semantics applies. - */ - Region selected_outside (const Region &other) const - { - return selected_interacting_generic (other, 1, false, false); - } - - /** - * @brief Returns all polygons of this which are not completly outside polygons from the other region - * - * This method is an out-of-place version of select_not_outside. - * - * Merged semantics applies. - */ - Region selected_not_outside (const Region &other) const - { - return selected_interacting_generic (other, 1, false, true); - } - - /** - * @brief Selects all polygons of this region which are completly inside polygons from the other region - * - * Merged semantics applies. - */ - Region &select_inside (const Region &other) - { - select_interacting_generic (other, -1, false, false); - return *this; - } - - /** - * @brief Selects all polygons of this region which are not completly inside polygons from the other region - * - * Merged semantics applies. - */ - Region &select_not_inside (const Region &other) - { - select_interacting_generic (other, -1, false, true); - return *this; - } - - /** - * @brief Returns all polygons of this which are completly inside polygons from the other region - * - * This method is an out-of-place version of select_inside. - * - * Merged semantics applies. - */ - Region selected_inside (const Region &other) const - { - return selected_interacting_generic (other, -1, true, false); - } - - /** - * @brief Returns all polygons of this which are not completly inside polygons from the other region - * - * This method is an out-of-place version of select_not_inside. - * - * Merged semantics applies. - */ - Region selected_not_inside (const Region &other) const - { - return selected_interacting_generic (other, -1, true, true); - } - - /** - * @brief Selects all polygons of this region which overlap or touch polygons from the other region - * - * Merged semantics applies. - */ - Region &select_interacting (const Region &other) - { - select_interacting_generic (other, 0, true, false); - return *this; - } - - /** - * @brief Selects all polygons of this region which do not overlap or touch polygons from the other region - * - * Merged semantics applies. - */ - Region &select_not_interacting (const Region &other) - { - select_interacting_generic (other, 0, true, true); - return *this; - } - - /** - * @brief Returns all polygons of this which overlap or touch polygons from the other region - * - * This method is an out-of-place version of select_interacting. - * - * Merged semantics applies. - */ - Region selected_interacting (const Region &other) const - { - return selected_interacting_generic (other, 0, true, false); - } - - /** - * @brief Returns all polygons of this which do not overlap or touch polygons from the other region - * - * This method is an out-of-place version of select_not_interacting. - * - * Merged semantics applies. - */ - Region selected_not_interacting (const Region &other) const - { - return selected_interacting_generic (other, 0, true, true); - } - - /** - * @brief Selects all polygons of this region which overlap or touch edges from the given edge collection - * - * Merged semantics applies to both operators. - */ - Region &select_interacting (const Edges &other) - { - select_interacting_generic (other, false); - return *this; - } - - /** - * @brief Selects all polygons of this region which do not overlap or touch edges from the edge collection - * - * Merged semantics applies to both operators. - */ - Region &select_not_interacting (const Edges &other) - { - select_interacting_generic (other, true); - return *this; - } - - /** - * @brief Returns all polygons of this which overlap or touch edges from the edge collection - * - * This method is an out-of-place version of select_interacting. - * - * Merged semantics applies to both operators. - */ - Region selected_interacting (const Edges &other) const - { - return selected_interacting_generic (other, false); - } - - /** - * @brief Returns all polygons of this which do not overlap or touch polygons from the other region - * - * This method is an out-of-place version of select_not_interacting. - * - * Merged semantics applies to both operators. - */ - Region selected_not_interacting (const Edges &other) const - { - return selected_interacting_generic (other, true); - } - - /** - * @brief Selects all polygons of this region which overlap polygons from the other region - * - * Merged semantics applies. - */ - Region &select_overlapping (const Region &other) - { - select_interacting_generic (other, 0, false, false); - return *this; - } - - /** - * @brief Selects all polygons of this region which do not overlap polygons from the other region - * - * Merged semantics applies. - */ - Region &select_not_overlapping (const Region &other) - { - select_interacting_generic (other, 0, false, true); - return *this; - } - - /** - * @brief Returns all polygons of this which overlap polygons from the other region - * - * This method is an out-of-place version of select_overlapping. - * - * Merged semantics applies. - */ - Region selected_overlapping (const Region &other) const - { - return selected_interacting_generic (other, 0, false, false); - } - - /** - * @brief Returns all polygons of this which do not overlap polygons from the other region - * - * This method is an out-of-place version of select_not_overlapping. - * - * Merged semantics applies. - */ - Region selected_not_overlapping (const Region &other) const - { - return selected_interacting_generic (other, 0, false, true); - } - - /** - * @brief Returns the holes - * - * This method returns the holes of the polygons. - * - * Merged semantics applies. - */ - Region holes () const; - - /** - * @brief Returns the hulls - * - * This method returns the hulls of the polygons. It does not merge the - * polygons before the hulls are derived. - * - * Merged semantics applies. - */ - Region hulls () const; - - /** - * @brief Returns all polygons which are in the other region - * - * This method will return all polygons which are part of another region. - * The match is done exactly. - * The "invert" flag can be used to invert the sense, i.e. with - * "invert" set to true, this method will return all polygons not - * in the other region. - * - * Merged semantics applies. - */ - Region in (const Region &other, bool invert = false) const; - - /** - * @brief Round corners (in-place) - * - * @param rinner The inner radius in DBU units - * @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) - { - Region r = rounded_corners (rinner, router, n); - swap (r); - } - - /** - * @brief Returns a new region with rounded corners (out of place) - */ - Region rounded_corners (double rinner, double router, unsigned int n) const; - - /** - * @brief Returns the smoothed region - * - * @param d The smoothing accuracy - */ - Region smoothed (coord_type d) const; - - /** - * @brief Smoothes the region (in-place) - */ - void smooth (coord_type d) - { - Region r = smoothed (d); - swap (r); - } - - /** - * @brief Returns the nth polygon - * - * This method will force the polygons to be inside the polygon vector. - * If that happens, the method may be costly and will invalidate any iterator. - * The iterator should be used whenever possible. - */ - const db::Polygon *nth (size_t n) const - { - ensure_valid_polygons (); - return n < m_polygons.size () ? &m_polygons.get_layer ().begin () [n] : 0; - } - - /** - * @brief Returns true, if the region has valid polygons stored within itself - */ - bool has_valid_polygons () const - { - // Note: we take a copy of the iterator since the at_end method may - // validate the iterator which will make it refer to a specifc configuration. - return db::RecursiveShapeIterator (m_iter).at_end (); - } - - /** - * @brief Gets the internal iterator - * - * This method is intended for users who know what they are doing - */ - const db::RecursiveShapeIterator &iter () const - { - return m_iter; - } - - /** - * @brief Ensures the region has valid polygons - * - * This method is const since it has const semantics. - */ - void ensure_valid_polygons () const; - - /** - * @brief Ensures the region has valid merged polygons - * - * It will make sure that begin_merged will deliver an - * iterator to a polygon with a unique memory location. - */ - void ensure_valid_merged_polygons () const; - - /** - * @brief Equality - */ - bool operator== (const db::Region &other) const; - - /** - * @brief Inequality - */ - bool operator!= (const db::Region &other) const - { - return !operator== (other); - } - - /** - * @brief Less operator - */ - bool operator< (const db::Region &other) const; - -private: - typedef db::layer polygon_layer_type; - typedef polygon_layer_type::iterator polygon_iterator_type; - - bool m_is_merged; - bool m_merged_semantics; - bool m_strict_handling; - bool m_merge_min_coherence; - mutable db::Shapes m_polygons; - mutable db::Shapes m_merged_polygons; - mutable db::Box m_bbox; - mutable bool m_bbox_valid; - mutable bool m_merged_polygons_valid; - mutable db::RecursiveShapeIterator m_iter; - db::ICplxTrans m_iter_trans; - bool m_report_progress; - std::string m_progress_desc; - - void init (); - void invalidate_cache (); - void set_valid_polygons (); - void ensure_bbox_valid () const; - void ensure_merged_polygons_valid () const; - EdgePairs 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; - EdgePairs 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; - void select_interacting_generic (const Region &other, int mode, bool touching, bool inverse); - Region selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; - Region selected_interacting_generic (const Edges &other, bool inverse) const; - void select_interacting_generic (const Edges &other, bool inverse); -}; -#endif - /** * @brief A polygon receiver putting the polygons into a Region object * diff --git a/src/db/db/dbRegionDelegate.cc b/src/db/db/dbRegionDelegate.cc new file mode 100644 index 000000000..42df393ad --- /dev/null +++ b/src/db/db/dbRegionDelegate.cc @@ -0,0 +1,91 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbRegionDelegate.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- + +RegionDelegate::RegionDelegate () +{ + m_report_progress = false; + m_merged_semantics = true; + m_strict_handling = false; + m_merge_min_coherence = false; +} + +RegionDelegate::RegionDelegate (const RegionDelegate &other) +{ + operator= (other); +} + +RegionDelegate & +RegionDelegate::operator= (const RegionDelegate &other) +{ + if (this != &other) { + m_report_progress = other.m_report_progress; + m_merged_semantics = other.m_merged_semantics; + m_strict_handling = other.m_strict_handling; + m_merge_min_coherence = other.m_merge_min_coherence; + } + return *this; +} + +RegionDelegate::~RegionDelegate () +{ + // .. nothing yet .. +} + +void RegionDelegate::enable_progress (const std::string &progress_desc) +{ + m_report_progress = true; + m_progress_desc = progress_desc; +} + +void RegionDelegate::disable_progress () +{ + m_report_progress = false; +} + +void RegionDelegate::set_min_coherence (bool f) +{ + m_merge_min_coherence = f; +} + +void RegionDelegate::set_merged_semantics (bool f) +{ + if (f != m_merged_semantics) { + m_merged_semantics = f; + merged_semantics_changed (); + } +} + +void RegionDelegate::set_strict_handling (bool f) +{ + m_strict_handling = f; +} + +} + diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h new file mode 100644 index 000000000..ecf10d292 --- /dev/null +++ b/src/db/db/dbRegionDelegate.h @@ -0,0 +1,206 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbRegionDelegate +#define HDR_dbRegionDelegate + +#include "dbCommon.h" + +#include "dbPolygon.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbEdgePairRelations.h" + +#include + +namespace db { + +class RecursiveShapeIterator; +class EdgeFilterBase; +class PolygonFilterBase; + +/** + * @brief The region iterator delegate + */ +class DB_PUBLIC RegionIteratorDelegate +{ +public: + RegionIteratorDelegate () { } + virtual ~RegionIteratorDelegate () { } + + typedef db::Polygon value_type; + + virtual bool at_end () const = 0; + virtual void increment () = 0; + virtual const value_type *get () const = 0; + virtual RegionIteratorDelegate *clone () const = 0; +}; + +/** + * @brief The delegate for the actual region implementation + */ +class DB_PUBLIC RegionDelegate +{ +public: + typedef db::Coord coord_type; + typedef db::coord_traits coord_traits; + typedef db::Polygon polygon_type; + typedef db::Vector vector_type; + typedef db::Point point_type; + typedef db::Box box_type; + typedef coord_traits::distance_type distance_type; + typedef coord_traits::perimeter_type perimeter_type; + typedef coord_traits::area_type area_type; + + RegionDelegate (); + virtual ~RegionDelegate (); + + RegionDelegate (const RegionDelegate &other); + RegionDelegate &operator= (const RegionDelegate &other); + + virtual RegionDelegate *clone () const = 0; + + void enable_progress (const std::string &progress_desc); + void disable_progress (); + + void set_min_coherence (bool f); + bool min_coherence () const + { + return m_merge_min_coherence; + } + + void set_merged_semantics (bool f); + bool merged_semantics () const + { + return m_merged_semantics; + } + + void set_strict_handling (bool f); + bool strict_handling () const + { + return m_strict_handling; + } + + virtual std::string to_string (size_t nmax) const = 0; + + virtual RegionIteratorDelegate *begin () const = 0; + virtual RegionIteratorDelegate *begin_merged () const = 0; + + virtual std::pair begin_iter () const = 0; + virtual std::pair begin_merged_iter () const = 0; + + virtual bool empty () const = 0; + virtual bool is_box () const = 0; + virtual bool is_merged () const = 0; + virtual size_t size () const = 0; + + virtual area_type area (const db::Box &box) const = 0; + virtual perimeter_type perimeter (const db::Box &box) const = 0; + virtual Box bbox () const = 0; + + virtual EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs isolated_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs notch_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs enclosing_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs overlap_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs separation_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs inside_check (const Region &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const = 0; + virtual EdgePairs grid_check (db::Coord gx, db::Coord gy) const = 0; + virtual EdgePairs angle_check (double min, double max, bool inverse) const = 0; + + virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) = 0; + virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy) = 0; + + 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 *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; + + virtual RegionDelegate *and_with (const Region &other) const = 0; + virtual RegionDelegate *not_with (const Region &other) const = 0; + virtual RegionDelegate *xor_with (const Region &other) const = 0; + virtual RegionDelegate *or_with (const Region &other) const = 0; + virtual RegionDelegate *add_in_place (const Region &other) = 0; + virtual RegionDelegate *add (const Region &other) const = 0; + + virtual RegionDelegate *selected_outside (const Region &other) const = 0; + virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; + virtual RegionDelegate *selected_inside (const Region &other) const = 0; + virtual RegionDelegate *selected_not_inside (const Region &other) const = 0; + virtual RegionDelegate *selected_interacting (const Region &other) const = 0; + virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0; + virtual RegionDelegate *selected_interacting (const Edges &other) const = 0; + 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; + virtual bool has_valid_merged_polygons () const = 0; + + virtual const db::RecursiveShapeIterator *iter () const = 0; + + virtual bool equals (const Region &other) const = 0; + virtual bool less (const Region &other) const = 0; + +protected: + const std::string &progress_desc () const + { + return m_progress_desc; + } + + bool report_progress () const + { + return m_report_progress; + } + + virtual void merged_semantics_changed () { } + +private: + bool m_merged_semantics; + bool m_strict_handling; + bool m_merge_min_coherence; + bool m_report_progress; + std::string m_progress_desc; +}; + +} + +#endif + diff --git a/src/db/unit_tests/dbTilingProcessor.cc b/src/db/unit_tests/dbTilingProcessor.cc index 5aa0b1216..c352cb19a 100644 --- a/src/db/unit_tests/dbTilingProcessor.cc +++ b/src/db/unit_tests/dbTilingProcessor.cc @@ -29,6 +29,7 @@ #include "gsiDecl.h" #include "dbWriter.h" #include "dbSaveLayoutOptions.h" +#include "dbShapeProcessor.h" #include #include