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 000000000..6d21d6933 Binary files /dev/null and b/testdata/algo/polygon_neighborhood.gds differ diff --git a/testdata/algo/polygon_neighborhood_au1.gds b/testdata/algo/polygon_neighborhood_au1.gds new file mode 100644 index 000000000..93c4064ca Binary files /dev/null and b/testdata/algo/polygon_neighborhood_au1.gds differ diff --git a/testdata/algo/polygon_neighborhood_au2.gds b/testdata/algo/polygon_neighborhood_au2.gds new file mode 100644 index 000000000..e54627eb7 Binary files /dev/null and b/testdata/algo/polygon_neighborhood_au2.gds differ diff --git a/testdata/algo/polygon_neighborhood_au3.gds b/testdata/algo/polygon_neighborhood_au3.gds new file mode 100644 index 000000000..a08972c78 Binary files /dev/null and b/testdata/algo/polygon_neighborhood_au3.gds differ diff --git a/testdata/algo/polygon_neighborhood_au4.gds b/testdata/algo/polygon_neighborhood_au4.gds new file mode 100644 index 000000000..4bde7632b Binary files /dev/null and b/testdata/algo/polygon_neighborhood_au4.gds differ diff --git a/testdata/algo/polygon_neighborhood_au5.gds b/testdata/algo/polygon_neighborhood_au5.gds new file mode 100644 index 000000000..1bae54dce Binary files /dev/null and b/testdata/algo/polygon_neighborhood_au5.gds differ 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") +