diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index 9d2fa8d39..42f770aff 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -724,8 +724,11 @@ Edges::select_interacting (const Region &other) scanner.insert ((char *) &*e, 0); } - for (Region::const_iterator p = other.begin (); ! p.at_end (); ++p) { - scanner.insert ((char *) &*p + 1, 1); + AddressablePolygonDelivery p = other.addressable_polygons (); + + for ( ; ! p.at_end (); ++p) { + // NOTE: dirty hack - we can take the address of the polygon because we used ensure_flat_polygons. + scanner.insert ((char *) p.operator-> () + 1, 1); } Edges output; @@ -753,8 +756,10 @@ Edges::select_not_interacting (const Region &other) scanner.insert ((char *) &*e, 0); } - for (Region::const_iterator p = other.begin (); ! p.at_end (); ++p) { - scanner.insert ((char *) &*p + 1, 1); + AddressablePolygonDelivery p = other.addressable_polygons (); + for ( ; ! p.at_end (); ++p) { + // NOTE: dirty hack - we can take the address of the polygon because we used ensure_flat_polygons. + scanner.insert ((char *) p.operator-> () + 1, 1); } std::set interacting; diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index c63ae42a5..439772415 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -559,8 +559,10 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) db::box_scanner scanner (report_progress (), progress_desc ()); scanner.reserve (size () + other.size ()); - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - scanner.insert ((char *) &*p + 1, 1); + 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 (); @@ -1019,23 +1021,28 @@ public: } 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_scanner.reserve (o.vertices ()); m_edges.clear (); - m_edges.reserve (o->vertices ()); + m_edges.reserve (o.vertices ()); - for (db::Polygon::polygon_edge_iterator e = o->begin_edge (); ! e.at_end (); ++e) { + 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 ()); + tl_assert (m_edges.size () == o.vertices ()); m_scanner.process (*mp_output, mp_output->distance (), db::box_convert ()); @@ -1043,26 +1050,31 @@ public: } 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_scanner.reserve (o1.vertices () + o2.vertices ()); m_edges.clear (); - m_edges.reserve (o1->vertices () + o2->vertices ()); + m_edges.reserve (o1.vertices () + o2.vertices ()); - for (db::Polygon::polygon_edge_iterator e = o1->begin_edge (); ! e.at_end (); ++e) { + 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) { + 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 ()); + 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). @@ -1092,18 +1104,26 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, 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 (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - scanner.insert (&*p, n); + for ( ; ! p.at_end (); ++p) { + scanner.insert (p.operator-> (), n); n += 2; } + AddressablePolygonDelivery po; + if (other) { + + po = other->addressable_merged_polygons (); + n = 1; - for (RegionIterator p (other->begin_merged ()); ! p.at_end (); ++p) { - scanner.insert (&*p, n); + for ( ; ! po.at_end (); ++po) { + scanner.insert (po.operator-> (), n); n += 2; } + } EdgeRelationFilter check (rel, d, metrics); @@ -1138,11 +1158,13 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord Poly2PolyCheck poly_check (edge_check); do { + size_t n = 0; for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - poly_check.finish (&*p, n); + poly_check.enter (*p, n); n += 2; } + } while (edge_check.prepare_next_pass ()); return result; @@ -1966,6 +1988,11 @@ 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; @@ -2205,6 +2232,12 @@ 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 { diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index c93b943de..1ab534af0 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -41,6 +41,8 @@ #include "tlString.h" #include "gsiObject.h" +#include + namespace db { class EdgeFilterBase; @@ -526,6 +528,7 @@ public: 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; @@ -636,6 +639,7 @@ public: 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; } @@ -883,6 +887,7 @@ public: 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; @@ -980,6 +985,7 @@ public: 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; @@ -999,6 +1005,61 @@ private: void ensure_merged_polygons_valid () const; }; +/** + * @brief A helper class allowing delivery of addressable polygons + * + * In some applications (i.e. box scanner), polygons need to be taken + * by address. The region cannot always deliver adressable polygons. + * This class help providing this ability by keeping a temporary copy + * if required. + */ + +class DB_PUBLIC AddressablePolygonDelivery +{ +public: + AddressablePolygonDelivery () + : m_iter (), m_valid (false) + { + // .. nothing yet .. + } + + AddressablePolygonDelivery (const RegionIterator &iter, bool valid) + : m_iter (iter), m_valid (valid) + { + if (! m_valid && ! m_iter.at_end ()) { + m_heap.push_back (*m_iter); + } + } + + bool at_end () const + { + return m_iter.at_end (); + } + + AddressablePolygonDelivery &operator++ () + { + ++m_iter; + if (! m_valid && ! m_iter.at_end ()) { + m_heap.push_back (*m_iter); + } + return *this; + } + + const db::Polygon *operator-> () const + { + if (m_valid) { + return m_iter.operator-> (); + } else { + return &m_heap.back (); + } + } + +private: + RegionIterator m_iter; + bool m_valid; + std::list m_heap; +}; + /** * @brief A region * @@ -2161,12 +2222,47 @@ public: /** * @brief Returns true, if the region has valid polygons stored within itself + * + * If the region has valid polygons, it is permissable to use the polygon's addresses + * from the iterator. Furthermore, the random access operator nth() is available. */ bool has_valid_polygons () const { return mp_delegate->has_valid_polygons (); } + /** + * @brief Returns an addressable delivery for polygons + * + * This object allows accessing the polygons by address, even if they + * are not delivered from a container. The magic is a heap object + * inside the delivery object. Hence, the deliver object must persist + * as long as the addresses are required. + */ + AddressablePolygonDelivery addressable_polygons () const + { + return AddressablePolygonDelivery (begin (), has_valid_polygons ()); + } + + /** + * @brief Returns true, if the region has valid merged polygons stored within itself + * + * If the region has valid merged polygons, it is permissable to use the polygon's addresses + * from the merged polygon iterator. Furthermore, the random access operator nth() is available. + */ + bool has_valid_merged_polygons () const + { + return mp_delegate->has_valid_merged_polygons (); + } + + /** + * @brief Returns an addressable delivery for merged polygons + */ + AddressablePolygonDelivery addressable_merged_polygons () const + { + return AddressablePolygonDelivery (begin_merged (), has_valid_merged_polygons ()); + } + /** * @brief Gets the internal iterator *