diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 2ef6f28eb..c0c0edb60 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1039,81 +1039,50 @@ AsIfFlatRegion::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db return new_region.release (); } -EdgePairsDelegate * -AsIfFlatRegion::cop_to_edge_pairs (db::CompoundRegionOperationNode &node) +template +static +void region_cop_impl (AsIfFlatRegion *region, db::Shapes *output_to, db::CompoundRegionOperationNode &node) { - db::local_processor proc; - proc.set_base_verbosity (base_verbosity ()); + db::local_processor proc; + proc.set_base_verbosity (region->base_verbosity ()); + + bool needs_merged = node.wants_merged (); + db::RegionIterator polygons (needs_merged ? region->begin_merged () : region->begin ()); std::vector > others; std::vector inputs = node.inputs (); for (std::vector::const_iterator i = inputs.begin (); i != inputs.end (); ++i) { - // @@@ in case of *i == null - what to do? - others.push_back (*i ? (*i)->begin () : begin ()); + others.push_back (*i ? (*i)->begin () : (needs_merged ? region->begin_merged () : region->begin ())); } - // @@@ really always "merged"? - db::RegionIterator polygons (begin_merged ()); - - std::auto_ptr output (new FlatEdgePairs ()); std::vector results; - results.push_back (&output->raw_edge_pairs ()); + results.push_back (output_to); - compound_local_operation op (&node); + compound_local_operation op (&node); proc.run_flat (polygons, others, &op, results); +} +EdgePairsDelegate * +AsIfFlatRegion::cop_to_edge_pairs (db::CompoundRegionOperationNode &node) +{ + std::auto_ptr output (new FlatEdgePairs ()); + region_cop_impl (this, &output->raw_edge_pairs (), node); return output.release (); } RegionDelegate * AsIfFlatRegion::cop_to_region (db::CompoundRegionOperationNode &node) { - db::local_processor proc; - proc.set_base_verbosity (base_verbosity ()); - - std::vector > others; - std::vector inputs = node.inputs (); - for (std::vector::const_iterator i = inputs.begin (); i != inputs.end (); ++i) { - // @@@ in case of *i == null - what to do? - others.push_back (*i ? (*i)->begin () : begin ()); - } - - // @@@ really always "merged"? - db::RegionIterator polygons (begin_merged ()); - std::auto_ptr output (new FlatRegion ()); - std::vector results; - results.push_back (&output->raw_polygons ()); - - compound_local_operation op (&node); - proc.run_flat (polygons, others, &op, results); - + region_cop_impl (this, &output->raw_polygons (), node); return output.release (); } EdgesDelegate * AsIfFlatRegion::cop_to_edges (db::CompoundRegionOperationNode &node) { - db::local_processor proc; - proc.set_base_verbosity (base_verbosity ()); - - std::vector > others; - std::vector inputs = node.inputs (); - for (std::vector::const_iterator i = inputs.begin (); i != inputs.end (); ++i) { - // @@@ in case of *i == null - what to do? - others.push_back (*i ? (*i)->begin () : begin ()); - } - - // @@@ really always "merged"? - db::RegionIterator polygons (begin_merged ()); - std::auto_ptr output (new FlatEdges ()); - std::vector results; - results.push_back (&output->raw_edges ()); - - compound_local_operation op (&node); - proc.run_flat (polygons, others, &op, results); - + region_cop_impl (this, &output->raw_edges (), node); return output.release (); } diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index 84e0863fb..0af279624 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -163,7 +163,9 @@ CompoundRegionOperationPrimaryNode::~CompoundRegionOperationPrimaryNode () std::vector CompoundRegionOperationPrimaryNode::inputs () const { - return std::vector (); + std::vector is; + is.push_back (0); + return is; } void CompoundRegionOperationPrimaryNode::do_compute_local (db::Layout *, const shape_interactions &interactions, std::vector > &results, size_t, double) const @@ -299,13 +301,16 @@ CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode () CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *child) { + child->keep (); m_children.push_back (child); init (); } CompoundRegionMultiInputOperationNode::CompoundRegionMultiInputOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b) { + a->keep (); m_children.push_back (a); + b->keep (); m_children.push_back (b); init (); } @@ -415,6 +420,17 @@ CompoundRegionMultiInputOperationNode::wants_variants () const return false; } +bool +CompoundRegionMultiInputOperationNode::wants_merged () const +{ + for (tl::shared_collection::const_iterator i = m_children.begin (); i != m_children.end (); ++i) { + if (i->wants_merged ()) { + return true; + } + } + return false; +} + // --------------------------------------------------------------------------------------------- CompoundRegionLogicalBoolOperationNode::CompoundRegionLogicalBoolOperationNode (LogicalOp op, bool invert, const std::vector &inputs) @@ -1113,18 +1129,58 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (db::edge_rel m_check.set_max_projection (options.max_projection); } +db::OnEmptyIntruderHint +CompoundRegionCheckOperationNode::on_empty_intruder_hint () const +{ + return (m_different_polygons || !inputs ().empty ()) ? OnEmptyIntruderHint::Drop : OnEmptyIntruderHint::Ignore; +} + +db::Coord +CompoundRegionCheckOperationNode::dist () const +{ + return m_check.distance (); +} + +bool +CompoundRegionCheckOperationNode::wants_merged () const +{ + return true; +} + void CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const { - db::check_local_operation op (m_check, m_different_polygons, true, false, m_options.shielded, m_options.opposite_filter, m_options.rect_filter); - op.compute_local (layout, interactions, results, max_vertex_count, area_ratio); + bool other_merged = (children () > 0 && !inputs ()[0]); + + db::check_local_operation op (m_check, m_different_polygons, children () > 0, other_merged, m_options.shielded, m_options.opposite_filter, m_options.rect_filter); + + tl_assert (results.size () == 1); + if (results.front ().empty ()) { + op.compute_local (layout, interactions, results, max_vertex_count, area_ratio); + } else { + std::vector > r; + r.resize (1); + op.compute_local (layout, interactions, r, max_vertex_count, area_ratio); + results.front ().insert (r.front ().begin (), r.front ().end ()); + } } void CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const { - db::check_local_operation op (m_check, m_different_polygons, true, false, m_options.shielded, m_options.opposite_filter, m_options.rect_filter); - op.compute_local (layout, interactions, results, max_vertex_count, area_ratio); + bool other_merged = (children () > 0 && !inputs ()[0]); + + db::check_local_operation op (m_check, m_different_polygons, children () > 0, other_merged, m_options.shielded, m_options.opposite_filter, m_options.rect_filter); + + tl_assert (results.size () == 1); + if (results.front ().empty ()) { + op.compute_local (layout, interactions, results, max_vertex_count, area_ratio); + } else { + std::vector > r; + r.resize (1); + op.compute_local (layout, interactions, r, max_vertex_count, area_ratio); + results.front ().insert (r.front ().begin (), r.front ().end ()); + } } } diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 92306c871..bf2b67505 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -85,6 +85,11 @@ public: */ virtual bool wants_variants () const { return false; } + /** + * @brief Returns true, if the processor wants to have merged primary inputs + */ + virtual bool wants_merged () const { return false; } + void compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const { implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio); @@ -362,6 +367,7 @@ public: virtual const TransformationReducer *vars () const; virtual bool wants_variants () const; + virtual bool wants_merged () const; virtual void invalidate_cache () const; @@ -384,7 +390,12 @@ protected: for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - child_interactions.add_subject_shape (i->first, interactions.subject_shape (i->first)); + if (child (child_index)->on_empty_intruder_hint () == OnEmptyIntruderHint::Drop) { + child_interactions.add_subject_shape (i->first, interactions.subject_shape (i->first)); + } else { + // this includes the subject-without-intruder "interaction" + child_interactions.add_subject (i->first, interactions.subject_shape (i->first)); + } for (typename shape_interactions::iterator2 ii = i->second.begin (); ii != i->second.end (); ++ii) { @@ -941,6 +952,10 @@ public: // specifies the result type virtual ResultType result_type () const { return EdgePairs; } + virtual OnEmptyIntruderHint on_empty_intruder_hint () const; + virtual db::Coord dist () const; + virtual bool wants_merged () const; + virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const; @@ -981,8 +996,14 @@ protected: shape_interactions single_interactions; - single_interactions.add_subject_shape (i->first, subject_shape); - const std::vector &intruders = single_interactions.intruders_for (i->first); + if (on_empty_intruder_hint () == OnEmptyIntruderHint::Drop) { + single_interactions.add_subject_shape (i->first, subject_shape); + } else { + // this includes the subject-without-intruder "interaction" + single_interactions.add_subject (i->first, subject_shape); + } + + const std::vector &intruders = interactions.intruders_for (i->first); for (typename std::vector::const_iterator ii = intruders.begin (); ii != intruders.end (); ++ii) { const std::pair &is = interactions.intruder_shape (*ii); single_interactions.add_intruder_shape (*ii, is.first, is.second); diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index e94e1dad0..6d7253eb7 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1763,6 +1763,23 @@ local_processor::compute_local_cell (const db::local_processor_conte shape_interactions interactions; + // 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 (shape_flags ()); !i.at_end (); ++i) { + + unsigned int id = interactions.next_id (); + if (subject_id0 == 0) { + subject_id0 = id; + } + + if (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop) { + const TS *ref = i->basic_ptr (typename TS::tag ()); + interactions.add_subject (id, *ref); + } + + } + for (std::vector::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) { const db::Shapes *intruder_shapes = 0; @@ -1777,23 +1794,6 @@ local_processor::compute_local_cell (const db::local_processor_conte db::box_convert inst_bci (*mp_intruder_layout, *il); - // 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 (shape_flags ()); !i.at_end (); ++i) { - - unsigned int id = interactions.next_id (); - if (subject_id0 == 0) { - subject_id0 = id; - } - - if (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop) { - const TS *ref = i->basic_ptr (typename TS::tag ()); - interactions.add_subject (id, *ref); - } - - } - typename std::map >::const_iterator ipl = intruders.second.find (*il); static std::set empty_intruders; @@ -1900,7 +1900,7 @@ template struct scan_shape2shape_same_layer_flat { void - operator () (const generic_shape_iterator &, bool, unsigned int, shape_interactions &, db::Coord) const + operator () (const generic_shape_iterator &, unsigned int, shape_interactions &, db::Coord) const { // cannot have different types on the same layer tl_assert (false); @@ -1911,7 +1911,7 @@ template struct scan_shape2shape_same_layer_flat { void - operator () (const generic_shape_iterator &subjects, bool needs_isolated_subjects, unsigned int intruder_layer, shape_interactions &interactions, db::Coord dist) const + operator () (const generic_shape_iterator &subjects, unsigned int intruder_layer, shape_interactions &interactions, db::Coord dist) const { db::box_scanner scanner; interaction_registration_shape1 rec (&interactions, intruder_layer); @@ -1924,22 +1924,32 @@ struct scan_shape2shape_same_layer_flat const T *shape = is.operator-> (); scanner.insert (shape, id); - // create subject for subject vs. nothing interactions - if (needs_isolated_subjects) { - interactions.add_subject (id, *shape); - } - } scanner.process (rec, dist, db::box_convert ()); } }; +template +struct add_subjects_vs_nothing_flat +{ + void + operator () (const generic_shape_iterator &subjects, shape_interactions &interactions) const + { + addressable_shape_delivery is (subjects); + for ( ; !is.at_end (); ++is) { + unsigned int id = interactions.next_id (); + const TS *shape = is.operator-> (); + interactions.add_subject (id, *shape); + } + } +}; + template struct scan_shape2shape_different_layers_flat { void - operator () (const generic_shape_iterator &subjects, const generic_shape_iterator &intruders, bool needs_isolated_subjects, unsigned int intruder_layer, shape_interactions &interactions, db::Coord dist) const + operator () (const generic_shape_iterator &subjects, const generic_shape_iterator &intruders, unsigned int intruder_layer, shape_interactions &interactions, db::Coord dist) const { db::box_scanner2 scanner; interaction_registration_shape2shape rec (0 /*layout*/, &interactions, intruder_layer); @@ -1956,46 +1966,14 @@ struct scan_shape2shape_different_layers_flat db::Box common_box = intruders_box & subjects_box; if (common_box.empty ()) { - - if (needs_isolated_subjects) { - for (generic_shape_iterator is = subjects; ! is.at_end (); ++is) { - // create subject for subject vs. nothing interactions - interactions.add_subject (interactions.next_id (), *is); - } - } - return; - } addressable_shape_delivery is; - if (needs_isolated_subjects) { - - box_convert bcs; - - is = addressable_shape_delivery (subjects); - for ( ; !is.at_end (); ++is) { - - unsigned int id = interactions.next_id (); - const TS *shape = is.operator-> (); - - if (bcs (*shape).overlaps (common_box)) { - scanner.insert1 (shape, id); - } - - // create subject for subject vs. nothing interactions - interactions.add_subject (id, *shape); - - } - - } else { - - is = addressable_shape_delivery (subjects.confined (common_box, true)); - for ( ; !is.at_end (); ++is) { - scanner.insert1 (is.operator-> (), interactions.next_id ()); - } - + is = addressable_shape_delivery (subjects.confined (common_box, true)); + for ( ; !is.at_end (); ++is) { + scanner.insert1 (is.operator-> (), interactions.next_id ()); } addressable_shape_delivery ii (intruders.confined (common_box, true)); @@ -2022,13 +2000,16 @@ local_processor::run_flat (const generic_shape_iterator &subject tl_assert (mp_intruder_top == 0); shape_interactions interactions; - bool needs_isolated_subjects = (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop); + + if (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop) { + add_subjects_vs_nothing_flat () (subjects, interactions); + } for (typename std::vector >::const_iterator il = intruders.begin (); il != intruders.end (); ++il) { if (*il == subjects) { - scan_shape2shape_same_layer_flat () (subjects, needs_isolated_subjects, (unsigned int) (il - intruders.begin ()), interactions, op->dist ()); + scan_shape2shape_same_layer_flat () (subjects, (unsigned int) (il - intruders.begin ()), interactions, op->dist ()); } else { - scan_shape2shape_different_layers_flat () (subjects, *il, needs_isolated_subjects, (unsigned int) (il - intruders.begin ()), interactions, op->dist ()); + scan_shape2shape_different_layers_flat () (subjects, *il, (unsigned int) (il - intruders.begin ()), interactions, op->dist ()); } } diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc new file mode 100644 index 000000000..79921532d --- /dev/null +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -0,0 +1,81 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "tlUnitTest.h" + +#include "dbRegion.h" +#include "dbCompoundOperation.h" +#include "dbReader.h" +#include "dbRecursiveShapeIterator.h" +#include "dbTestSupport.h" + +#include "tlStream.h" + +#include + +TEST(1_Basic) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/drc/compound_1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::RegionCheckOptions check_options; + check_options.metrics = db::Projection; + + db::CompoundRegionCheckOperationNode width_check (db::WidthRelation, false /*==same polygon*/, 1050, check_options); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + db::Region r (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), l1)); + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + db::Region r2 (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), l2)); + + db::EdgePairs res = r.cop_to_edge_pairs (width_check); + + unsigned int l1000 = ly.get_layer (db::LayerProperties (1000, 0)); + res.insert_into (&ly, *ly.begin_top_down (), l1000); + + db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode (); + db::CompoundRegionCheckOperationNode space_check (primary, db::SpaceRelation, true /*==different polygons*/, 1050, check_options); + + res = r.cop_to_edge_pairs (space_check); + + unsigned int l1001 = ly.get_layer (db::LayerProperties (1001, 0)); + res.insert_into (&ly, *ly.begin_top_down (), l1001); + + db::CompoundRegionOperationSecondaryNode *secondary = new db::CompoundRegionOperationSecondaryNode (&r2); + db::CompoundRegionCheckOperationNode sep_check (secondary, db::SpaceRelation, true /*==different polygons*/, 1050, check_options); + + res = r.cop_to_edge_pairs (sep_check); + + unsigned int l1002 = ly.get_layer (db::LayerProperties (1002, 0)); + res.insert_into (&ly, *ly.begin_top_down (), l1002); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/drc/compound_au1.gds"); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 4efc7e5ad..f2ac4297b 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -7,6 +7,7 @@ TARGET = db_tests include($$PWD/../../lib_ut.pri) SOURCES = \ + dbCompoundOperationTests.cc \ dbWriterTools.cc \ dbLoadLayoutOptionsTests.cc \ dbSaveLayoutOptionsTests.cc \ diff --git a/testdata/drc/compound_1.gds b/testdata/drc/compound_1.gds new file mode 100644 index 000000000..001eefe47 Binary files /dev/null and b/testdata/drc/compound_1.gds differ diff --git a/testdata/drc/compound_au1.gds b/testdata/drc/compound_au1.gds new file mode 100644 index 000000000..9136405ae Binary files /dev/null and b/testdata/drc/compound_au1.gds differ