From 3073c1917f6c18c564a9b2e387be3daaab240b17 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 31 Oct 2024 22:55:46 +0100 Subject: [PATCH] Some enhancements: internal merging, tests --- src/db/db/dbEdgeNeighborhood.cc | 42 ++++- src/db/db/gsiDeclDbEdgeNeighborhood.cc | 6 +- src/db/unit_tests/dbEdgeNeighborhoodTests.cc | 171 +++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 1 + testdata/algo/edge_neighborhood.gds | Bin 0 -> 1286 bytes testdata/algo/edge_neighborhood_au1.gds | Bin 0 -> 1622 bytes testdata/algo/edge_neighborhood_au2.gds | Bin 0 -> 4038 bytes testdata/algo/edge_neighborhood_au3.gds | Bin 0 -> 2566 bytes testdata/algo/edge_neighborhood_au4.gds | Bin 0 -> 1350 bytes testdata/algo/edge_neighborhood_au5.gds | Bin 0 -> 2438 bytes 10 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 src/db/unit_tests/dbEdgeNeighborhoodTests.cc create mode 100644 testdata/algo/edge_neighborhood.gds create mode 100644 testdata/algo/edge_neighborhood_au1.gds create mode 100644 testdata/algo/edge_neighborhood_au2.gds create mode 100644 testdata/algo/edge_neighborhood_au3.gds create mode 100644 testdata/algo/edge_neighborhood_au4.gds create mode 100644 testdata/algo/edge_neighborhood_au5.gds diff --git a/src/db/db/dbEdgeNeighborhood.cc b/src/db/db/dbEdgeNeighborhood.cc index 88c6ca56e..e4c9fbe20 100644 --- a/src/db/db/dbEdgeNeighborhood.cc +++ b/src/db/db/dbEdgeNeighborhood.cc @@ -165,9 +165,9 @@ private: return; } + // compute normal and unit vector along edge db::DVector e = db::DVector (edge.d ()); e = e * (1.0 / e.double_length ()); - db::DVector ne (-e.y (), e.x ()); // transform on the edge @@ -183,11 +183,37 @@ private: db::Coord xmin = -m_bext - 1; db::Coord xmax = ref_edge.dx () + m_eext + 1; + db::SimplePolygon per_edge_clip_box (db::Box (xmin, -m_din - 1, xmax, m_dout + 1)); + + // compute the merged neighbors + std::map > merged_neighbors; + + db::EdgeProcessor ep; for (auto n = neighbors.begin (); n != neighbors.end (); ++n) { + + ep.clear (); + + size_t id = 0; + for (auto nn = n->second.begin (); nn != n->second.end (); ++nn) { + for (auto e = (*nn)->begin_edge (); ! e.at_end (); ++e) { + ep.insert (itrans * (move * *e), id); + } + id += 2; + } + + ep.insert (per_edge_clip_box, size_t (1)); + + db::BooleanOp and_op (db::BooleanOp::And); + db::PolygonContainer pc (merged_neighbors [n->first]); + db::PolygonGenerator pg (pc, false); + ep.process (pg, and_op); + + } + + for (auto n = merged_neighbors.begin (); n != merged_neighbors.end (); ++n) { for (auto p = n->second.begin (); p != n->second.end (); ++p) { - db::Polygon poly = itrans * (move * **p); - for (auto p = poly.begin_edge (); ! p.at_end (); ++p) { - db::Edge e = *p; + for (auto pe = p->begin_edge (); ! pe.at_end (); ++pe) { + db::Edge e = *pe; xpos.insert (std::max (xmin, std::min (xmax, e.p1 ().x ()))); xpos.insert (std::max (xmin, std::min (xmax, e.p2 ().x ()))); } @@ -210,12 +236,12 @@ private: db::Box clip_box (xfrom, -m_din - 1, xto, m_dout + 1); // NOTE: this could be more efficient if we had a multi-layer capable trapezoid decomposition tool - for (auto n = neighbors.begin (); n != neighbors.end (); ++n) { + for (auto n = merged_neighbors.begin (); n != merged_neighbors.end (); ++n) { + + EdgeNeighborhoodVisitor::neighbor_shapes_type polygons; - EdgeNeighborhoodVisitor::neighbor_shapes_type polygons; for (auto p = n->second.begin (); p != n->second.end (); ++p) { - db::Polygon poly = itrans * (move * **p); - db::clip_poly (poly, clip_box, polygons, false); + db::clip_poly (*p, clip_box, polygons, false); } if (!polygons.empty ()) { diff --git a/src/db/db/gsiDeclDbEdgeNeighborhood.cc b/src/db/db/gsiDeclDbEdgeNeighborhood.cc index b3b770d7b..ede33d277 100644 --- a/src/db/db/gsiDeclDbEdgeNeighborhood.cc +++ b/src/db/db/gsiDeclDbEdgeNeighborhood.cc @@ -218,9 +218,9 @@ gsi::ClassExt decl_CompoundRegionOperationNode_ "@param children The inputs to use. The first one in the primary input, the others are neighbors.\n" "@param visitor The visitor object (see \\EdgeNeighborhoodVisitor) receiving the edge events.\n" "@param bext The search window extension to use at the edge beginning.\n" - "@param eext The search window extension to use at the edge beginning.\n" - "@param din The search window extension to use at the edge beginning.\n" - "@param dout The search window extension to use at the edge beginning.\n" + "@param eext The search window extension to use at the edge end.\n" + "@param din The search window extension to the 'outside' of the edge.\n" + "@param dout The search window extension to the 'inside' of the edge.\n" "\n" "This constructor has been introduced in version 0.29.9.\n" ) diff --git a/src/db/unit_tests/dbEdgeNeighborhoodTests.cc b/src/db/unit_tests/dbEdgeNeighborhoodTests.cc new file mode 100644 index 000000000..27bebd33c --- /dev/null +++ b/src/db/unit_tests/dbEdgeNeighborhoodTests.cc @@ -0,0 +1,171 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 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 "dbEdgeNeighborhood.h" +#include "dbReader.h" +#include "dbTestSupport.h" + +#include "tlStream.h" + +#include + +namespace +{ + +class ENPrimaryCopyVisitor + : public db::EdgeNeighborhoodVisitor +{ +public: + ENPrimaryCopyVisitor () + { + set_result_type (db::CompoundRegionOperationNode::ResultType::Region); + } + + void begin_polygon (const db::Layout *, const db::Cell *, const db::Polygon &polygon) + { + output_polygon (polygon); + } +}; + +class ENPrimaryCopyIntruderVisitor + : public db::EdgeNeighborhoodVisitor +{ +public: + ENPrimaryCopyIntruderVisitor (unsigned int input) + { + set_result_type (db::CompoundRegionOperationNode::ResultType::Region); + m_input = input; + } + + void on_edge (const db::Layout * /*layout*/, const db::Cell * /*cell*/, const db::Edge &edge, const neighbors_type &neighbors) + { + // Compute transformation to original edge + db::DVector e = db::DVector (edge.d ()); + e = e * (1.0 / e.double_length ()); + db::DVector ne (-e.y (), e.x ()); + + db::IMatrix2d trans (e.x (), ne.x (), e.y (), ne.y ()); + db::Disp move (edge.p1 () - db::Point ()); + + for (auto n = neighbors.begin (); n != neighbors.end (); ++n) { + for (auto nn = n->second.begin (); nn != n->second.end (); ++nn) { + if (nn->first == m_input) { + for (auto p = nn->second.begin (); p != nn->second.end (); ++p) { + output_polygon (move * (trans * *p)); + } + } + } + } + } + +private: + unsigned int m_input; +}; + +} + +static void prep_layer (db::Layout &ly, int gds_layer, db::Region &r, db::DeepShapeStore &dss, bool deep) +{ + unsigned int li = ly.get_layer (db::LayerProperties (gds_layer, 0)); + if (deep) { + r = db::Region (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), li), dss); + } else { + r = db::Region (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), li)); + } +} + +static void run_test (tl::TestBase *_this, db::EdgeNeighborhoodVisitor &visitor, const std::string &au_name, bool deep = true, db::Coord bext = 0, db::Coord eext = 0, db::Coord din = 0, db::Coord dout = 0) +{ + db::Layout ly; + { + std::string fn (tl::testdata ()); + fn += "/algo/edge_neighborhood.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::DeepShapeStore dss; + + db::Region r1, r2, r3; + prep_layer (ly, 1, r1, dss, deep); + prep_layer (ly, 2, r2, dss, deep); + prep_layer (ly, 3, r3, dss, deep); + + std::vector children; + children.push_back (new db::CompoundRegionOperationPrimaryNode ()); + children.push_back (new db::CompoundRegionOperationForeignNode ()); + children.push_back (new db::CompoundRegionOperationSecondaryNode (&r2)); + children.push_back (new db::CompoundRegionOperationSecondaryNode (&r3)); + + db::EdgeNeighborhoodCompoundOperationNode en_node (children, &visitor, bext, eext, din, dout); + + unsigned int l100 = ly.get_layer (db::LayerProperties (100, 0)); + + if (en_node.result_type () == db::CompoundRegionOperationNode::ResultType::Region) { + auto res = r1.cop_to_region (en_node); + res.insert_into (&ly, *ly.begin_top_down (), l100); + } else if (en_node.result_type () == db::CompoundRegionOperationNode::ResultType::Edges) { + auto res = r1.cop_to_edges (en_node); + res.insert_into (&ly, *ly.begin_top_down (), l100); + } else if (en_node.result_type () == db::CompoundRegionOperationNode::ResultType::EdgePairs) { + auto res = r1.cop_to_edge_pairs (en_node); + res.insert_into (&ly, *ly.begin_top_down (), l100); + } + + db::compare_layouts (_this, ly, tl::testdata () + au_name); +} + +TEST(1) +{ + ENPrimaryCopyVisitor visitor; + run_test (_this, visitor, "/algo/edge_neighborhood_au1.gds"); +} + + +TEST(2) +{ + ENPrimaryCopyIntruderVisitor visitor (0); + run_test (_this, visitor, "/algo/edge_neighborhood_au2.gds", true, 100, 100, 100, 2000); +} + +TEST(3) +{ + ENPrimaryCopyIntruderVisitor visitor (1); + run_test (_this, visitor, "/algo/edge_neighborhood_au3.gds", true, 100, 100, 100, 2000); +} + +TEST(4) +{ + ENPrimaryCopyIntruderVisitor visitor (2); + run_test (_this, visitor, "/algo/edge_neighborhood_au4.gds", true, 100, 100, 100, 2000); +} + +TEST(5) +{ + ENPrimaryCopyIntruderVisitor visitor (3); + run_test (_this, visitor, "/algo/edge_neighborhood_au5.gds", true, 100, 100, 100, 2000); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index a5ef9690e..67e131894 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri) SOURCES = \ dbCompoundOperationTests.cc \ + dbEdgeNeighborhoodTests.cc \ dbFillToolTests.cc \ dbLogTests.cc \ dbRecursiveInstanceIteratorTests.cc \ diff --git a/testdata/algo/edge_neighborhood.gds b/testdata/algo/edge_neighborhood.gds new file mode 100644 index 0000000000000000000000000000000000000000..75c723e1c4c3332cd86dd37ceb7de9e7642ffd42 GIT binary patch literal 1286 zcmaizJ5L)?5QUG|=B@=!NCe`cSaPH^QG^mi!=pevC89)%3ksBqk}_p}Leix~O5+ZG zf=e2sxIl7>NE8$AH^QOV>EsI{r3ynKgs%MzCDut>v{Zs*2tPU1I}%*Y&1P+q5jHf{&Sqan=hb@ z3b)Yv!K&dF-L{`IXC04i*MaE$j~8!Lk5Qo!u6eZbCVbFrRukwkNe(v@7{CIyKu;|O;mDOv58?+F^&;T z$Nwm0?&I1r@FYLq0;i7z7OEg~@U40zr)w0OV-U*u1T>x!){k@mcZp~e0A zN&fMU@>xf|$#V=XKKTBtNv)sA{2zboA?w%m^!?0{Ia34b)}A-Cc!-7k%U%7)slS`Z zp@cHK(A;Cza8KQm*O^+U_ny{((K`2fFAUtPl}v4N@B9Dk6*;Ym{5|L1mCjx-CH<1c ze);!<*@_S^zUsfB#eFq#zaoC9GHC3p4W9Ad>LRsg++%{zJGrh%@3pqngG7s``M`^Y z$mOacd-d`}dq%Xl$N2tyuYM}3chf8U-h4N-c)$c-J3U%g^qs+jL%`7DzPm~OuU8_C zBN5`|s(Q@O;*Fy;|7w!?(brmc>{*L@jT86lTcK|38^7vefUfuXX8d~KcRcL%>-RgW z4xRH}`_S*T?T*%ObvD@>wl{6qn-TG>&{@!zyPbF6Sr_ruXLp=+5#MHs;w@)QAO9}1 Jrs#Do;2H<-=`8>N literal 0 HcmV?d00001 diff --git a/testdata/algo/edge_neighborhood_au2.gds b/testdata/algo/edge_neighborhood_au2.gds new file mode 100644 index 0000000000000000000000000000000000000000..209b56eb017151973a5399418b6c28802bcb28a5 GIT binary patch literal 4038 zcma)9OG{Nz6kgt|$4gljJuDOzorLs;=rIU;K~azc1!?4$ad+k2h$*xy=vE16U((=yOe>0Xyz zG9-uPgd9r$mRcpdbL*i~{`hv|;`R5ZW?$c%l!2}mc3C!gcS5AICX(%` zNQY#5D7B)1)k4d?mP!9K_FikV zH-ygJ471-@Yf^zn@C=>NzW^>k6FeVYqn7{s;wrX_TUvA zd-%k?b=jAbG{qe>Kk^6*b?`3VxSf5y?k%?Cqp` zXASjaWcPa!B6&Ss*M9Lr2y1g80RP-HjS%M&+e+Vm6 zmOl~ovvuD-`qi3!ePem2vlX?pb#5cX^~3j}ZN`Cm!Y`0~saFg3 z>1;=DZ9T^1G<0VBHv5rzy93JclOLJ)^0zwycM|W0l_|R$faG=Fx%vP7V*Lh0+~_+Z z;mP9s{>bBpf6fc?gFig~_NJ&lX`t3&dD!xfNdAd$ zk8{UcfI8s01Ig>$ZxO%g1$m&}tb5u6oK-cu>yq==x6BKx`Pd7q8{Rhfjn&CVbp2!Q zK(9PU)X(N4`S$jhSNIO!L`3qXS)Ighy6vAf#JNHLMDlv~xbdTZV!tTH{c2AnU%IOj z|B3D%+8luX;(bpYDz87+Kk5d5K(~4==A_Qg#@tkd z|Hl75uK)ah1NHgRdcKJ|7i`^&-}*=ImpH%6=TF|hf12^dI5GP$w}}4}Kjtpq8JIh( zD>jFKOr_g7#Ba&}-f3Z(t QhxZ?mJmc@yIo2uv0AVXbX#fBK literal 0 HcmV?d00001 diff --git a/testdata/algo/edge_neighborhood_au3.gds b/testdata/algo/edge_neighborhood_au3.gds new file mode 100644 index 0000000000000000000000000000000000000000..563bc732230bae7922a9c8407f4b5040b46dc0fd GIT binary patch literal 2566 zcmai0ziU%b6h3)L-wU={MQJN3B;X<kW?#HRLsyJx-^4Bp^KycKtXYF6dcSV z`X|(_OT|)zW)LDcWN^sfkRi|vh2#0|c_+E4-sfAs;k{+F) zGR@HvRsG*ojN*s)Zxfx%Pu*I6b?w2IkNq1f+e@u?PuFO1D#I?0*B;l23Pqy$WJEcN zPenv@`E;IncY`Q7P%PJ&+Z7^1sdkF&^J8gnuC${ab{%Q z*{2$o`c3K`S-Z}O*6vPf?b*22dZuuuakdJNM4dmzXuRmfk9EQxvjLCIhIU0~L%U); zFk~;M?7ij*{ChTx)`R~2*?@QvzoPa{*F*j>i#5(s+*@hCbw%8^XV?hwaU8yR5qN?^eX2>tTEJJ=xU$r*py8!_5!lGxUf0K_}Wr z>zmb4`7Hf7|B|Qa5PtDK=Rf7M>TkLQ`g0QY(2uT%@*kf&`!>S4!yK`5=+0;QZI#Gq GE6^W_-Vn+F literal 0 HcmV?d00001 diff --git a/testdata/algo/edge_neighborhood_au4.gds b/testdata/algo/edge_neighborhood_au4.gds new file mode 100644 index 0000000000000000000000000000000000000000..451dd3bd1fd5e2dcab0490d4bbbf0da0d2132700 GIT binary patch literal 1350 zcmb7@ze`(D6vw}LNp3=GtD>l-ffTxwQcQ5sI*73fiiKv#5IQ+@aO~JWq1`$bx@6No z!O=z0L9m11;E=%~gF}W48HD5g-s4GLpf{y&`8>Y&oOjQU?}I~i@PvyW_t-!Ym#{{H&~?Vn`*Gv9|~|9T$3pEa^(&VY04SB<6zE!00TnExE-@8&Zo zVuD-f{AAT|FI>&fnX`_^p4WlN7Gu2^#>Q$VFPn`0@Q+xL^Sa2*HDfm)WBn-Umn7|% z+e20>Lf(DTccbaPoAka?`Ju}&W8ZD?jQ7@noIQ2VNIvi6xsu-N?x_b!)8qNTVq2uQ zt>mtj&U9y_>7MEPv%~&5QN5d9;j{Y7XnJ5IUpGD3Qu@u{=@DQw-ETLVf3YIcJ{BQ+ z+v+i+>Fwiq{`~^$qp!8^v}aBCGmhM^{|e{Ez40lp2MoN=f5xAO{6`P_`HlLWU5Cwi TuWgNb?Mr&r|Ff%t|4t4MVa0|% literal 0 HcmV?d00001 diff --git a/testdata/algo/edge_neighborhood_au5.gds b/testdata/algo/edge_neighborhood_au5.gds new file mode 100644 index 0000000000000000000000000000000000000000..fda0698d3b97e42a8101a9b4788d462703311068 GIT binary patch literal 2438 zcma);ziU%b6vt0q+Lxf!DoRsnp@NGPsU-;h7^KyT6$LYN2rlj5(9zMwU2ze*2o44u z^iSy6C1NN-1q&5AWN_#p^bLUqTDYF?J^3c@RqxZce8Rc+`_9jMUnG_&s>@^{D(%S$ znUXQNCNt^ZQjX$B5AKMZFAm?He|7!g=a0$Fh4rhAcTbjNayUm9$4ifEB12`7_*5hX ziBCr&a^+0Xx#p@!Y0Ee@=iIl8A|&mlEg3rdSG`E(nR7b{D01nt$aI&a-7}zfZo71(Xn`kB$$>JznxT^Z2BC)SOa zy=28^5Tre<7nx~0*I6{8SJf}pGmv&=+JAA7KPqazF)Mg(y(MY)4Ct-XqYa~WMozAa zkhE)egZi&GoNI452X+>1#z@-R8)5y?IO4-xTi)rJrCn?6THAWQ9{#Z}X_~%I+H?FPZfMyncv>$AS{o`)kKeW4*GeXk7e;C%| zZcCQ!9;J??Jz37tzwYUk(BXZg*ZcLb{`&`uAA}D1kci*b!+Nca-jt}7oiY9L`LhPn ze(bDe`k(fXKJNa|e0uyJ|DF5h2b`#DA72az|F#~AU%#bm*6-;x?YTbH7D>Bj`mCnn zSKse3ub}BF+a&FtK|TEAPGlU_miYx~KXzAU{6h!-d=GUX?Rn=HGmi7-&yUtU{ojE0 ZJU#k{esO-#Kg