From 91e68cef027ea96ecf22fe5a1a1a32350b0557a3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 6 Mar 2024 17:39:30 +0100 Subject: [PATCH] Fixed a number of issues with edge booleans in deep mode - andnot was falling back to flat - "intersections" with second argument empty was delivering wrong results - output of "intersections" is raw now to preserve dots - enhanced tests for these cases --- src/db/db/dbDeepEdges.cc | 39 ++++++++++++----- src/db/db/dbDeepEdges.h | 2 +- src/db/db/dbEdgesLocalOperations.cc | 3 ++ src/db/unit_tests/dbDeepEdgesTests.cc | 60 ++++++++++++++++++++++++-- testdata/algo/deep_edges_au3.gds | Bin 6170 -> 21182 bytes 5 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 9343ae457..e266660fc 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -916,10 +916,19 @@ EdgesDelegate *DeepEdges::merged () const return res.release (); } -DeepLayer +std::pair DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const { + std::vector output_layers; + DeepLayer dl_out (deep_layer ().derived ()); + output_layers.push_back (dl_out.layer ()); + + DeepLayer dl_out2; + if (op == EdgeAndNot) { + dl_out2 = DeepLayer (deep_layer ().derived ()); + output_layers.push_back (dl_out2.layer ()); + } db::EdgeBoolAndOrNotLocalOperation local_op (op); @@ -929,9 +938,9 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers); - return dl_out; + return std::make_pair (dl_out, dl_out2); } std::pair @@ -965,17 +974,25 @@ EdgesDelegate *DeepEdges::intersections (const Edges &other) const { const DeepEdges *other_deep = dynamic_cast (other.delegate ()); - if (empty () || other.empty ()) { + if (empty ()) { return clone (); + } else if (other.empty ()) { + + // NOTE: we do not use "EmptyEdges" as we want to maintain + return new DeepEdges (deep_layer ().derived ()); + } else if (! other_deep) { return AsIfFlatEdges::intersections (other); } else { - return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections)); + db::DeepEdges *res = new DeepEdges (and_or_not_with (other_deep, EdgeIntersections).first); + // this is to preserve dots in later steps + res->set_merged_semantics (false); + return res; } } @@ -999,7 +1016,7 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const } else { - return new DeepEdges (and_or_not_with (other_deep, EdgeAnd)); + return new DeepEdges (and_or_not_with (other_deep, EdgeAnd).first); } } @@ -1018,7 +1035,7 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const } else { - return new DeepEdges (and_or_not_with (other_deep, EdgeNot)); + return new DeepEdges (and_or_not_with (other_deep, EdgeNot).first); } } @@ -1094,7 +1111,7 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const std::pair DeepEdges::andnot_with (const Edges &other) const { - const DeepRegion *other_deep = dynamic_cast (other.delegate ()); + const DeepEdges *other_deep = dynamic_cast (other.delegate ()); if (empty ()) { @@ -1111,7 +1128,7 @@ DeepEdges::andnot_with (const Edges &other) const } else { - auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/); + auto res = and_or_not_with (other_deep, EdgeAndNot); return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second)); } @@ -1137,8 +1154,8 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const // 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, EdgeNot)); - DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot)); + DeepLayer n1 (and_or_not_with (other_deep, EdgeNot).first); + DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot).first); n1.add_from (n2); return new DeepEdges (n1); diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 7309f93da..ac91001e5 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -188,7 +188,7 @@ private: void init (); void ensure_merged_edges_valid () const; - DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const; + std::pair and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const; std::pair edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const; EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const; virtual EdgesDelegate *pull_generic (const Edges &edges) const; diff --git a/src/db/db/dbEdgesLocalOperations.cc b/src/db/db/dbEdgesLocalOperations.cc index a27183282..3572b131c 100644 --- a/src/db/db/dbEdgesLocalOperations.cc +++ b/src/db/db/dbEdgesLocalOperations.cc @@ -94,6 +94,9 @@ EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, db::C if (! is_and) { result.insert (subject); } + if (result2) { + result2->insert (subject); + } } else { scanner.insert (&subject, 0); any_subject = true; diff --git a/src/db/unit_tests/dbDeepEdgesTests.cc b/src/db/unit_tests/dbDeepEdgesTests.cc index dfa2c7bad..f214f42a4 100644 --- a/src/db/unit_tests/dbDeepEdgesTests.cc +++ b/src/db/unit_tests/dbDeepEdgesTests.cc @@ -146,6 +146,7 @@ TEST(3_Edge2EdgeBooleans) unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + unsigned int lempty = ly.insert_layer (); db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); @@ -153,7 +154,11 @@ TEST(3_Edge2EdgeBooleans) db::Edges e2 = r2.edges (); db::Edges e3 = r3.edges (); + db::Edges e3copy = r3.edges (); db::Edges e2and3 = r2and3.edges (); + db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty), dss); + db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0)); + db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0)); db::Layout target; unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); @@ -162,11 +167,58 @@ TEST(3_Edge2EdgeBooleans) target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e3); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ()); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 - e2and3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 ^ e2and3); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.intersections(e2and3)); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), e3.intersections(e2)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second); + + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2)); + // test, whether dots are not merged + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2)); CHECKPOINT(); db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3.gds"); diff --git a/testdata/algo/deep_edges_au3.gds b/testdata/algo/deep_edges_au3.gds index 4bb15fdecccb5de9c46523913bfa00fa35d0bfe8..b6d89fd5e82c5162bae3d2c88b0c1c08fcd9fc46 100644 GIT binary patch literal 21182 zcmbW9!LMXR6^Cp3J$l|eXU1V1LL>w+(L@YUgBW5W6Cp%=0Y@`Tj4}KXuH2E3u+o)# zU9j_CaKYMzZrtmFm2qP-2`i(}*6Gtl*R9*%*Y`aZT+;V_eX35K^E;>N-lnX}YW0iq z?6uYPf0dK6E>D)b<>mgr%h_uE_QmU^+&g*V{%gN^<*h&e@$vWH_|vyP{QWNPt=F?wqHlKYxuBBZ2dnv2mwrl%5uI2Q} zJzvMS=Qkg0Hvjv0v)O!5%E|NfTixESB!!s9QqlT>f3e79M0kMIU#>Vqk zvW1k|`kL9oI7CY0P$`TbGrN`W@kvA>HS5{?s`nE4u=mDxev2qwukVqq zq@Y$Jl_P{c>J_sUt9vjukm|iLiw&hPHjwIlIP?4uXkODe9Qr7wuzn%ce3#duk5UTj z*Q+$I^ajKRQW_iguVf1;we`B$!Z<`q<4`G#L!>kge?;@@M>vaKqsik zEhvE6LLVa4&uiw53z}C_5c5cB9KL0?FbtB*ShvnpVXtsztmCvyItGoam{he z`8tL#ZSU7>aJ7@W)voPx=gU88oqoB_qh3${Q296Z*Y4l)v8_TJfV^T|P^`6?!xbH*pggE@2{@M9^Ar-3<-dx?!9^n+<8GPf_ffO+$|76oh1yAOV|VB%(ep9F?D8UGmQxW)x9{ZqZr{1g zyjt|vtXMR!eGY`p>mMznGNS6pwwb$hgk#=a##WoxavLMm;wDm>_hQMKkmehC%6gIq=`=LHp3 zsA-j7>Wvs7DBBTRZG?l03f1S=&;uZq+8b&UBdzPUD8K3|PkW?=RNtu$+AAZJ&Ox3m z?Yqc2x9PKGq|ytaqPxiI=Oxt8K`x?HqtI3=b?jdc^Z-by0wARdfRrkLQLF$)ecn}G zc9lUl(3a}P5h^Nd_5zdq5=zttsf=1s8>F;nLrN7uD5-ivMK*#)2^F0X)Mb21oOuO1 zDWq~2&?0K6dPrqVK$jwvbSX%w0wC3*_FxZylq!HxtN=polzO{+A8HCxIj>e>hpH!( zWF=CXl}Kq;A{Dl_ec_?{C6rWHqqqk^N;_DjbeAoZ=!Q_D8~DbDMwC+fJ<-s!A*J~x zlz2lZi4CD74uz7g5-E)+q%@+0x>{_AVxujs4oGPwLQ2&JDOEP4S}kcdCmj(|X{%M( zLFa{vhzjb!xeZcU^^npEi*Ez<(Oc&@-KQXx-hh3IP_j=!O5;!{iFu^1>O(naJ7Nn? zDvaWYGK%*pLP>9flvbi66zo%kl8y)|)eWSYUbOj5bOWgxQQV~nCHoYiq{0d%HAUWl zlhYogv^pTA3Lumy08**|NaYCOq#dcW1qxskD}Ydv%Sg3Y&+D*H5lXTWDa}fxG%Jw` zTewdVN_tVFSOJjg>+ zcqS#3bPhuGx-p!62_+qo{E|SPnE$R{sQCC^?TpN;OI-(I});0gzG!KuQ(B zC{_TY_&iD|(G8?jH;zzn9wn5h4N|H$NU7Q&RacpJqe4m56DrmVG)gGhJK(Q^VwLw@ z%Alf1=`H{%RREzx0gzG!KuQ$=DOCWYSOJ8RTt-TBSt!X$q%NNGeNr4c36 z)nY>w8*OQIKuRkSQmQscsj?xJw%TdWa2|zJ+Jf^aq2xRYDXn@)X@$jKwI&7UHc08Y z4N}wUFr2_372eou)Ii~{TKjobyVLgpgbIxcZ|tu9{tKzz8_R9wD!0yj7~uu!yyh2D zn#)3oZXgw&$M;2rlFl3{)n24DQ;^cEL@I5;d6ZGyiwYG{3mSz~&I`_?gpytqsmv>Q zvl=O_4np<1G3=y}$`Qg|Pbldegpw{rs6!pmk>4)Y|8wHQiwAH1v~FYT?~~8&<}aDI zzdWvr68~(KZoGH?Gro84L%#RiW4`yo5Bc7Ar@w-pjPuoxnfvi~_};_!`QE#K+uy4m IJUuP{2QvBOKL7v# delta 720 zcmaKpJxc>Y5QcXzxlKGp6TIvtcbD@bArb@?C5j?`A&3|?iiM=npO9Jzq!lcJ(`jKE zv5nYRNwBcCQxw6*K6YZ|%tnI>+PuuWJ0H)^UY+uzks=dJ)3%w*wa^O-GMz~lV&Z$u z!kWl0FEC~X^qKkniItnP=H%k#aP7Fb#a#W*y7S^4hetaB6|D=ZMigcP<2(k1un$+7 zfahQjx@Itk>YEwJ>*VJG9@KRK6+O!3k6fv8Wjj~?%Joej_IONH<)G}iu+!P0=9ZlV zG>s&WLrvsReUr4s5yPn7Ipl@de^0r%H%|r9)v{@L=!;?$u{+oZZ*%|O>M?VvD7elA1$+)vsVBc(|v12idO zk@wvkzV?erwwYv`Nh&7v$Rrh$R7|MIgcZmn+f1zv#3U6H`cEeO31q^JBa>82*cq8x zlZc6G$@^{r8n%P`PaMVtyxSH$c}XZ_4Jb|Z&@t>f^c5xBgM++<5v}rCMYXI4Z>_V{ Zp@ILugc(9?F0U=E!|O)xMSY{2e*jIpsQ~~0