From 2e619983729714589e1bdb1d8e37aa6c4c668cf4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 6 Oct 2018 01:40:01 +0200 Subject: [PATCH] WIP: interactions with same layer (needs finishing) --- .../tools/netx/db_plugin/dbHierProcessor.cc | 374 ++++++++++++++---- .../tools/netx/db_plugin/dbHierProcessor.h | 56 ++- src/plugins/tools/netx/testdata/hlp1.oas | Bin 691 -> 740 bytes src/plugins/tools/netx/testdata/hlp2.oas | Bin 1039 -> 1134 bytes src/plugins/tools/netx/testdata/hlp3.oas | Bin 755 -> 817 bytes src/plugins/tools/netx/testdata/hlp4.oas | Bin 768 -> 830 bytes src/plugins/tools/netx/testdata/hlp5.oas | Bin 868 -> 936 bytes src/plugins/tools/netx/testdata/hlp6.oas | Bin 1298 -> 1468 bytes src/plugins/tools/netx/testdata/hlp7.oas | Bin 795 -> 839 bytes src/plugins/tools/netx/testdata/hlp8.oas | Bin 955 -> 1026 bytes .../netx/unit_tests/dbHierProcessorTests.cc | 193 ++++++++- 11 files changed, 533 insertions(+), 90 deletions(-) diff --git a/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc b/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc index 94fb1435d..39405385f 100644 --- a/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc +++ b/src/plugins/tools/netx/db_plugin/dbHierProcessor.cc @@ -72,6 +72,8 @@ BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and) // .. nothing yet .. } +// --------------------------------------------------------------------------------------------- + LocalOperation::on_empty_intruder_mode BoolAndOrNotLocalOperation::on_empty_intruder_hint () const { @@ -85,36 +87,36 @@ BoolAndOrNotLocalOperation::description () const } void -BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const std::map > &interactions, std::set &result) const +BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::set &result) const { db::EdgeProcessor ep; size_t p1 = 0, p2 = 1; std::set others; - for (std::map >::const_iterator r = interactions.begin (); r != interactions.end (); ++r) { - - // TODO: vector could be set - bool found = false; - for (std::vector::const_iterator i = r->second.begin (); i != r->second.end () && ! found; ++i) { - found = (*i == r->first); + for (ShapeInteractions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (ShapeInteractions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.shape (*j)); } - if (found) { - // shortcut (and: keep, not: drop) + } + + for (ShapeInteractions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.shape (i->first); + if (others.find (subject) != others.end ()) { if (m_is_and) { - result.insert (r->first); + result.insert (subject); } - } else if (r->second.empty ()) { + } else if (i->second.empty ()) { // shortcut (not: keep, and: drop) if (! m_is_and) { - result.insert (r->first); + result.insert (subject); } } else { - for (db::PolygonRef::polygon_edge_iterator e = r->first.begin_edge (); ! e.at_end(); ++e) { + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { ep.insert (*e, p1); } p1 += 2; - others.insert (r->second.begin (), r->second.end ()); } } @@ -136,6 +138,64 @@ BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const std::map &result) const +{ + if (m_wrap_count == 0) { + return; + } + + db::EdgeProcessor ep; + + size_t p1 = 0, p2 = 1; + std::set seen2; + + for (ShapeInteractions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.shape (i->first); + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p1); + } + p1 += 2; + + for (db::ShapeInteractions::iterator2 o = i->second.begin (); o != i->second.end (); ++o) { + // don't take the same (really the same, not an identical one) shape twice - the interaction + // set does not take care to list just one copy of the same item on the intruder side. + if (seen2.find (*o) == seen2.end ()) { + seen2.insert (*o); + const db::PolygonRef &intruder = interactions.shape (*o); + for (db::PolygonRef::polygon_edge_iterator e = intruder.begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p2); + } + p2 += 2; + } + } + + } + + db::MergeOp op (m_wrap_count - 1); + db::PolygonRefGenerator pr (layout, result); + db::PolygonGenerator pg (pr, true, true); + ep.process (pg, op); +} + +SelfOverlapMergeLocalOperation::on_empty_intruder_mode SelfOverlapMergeLocalOperation::on_empty_intruder_hint () const +{ + return m_wrap_count > 1 ? LocalOperation::Drop : LocalOperation::Copy; +} + +std::string SelfOverlapMergeLocalOperation::description () const +{ + return tl::sprintf (tl::to_string (tr ("Self-overlap (wrap count %d)")), int (m_wrap_count)); +} + // --------------------------------------------------------------------------------------------- // LocalProcessorCellContext implementation @@ -262,6 +322,63 @@ LocalProcessorCellContexts::compute_results (LocalProcessorContexts &contexts, d proc->push_results (cell, output_layer, common); } +// --------------------------------------------------------------------------------------------- + +ShapeInteractions::ShapeInteractions () + : m_id (0) +{ + // .. nothing yet .. +} + +bool +ShapeInteractions::has_shape_id (unsigned int id) const +{ + return m_shapes.find (id) != m_shapes.end (); +} + +void +ShapeInteractions::add_shape (unsigned int id, const db::PolygonRef &shape) +{ + m_shapes [id] = shape; +} + +void +ShapeInteractions::add_subject (unsigned int id, const db::PolygonRef &shape) +{ + add_shape (id, shape); + m_interactions.insert (std::make_pair (id, container::value_type::second_type ())); +} + +void +ShapeInteractions::add_interaction (unsigned int subject_id, unsigned int intruder_id) +{ + m_interactions [subject_id].push_back (intruder_id); +} + +const std::vector & +ShapeInteractions::intruders_for (unsigned int subject_id) const +{ + iterator i = m_interactions.find (subject_id); + if (i == m_interactions.end ()) { + static std::vector empty; + return empty; + } else { + return i->second; + } +} + +const db::PolygonRef & +ShapeInteractions::shape (unsigned int id) const +{ + std::map::const_iterator i = m_shapes.find (id); + if (i == m_shapes.end ()) { + static db::PolygonRef s; + return s; + } else { + return i->second; + } +} + // --------------------------------------------------------------------------------------------- // Helper classes for the LocalProcessor @@ -274,46 +391,73 @@ inline unsigned int polygon_ref_flags () } struct InteractionRegistrationShape2Shape - : db::box_scanner_receiver2 + : db::box_scanner_receiver2 { public: - InteractionRegistrationShape2Shape (db::Layout *layout, std::map > *result) + InteractionRegistrationShape2Shape (db::Layout *layout, ShapeInteractions *result) : mp_result (result), mp_layout (layout) { // nothing yet .. } - void add (const db::PolygonRef *ref1, int, const db::PolygonRef *ref2, int) + void add (const db::PolygonRef *ref1, unsigned int id1, const db::PolygonRef *ref2, unsigned int id2) { + mp_result->add_shape (id1, *ref1); + if (mp_layout) { // In order to guarantee the refs come from the subject layout, we'd need to // rewrite them to the subject layout if required. - db::Polygon poly = ref2->obj ().transformed (ref2->trans ()); - (*mp_result) [*ref1].push_back (db::PolygonRef (poly, mp_layout->shape_repository ())); + if (!mp_result->has_shape_id (id2)) { + db::Polygon poly = ref2->obj ().transformed (ref2->trans ()); + mp_result->add_shape (id2, db::PolygonRef (poly, mp_layout->shape_repository ())); + } } else { - (*mp_result) [*ref1].push_back (*ref2); + mp_result->add_shape (id2, *ref2); } + mp_result->add_interaction (id1, id2); } private: - std::map > *mp_result; + ShapeInteractions *mp_result; db::Layout *mp_layout; }; -struct InteractionRegistrationShape2Inst - : db::box_scanner_receiver2 +struct InteractionRegistrationShape1 + : db::box_scanner_receiver { public: - InteractionRegistrationShape2Inst (db::Layout *subject_layout, const db::Layout *intruder_layout, unsigned int intruder_layer, db::Coord dist, std::map > *result) + InteractionRegistrationShape1 (ShapeInteractions *result) + : mp_result (result) + { + // nothing yet .. + } + + void add (const db::PolygonRef *ref1, unsigned int id1, const db::PolygonRef *ref2, unsigned int id2) + { + mp_result->add_shape (id1, *ref1); + mp_result->add_shape (id2, *ref2); + mp_result->add_interaction (id1, id2); + } + +private: + ShapeInteractions *mp_result; +}; + +struct InteractionRegistrationShape2Inst + : db::box_scanner_receiver2 +{ +public: + InteractionRegistrationShape2Inst (db::Layout *subject_layout, const db::Layout *intruder_layout, unsigned int intruder_layer, db::Coord dist, ShapeInteractions *result) : mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), m_intruder_layer (intruder_layer), m_dist (dist), mp_result (result) { // nothing yet .. } - void add (const db::PolygonRef *ref, int, const db::CellInstArray *inst, int) + void add (const db::PolygonRef *ref, unsigned int id1, const db::CellInstArray *inst, unsigned int inst_id) { const db::Cell &intruder_cell = mp_intruder_layout->cell (inst->object ().cell_index ()); db::box_convert inst_bc (*mp_intruder_layout, m_intruder_layer); + mp_result->add_shape (id1, *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) { @@ -327,12 +471,23 @@ public: si.shape_flags (polygon_ref_flags ()); while (! si.at_end ()) { - // @@@ it should be easier to transform references const db::PolygonRef *ref2 = si.shape ().basic_ptr (db::PolygonRef::tag ()); - db::Polygon poly = ref2->obj ().transformed (tn * si.trans () * db::ICplxTrans (ref2->trans ())); - // NOTE: we intentionally rewrite to the subject layout - this way polygon refs in the context come from the - // subject, not from the intruder. - (*mp_result)[*ref].push_back (db::PolygonRef (poly, mp_subject_layout->shape_repository())); + + // reuse the same id for shapes from the same instance -> this avoid duplicates with different IDs on + // the intruder side. + std::map, unsigned int>::const_iterator k = m_inst_shape_ids.find (std::make_pair (inst_id, ref2)); + if (k == m_inst_shape_ids.end ()) { + + k = m_inst_shape_ids.insert (std::make_pair (std::make_pair (inst_id, ref2), mp_result->next_id ())).first; + + db::Polygon poly = ref2->obj ().transformed (tn * si.trans () * db::ICplxTrans (ref2->trans ())); + // NOTE: we intentionally rewrite to the subject layout - this way polygon refs in the context come from the + // subject, not from the intruder. + mp_result->add_shape (k->second, db::PolygonRef (poly, mp_subject_layout->shape_repository())); + + } + + mp_result->add_interaction (id1, k->second); ++si; @@ -348,7 +503,8 @@ private: const db::Layout *mp_intruder_layout; unsigned int m_intruder_layer; db::Coord m_dist; - std::map > *mp_result; + ShapeInteractions *mp_result; + std::map, unsigned int> m_inst_shape_ids; }; static bool @@ -414,7 +570,7 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u } struct InteractionRegistrationInst2Inst - : db::box_scanner_receiver2 + : db::box_scanner_receiver2 { public: typedef std::pair, std::set > interaction_value_type; @@ -425,14 +581,26 @@ public: // nothing yet .. } - void add (const db::CellInstArray *inst1, int, const db::CellInstArray *inst2, int) + void add (const db::CellInstArray *inst1, unsigned int id1, const db::CellInstArray *inst2, unsigned int id2) { - // @@@ TODO: always insert, if both instances come from different layouts // NOTE: self-interactions are possible for arrays: different elements of the // array may interact which is a cell-external interaction. - if ((mp_subject_layout != mp_intruder_layout || *inst1 != *inst2 || inst1->size () > 1) - && instances_interact (mp_subject_layout, inst1, m_subject_layer, mp_intruder_layout, inst2, m_intruder_layer, m_dist)) { - (*mp_result) [inst1].first.insert (inst2); + if (mp_subject_layout != mp_intruder_layout || id1 != id2 || inst1->size () > 1) { + + bool ignore = false; + if (mp_subject_layout == mp_intruder_layout && m_subject_layer == m_intruder_layer) { + if (m_interactions.find (std::make_pair (id2, id1)) != m_interactions.end ()) { + // for self interactions ignore the reverse interactions + ignore = true; + } else { + m_interactions.insert (std::make_pair (id1, id2)); + } + } + + if (! ignore && instances_interact (mp_subject_layout, inst1, m_subject_layer, mp_intruder_layout, inst2, m_intruder_layer, m_dist)) { + (*mp_result) [inst1].first.insert (inst2); + } + } } @@ -441,6 +609,7 @@ private: unsigned int m_subject_layer, m_intruder_layer; db::Coord m_dist; std::map, std::set > > *mp_result; + std::set > m_interactions; }; static bool @@ -473,7 +642,7 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins } struct InteractionRegistrationInst2Shape - : db::box_scanner_receiver2 + : db::box_scanner_receiver2 { public: InteractionRegistrationInst2Shape (const db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, std::map, std::set > > *result) @@ -482,7 +651,7 @@ public: // nothing yet .. } - void add (const db::CellInstArray *inst, int, const db::PolygonRef *ref, int) + void add (const db::CellInstArray *inst, unsigned int, const db::PolygonRef *ref, unsigned int) { if (instance_shape_interacts (mp_subject_layout, inst, m_subject_layer, *ref, m_dist)) { (*mp_result) [inst].second.insert (*ref); @@ -599,23 +768,44 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts, db::box_scanner2 scanner; InteractionRegistrationInst2Inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.intruder_layer (), dist, &interactions); - for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { - if (! inst_bcs (i->cell_inst ()).empty ()) { - scanner.insert1 (&i->cell_inst (), 0); - } - } + unsigned int id = 0; - if (intruder_cell) { - for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) { + if (subject_cell == intruder_cell) { + + // Use the same id's for same instances - this way we can easily detect same instances + // and don't make the self-interacting + + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + unsigned int iid = ++id; + if (! inst_bcs (i->cell_inst ()).empty ()) { + scanner.insert1 (&i->cell_inst (), iid); + } if (! inst_bci (i->cell_inst ()).empty ()) { - scanner.insert2 (&i->cell_inst (), 0); + scanner.insert2 (&i->cell_inst (), iid); } } + + } else { + + for (db::Cell::const_iterator i = subject_cell->begin (); !i.at_end (); ++i) { + if (! inst_bcs (i->cell_inst ()).empty ()) { + scanner.insert1 (&i->cell_inst (), ++id); + } + } + + if (intruder_cell) { + for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) { + if (! inst_bci (i->cell_inst ()).empty ()) { + scanner.insert2 (&i->cell_inst (), ++id); + } + } + } + } for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { - scanner.insert2 (i.operator-> (), 0); + scanner.insert2 (i.operator-> (), ++id); } } @@ -724,36 +914,69 @@ LocalProcessor::compute_local_cell (LocalProcessorContexts &contexts, db::Cell * // local shapes vs. child cell - std::map > interactions; + ShapeInteractions interactions; db::box_convert inst_bci (*mp_intruder_layout, contexts.intruder_layer ()); - if (op->on_empty_intruder_hint () != LocalOperation::Drop) { - // insert dummy interactions to accommodate subject vs. nothing - for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { - interactions.insert (std::make_pair (*i->basic_ptr (db::PolygonRef::tag ()), std::vector ())); + // insert dummy interactions to accommodate subject vs. nothing and assign an ID + // range for the subject shapes. + unsigned int subject_id0 = 0; + for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { + + unsigned int id = interactions.next_id (); + if (subject_id0 == 0) { + subject_id0 = id; } + + if (op->on_empty_intruder_hint () != LocalOperation::Drop) { + const db::PolygonRef *ref = i->basic_ptr (db::PolygonRef::tag ()); + interactions.add_subject (id, *ref); + } + } if (! subject_shapes->empty () && (intruder_shapes || ! intruders.second.empty ())) { - db::box_scanner2 scanner; - InteractionRegistrationShape2Shape rec (mp_subject_layout == mp_intruder_layout ? 0 : mp_subject_layout, &interactions); + if (subject_cell == intruder_cell && contexts.subject_layer () == contexts.intruder_layer ()) { - for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { - scanner.insert1 (i->basic_ptr (db::PolygonRef::tag ()), 0); - } + db::box_scanner scanner; + InteractionRegistrationShape1 rec (&interactions); - for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { - scanner.insert2 (i.operator-> (), 0); - } - - if (intruder_shapes) { - for (db::Shapes::shape_iterator i = intruder_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { - scanner.insert2 (i->basic_ptr (db::PolygonRef::tag ()), 0); + unsigned int id = subject_id0; + for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { + const db::PolygonRef *ref = i->basic_ptr (db::PolygonRef::tag ()); + scanner.insert (ref, id++); } - } - scanner.process (rec, op->dist (), db::box_convert (), db::box_convert ()); + for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { + scanner.insert (i.operator-> (), interactions.next_id ()); + } + + scanner.process (rec, op->dist (), db::box_convert ()); + + } else { + + db::box_scanner2 scanner; + InteractionRegistrationShape2Shape rec (mp_subject_layout == mp_intruder_layout ? 0 : mp_subject_layout, &interactions); + + unsigned int id = subject_id0; + for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { + const db::PolygonRef *ref = i->basic_ptr (db::PolygonRef::tag ()); + scanner.insert1 (ref, id++); + } + + for (std::set::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) { + scanner.insert2 (i.operator-> (), interactions.next_id ()); + } + + if (intruder_shapes) { + for (db::Shapes::shape_iterator i = intruder_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { + scanner.insert2 (i->basic_ptr (db::PolygonRef::tag ()), interactions.next_id ()); + } + } + + scanner.process (rec, op->dist (), db::box_convert (), db::box_convert ()); + + } } @@ -762,21 +985,30 @@ LocalProcessor::compute_local_cell (LocalProcessorContexts &contexts, db::Cell * db::box_scanner2 scanner; InteractionRegistrationShape2Inst rec (mp_subject_layout, mp_intruder_layout, contexts.intruder_layer (), op->dist (), &interactions); + unsigned int id = subject_id0; for (db::Shapes::shape_iterator i = subject_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) { - scanner.insert1 (i->basic_ptr (db::PolygonRef::tag ()), 0); + scanner.insert1 (i->basic_ptr (db::PolygonRef::tag ()), id++); } - if (intruder_cell) { + unsigned int inst_id = 0; + + if (subject_cell == intruder_cell && contexts.subject_layer () == contexts.intruder_layer ()) { + + // Same cell, same layer -> no shape to child instance interactions because this will be taken care of + // by the instances themselves (and their intruders). This also means, we prefer to deal with + // interactions low in the hierarchy. + + } else if (intruder_cell) { for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) { if (! inst_bci (i->cell_inst ()).empty ()) { - scanner.insert2 (&i->cell_inst (), 0); + scanner.insert2 (&i->cell_inst (), ++inst_id); } } } for (std::set::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) { if (! inst_bci (*i).empty ()) { - scanner.insert2 (i.operator-> (), 0); + scanner.insert2 (i.operator-> (), ++inst_id); } } diff --git a/src/plugins/tools/netx/db_plugin/dbHierProcessor.h b/src/plugins/tools/netx/db_plugin/dbHierProcessor.h index 07418d6af..4cceeac97 100644 --- a/src/plugins/tools/netx/db_plugin/dbHierProcessor.h +++ b/src/plugins/tools/netx/db_plugin/dbHierProcessor.h @@ -39,6 +39,44 @@ class LocalProcessor; class LocalProcessorCellContext; class LocalProcessorContexts; +// @@@ TODO: move this somewhere else? +class DB_PLUGIN_PUBLIC ShapeInteractions +{ +public: + typedef std::map > container; + typedef container::const_iterator iterator; + typedef container::value_type::second_type::const_iterator iterator2; + + ShapeInteractions (); + + iterator begin () const + { + return m_interactions.begin (); + } + + iterator end () const + { + return m_interactions.end (); + } + + bool has_shape_id (unsigned int id) const; + void add_shape (unsigned int id, const db::PolygonRef &shape); + void add_subject (unsigned int id, const db::PolygonRef &shape); + void add_interaction (unsigned int subject_id, unsigned int intruder_id); + const std::vector &intruders_for (unsigned int subject_id) const; + const db::PolygonRef &shape (unsigned int id) const; + + unsigned int next_id () + { + return ++m_id; + } + +private: + std::map > m_interactions; + std::map m_shapes; + unsigned int m_id; +}; + class DB_PLUGIN_PUBLIC LocalOperation { public: @@ -49,7 +87,7 @@ public: LocalOperation () { } virtual ~LocalOperation () { } - virtual void compute_local (db::Layout *layout, const std::map > &interactions, std::set &result) const = 0; + virtual void compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::set &result) const = 0; virtual on_empty_intruder_mode on_empty_intruder_hint () const = 0; virtual std::string description () const = 0; virtual db::Coord dist () const { return 0; } @@ -61,7 +99,7 @@ class DB_PLUGIN_PUBLIC BoolAndOrNotLocalOperation public: BoolAndOrNotLocalOperation (bool is_and); - virtual void compute_local (db::Layout *layout, const std::map > &interactions, std::set &result) const; + virtual void compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::set &result) const; virtual on_empty_intruder_mode on_empty_intruder_hint () const; virtual std::string description () const; @@ -69,6 +107,20 @@ private: bool m_is_and; }; +class DB_PLUGIN_PUBLIC SelfOverlapMergeLocalOperation + : public LocalOperation +{ +public: + SelfOverlapMergeLocalOperation (unsigned int wrap_count); + + virtual void compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::set &result) const; + virtual on_empty_intruder_mode on_empty_intruder_hint () const; + virtual std::string description () const; + +private: + unsigned int m_wrap_count; +}; + // @@@ TODO: should be hidden (private data?) struct DB_PLUGIN_PUBLIC LocalProcessorCellDrop { diff --git a/src/plugins/tools/netx/testdata/hlp1.oas b/src/plugins/tools/netx/testdata/hlp1.oas index 7dee89a076c77d0e72e4a3c29d851723d02402dc..39fe2a5dd1427b939ce55a6a6aa8e56e23c28b17 100644 GIT binary patch delta 27 jcmdnY`h<1EW=3XF%e;vX^%$8ZA7uP6`2r&^69WSPjtmJP delta 19 bcmaFDx|wyuW=2M)$sZX%PGaI=VqgFON>>IU diff --git a/src/plugins/tools/netx/testdata/hlp2.oas b/src/plugins/tools/netx/testdata/hlp2.oas index b344983c451e2db53a2bbf9fbdde0fd8d0e89a8a..bbdb6edb80fb796c03b24262a0f42fd2a3091fca 100644 GIT binary patch delta 146 zcmeC@c*ilJQoxXz&Dq1#$Hj=5ImADJmvM4Cqos+cWga8b1&tfBy`n$4L@gMZ9%z5i z`?H*JrXYxOfaing-Cc}883T~213Yu5GV(G^?EJ$A*LPtl;{vvczZJ!JnFK#DOpw_z pg;DSW7N4FVDH0PNNQ&?ph` m0gxQHlmQfb0szz&lR5)50~C1yqc;Kp0Roe81N#JkfB*o-$QL&N diff --git a/src/plugins/tools/netx/testdata/hlp3.oas b/src/plugins/tools/netx/testdata/hlp3.oas index 10ecef81b160e9b52e01652290c367dbf9e923f3..feb47dd7bc753373cf83401efc8ed84b1d4df203 100644 GIT binary patch delta 87 zcmey&x{+-|8l#%1Wga8b1&tfB7nU+EU=y`qWO|_eLGQ*RCI%4ug2n-!1F8$yCZ{p> oN`jRh;Q7HdLFR_6s0Jg`0iF+{H)b(1O=e{JFj;_!mx+M^0QNH*7XSbN delta 15 WcmdnU_L+4<8sp?1#@@w-OpE|AK?O?y diff --git a/src/plugins/tools/netx/testdata/hlp4.oas b/src/plugins/tools/netx/testdata/hlp4.oas index 9da959541d776048b6bf490829585188091ca774..508689d78384331dd520173a06f620bce6f41563 100644 GIT binary patch delta 101 zcmV-r0Gj`R2EGQ6c@QxJ217_mOhhsR15{5?4FQvI0VDwck%{F46)|p+lziZUF+o4EPF=9M~PR H^#Kb3jW`{5 delta 83 zcmV-Z0IdJM27m^Tc@Q!K217_mOhhpQ15{5?4FQp^9@ciKFP`@E7ssUnu5WO*raq@4*OioeB Xya_S~<})!(E@b*Rxq*p?iGcwC8bTH- delta 28 kcmZ3%{)BBqKI7!cj6IXhnKBufCU0c=I{5$-2NMGW0GHYcKL7v# diff --git a/src/plugins/tools/netx/testdata/hlp6.oas b/src/plugins/tools/netx/testdata/hlp6.oas index 29ec3733c6c391a929dd5a735f746569790a9a25..56db21f0ac53065c3451ab3f5d4bb594487ff39e 100644 GIT binary patch delta 51 zcmbQlwTF9y7!$9kWga8b0iGXR9qKn^C#y4>Y!+ks!^jL2o;;Z;jge`xBFp>91}uC` G3=9B;2o3K5 delta 25 hcmdnPJ&9|B7}Mr(raz2~Op_0?{G5D&g@uWM0RVCj2lfB} diff --git a/src/plugins/tools/netx/testdata/hlp7.oas b/src/plugins/tools/netx/testdata/hlp7.oas index a8c2a5649f187110296a98af298e5be80c4db14b..36664d1a9e823bfd6ba6799c4c70f86b0a4b9704 100644 GIT binary patch delta 105 zcmV-v0G9uo2FC`Fa}@?dNJ&gYF#`odPgX@z0|Qh~Pz?c-h5Oh_yO>u1ON*Fz&;WbcLD&^7SJfL Lg8~4v>j5wUQkox& delta 89 zcmX@kHk)liu_&vvf0%0!Gn=!Ar;m#vGjoW4059Xj1Amx!876j^>oEzwVEC|zg`44k rosi%U#tAYz#JQPXuy0`LXB61LB2v!8a7FBb#)f7lu!_y%Oa_bqfNU9i diff --git a/src/plugins/tools/netx/testdata/hlp8.oas b/src/plugins/tools/netx/testdata/hlp8.oas index 670bec10b96c52c1408917ee6d6a2eba04ee59a3..9b32237c9ff7f20a379f22f478157cdec583377b 100644 GIT binary patch delta 168 zcmdnZ-o!DXSdPuv!_&vbkeSulKg>0VnLRkv$=TJ%hnYFVKY*8Uass0{Bg4drXPHF} z^CrGg6y{|T{J}6mW`{U8!vQ-X!5@qa43n2LCa8+)<}orI;Q1hWLzaP;8AZ(prVoo) z7(}g8875~i1j>i5!Ha|n8hek%XCHTg2sksCWguCOm>V+lMgcen0$eWm5G4? E0Q1i-uK)l5 delta 116 zcmZqT*v&qnSdP`%Kg>0Vna$b5)5pb-nLRkv$=TJ%hnYFVKY*8U;>oj2ybKd3nhP)q zo?zf+IAA9v_=9nR%ntF%XBiU|c$uL*h|CA34~tkBM9P^Mu83XG*wD;0`3RF8v#4e2 M > &interactions, std::set &result) const + virtual void compute_local (db::Layout *layout, const db::ShapeInteractions &interactions, std::set &result) const { - std::map > sized_interactions = interactions; - for (std::map >::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) { - for (std::vector::iterator j = i->second.begin (); j != i->second.end (); ++j) { - db::Polygon poly = j->obj ().transformed (j->trans ()); + db::ShapeInteractions sized_interactions = interactions; + for (db::ShapeInteractions::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) { + for (db::ShapeInteractions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + const db::PolygonRef &ref = interactions.shape (*j); + db::Polygon poly = ref.obj ().transformed (ref.trans ()); poly.size (m_dist, m_dist); - *j = db::PolygonRef (poly, layout->shape_repository ()); + sized_interactions.add_shape (*j, db::PolygonRef (poly, layout->shape_repository ())); } } BoolAndOrNotLocalOperation::compute_local (layout, sized_interactions, result); @@ -130,8 +132,12 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in p.layer = 2; p.datatype = 0; - lmap.map (db::LDPair (2, 0), l2 = layout_org.insert_layer ()); - layout_org.set_properties (l2, p); + if (mode == TMSelfOverlap) { + lmap.map (db::LDPair (2, 0), l2 = l1); + } else { + lmap.map (db::LDPair (2, 0), l2 = layout_org.insert_layer ()); + layout_org.set_properties (l2, p); + } p.layer = out_layer_num; p.datatype = 0; @@ -146,21 +152,30 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in layout_org.clear_layer (lout); normalize_layer (layout_org, l1); - normalize_layer (layout_org, l2); + if (l1 != l2) { + normalize_layer (layout_org, l2); + } - db::BoolAndOrNotLocalOperation op (mode == TMAnd); + db::LocalOperation *lop = 0; + db::BoolAndOrNotLocalOperation bool_op (mode == TMAnd); + db::SelfOverlapMergeLocalOperation self_intersect_op (2); + if (mode == TMSelfOverlap) { + lop = &self_intersect_op; + } else { + lop = &bool_op; + } if (single) { db::LocalProcessor proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ())); if (! context_doc) { - proc.run (&op, l1, l2, lout); + proc.run (lop, l1, l2, lout); } else { db::LocalProcessorContexts contexts; - proc.compute_contexts (contexts, &op, l1, l2); + proc.compute_contexts (contexts, lop, l1, l2); *context_doc = contexts_to_s (&layout_org, contexts); - proc.compute_results (contexts, &op, lout); + proc.compute_results (contexts, lop, lout); } } else { @@ -170,12 +185,12 @@ void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode mode, in db::LocalProcessor proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()), &layout_org2, &layout_org2.cell (*layout_org2.begin_top_down ())); if (! context_doc) { - proc.run (&op, l1, l2, lout); + proc.run (lop, l1, l2, lout); } else { db::LocalProcessorContexts contexts; - proc.compute_contexts (contexts, &op, l1, l2); + proc.compute_contexts (contexts, lop, l1, l2); *context_doc = contexts_to_s (&layout_org, contexts); - proc.compute_results (contexts, &op, lout); + proc.compute_results (contexts, lop, lout); } } @@ -835,3 +850,147 @@ TEST(TwoInputsNotWithSize10) // Array instances, NOT run_test_bool2_with_size (_this, "hlp10.oas", TMNot, 150, 103); } + +TEST(BasicSelfOverlap1) +{ + // Simple flat AND + run_test_bool (_this, "hlp1.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap2) +{ + // Up/down and down/up interactions, AND + run_test_bool (_this, "hlp2.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap3) +{ + // Variant building, AND + run_test_bool (_this, "hlp3.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap4) +{ + // Sibling interactions, variant building, AND + run_test_bool (_this, "hlp4.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap5) +{ + // Variant building with intermediate hierarchy, AND + run_test_bool (_this, "hlp5.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap6) +{ + // Extreme variants (copy, vanishing), AND + run_test_bool (_this, "hlp6.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap7) +{ + // Context replication - direct and indirect, AND + run_test_bool (_this, "hlp7.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap8) +{ + // Mixed sibling-parent contexts, AND + run_test_bool (_this, "hlp8.oas", TMSelfOverlap, 110); +} + +TEST(BasicSelfOverlap9) +{ + // Top-level ring structure, AND + std::string doc; + run_test_bool (_this, "hlp9.oas", TMSelfOverlap, 110, &doc); + EXPECT_EQ (doc, + // This means: the interaction test is strong enough, so it does not see interactions between the + // ring and the cells embedded inside the ring. So there is only one cell context. Some shapes + // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than + // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. + "TOP[1] 0 insts, 0 shapes (1 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" + "CHILD1[1] 0 insts, 4 shapes (2 times)\n" + ); +} + +TEST(BasicSelfOverlap10) +{ + // Array instances, AND + run_test_bool (_this, "hlp10.oas", TMSelfOverlap, 110); +} + +#if 0 // @@@ +TEST(BasicSelfOverlapWithSize1) +{ + // Simple flat AND + run_test_bool_with_size (_this, "hlp1.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize2) +{ + // Up/down and down/up interactions, AND + run_test_bool_with_size (_this, "hlp2.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize3) +{ + // Variant building, AND + run_test_bool_with_size (_this, "hlp3.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize4) +{ + // Sibling interactions, variant building, AND + run_test_bool_with_size (_this, "hlp4.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize5) +{ + // Variant building with intermediate hierarchy, AND + run_test_bool_with_size (_this, "hlp5.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize6) +{ + // Extreme variants (copy, vanishing), AND + run_test_bool_with_size (_this, "hlp6.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize7) +{ + // Context replication - direct and indirect, AND + run_test_bool_with_size (_this, "hlp7.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize8) +{ + // Mixed sibling-parent contexts, AND + run_test_bool_with_size (_this, "hlp8.oas", TMSelfOverlap, 1500, 111); +} + +TEST(BasicSelfOverlapWithSize9) +{ + // Top-level ring structure, AND + std::string doc; + run_test_bool_with_size (_this, "hlp9.oas", TMSelfOverlap, 1500, 111, &doc); + EXPECT_EQ (doc, + // This means: the interaction test is strong enough, so it does not see interactions between the + // ring and the cells embedded inside the ring. So there is only one cell context. Some shapes + // from atop the CHILD cell don't interact with shapes inside CHILD, so there are 4 shapes rather than + // 6. And the shapes from top inside the ring are not seen by the RING's subject shapes. + "TOP[1] 0 insts, 0 shapes (1 times)\n" + "RING[1] 0 insts, 0 shapes (1 times)\n" + "CHILD1[1] 0 insts, 6 shapes (2 times)\n" + ); +} + +TEST(BasicSelfOverlapWithSize10) +{ + // Array instances, AND + run_test_bool_with_size (_this, "hlp10.oas", TMSelfOverlap, 150, 111); +} +#endif + +