From ffafebcaae3a03db371255092f49b705ebe937e7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 2 Aug 2025 16:12:49 +0200 Subject: [PATCH] Adding 'merge_props' and 'merged_props' to DRC --- src/db/db/dbRegionDelegate.cc | 2 +- src/db/db/gsiDeclDbRegion.cc | 40 +++++++--------- src/db/unit_tests/dbDeepRegionTests.cc | 2 + src/drc/drc/built-in-macros/_drc_layer.rb | 56 ++++++++++++++++++++-- src/drc/unit_tests/drcSimpleTests.cc | 10 ++++ testdata/drc/drcSimpleTests_141.drc | 24 ++++++++++ testdata/drc/drcSimpleTests_141.gds | Bin 0 -> 1074 bytes testdata/drc/drcSimpleTests_au141.gds | Bin 0 -> 2532 bytes testdata/drc/drcSimpleTests_au141d.gds | Bin 0 -> 2322 bytes testdata/ruby/dbRegionTest.rb | 8 ++-- 10 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_141.drc create mode 100644 testdata/drc/drcSimpleTests_141.gds create mode 100644 testdata/drc/drcSimpleTests_au141.gds create mode 100644 testdata/drc/drcSimpleTests_au141d.gds diff --git a/src/db/db/dbRegionDelegate.cc b/src/db/db/dbRegionDelegate.cc index 3f8997967..2ce4e640d 100644 --- a/src/db/db/dbRegionDelegate.cc +++ b/src/db/db/dbRegionDelegate.cc @@ -33,7 +33,7 @@ RegionDelegate::RegionDelegate () m_base_verbosity = 30; m_report_progress = false; m_merged_semantics = true; - m_join_properties_on_merge = true; + m_join_properties_on_merge = false; m_strict_handling = false; m_merge_min_coherence = false; } diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index b2fcb38d4..1bd93d5d0 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1059,9 +1059,9 @@ static void break_polygons (db::Region *r, size_t max_vertex_count, double max_a r->process (db::PolygonBreaker (max_vertex_count, max_area_ratio)); } -static db::Region &merge_ext1 (db::Region *r, int min_wc, bool jpm) +static db::Region &merge_ext1 (db::Region *r, int min_wc) { - r->merge (false, std::max (0, min_wc - 1), jpm); + r->merge (false, std::max (0, min_wc - 1)); return *r; } @@ -1071,9 +1071,9 @@ static db::Region &merge_ext2 (db::Region *r, bool min_coherence, int min_wc, bo return *r; } -static db::Region merged_ext1 (db::Region *r, int min_wc, bool jpm) +static db::Region merged_ext1 (db::Region *r, int min_wc) { - return r->merged (false, std::max (0, min_wc - 1), jpm); + return r->merged (false, std::max (0, min_wc - 1)); } static db::Region merged_ext2 (db::Region *r, bool min_coherence, int min_wc, bool jpm) @@ -1747,14 +1747,13 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", method ("join_properties_on_merge=", &db::Region::set_join_properties_on_merge, gsi::arg ("f"), "@brief Sets a flag indication whether to join properties on merge\n" "\n" - "When this flag is set to true (the default), properties are joined on 'merge'.\n" + "When this flag is set to true, properties are joined on 'merge'.\n" "That is: shapes merging into bigger shapes will have their properties joined.\n" - "With the flag set to false, 'merge' will not join properties and return merged\n" + "With the flag set to false (the default), 'merge' will not join properties and return merged\n" "shapes only if the sub-shapes have the same properties - i.e. properties form\n" "different classes on merge.\n" "\n" - "This attribute has been introduced in version 0.30.3. The default has changed from 'don't join properties' to " - "'join properties' in that version." + "This attribute has been introduced in version 0.30.3." ) + method ("join_properties_on_merge?", &db::Region::join_properties_on_merge, "@brief Gets a flag indication whether to join properties on merge\n" @@ -2398,13 +2397,13 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "@return The region after it has been merged (self).\n" "\n" "Merging removes overlaps and joins touching polygons.\n" - "If the region is already merged, this method does nothing\n" + "If the region is already merged, this method does nothing.\n" + "This method will behave according to the settings of the \\min_coherence and \\join_properties_on_merge attributes." ) + - method_ext ("merge", &merge_ext1, gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", true), + method_ext ("merge", &merge_ext1, gsi::arg ("min_wc"), "@brief Merge the region with options\n" "\n" "@param min_wc Overlap selection\n" - "@param join_properties_on_merge See below\n" "@return The region after it has been merged (self).\n" "\n" "Merging removes overlaps and joins touching polygons.\n" @@ -2412,16 +2411,9 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons overlap. The value specifies the number of polygons that need to overlap. A value of 2 " "means that output is only produced if two or more polygons overlap.\n" "\n" - "The 'join_properties_on_merge' argument indicates how properties should be handled: if true, " - "the properties of the constituents are joined and attached to the merged shape. If false, " - "only shapes with the same properties are merged - i.e. different properties form shape classes " - "that are merged individually.\n" - "\n" - "This method is equivalent to \"merge(false, min_wc, join_properties_on_merge).\n" - "\n" - "'join_properties_on_merge' has been added in version 0.30.3." + "This method is equivalent to \"merge(false, min_wc, false).\n" ) + - method_ext ("merge", &merge_ext2, gsi::arg ("min_coherence"), gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", true), + method_ext ("merge", &merge_ext2, gsi::arg ("min_coherence"), gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", false), "@brief Merge the region with options\n" "\n" "@param min_coherence A flag indicating whether the resulting polygons shall have minimum coherence\n" @@ -2449,24 +2441,24 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merging removes overlaps and joins touching polygons.\n" "If the region is already merged, this method does nothing.\n" + "This method will behave according to the settings of the \\min_coherence and \\join_properties_on_merge attributes.\n" "In contrast to \\merge, this method does not modify the region but returns a merged copy.\n" ) + - method_ext ("merged", &merged_ext1, gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", true), + method_ext ("merged", &merged_ext1, gsi::arg ("min_wc"), "@brief Returns the merged region (with options)\n" "\n" "@param min_wc Overlap selection\n" - "@param join_properties_on_merge See below\n" "@return The region after it has been merged.\n" "\n" "This version provides one additional options: \"min_wc\" controls whether output is only produced if multiple " "polygons overlap. The value specifies the number of polygons that need to overlap. A value of 2 " "means that output is only produced if two or more polygons overlap.\n" "\n" - "This method is equivalent to \"merged(false, min_wc, join_properties_on_merge)\".\n" + "This method is equivalent to \"merged(false, min_wc, false)\".\n" "\n" "In contrast to \\merge, this method does not modify the region but returns a merged copy.\n" ) + - method_ext ("merged", &merged_ext2, gsi::arg ("min_coherence"), gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", true), + method_ext ("merged", &merged_ext2, gsi::arg ("min_coherence"), gsi::arg ("min_wc"), gsi::arg ("join_properties_on_merge", false), "@brief Returns the merged region (with options)\n" "\n" "@param min_coherence A flag indicating whether the resulting polygons shall have minimum coherence\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index fd714701f..a5ecd88b7 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -2151,6 +2151,8 @@ TEST(40_BoolWithProperties) db::RecursiveShapeIterator si1 (ly, top_cell, l1); si1.apply_property_translator (db::PropertiesTranslator::make_pass_all ()); db::Region r1 (si1, dss); + EXPECT_EQ (r1.join_properties_on_merge (), false); + r1.set_join_properties_on_merge (true); EXPECT_EQ (r1.join_properties_on_merge (), true); r1.set_join_properties_on_merge (false); EXPECT_EQ (r1.join_properties_on_merge (), false); diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index bda81aac9..ee8a7ad42 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -5103,18 +5103,66 @@ CODE # Like \merged, but modifies the input and returns a reference to the # new layer. - def merged(*args) + def merged(overlap_count = 1) @engine._context("merged") do requires_edges_or_region - aa = args.collect { |a| @engine._prep_value(a) } + aa = [ @engine._prep_value(overlap_count) ] DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :merged, *aa)) end end - def merge(*args) + def merge(overlap_count = 1) @engine._context("merge") do requires_edges_or_region - aa = args.collect { |a| @engine._prep_value(a) } + aa = [ @engine._prep_value(overlap_count) ] + if @engine.is_tiled? + # in tiled mode, no modifying versions are available + self.data = @engine._tcmd(self.data, 0, self.data.class, :merged, *aa) + else + @engine._tcmd(self.data, 0, self.data.class, :merge, *aa) + end + self + end + end + + # %DRC% + # @name merged_props + # @brief Merges and joins properties of the shapes + # @synopsis layer.merged_props([overlap_count]) + # + # Returns the merged input. Unlike the plain \merged method, this version + # will join properties on merged shapes. Properties with the same name + # will be merged by computing the maximum value of the parts. + # + # For example: + # Properties @tt { "A" => 17, "C" => 2.5 } @/tt merged with @tt { "A" => 1, "B" => "a text" } @/tt will give + # @tt { "A" => 17, "B" => "a text", "C" => 2.5 } @/tt. + # + # The plain \merged method will treat shapes with different properties as + # separate entities and will not merge them. + # + # Currently, this method is available for polygon layers only. + + # %DRC% + # @name merge_props + # @brief Merges the layer and joins the properties (modifies the layer) + # @synopsis layer.merge_props([overlap_count]) + # + # Like \merged_props, but modifies the input and returns a reference to the + # new layer. + + def merged_props(overlap_count = 1) + @engine._context("merged") do + requires_region + aa = [ self.data.min_coherence, @engine._prep_value(overlap_count), true ] + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :merged, *aa)) + end + end + + def merge_props(overlap_count = 1) + @engine._context("merge") do + requires_region + aa = [ self.data.min_coherence, @engine._prep_value(overlap_count), true ] if @engine.is_tiled? # in tiled mode, no modifying versions are available self.data = @engine._tcmd(self.data, 0, self.data.class, :merged, *aa) diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index c0850edb1..e5c740e76 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -2003,3 +2003,13 @@ TEST(140d_target_modification) { run_test (_this, "140", true); } + +TEST(141_merge_properties) +{ + run_test (_this, "141", false); +} + +TEST(141d_merge_properties) +{ + run_test (_this, "141", true); +} diff --git a/testdata/drc/drcSimpleTests_141.drc b/testdata/drc/drcSimpleTests_141.drc new file mode 100644 index 000000000..89ed7d0f0 --- /dev/null +++ b/testdata/drc/drcSimpleTests_141.drc @@ -0,0 +1,24 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0, enable_props) + +l1.output(1, 0) + +l1.merged_props.output(10, 0) + +l1d = l1.dup +l1d.merge_props +l1d.output(11, 0) + +l1.merged_props(2).output(20, 0) + +l1d = l1.dup +l1d.merge_props(2) +l1d.output(21, 0) + diff --git a/testdata/drc/drcSimpleTests_141.gds b/testdata/drc/drcSimpleTests_141.gds new file mode 100644 index 0000000000000000000000000000000000000000..d17af6401073991e42e0df2b372b78d8bd3ed720 GIT binary patch literal 1074 zcmb7DJxc>Y6r9_=dpR^p{HWv#5j%sTC{Ykef{iF>kwQX#fQ3K8R$ZZ8}6E*I2=&1`n}&6}O~4g#gl5qYZgfe;E6Xsozvgi211n!utC4jR|B zdS zOZY8kV?1ZeF;zB-kR^|| z%2Cj46O-X^0D7Aa`D19*6>zZLW@I?j73I}gi7Xn9DWjY{RW|i}WAsfN3AQ-^VxPC2u4E literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au141.gds b/testdata/drc/drcSimpleTests_au141.gds new file mode 100644 index 0000000000000000000000000000000000000000..20af5373edfc07e460398957f93671223f227b92 GIT binary patch literal 2532 zcmd^=y)Hyi5Xa}9d-v@63<;f5=lTpmBCD7LeOLc${`RiaRO z0EL2X3x&${pL1q*@5b(0Y(%2C`Q4pkKJJm^-2ib0kg1o0G;XQ_*FgVBW6Ffp^f01+0*_q-G zHqTQ*{rAWNMhozHNUoN3l-RDZB(p7062hsXt*OZYCOh*;64kI8g7a9$<+ zoL&48r%|3*`@{Xt`f{34 zqBWwWwqo%-&@mp6b?xdBsvYE5pWc{PA$zGRRb5QAOEgSBR8rr|ZrKP$)t=an@i%IbXN;m$|S;$Le-?<{9 literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSimpleTests_au141d.gds b/testdata/drc/drcSimpleTests_au141d.gds new file mode 100644 index 0000000000000000000000000000000000000000..76f8373dbbf1745affe4a3bb98256a5865c75ff7 GIT binary patch literal 2322 zcmd^=Jx|+E6oy}4I~R+jRrp#ek8HIHty%>ngaXQfh*SoK3T5cnp+kQFLsz5@3~Xg! zKq>JJeG0_}=65o{xK+KthNQNCGi(ix>h` zl#%A|5ewN|Sq3J<(&ExqZT0j=d%kfzv-f>t9Z6}hpOkV5h+;rK69^!m3job($nOOp zs2hsUyx#^q>3}`1ErWey_q2ZWkH&iSQ>TwLqp#yo&(ZCZ@}+e}gRAwK?RY&6qm34rm8fMwu1;yJ% z8s&Z-KzK+G_P;=#i}#Q(0zOqqO3NEI`CL@`zGXk79uCrAAN19wA-=MpIy==(tud-= zWv?sxG|%Y$ZP00F*?onXv<&4ZKHH|drP~i%xznEOcMcr4{G94jRdt3Zrp{=WhcL~L zrQ0Wa=I9T#3KL@0M(rDPuFhT69Mla}Myh7dIohtccHDK(_3u%M?&^6@YKaEdmf@w* z_hhfLkEZ8};um$l`Ywct=u#KXN|H&%one}") rr = r.dup - rr.join_properties_on_merge = false - assert_equal(rr.join_properties_on_merge, false) + rr.join_properties_on_merge = true + assert_equal(rr.join_properties_on_merge, true) s = rr.each_merged.collect(&:to_s).join(";") - assert_equal(s, "(10,20;10,220;110,220;110,20) props={};(0,0;0,200;100,200;100,0) props={1=>one}") - s = r.each_merged.collect(&:to_s).join(";") assert_equal(s, "(0,0;0,200;10,200;10,220;110,220;110,20;100,20;100,0) props={1=>one}") + s = r.each_merged.collect(&:to_s).join(";") + assert_equal(s, "(10,20;10,220;110,220;110,20) props={};(0,0;0,200;100,200;100,0) props={1=>one}") r = RBA::Region::new r.insert(RBA::BoxWithProperties::new(RBA::Box::new(0, 0, 100, 200), { 1 => "one" }))