diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 7b249ef60..989993c71 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -300,117 +300,6 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const 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 { @@ -424,30 +313,31 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) return clone (); } - db::box_scanner scanner (report_progress (), progress_desc ()); - scanner.reserve (size () + other.size ()); + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatRegion (false)); + region_to_edge_interaction_filter filter (output->raw_polygons (), inverse); AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); for ( ; ! p.at_end (); ++p) { - scanner.insert ((char *) p.operator-> () + 1, 1); + scanner.insert1 (p.operator-> (), 0); + if (inverse) { + filter.preset (p.operator-> ()); + } } AddressableEdgeDelivery e (other.addressable_edges ()); for ( ; ! e.at_end (); ++e) { - scanner.insert ((char *) e.operator-> (), 0); + scanner.insert2 (e.operator-> (), 0); } - std::auto_ptr output (new FlatRegion (false)); - EdgeOrRegionBoxConverter bc; + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - 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); + if (inverse) { filter.fill_output (); } diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index 7235781e5..7b504287f 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -27,9 +27,75 @@ #include "dbCommon.h" #include "dbRegionDelegate.h" +#include "dbPolygon.h" +#include "dbEdge.h" +#include "dbBoxScanner.h" + +#include namespace db { +/** + * @brief A helper class for the region to edge interaction functionality + */ +template +class DB_PUBLIC region_to_edge_interaction_filter + : public db::box_scanner_receiver2 +{ +public: + region_to_edge_interaction_filter (OutputContainer &output, bool inverse) + : mp_output (&output), m_inverse (inverse) + { + // .. nothing yet .. + } + + void preset (const db::Polygon *poly) + { + m_seen.insert (poly); + } + + void add (const db::Polygon *p, size_t, const db::Edge *e, size_t) + { + if ((m_seen.find (p) == m_seen.end ()) != m_inverse) { + + // A polygon and an edge interact if the edge is either inside completely + // of at least one edge of the polygon intersects with the edge + bool interacts = false; + if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) { + interacts = true; + } else { + for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) { + if ((*pe).intersect (*e)) { + interacts = true; + } + } + } + + if (interacts) { + if (m_inverse) { + m_seen.erase (p); + } else { + m_seen.insert (p); + mp_output->insert (*p); + } + } + + } + } + + void fill_output () + { + for (std::set::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) { + mp_output->insert (**p); + } + } + +private: + OutputContainer *mp_output; + std::set m_seen; + bool m_inverse; +}; + /** * @brief Provides default flat implementations */ diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 459a0088d..53b97f918 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1328,11 +1328,93 @@ private: mutable db::EdgeProcessor m_ep; }; +struct ResultInserter +{ + ResultInserter (db::Layout *layout, std::unordered_set &result) + : mp_layout (layout), mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Polygon &p) + { + (*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ())); + } + +private: + db::Layout *mp_layout; + std::unordered_set *mp_result; +}; + +class InteractingWithEdgeLocalOperation + : public local_operation +{ +public: + InteractingWithEdgeLocalOperation (bool inverse) + : m_inverse (inverse) + { + // .. nothing yet .. + } + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + m_scanner.clear (); + + ResultInserter inserter (layout, result); + region_to_edge_interaction_filter filter (inserter, m_inverse); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + m_scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.subject_shape (i->first); + heap.push_back (subject.obj ().transformed (subject.trans ())); + + m_scanner.insert1 (&heap.back (), 0); + if (m_inverse) { + filter.preset (&heap.back ()); + } + + } + + m_scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + if (m_inverse) { + filter.fill_output (); + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + if (!m_inverse) { + return Drop; + } else { + return Copy; + } + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)")); + } + +private: + bool m_inverse; + mutable db::box_scanner2 m_scanner; +}; + } RegionDelegate * DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const { + // with these flag set to true, the resulting polygons are broken again. + bool split_after = false; + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); if (! other_deep) { return db::AsIfFlatRegion::selected_interacting_generic (other, mode, touching, inverse); @@ -1347,24 +1429,52 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (m_deep_layer.store ()->threads ()); -#if defined(SPLIT ) - // with these settings, the resulting polygons are broken again ... - proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); - proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); -#endif + if (split_after) { + proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); + proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + } - proc.run (&op, m_merged_polygons.layer (), other_deep->merged_deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); db::DeepRegion *res = new db::DeepRegion (dl_out); - res->set_is_merged (true); + if (! split_after) { + res->set_is_merged (true); + } return res; } RegionDelegate * DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) const { - // TODO: implement hierarchically - return db::AsIfFlatRegion::selected_interacting_generic (other, inverse); + // with these flag set to true, the resulting polygons are broken again. + bool split_after = false; + + const db::DeepEdges *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + return db::AsIfFlatRegion::selected_interacting_generic (other, inverse); + } + + ensure_merged_polygons_valid (); + + DeepLayer dl_out (m_deep_layer.derived ()); + + db::InteractingWithEdgeLocalOperation op (inverse); + + db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (m_deep_layer.store ()->threads ()); + if (split_after) { + proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); + proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + } + + proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + db::DeepRegion *res = new db::DeepRegion (dl_out); + if (! split_after) { + res->set_is_merged (true); + } + return res; } } diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 121a8c16b..b549ac921 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -237,6 +237,30 @@ private: Trans m_trans; }; +// --------------------------------------------------------------------------------------------- + +/** + * @brief Safe enlargement of a box + * Boxes must not vanish when augmented for overlapping queries. Hence we must not make + * the boxes shrinked too much on enlarge. + */ +db::Box safe_box_enlarged (const db::Box &box, db::Coord dx, db::Coord dy) +{ + if (box.empty ()) { + return box; + } else { + db::Coord w2 = db::Coord (box.width () / 2); + db::Coord h2 = db::Coord (box.height () / 2); + if (dx + w2 < 0) { + dx = -w2; + } + if (dy + h2 < 0) { + dy = -h2; + } + return box.enlarged (db::Vector (dx, dy)); + } +} + // --------------------------------------------------------------------------------------------- // LocalProcessorCellContext implementation @@ -723,7 +747,7 @@ public: // Find all instance array members that potentially interact with the shape and use // add_shapes_from_intruder_inst on them db::Box ref_box = db::box_convert () (*ref); - for (db::CellInstArray::iterator n = inst->begin_touching (ref_box.enlarged (db::Vector (m_dist - 1, m_dist - 1)), inst_bc); !n.at_end (); ++n) { + for (db::CellInstArray::iterator n = inst->begin_touching (safe_box_enlarged (ref_box, m_dist - 1, m_dist - 1), inst_bc); !n.at_end (); ++n) { db::ICplxTrans tn = inst->complex_trans (*n); db::Box region = ref_box.transformed (tn.inverted ()).enlarged (db::Vector (m_dist, m_dist)) & intruder_cell.bbox (m_intruder_layer).enlarged (db::Vector (m_dist, m_dist)); if (! region.empty ()) { @@ -794,7 +818,7 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u // TODO: in some cases, it may be possible to optimize this for arrays - for (db::CellInstArray::iterator k = inst2->begin_touching (ibox1.enlarged (db::Vector (-1, -1)), inst2_bc); ! k.at_end (); ++k) { + for (db::CellInstArray::iterator k = inst2->begin_touching (safe_box_enlarged (ibox1, -1, -1), inst2_bc); ! k.at_end (); ++k) { if (inst1 == inst2 && *n == *k) { // skip self-interactions - this is handled inside the cell @@ -887,7 +911,7 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins db::box_convert inst_bc (*layout, layer); db::Box rbox = db::box_convert () (ref); - for (db::CellInstArray::iterator n = inst->begin_touching (rbox.enlarged (db::Vector (dist - 1, dist - 1)), inst_bc); ! n.at_end (); ++n) { + for (db::CellInstArray::iterator n = inst->begin_touching (safe_box_enlarged (rbox, dist - 1, dist - 1), inst_bc); ! n.at_end (); ++n) { db::ICplxTrans tn = inst->complex_trans (*n); db::Box cbox = (tn * cell.bbox (layer)).enlarged (db::Vector (dist, dist)) & rbox.enlarged (db::Vector (dist, dist)); @@ -1293,7 +1317,7 @@ void local_processor::compute_contexts (local_processor_contexts::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) { - for (db::CellInstArray::iterator k = (*j)->begin_touching (nbox.enlarged (db::Vector (-1, -1)), inst_bcii); ! k.at_end (); ++k) { + for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) { db::ICplxTrans tk = (*j)->complex_trans (*k); // NOTE: no self-interactions if (i->first != *j || tn != tk) { @@ -1568,7 +1592,20 @@ local_processor::compute_local_cell (const db::local_processor_conte } - op->compute_local (mp_subject_layout, interactions, result, m_max_vertex_count, m_area_ratio); + if (interactions.begin () != interactions.end ()) { + + if (interactions.begin_intruders () == interactions.end_intruders ()) { + + typename local_operation::on_empty_intruder_mode eh = op->on_empty_intruder_hint (); + if (eh == local_operation::Drop) { + return; + } + + } + + op->compute_local (mp_subject_layout, interactions, result, m_max_vertex_count, m_area_ratio); + + } } template class DB_PUBLIC local_processor; diff --git a/src/db/db/dbHierProcessor.h b/src/db/db/dbHierProcessor.h index 9e4a11cb2..1326cffa9 100644 --- a/src/db/db/dbHierProcessor.h +++ b/src/db/db/dbHierProcessor.h @@ -54,6 +54,8 @@ public: typedef std::unordered_map > container; typedef container::const_iterator iterator; typedef container::value_type::second_type::const_iterator iterator2; + typedef typename std::unordered_map::const_iterator subject_iterator; + typedef typename std::unordered_map::const_iterator intruder_iterator; shape_interactions (); @@ -67,6 +69,26 @@ public: return m_interactions.end (); } + subject_iterator begin_subjects () const + { + return m_subject_shapes.begin (); + } + + subject_iterator end_subjects () const + { + return m_subject_shapes.end (); + } + + intruder_iterator begin_intruders () const + { + return m_intruder_shapes.begin (); + } + + intruder_iterator end_intruders () const + { + return m_intruder_shapes.end (); + } + bool has_intruder_shape_id (unsigned int id) const; bool has_subject_shape_id (unsigned int id) const; void add_intruder_shape (unsigned int id, const TI &shape); diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index bd72575fb..f00fff9fe 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -781,31 +781,50 @@ TEST(14_Interacting) db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); db::Region r6 (db::RecursiveShapeIterator (ly, top_cell, l6), dss); - db::Layout target; - unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + { + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.selected_interacting (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.selected_not_interacting (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.selected_inside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.selected_not_inside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r2.selected_outside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r2.selected_not_outside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (16, 0)), r2.selected_overlapping (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (17, 0)), r2.selected_not_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.selected_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.selected_not_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.selected_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.selected_not_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r2.selected_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r2.selected_not_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (16, 0)), r2.selected_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (17, 0)), r2.selected_not_overlapping (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r6.selected_interacting (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r6.selected_not_interacting (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r6.selected_inside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r6.selected_not_inside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r6.selected_outside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r6.selected_not_outside (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r6.selected_overlapping (r1)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r6.selected_not_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r6.selected_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r6.selected_not_interacting (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r6.selected_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r6.selected_not_inside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r6.selected_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r6.selected_not_outside (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r6.selected_overlapping (r1)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r6.selected_not_overlapping (r1)); - EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true); + EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true); - CHECKPOINT(); - db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14.gds"); + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14a.gds"); + } + + db::Edges r1e = r1.edges (); + + { + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r6); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1e); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r6.selected_interacting (r1e)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r6.selected_not_interacting (r1e)); + + EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), true); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14b.gds"); + } } TEST(15_Filtered) diff --git a/testdata/algo/deep_region_au14.gds b/testdata/algo/deep_region_au14a.gds similarity index 100% rename from testdata/algo/deep_region_au14.gds rename to testdata/algo/deep_region_au14a.gds