From d141c0895da17c9cf9e004c001377875806498f9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 14 Jun 2020 18:12:17 +0200 Subject: [PATCH] Added tests for Region's andnot. --- src/db/db/dbAsIfFlatRegion.cc | 65 +++++++++++++++++++++++ src/db/db/dbAsIfFlatRegion.h | 1 + src/db/db/dbDeepRegion.cc | 51 ++++++++++++++++++ src/db/db/dbDeepRegion.h | 2 + src/db/db/dbEmptyRegion.h | 1 + src/db/db/dbRegion.h | 11 ++++ src/db/db/dbRegionDelegate.h | 1 + src/db/db/gsiDeclDbRegion.cc | 21 ++++++++ src/db/unit_tests/dbDeepRegionTests.cc | 70 +++++++++++++++++++------ src/db/unit_tests/dbRegionTests.cc | 15 ++++++ testdata/algo/deep_region_au3b.gds | Bin 0 -> 3242 bytes 11 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 testdata/algo/deep_region_au3b.gds diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index dbc00918e..5da06de10 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1115,6 +1115,71 @@ AsIfFlatRegion::not_with (const Region &other) const } } + +std::pair +AsIfFlatRegion::andnot_with (const Region &other) const +{ + if (empty ()) { + + // Nothing to do + return std::make_pair (new EmptyRegion (), new EmptyRegion ()); + + } else if (other.empty () && ! strict_handling ()) { + + // Nothing to do + return std::make_pair (new EmptyRegion (), clone ()); + + } else if (! bbox ().overlaps (other.bbox ()) && ! strict_handling ()) { + + // Nothing to do + return std::make_pair (new EmptyRegion (), clone ()); + + } else { + + // Generic case + db::EdgeProcessor ep (report_progress (), progress_desc ()); + ep.set_base_verbosity (base_verbosity ()); + + // count edges and reserve memory + size_t n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + // insert the polygons into the processor + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + n = 1; + for (RegionIterator p (other.begin ()); ! p.at_end (); ++p, n += 2) { + ep.insert (*p, n); + } + + std::auto_ptr new_region1 (new FlatRegion (true)); + db::BooleanOp op1 (db::BooleanOp::And); + db::ShapeGenerator pc1 (new_region1->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg1 (pc1, false /*don't resolve holes*/, min_coherence ()); + + std::auto_ptr new_region2 (new FlatRegion (true)); + db::BooleanOp op2 (db::BooleanOp::ANotB); + db::ShapeGenerator pc2 (new_region2->raw_polygons (), true /*clear*/); + db::PolygonGenerator pg2 (pc2, false /*don't resolve holes*/, min_coherence ()); + + std::vector > procs; + procs.push_back (std::make_pair (&pg1, &op1)); + procs.push_back (std::make_pair (&pg2, &op2)); + ep.process (procs); + + return std::make_pair (new_region1.release (), new_region2.release ()); + + } +} + RegionDelegate * AsIfFlatRegion::xor_with (const Region &other) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index ed7b53227..a6c106618 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -154,6 +154,7 @@ public: virtual RegionDelegate *not_with (const Region &other) const; virtual RegionDelegate *xor_with (const Region &other) const; virtual RegionDelegate *or_with (const Region &other) const; + virtual std::pair andnot_with (const Region &) const; virtual RegionDelegate *add_in_place (const Region &other) { diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index f5eba16fa..507689b37 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -542,6 +542,31 @@ DeepRegion::not_with (const Region &other) const } } +std::pair +DeepRegion::andnot_with (const Region &other) const +{ + const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + + if (empty ()) { + + return std::make_pair (clone (), clone ()); + + } else if (other.empty ()) { + + return std::make_pair (other.delegate ()->clone (), clone ()); + + } else if (! other_deep) { + + return AsIfFlatRegion::andnot_with (other); + + } else { + + std::pair res = and_and_not_with (other_deep); + return std::make_pair (new DeepRegion (res.first), new DeepRegion (res.second)); + + } +} + DeepLayer DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const { @@ -560,6 +585,32 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const return dl_out; } +std::pair +DeepRegion::and_and_not_with (const DeepRegion *other) const +{ + DeepLayer dl_out1 (deep_layer ().derived ()); + DeepLayer dl_out2 (deep_layer ().derived ()); + + db::TwoBoolAndNotLocalOperation op; + + 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_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 { diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 1c672d430..44dcc87bb 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -83,6 +83,7 @@ public: virtual RegionDelegate *and_with (const Region &other) const; virtual RegionDelegate *not_with (const Region &other) const; virtual RegionDelegate *xor_with (const Region &other) const; + virtual std::pair andnot_with (const Region &) const; virtual RegionDelegate *add_in_place (const Region &other); virtual RegionDelegate *add (const Region &other) const; @@ -184,6 +185,7 @@ private: void ensure_merged_polygons_valid () const; const DeepLayer &merged_deep_layer () const; DeepLayer and_or_not_with(const DeepRegion *other, bool and_op) const; + std::pair and_and_not_with (const DeepRegion *other) const; EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index ec40deffa..b6e8848b3 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -95,6 +95,7 @@ public: virtual RegionDelegate *and_with (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *not_with (const Region &) const { return new EmptyRegion (); } + virtual std::pair andnot_with (const Region &) 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 *add_in_place (const Region &other); diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 0bc2b47fa..ae2246366 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1145,6 +1145,17 @@ public: return *this; } + /** + * @brief Two-bool ANDNOT operation + * + * The first region delivered will be the AND result, the second one the NOT result. + */ + std::pair andnot (const Region &other) const + { + std::pair res = mp_delegate->andnot_with (other); + return std::make_pair (Region (res.first), Region (res.second)); + } + /** * @brief Selects all polygons of this region which are completly outside polygons from the other region * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index e69f1d2e9..c7f33de62 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -263,6 +263,7 @@ public: virtual RegionDelegate *or_with (const Region &other) 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) const = 0; virtual RegionDelegate *selected_outside (const Region &other) const = 0; virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 3adf813e4..0201a444e 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -548,6 +548,17 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other, max_projection.is_nil () ? std::numeric_limits::max () : max_projection.to ()); } +static std::vector andnot (const db::Region *r, const db::Region &other) +{ + std::pair rp = r->andnot (other); + + std::vector res; + res.resize (2, db::Region ()); + res [0] = rp.first; + res [1] = rp.second; + return res; +} + static int euclidian_metrics () { return db::Euclidian; @@ -1311,6 +1322,16 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" ) + + method_ext ("andnot", &andnot, gsi::arg ("other"), + "@brief Returns the boolean AND and NOT between self and the other region\n" + "\n" + "@return A two-element array of regions with the first one being the AND result and the second one being the NOT result\n" + "\n" + "This method will compute the boolean AND and NOT between two regions simultaneously. " + "Because this requires a single sweep only, using this method is faster than doing AND and NOT separately.\n" + "\n" + "This method has been added in version 0.27.\n" + ) + method ("&", &db::Region::operator&, gsi::arg ("other"), "@brief Returns the boolean AND between self and the other region\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index e4792df01..8cf5dc65f 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -172,6 +172,13 @@ TEST(3_BoolAndNot) db::Region r42minus3 = r42 - r3; db::Region r42minus42 = r42 - r42; + db::Region tr2minus3 = r2.andnot (r3).second; + db::Region tr2minusbox = r2.andnot (box).second; + db::Region tr2minus42 = r2.andnot (r42).second; + db::Region trboxminus3 = box.andnot (r3).second; + db::Region tr42minus3 = r42.andnot (r3).second; + db::Region tr42minus42 = r42.andnot (r42).second; + db::Region r2and3 = r2 & r3; db::Region r2andbox = r2 & box; db::Region r2and42 = r2 & r42; @@ -179,27 +186,58 @@ TEST(3_BoolAndNot) db::Region r42and3 = r42 & r3; db::Region r42and42 = r42 & r42; + db::Region tr2and3 = r2.andnot (r3).first; + db::Region tr2andbox = r2.andnot (box).first; + db::Region tr2and42 = r2.andnot (r42).first; + db::Region trboxand3 = box.andnot (r3).first; + db::Region tr42and3 = r42.andnot (r3).first; + db::Region tr42and42 = r42.andnot (r42).first; + EXPECT_EQ (r2and3.is_merged (), false); - 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)), r2minus3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2minusbox); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2minus42); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxminus3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42minus3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42minus42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2minus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2minusbox); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2minus42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxminus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42minus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42minus42); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2and3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2andbox); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r2and42); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rboxand3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r42and3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r42and42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2andbox); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r2and42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rboxand3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r42and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r42and42); - CHECKPOINT(); - db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3.gds"); + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3.gds"); + } + + { + 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)), tr2minus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), tr2minusbox); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), tr2minus42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), trboxminus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), tr42minus3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), tr42minus42); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), tr2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), tr2andbox); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), tr2and42); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), trboxand3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), tr42and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), tr42and42); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au3b.gds"); + } } TEST(4_Add) diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index c5b7c56fc..7fcbf2ac5 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -202,6 +202,13 @@ TEST(3) EXPECT_EQ ((db::Region () & r).to_string (), ""); EXPECT_EQ ((db::Region () & r).empty (), true); + EXPECT_EQ (r.andnot(rr).first.to_string (), "(10,20;10,220;110,220;110,20)"); + EXPECT_EQ (rr.andnot(r).first.to_string (), "(10,20;10,220;110,220;110,20)"); + EXPECT_EQ (r.andnot(db::Region ()).first.to_string (), ""); + EXPECT_EQ (r.andnot(db::Region ()).first.empty (), true); + EXPECT_EQ (db::Region ().andnot(r).first.to_string (), ""); + EXPECT_EQ (db::Region ().andnot(r).first.empty (), true); + r &= rr; EXPECT_EQ (r.is_box (), true); EXPECT_EQ (r.empty (), false); @@ -289,6 +296,14 @@ TEST(7) EXPECT_EQ ((db::Region () - r).empty (), true); EXPECT_EQ ((db::Region () - r).is_merged (), true); + EXPECT_EQ (r.andnot(db::Region (db::Box (db::Point (10, 20), db::Point (110, 220)))).second.to_string (), "(-100,-100;-100,400;200,400;200,-100/10,20;110,20;110,220;10,220)"); + EXPECT_EQ (r.andnot(db::Region ()).second.to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,400;200,400;200,-100)"); + EXPECT_EQ (r.andnot(db::Region ()).second.empty (), false); + EXPECT_EQ (r.andnot(db::Region ()).second.is_merged (), false); + EXPECT_EQ (db::Region ().andnot(r).second.to_string (), ""); + EXPECT_EQ (db::Region ().andnot(r).second.empty (), true); + EXPECT_EQ (db::Region ().andnot(r).second.is_merged (), true); + r -= db::Region (db::Box (db::Point (10, 20), db::Point (110, 220))); EXPECT_EQ (r.is_box (), false); EXPECT_EQ (r.empty (), false); diff --git a/testdata/algo/deep_region_au3b.gds b/testdata/algo/deep_region_au3b.gds new file mode 100644 index 0000000000000000000000000000000000000000..e741130cf5923c40ac43e1ebeb4a35e8fac74760 GIT binary patch literal 3242 zcmai$K}b|l6o!v8&o|>ZPSfa&GDsUy2n?elabaW%WyusKB9agYE~JI4RtAC~6bON> zs)f5ia3x4YYd39NxoP7GR?IMt$Ra z<|R76E2{U_b&k#r_o4g3dcye`v7S`cbth}Hx5UYbeW9zNCeWJ|hof092ZTx%?sdlp+oEZ4Q2oV#|G zoV$KMId?n0>)5=}<7C~Vo5{K9wdCB3!!Q@Py*=ud^HX)p`Kh|xsgjI`Zn>;C*XORE zH&k85%)_n895Qa#cduw&_loLzzLAXE_0=P-s~)MY&zKSO`*Mui_5A}{*FT`T8}lUN zcKwil+eL=_+b%M^qx#_;)d%_LZH=72$jE`#jU1?M>^I4{ef~s6>n19yn|e$#Zr9hA zw63!&{v#Q;>ES!nfzZK!B;z(ce1|#^I{1%d+@^=`PzOQ>|B;N_^za?( zKJ??6~ogPZK{jy+=urLQ(T%=DX@h#M>9O4s<@7e-DOC-_g8M`{ox&5ybN!LPDQk zP(6tLrLB;d+i_vm5D@D|Ua5UMH%Zl%_d=q7c~$#^n2)?tb(LLG>Iy;n-p$3JJE(f6<%evhEncZ1)N!m_?6g=NMsy(ck!aYO5h8>-`Xh2NPVZ<()t z;yZ%*@Dm6>A>QDphWT2D`OxuQ;X8wPgT6c1{}lX~9oO@w4>1qFCy3t}aT4d;Hmc`M zp9cEq{@DK&`nNA?fB4h)q46i_`_;rr^r!FYJ~aMBzV1`wOX%t2pntRZ{{Bi^I-fp; zf3ZLM7;)^6KJVPr{n5vPzFB{Nf8{;xU-$8