From bf47805b29617da166edf674be424aa66a2b76fe Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 16 Jan 2023 01:00:03 +0100 Subject: [PATCH] WIP: support for properties in deep andnot, tests --- src/db/db/dbAsIfFlatRegion.cc | 10 +- src/db/db/dbAsIfFlatRegion.h | 4 +- src/db/db/dbDeepRegion.cc | 66 +++++++++---- src/db/db/dbDeepRegion.h | 4 +- src/db/db/dbEmptyRegion.cc | 7 +- src/db/db/dbEmptyRegion.h | 4 +- src/db/db/dbLocalOperation.cc | 128 ++++++++++++++++++++++++- src/db/db/dbLocalOperation.h | 22 ++++- src/db/db/dbRegion.h | 47 ++++++++- src/db/db/dbRegionDelegate.h | 4 +- src/db/db/gsiDeclDbRegion.cc | 56 +++++++++++ src/db/unit_tests/dbDeepRegionTests.cc | 78 +++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- 13 files changed, 388 insertions(+), 45 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index c61252fb4..1bc857f40 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1641,7 +1641,7 @@ AsIfFlatRegion::andnot_with (const Region &other, PropertyConstraint property_co } RegionDelegate * -AsIfFlatRegion::xor_with (const Region &other) const +AsIfFlatRegion::xor_with (const Region &other, PropertyConstraint prop_constraint) const { if (empty () && ! other.strict_handling ()) { @@ -1654,10 +1654,12 @@ AsIfFlatRegion::xor_with (const Region &other) const } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling () && ! other.strict_handling ()) { // Simplified handling for disjunct case - return or_with (other); + return or_with (other, prop_constraint); } else { + // @@@ TODO: implement property constraint + // Generic case db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); @@ -1694,7 +1696,7 @@ AsIfFlatRegion::xor_with (const Region &other) const } RegionDelegate * -AsIfFlatRegion::or_with (const Region &other) const +AsIfFlatRegion::or_with (const Region &other, PropertyConstraint prop_constraint) const { if (empty () && ! other.strict_handling ()) { @@ -1712,6 +1714,8 @@ AsIfFlatRegion::or_with (const Region &other) const } else { + // @@@ TODO: implement property constraint + // Generic case db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index c5ed1dcde..99c1596e1 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -124,8 +124,8 @@ public: virtual RegionDelegate *and_with (const Region &other, PropertyConstraint property_constraint) const; virtual RegionDelegate *not_with (const Region &other, PropertyConstraint property_constraint) const; - virtual RegionDelegate *xor_with (const Region &other) const; - virtual RegionDelegate *or_with (const Region &other) const; + virtual RegionDelegate *xor_with (const Region &other, PropertyConstraint prop_constraint) const; + virtual RegionDelegate *or_with (const Region &other, PropertyConstraint prop_constraint) const; virtual std::pair andnot_with (const Region &other, PropertyConstraint property_constraint) const; virtual RegionDelegate *add_in_place (const Region &other) diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 843180d50..4f364ddc9 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -743,8 +743,9 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain } RegionDelegate * -DeepRegion::or_with (const Region &other) const +DeepRegion::or_with (const Region &other, db::PropertyConstraint /*property_constraint*/) const { + // @@@ TODO: implement property_constraint RegionDelegate *res = add (other); return res->merged_in_place (); } @@ -815,35 +816,58 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyC std::pair DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const { - // @@@ TODO: implement property_constraint - DeepLayer dl_out1 (deep_layer ().derived ()); DeepLayer dl_out2 (deep_layer ().derived ()); - db::TwoBoolAndNotLocalOperation op; + if (property_constraint == db::NoPropertyConstraint) { - db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); - proc.set_base_verbosity (base_verbosity ()); - proc.set_description (progress_desc ()); - proc.set_report_progress (report_progress ()); - proc.set_threads (deep_layer ().store ()->threads ()); - proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); - proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); + db::TwoBoolAndNotLocalOperation op; - std::vector il; - il.push_back (other->deep_layer ().layer ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - std::vector ol; - ol.push_back (dl_out1.layer ()); - ol.push_back (dl_out2.layer ()); + std::vector il; + il.push_back (other->deep_layer ().layer ()); - proc.run (&op, deep_layer ().layer (), il, ol); + std::vector ol; + ol.push_back (dl_out1.layer ()); + ol.push_back (dl_out2.layer ()); + + proc.run (&op, deep_layer ().layer (), il, ol); + + } else { + + db::TwoBoolAndNotLocalOperationWithProperties op (&deep_layer ().layout (), &other->deep_layer ().layout (), property_constraint); + + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); + + std::vector il; + il.push_back (other->deep_layer ().layer ()); + + std::vector ol; + ol.push_back (dl_out1.layer ()); + ol.push_back (dl_out2.layer ()); + + proc.run (&op, deep_layer ().layer (), il, ol); + + } return std::make_pair (dl_out1, dl_out2); } RegionDelegate * -DeepRegion::xor_with (const Region &other) const +DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_constraint) const { const DeepRegion *other_deep = dynamic_cast (other.delegate ()); @@ -859,14 +883,14 @@ DeepRegion::xor_with (const Region &other) const } else if (! other_deep) { - return AsIfFlatRegion::xor_with (other); + return AsIfFlatRegion::xor_with (other, property_constraint); } else { // Implement XOR as (A-B)+(B-A) - only this implementation // is compatible with the local processor scheme - DeepLayer n1 (and_or_not_with (other_deep, false, db::NoPropertyConstraint)); - DeepLayer n2 (other_deep->and_or_not_with (this, false, db::NoPropertyConstraint)); + DeepLayer n1 (and_or_not_with (other_deep, false, property_constraint)); + DeepLayer n2 (other_deep->and_or_not_with (this, false, property_constraint)); n1.add_from (n2); return new DeepRegion (n1); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 33948b66b..4ce347bff 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -101,8 +101,8 @@ public: virtual RegionDelegate *and_with (const Region &other, db::PropertyConstraint property_constraint) const; virtual RegionDelegate *not_with (const Region &other, db::PropertyConstraint property_constraint) const; - virtual RegionDelegate *xor_with (const Region &other) const; - virtual RegionDelegate *or_with (const Region &other) const; + virtual RegionDelegate *xor_with (const Region &other, db::PropertyConstraint property_constraint) const; + virtual RegionDelegate *or_with (const Region &other, db::PropertyConstraint property_constraint) const; virtual std::pair andnot_with (const Region &, db::PropertyConstraint property_constraint) const; virtual RegionDelegate *add_in_place (const Region &other); diff --git a/src/db/db/dbEmptyRegion.cc b/src/db/db/dbEmptyRegion.cc index b1baa137e..197493f56 100644 --- a/src/db/db/dbEmptyRegion.cc +++ b/src/db/db/dbEmptyRegion.cc @@ -67,19 +67,20 @@ EmptyRegion::add (const Region &other) const } RegionDelegate * -EmptyRegion::xor_with (const Region &other) const +EmptyRegion::xor_with (const Region &other, db::PropertyConstraint prop_constraint) const { - return or_with (other); + return or_with (other, prop_constraint); } RegionDelegate * -EmptyRegion::or_with (const Region &other) const +EmptyRegion::or_with (const Region &other, db::PropertyConstraint /*prop_constraint*/) const { if (other.empty ()) { return new EmptyRegion (); } else if (! other.strict_handling ()) { return other.delegate ()->clone (); } else { + // @@@ TODO: implement prop_constraint return other.delegate ()->merged (); } } diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 50a37cf4f..831a93f6e 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -101,8 +101,8 @@ public: virtual RegionDelegate *and_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); } virtual RegionDelegate *not_with (const Region &, db::PropertyConstraint) const { return new EmptyRegion (); } virtual std::pair andnot_with (const Region &, db::PropertyConstraint) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } - virtual RegionDelegate *xor_with (const Region &other) const; - virtual RegionDelegate *or_with (const Region &other) const; + virtual RegionDelegate *xor_with (const Region &other, db::PropertyConstraint prop_constraint) const; + virtual RegionDelegate *or_with (const Region &other, db::PropertyConstraint prop_constraint) const; virtual RegionDelegate *add_in_place (const Region &other); virtual RegionDelegate *add (const Region &other) const; diff --git a/src/db/db/dbLocalOperation.cc b/src/db/db/dbLocalOperation.cc index 5cfbf535d..1947b0c32 100644 --- a/src/db/db/dbLocalOperation.cc +++ b/src/db/db/dbLocalOperation.cc @@ -171,7 +171,7 @@ BoolAndOrNotLocalOperation::do_compute_local (db::Layout *layout, const shape_in } - if (! others.empty () || p1 > 0) { + if (! others.empty () && p1 > 0) { for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { @@ -217,8 +217,6 @@ BoolAndOrNotLocalOperationWithProperties::do_compute_local (db::Layout *layout, db::PropertyMapper pms (*layout, *mp_subject_layout); db::PropertyMapper pmi (*layout, *mp_intruder_layout); - // @@@ TODO: implement different property constraint etc. - tl_assert (results.size () == 1); std::unordered_set &result = results.front (); @@ -356,7 +354,7 @@ TwoBoolAndNotLocalOperation::do_compute_local (db::Layout *layout, const shape_i } - if (! others.empty () || p1 > 0) { + if (! others.empty () && p1 > 0) { for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { @@ -391,6 +389,128 @@ std::string TwoBoolAndNotLocalOperation::description () const return tl::to_string (tr ("ANDNOT operation")); } +// --------------------------------------------------------------------------------------------- +// TwoBoolAndNotLocalOperationWithProperties implementation + +TwoBoolAndNotLocalOperationWithProperties::TwoBoolAndNotLocalOperationWithProperties (const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint) + : db::local_operation (), + m_property_constraint (property_constraint), mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout) +{ + // .. nothing yet .. +} + +void +TwoBoolAndNotLocalOperationWithProperties::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t max_vertex_count, double area_ratio) const +{ + db::PropertyMapper pms (*layout, *mp_subject_layout); + db::PropertyMapper pmi (*layout, *mp_intruder_layout); + + tl_assert (results.size () == 2); + std::unordered_set &result0 = results [0]; + std::unordered_set &result1 = results [1]; + + db::EdgeProcessor ep; + + std::map, std::set > > by_prop_id; + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRefWithProperties &subject = interactions.subject_shape (i->first); + + if (i->second.empty ()) { + + result1.insert (db::PolygonRefWithProperties (subject, pms (subject.properties_id ()))); + + } else { + + db::properties_id_type prop_id_s = (m_property_constraint != db::NoPropertyConstraint ? pms (subject.properties_id ()) : 0); + + std::pair, std::set > &shapes_by_prop = by_prop_id [prop_id_s]; + shapes_by_prop.first.push_front (subject); + + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + const db::PolygonRefWithProperties &intruder = interactions.intruder_shape (*j).second; + db::properties_id_type prop_id_i = (m_property_constraint != db::NoPropertyConstraint ? pmi (intruder.properties_id ()) : 0); + if ((prop_id_i != prop_id_s) == (m_property_constraint == db::DifferentPropertiesConstraint)) { + shapes_by_prop.second.insert (intruder); + } + } + + } + + } + + for (auto p2s = by_prop_id.begin (); p2s != by_prop_id.end (); ++p2s) { + + ep.clear (); + size_t p1 = 0, p2 = 1; + + const std::set &others = p2s->second.second; + db::properties_id_type prop_id = p2s->first; + + for (auto s = p2s->second.first.begin (); s != p2s->second.first.end (); ++s) { + + const db::PolygonRef &subject = *s; + if (others.find (subject) != others.end ()) { + result0.insert (db::PolygonRefWithProperties (subject, prop_id)); + } else if (others.empty ()) { + // shortcut (not: keep, and: drop) + result1.insert (db::PolygonRefWithProperties (subject, prop_id)); + } else { + for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p1); + } + p1 += 2; + } + + } + + if (! others.empty () && p1 > 0) { + + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end(); ++e) { + ep.insert (*e, p2); + } + p2 += 2; + } + + std::unordered_set result0_wo_props; + std::unordered_set result1_wo_props; + + db::BooleanOp op0 (db::BooleanOp::And); + db::PolygonRefGenerator pr0 (layout, result0_wo_props); + db::PolygonSplitter splitter0 (pr0, area_ratio, max_vertex_count); + db::PolygonGenerator pg0 (splitter0, true, true); + + db::BooleanOp op1 (db::BooleanOp::ANotB); + db::PolygonRefGenerator pr1 (layout, result1_wo_props); + db::PolygonSplitter splitter1 (pr1, area_ratio, max_vertex_count); + db::PolygonGenerator pg1 (splitter1, true, true); + + ep.set_base_verbosity (50); + + std::vector > procs; + procs.push_back (std::make_pair (&pg0, &op0)); + procs.push_back (std::make_pair (&pg1, &op1)); + ep.process (procs); + + for (auto r = result0_wo_props.begin (); r != result0_wo_props.end (); ++r) { + result0.insert (db::PolygonRefWithProperties (*r, prop_id)); + } + for (auto r = result1_wo_props.begin (); r != result1_wo_props.end (); ++r) { + result1.insert (db::PolygonRefWithProperties (*r, prop_id)); + } + + } + + } +} + +std::string TwoBoolAndNotLocalOperationWithProperties::description () const +{ + return tl::to_string (tr ("ANDNOT operation")); +} + // --------------------------------------------------------------------------------------------- SelfOverlapMergeLocalOperation::SelfOverlapMergeLocalOperation (unsigned int wrap_count) diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index 4982b6d4d..cfc3471d9 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -148,7 +148,7 @@ private: }; /** - * @brief Implements a boolean AND or NOT operation + * @brief Implements a boolean AND or NOT operation with property handling */ class DB_PUBLIC BoolAndOrNotLocalOperationWithProperties : public local_operation @@ -182,6 +182,26 @@ public: virtual std::string description () const; }; +/** + * @brief Implements a boolean AND plus NOT operation + * + * This processor delivers two outputs: the first one having the AND result, the second + * one having the NOT result. + */ +class DB_PUBLIC TwoBoolAndNotLocalOperationWithProperties + : public local_operation +{ +public: + TwoBoolAndNotLocalOperationWithProperties (const db::Layout *subject_layout, const db::Layout *intruder_layout, db::PropertyConstraint property_constraint); + + virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &result, size_t max_vertex_count, double area_ratio) const; + virtual std::string description () const; + +private: + db::PropertyConstraint m_property_constraint; + const db::Layout *mp_subject_layout, *mp_intruder_layout; +}; + /** * @brief Implements a merge operation with an overlap count * With a given wrap_count, the result will only contains shapes where diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 0594930a3..0848c006d 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1116,7 +1116,15 @@ public: */ Region operator^ (const Region &other) const { - return Region (mp_delegate->xor_with (other)); + return Region (mp_delegate->xor_with (other, db::NoPropertyConstraint)); + } + + /** + * @brief Boolean XOR operator with options + */ + Region bool_xor (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const + { + return Region (mp_delegate->xor_with (other, prop_constraint)); } /** @@ -1127,7 +1135,19 @@ public: */ Region &operator^= (const Region &other) { - set_delegate (mp_delegate->xor_with (other)); + set_delegate (mp_delegate->xor_with (other, db::NoPropertyConstraint)); + return *this; + } + + /** + * @brief In-place boolean XOR operator with options + * + * This method does not necessarily merge the region. To ensure the region + * is merged, call merge afterwards. + */ + Region &bool_xor_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) + { + set_delegate (mp_delegate->xor_with (other, prop_constraint)); return *this; } @@ -1138,7 +1158,17 @@ public: */ Region operator| (const Region &other) const { - return Region (mp_delegate->or_with (other)); + return Region (mp_delegate->or_with (other, db::NoPropertyConstraint)); + } + + /** + * @brief Boolean OR operator with options + * + * This method merges the polygons of both regions. + */ + Region bool_or (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) const + { + return Region (mp_delegate->or_with (other, prop_constraint)); } /** @@ -1146,7 +1176,16 @@ public: */ Region &operator|= (const Region &other) { - set_delegate (mp_delegate->or_with (other)); + set_delegate (mp_delegate->or_with (other, db::NoPropertyConstraint)); + return *this; + } + + /** + * @brief In-place boolean OR operator + */ + Region &bool_or_with (const Region &other, PropertyConstraint prop_constraint = db::NoPropertyConstraint) + { + set_delegate (mp_delegate->or_with (other, prop_constraint)); return *this; } diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index bb34426b1..1e925b5b2 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -275,8 +275,8 @@ public: virtual RegionDelegate *and_with (const Region &other, PropertyConstraint prop_constraint) const = 0; virtual RegionDelegate *not_with (const Region &other, PropertyConstraint prop_constraint) const = 0; - virtual RegionDelegate *xor_with (const Region &other) const = 0; - virtual RegionDelegate *or_with (const Region &other) const = 0; + virtual RegionDelegate *xor_with (const Region &other, PropertyConstraint prop_constraint) const = 0; + virtual RegionDelegate *or_with (const Region &other, PropertyConstraint prop_constraint) const = 0; virtual RegionDelegate *add_in_place (const Region &other) = 0; virtual RegionDelegate *add (const Region &other) const = 0; virtual std::pair andnot_with (const Region &other, PropertyConstraint prop_constraint) const = 0; diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 64dc161e6..867ad4090 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1660,6 +1660,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method will compute the boolean NOT (intersection) between two regions. " "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." ) + method ("-=", &db::Region::operator-=, gsi::arg ("other"), "@brief Performs the boolean NOT between self and the other region\n" @@ -1676,6 +1680,10 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method will compute the boolean NOT (intersection) between two regions. " "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." ) + method ("^", &db::Region::operator^, gsi::arg ("other"), "@brief Returns the boolean XOR between self and the other region\n" @@ -1685,6 +1693,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean XOR (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("xor", &db::Region::bool_xor, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Returns the boolean XOR between self and the other region\n" + "\n" + "@return The result of the boolean XOR operation\n" + "\n" + "This method will compute the boolean XOR (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("^=", &db::Region::operator^=, gsi::arg ("other"), "@brief Performs the boolean XOR between self and the other region\n" "\n" @@ -1693,6 +1713,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method will compute the boolean XOR (intersection) between two regions. " "The result is often but not necessarily always merged.\n" ) + + method ("xor_with", &db::Region::bool_xor_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Performs the boolean XOR between self and the other region\n" + "\n" + "@return The region after modification (self)\n" + "\n" + "This method will compute the boolean XOR (intersection) between two regions. " + "The result is often but not necessarily always merged.\n" + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("\\|", &db::Region::operator|, gsi::arg ("other"), "@brief Returns the boolean OR between self and the other region\n" "\n" @@ -1701,6 +1733,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The boolean OR is implemented by merging the polygons of both regions. To simply join the regions " "without merging, the + operator is more efficient." ) + + method ("or", &db::Region::bool_or, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Returns the boolean OR between self and the other region\n" + "\n" + "@return The resulting region\n" + "\n" + "The boolean OR is implemented by merging the polygons of both regions. To simply join the regions " + "without merging, the + operator is more efficient." + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("\\|=", &db::Region::operator|=, gsi::arg ("other"), "@brief Performs the boolean OR between self and the other region\n" "\n" @@ -1709,6 +1753,18 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The boolean OR is implemented by merging the polygons of both regions. To simply join the regions " "without merging, the + operator is more efficient." ) + + method ("or_with", &db::Region::bool_or_with, gsi::arg ("other"), gsi::arg ("property_constraint", db::NoPropertyConstraint), + "@brief Performs the boolean OR between self and the other region\n" + "\n" + "@return The region after modification (self)\n" + "\n" + "The boolean OR is implemented by merging the polygons of both regions. To simply join the regions " + "without merging, the + operator is more efficient." + "It allows specification of a property constaint - e.g. only performing the boolean operation between " + "shapes with the same user properties.\n" + "\n" + "This variant has been introduced in version 0.28.4." + ) + method ("+", &db::Region::operator+, gsi::arg ("other"), "@brief Returns the combined region of self and the other region\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 6922b1dc6..1d162d43a 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -2126,6 +2126,84 @@ TEST(31_in_and_out) db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au31.gds"); } +TEST(40_BoolWithProperties) +{ + db::Layout ly; + { + std::string fn (tl::testdata ()); + fn += "/algo/deep_region_40.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty + + db::RecursiveShapeIterator si1 (ly, top_cell, l1); + si1.shape_flags (db::ShapeIterator::All | db::ShapeIterator::RegardProperties); + db::Region r1 (si1, dss); + + db::RecursiveShapeIterator si2 (ly, top_cell, l2); + si2.shape_flags (db::ShapeIterator::All | db::ShapeIterator::RegardProperties); + db::Region r2 (si2, dss); + + db::RecursiveShapeIterator si3 (ly, top_cell, l3); + si3.shape_flags (db::ShapeIterator::All | db::ShapeIterator::RegardProperties); + db::Region r3 (si3, dss); + + 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 (1, 0)), r1); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.merged ()); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.merged ()); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1 & r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.bool_and (r2, db::NoPropertyConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r1.bool_and (r2, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r1.bool_and (r2, db::DifferentPropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r3.bool_and (r2, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r3.bool_and (r2, db::DifferentPropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r1.bool_and (r3, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r1.bool_and (r3, db::DifferentPropertiesConstraint)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r1 - r2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r1.bool_not (r2, db::NoPropertyConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), r1.bool_not (r2, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), r1.bool_not (r2, db::DifferentPropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), r3.bool_not (r2, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), r3.bool_not (r2, db::DifferentPropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), r1.bool_not (r3, db::SamePropertiesConstraint)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (37, 0)), r1.bool_not (r3, db::DifferentPropertiesConstraint)); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r1.andnot (r2).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r1.andnot (r2).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), r1.andnot (r2, db::SamePropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), r1.andnot (r2, db::SamePropertiesConstraint).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), r1.andnot (r2, db::DifferentPropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), r1.andnot (r2, db::DifferentPropertiesConstraint).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), r3.andnot (r2, db::SamePropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (47, 0)), r3.andnot (r2, db::SamePropertiesConstraint).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (48, 0)), r3.andnot (r2, db::DifferentPropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (49, 0)), r3.andnot (r2, db::DifferentPropertiesConstraint).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), r1.andnot (r3, db::SamePropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), r1.andnot (r3, db::SamePropertiesConstraint).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), r1.andnot (r3, db::DifferentPropertiesConstraint).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), r1.andnot (r3, db::DifferentPropertiesConstraint).second); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au40.gds"); +} + TEST(100_Integration) { db::Layout ly; diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index bc0b60cad..351bf8860 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -83,7 +83,8 @@ SOURCES = \ dbArrayTests.cc \ dbDeepTextsTests.cc \ dbNetShapeTests.cc \ - dbHierNetsProcessorTests.cc + dbHierNetsProcessorTests.cc \ + dbAsIfFlatRegionTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC