From 1f44a951f492c258a8a2a6018a5d2fc11ce05cf7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 3 Feb 2025 20:47:31 +0100 Subject: [PATCH] Polygon neighborhood compound operation --- src/db/db/gsiDeclDbEdgeNeighborhood.cc | 4 +- src/db/db/gsiDeclDbPolygonNeighborhood.cc | 12 +- .../unit_tests/dbPolygonNeighborhoodTests.cc | 161 ++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 1 + src/rba/unit_tests/rbaTests.cc | 1 + testdata/algo/polygon_neighborhood.gds | Bin 0 -> 1286 bytes testdata/algo/polygon_neighborhood_au1.gds | Bin 0 -> 1622 bytes testdata/algo/polygon_neighborhood_au2.gds | Bin 0 -> 1556 bytes testdata/algo/polygon_neighborhood_au3.gds | Bin 0 -> 1826 bytes testdata/algo/polygon_neighborhood_au4.gds | Bin 0 -> 1502 bytes testdata/algo/polygon_neighborhood_au5.gds | Bin 0 -> 1772 bytes testdata/ruby/dbPolygonNeighborhood.rb | 142 +++++++++++++++ 12 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 src/db/unit_tests/dbPolygonNeighborhoodTests.cc create mode 100644 testdata/algo/polygon_neighborhood.gds create mode 100644 testdata/algo/polygon_neighborhood_au1.gds create mode 100644 testdata/algo/polygon_neighborhood_au2.gds create mode 100644 testdata/algo/polygon_neighborhood_au3.gds create mode 100644 testdata/algo/polygon_neighborhood_au4.gds create mode 100644 testdata/algo/polygon_neighborhood_au5.gds create mode 100644 testdata/ruby/dbPolygonNeighborhood.rb diff --git a/src/db/db/gsiDeclDbEdgeNeighborhood.cc b/src/db/db/gsiDeclDbEdgeNeighborhood.cc index 94b0a3961..9711d2897 100644 --- a/src/db/db/gsiDeclDbEdgeNeighborhood.cc +++ b/src/db/db/gsiDeclDbEdgeNeighborhood.cc @@ -231,11 +231,11 @@ static db::CompoundRegionOperationNode *new_edge_neighborhood (const std::vector return new db::EdgeNeighborhoodCompoundOperationNode (children, visitor, bext, eext, din, dout); } -gsi::ClassExt decl_CompoundRegionOperationNode_ext ( +gsi::ClassExt decl_CompoundRegionOperationNode_ext_EdgeNeighborhood ( gsi::constructor ("new_edge_neighborhood", &new_edge_neighborhood, gsi::arg ("children"), gsi::arg ("visitor"), gsi::arg ("bext", 0), gsi::arg ("eext", 0), gsi::arg ("din", 0), gsi::arg ("dout", 0), "@brief Creates a new edge neighborhood collector\n" "\n" - "@param children The inputs to use. The inputs are enumrated by base zero indexes in the visitor callback.\n" + "@param children The inputs to use. The inputs are enumerated by base zero indexes in the visitor callback.\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 end.\n" diff --git a/src/db/db/gsiDeclDbPolygonNeighborhood.cc b/src/db/db/gsiDeclDbPolygonNeighborhood.cc index bf5d373ca..37c0ffded 100644 --- a/src/db/db/gsiDeclDbPolygonNeighborhood.cc +++ b/src/db/db/gsiDeclDbPolygonNeighborhood.cc @@ -123,17 +123,17 @@ Class decl_PolygonNeighborhoodVisitorImpl ( // --------------------------------------------------------------------------------- // PolygonNeighborhoodCompoundOperationNode binding -static db::CompoundRegionOperationNode *new_edge_neighborhood (const std::vector &children, db::PolygonNeighborhoodVisitor *visitor, const db::Coord dist) +static db::CompoundRegionOperationNode *new_polygon_neighborhood (const std::vector &children, db::PolygonNeighborhoodVisitor *visitor, const db::Coord dist) { return new db::PolygonNeighborhoodCompoundOperationNode (children, visitor, dist); } -gsi::ClassExt decl_CompoundRegionOperationNode_ext ( - gsi::constructor ("new_polygon_neighborhood", &new_edge_neighborhood, gsi::arg ("children"), gsi::arg ("visitor"), gsi::arg ("dist", 0), - "@brief Creates a new edge neighborhood collector\n" +gsi::ClassExt decl_CompoundRegionOperationNode_ext_PolygonNeighborhood ( + gsi::constructor ("new_polygon_neighborhood", &new_polygon_neighborhood, gsi::arg ("children"), gsi::arg ("visitor"), gsi::arg ("dist", 0), + "@brief Creates a new polygon neighborhood collector\n" "\n" - "@param children The inputs to use. The inputs are enumrated by base zero indexes in the visitor callback.\n" - "@param visitor The visitor object (see \\PolygonNeighborhoodVisitor) receiving the edge events.\n" + "@param children The inputs to use. The inputs are enumerated by base zero indexes in the visitor callback.\n" + "@param visitor The visitor object (see \\PolygonNeighborhoodVisitor) receiving the polygon events.\n" "@param dist The search distance in which to look up neighbors.\n" "\n" "This constructor has been introduced in version 0.30.0.\n" diff --git a/src/db/unit_tests/dbPolygonNeighborhoodTests.cc b/src/db/unit_tests/dbPolygonNeighborhoodTests.cc new file mode 100644 index 000000000..966523a42 --- /dev/null +++ b/src/db/unit_tests/dbPolygonNeighborhoodTests.cc @@ -0,0 +1,161 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbPolygonNeighborhood.h" +#include "dbReader.h" +#include "dbTestSupport.h" + +#include "tlStream.h" + +#include + +namespace +{ + +class PNPrimaryCopyVisitor + : public db::PolygonNeighborhoodVisitor +{ +public: + PNPrimaryCopyVisitor () + { + set_result_type (db::CompoundRegionOperationNode::ResultType::Region); + } + + void neighbors (const db::Layout *, const db::Cell *, const db::PolygonWithProperties &polygon, const neighbors_type &) + { + output_polygon (polygon); + } +}; + +class PNPrimaryCopyIntruderVisitor + : public db::PolygonNeighborhoodVisitor +{ +public: + PNPrimaryCopyIntruderVisitor (unsigned int input) + { + set_result_type (db::CompoundRegionOperationNode::ResultType::Edges); + m_input = input; + } + + void neighbors (const db::Layout *, const db::Cell *, const db::PolygonWithProperties &polygon, const neighbors_type &neighbors) + { + for (auto n = neighbors.begin (); n != neighbors.end (); ++n) { + if (n->first == m_input) { + for (auto p = n->second.begin (); p != n->second.end (); ++p) { + output_edge (db::Edge (polygon.box ().center (), p->box ().center ())); + } + } + } + } + +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::PolygonNeighborhoodVisitor &visitor, const std::string &au_name, bool deep = true, db::Coord dist = 0) +{ + db::Layout ly; + { + std::string fn (tl::testdata ()); + fn += "/algo/polygon_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::PolygonNeighborhoodCompoundOperationNode en_node (children, &visitor, dist); + + 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) +{ + PNPrimaryCopyVisitor visitor; + run_test (_this, visitor, "/algo/polygon_neighborhood_au1.gds"); +} + + +TEST(2) +{ + PNPrimaryCopyIntruderVisitor visitor (0); + run_test (_this, visitor, "/algo/polygon_neighborhood_au2.gds", true, 2000); +} + +TEST(3) +{ + PNPrimaryCopyIntruderVisitor visitor (1); + run_test (_this, visitor, "/algo/polygon_neighborhood_au3.gds", true, 2000); +} + +TEST(4) +{ + PNPrimaryCopyIntruderVisitor visitor (2); + run_test (_this, visitor, "/algo/polygon_neighborhood_au4.gds", true, 2000); +} + +TEST(5) +{ + PNPrimaryCopyIntruderVisitor visitor (3); + run_test (_this, visitor, "/algo/polygon_neighborhood_au5.gds", true, 2000); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 7363746df..5183520f5 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -12,6 +12,7 @@ SOURCES = \ dbFillToolTests.cc \ dbLogTests.cc \ dbObjectWithPropertiesTests.cc \ + dbPolygonNeighborhoodTests.cc \ dbRecursiveInstanceIteratorTests.cc \ dbRegionCheckUtilsTests.cc \ dbTriangleTests.cc \ diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index 01e91bda6..7b23e3940 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -102,6 +102,7 @@ RUBYTEST (dbEdgePairTest, "dbEdgePairTest.rb") RUBYTEST (dbEdgesTest, "dbEdgesTest.rb") RUBYTEST (dbEdgeTest, "dbEdgeTest.rb") RUBYTEST (dbEdgeNeighborhood, "dbEdgeNeighborhood.rb") +RUBYTEST (dbPolygonNeighborhood, "dbPolygonNeighborhood.rb") RUBYTEST (dbGlyphs, "dbGlyphs.rb") RUBYTEST (dbHierNetworkProcessorTests, "dbHierNetworkProcessorTests.rb") RUBYTEST (dbInstanceTest, "dbInstanceTest.rb") diff --git a/testdata/algo/polygon_neighborhood.gds b/testdata/algo/polygon_neighborhood.gds new file mode 100644 index 0000000000000000000000000000000000000000..6d21d6933633cb86344b19e99412874d425ee61b GIT binary patch literal 1286 zcmaizy-QqC5XH~FUGFYv;wP>W!9bc2f{KlrBKQf4fox$RR+g42^Cu)-%7D#w`X^Z0 zC|U?w2o@=}urOe;g~b-aIOopJ`U1J@YkrS&XWpHU^AM0_+n6Y1<-aJPgenFwlz&Gh z3tu*tfsta*=cS)>o2LiOh1H|!`u@%qCVIN$g|PLt29zp5c$Mkb!|M#d$AO~A$sSO? zG)^vxT)hRHu9q)S8vJiQQ2i!y(=ob)#+uy+?r4b=__<|6*RGaV$bUteeN2 zt~ZX;`Hy3)kG{6P^PY8GXPmg-{uR!Rd*d^?7}4=Q{~0}x`E3vD{QmVjyN;VvudTJc IR#ukq1Y<*Py8r+H literal 0 HcmV?d00001 diff --git a/testdata/algo/polygon_neighborhood_au1.gds b/testdata/algo/polygon_neighborhood_au1.gds new file mode 100644 index 0000000000000000000000000000000000000000..93c4064ca6fd87aadfce13120b32eba9253e10a5 GIT binary patch literal 1622 zcmbVMze}7!5PkQ3=iY%PDv_u}FkllTBu5BDgNVNZh6Hkjg`~1bVQJ}~kaU&-o9mK4 z!P3SM3qgy3MT#pd6fCZ=xI!5B?cCh$LH3M(&HI?$w>$IZ?Z6?+)-h4YN*BnGV+2EZ z9si@8xsUIcfRVg!e(~Fz55ImiW>@xJ)^*3 z!6r~TR-9ZAIe7{gTD)|O;_yHD!0499X@dw%Jp-njh87Q);EVhzb6v5qA=0df7+Tz) zpX48GDxY=a=RC*I;=S*`9@F}X%>U8X4zhk-Pv6fRnKLz@Zq16J#X~IQKhW0yG4*$& z1(Y$sE}ZW$Yq)W@=yj&n>Ai4nXL%%a$ElmE$*v{`xWs+l|f@)ZSaiuRvW23;~o=y-pO@Edatpe9wb^k%?Do8 zMXpvA*{fH-wP!?&dyMbTJM~jhy_;U)_x8J?#RDez+UdcXqVEj)_W(nS`|c+BM>8Vz zeG%f-s(Q@O;`RMB|9Xu1(brmc>{*L@jT86lTcK|38^6hg0B!H{&G_}eZ+Y13*X?&! z9XjW|_O9D&Us_tv>1?t$Y;W4IGb7?zp|hYXcRTOCvo7MR&+a(uBEHQM#s8c&UHrSu Jnv&PGh#Qp!=7S4?O~jx=EQAyyTUbO8*&@Xj!RtM9-`zaH+0AQyk2`Z_?#CGfWZ4p0m8|v?8FDny z!o~7G>REVr{|?a1$8OKPy#C<*+uqIjwJV)Bj~CGz8=?zg@lhM7)`4&&Lj~bz2H?`M zTx4SfsBIaiW<|c71)LtQZJ~Pnzj|O|Rb;zI0_V;H7y3?*M<(-kCj#)|1#N4~>zoE{&3|K6n4Pcr`#FZRj$Z9RQIb7ao!0sGdUae6$)V*cZU{-0w1 z!$bvjjB^S*ub4H$=`g2#X0OwGH`_p?!@cT-p?j^8GfUiicf?+i&9=z5ZSI{f_G&BX zm#plUAMcp02>I)o{X0Fb)s*K|(#I-ekG0z98THnH>^{__oy z?z#xMyI>x3dc3=y*6&R+KlGF+T+Ci_Ey+8&W+#HY{bC(d^5Tp^@WGEfB*WO zRmaJx*X|WwJ7ivaQuI1Z^M%wKc|5(zH}X+!$q5_nhEXbD`kKfeO{8GVYqW~hoqTRp cDi5R*`Tj}d_fzLVRebyGhtX6u?MfAY0Zam%761SM literal 0 HcmV?d00001 diff --git a/testdata/algo/polygon_neighborhood_au3.gds b/testdata/algo/polygon_neighborhood_au3.gds new file mode 100644 index 0000000000000000000000000000000000000000..a08972c7898194c2e54c5d136354ac0d85665c13 GIT binary patch literal 1826 zcmb7EJ!=$E6g@k$c{^fs6;~6N95v)>Jq_D8G@CRsTDcEeM zKOtqB1cM5(5K@S2VG%)OixgV~ukXA&cQXOsW_Fr0+;`91d(S;@;E*KCXjYQiFC<9O zKoeJr@5mDOXz?DM zXmS7jD1T#B`J5x&<#!A%KDhq=xXw>x|7TtuAm`WfczyQBo~Z$K>rES4Jj6o(qka9) zQGYj9L55LoVfPKYhCA=(yw21*p1aio>TTwFFAU7pNhX$=d;f@Bk*$`<_Z{ZW=eb@= z`Xwp)<>v=>D?@6sAS2G`VXGDv8EY?pC=BJ`sn_l5_=dGc|14j6|>3UnyZwANL07HxW?MC@u zZi#f(MTmO~>M=u$ch=+l{c-k3U+dgO&syAT9I3B&g}QNXd?sfD^u5nJ_psOR zu-`d#*qry;gWPM!)N4<3t=$xFNLEk7*BiVeKR%26d8U=mzSIh3S*o|!I`nlk>yy6% zbW>il6bqQTA@bJ`O>N3{XxYQo%4=B7k{v2*ST$4y5mlwEhWw{-&%fsKrH8G>G62L|Uy-Q7}V?;?%*RLx+wIjvaJ!6m-a@ ze?rGD6$=U#6gm{iAW}t2h9Vh?pZDA^U-ATR;#aOnx%c*U``XOv#pcV0bEuUD=$xB-&;W`V;0`4yz#UEioF7d^ z))#^DrsBku$j4KFq4DKS6p#E<4~#8~Y_*BN=`+CDj-l}ZBYKg~8P65l3nHDmh@tWR z{-}O^QT6O2-Qhik#t+WFKd$`~S^v?eePsW79?#DjSu#s@CcKhm53an9e3 z6_8%Gxqk7Sdoo}$o3XvXS%U|l=MrI z_siEetX72h^RfOL8t=Qw?<=PdU4|L^Zi8pMw|dCgllK_WGbhg#>Am)XdXQ**Tn}7m ziR{fPa#xq$>CTA8d(7ug`~7pGnwwtXcm0K-@c|=x-E^g?=r@CdtAL^Le!EfqhpQs3 zH4)<8ta{AQ_|{rnzdz3U=xgme?^)yhj3fE=t#EGK8^4LE06p*X&G_@6?|RtJ?{B}e z>##ZRwL4v}9Z;`5>dx9t@`YrTG~8b08~O5HWOqsA+bfYDE1F@L3Yfes^4k|u|0MG3 f#{a6=-LWS?X**!(W>_xWDLdO;>Z{7WzastsC(D#5 literal 0 HcmV?d00001 diff --git a/testdata/algo/polygon_neighborhood_au5.gds b/testdata/algo/polygon_neighborhood_au5.gds new file mode 100644 index 0000000000000000000000000000000000000000..1bae54dcee5cf677f1ee358d808b95c643e5d710 GIT binary patch literal 1772 zcmbVMJ!n%=6#nvFdK0lV6{D>fs6_`+(ISFBh_qUvqF{y$#i@fs2M0$7M+e;;1($3( zI68FfQn8>=2cd&V5Qi!vL5c(^9`AQgPVxkA()2CgHhx3KYqUBex8GhSzE9nW2@0;M{0y%&1s>LiEenR~TQuE=Utp8JxH{8 zoDZC8h-}U&a#v^G=+1~1_n57pcIT&}TANg z@6L-fmPLr0bLufei#L|z{H<~JM_=pQSO2h5tQIC^nMgI6JxxrtTv_e0Y$fvg=KkkZr zekJnl;b1Ia#)ljtQPg(|3KvTQR4P$sq3iy&RBzK$bTB$ Lot>-Tx1Gmdb%w~C literal 0 HcmV?d00001 diff --git a/testdata/ruby/dbPolygonNeighborhood.rb b/testdata/ruby/dbPolygonNeighborhood.rb new file mode 100644 index 000000000..a5755d4cc --- /dev/null +++ b/testdata/ruby/dbPolygonNeighborhood.rb @@ -0,0 +1,142 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2025 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 + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class MyVisitor < RBA::PolygonNeighborhoodVisitor + + def initialize + @log = {} + @current_log = nil + end + + def log + @log.keys.sort { |a,b| a < b ? -1 : (a == b ? 0 : 1) }.collect { |k| @log[k].join("") }.join("") + end + + def neighbors(layout, cell, polygon, neighborhood) + polygon = polygon.dup + output(polygon) + @log[polygon] ||= [] + @current_log = @log[polygon] + @current_log << "Polygon: #{polygon}\n" + neighborhood.each do |inp, poly| + poly_str = poly.collect { |p| p.to_s }.join("/") + @current_log << " #{inp}: #{poly_str}\n" + end + end + +end + +class MyVisitor2 < RBA::PolygonNeighborhoodVisitor + + def initialize + self.result_type = RBA::CompoundRegionOperationNode::ResultType::Edges + end + + def neighbors(layout, cell, polygon, neighborhood) + neighborhood.each do |inp, poly| + poly.each do |p| + e = RBA::Edge::new(polygon.bbox.center, p.bbox.center) + output(e) + end + end + end + +end + +class DBPolygonNeighborhood_TestClass < TestBase + + # basic events + def test_1 + + ly = RBA::Layout::new + + l1 = ly.layer(1, 0) + cell = ly.create_cell("TOP") + + pid1 = RBA::Layout::properties_id({ 1 => "one" }) + + cell.shapes(l1).insert(RBA::Box::new(0, 0, 1000, 1000), pid1) + cell.shapes(l1).insert(RBA::Box::new(-1100, 0, -100, 1000)) + + prim = RBA::Region::new(cell.begin_shapes_rec(l1)) + prim.enable_properties + + visitor = MyVisitor::new + + visitor.result_type = RBA::CompoundRegionOperationNode::ResultType::Region + assert_equal(visitor.result_type, RBA::CompoundRegionOperationNode::ResultType::Region) + + dist = 101 + + children = [ + RBA::CompoundRegionOperationNode::new_foreign + ] + + node = RBA::CompoundRegionOperationNode::new_polygon_neighborhood(children, visitor, dist) + res = prim.complex_op(node) + + assert_equal(visitor.log, + "Polygon: (-1100,0;-1100,1000;-100,1000;-100,0) props={}\n" + + " 0: (0,0;0,1000;1000,1000;1000,0) props={1=>one}\n" + + "Polygon: (0,0;0,1000;1000,1000;1000,0) props={1=>one}\n" + + " 0: (-1100,0;-1100,1000;-100,1000;-100,0) props={}\n" + ) + + assert_equal(res.to_s, "(-1100,0;-1100,1000;-100,1000;-100,0);(0,0;0,1000;1000,1000;1000,0){1=>one}") + + end + + # edge pair output, to_original_trans + def test_2 + + ly = RBA::Layout::new + + l1 = ly.layer(1, 0) + cell = ly.create_cell("TOP") + + cell.shapes(l1).insert(RBA::Box::new(0, 0, 1000, 1000)) + cell.shapes(l1).insert(RBA::Box::new(-1100, 0, -100, 1000)) + + prim = RBA::Region::new(cell.begin_shapes_rec(l1)) + + visitor = MyVisitor2::new + + dist = 101 + + children = [ + RBA::CompoundRegionOperationNode::new_foreign + ] + + node = RBA::CompoundRegionOperationNode::new_polygon_neighborhood(children, visitor, dist) + res = prim.complex_op(node) + + assert_equal(res.to_s, "(-600,500;500,500);(500,500;-600,500)") + + end + +end + +load("test_epilogue.rb") +