From ddf36290fa62bd4fbd62ba4b9f0551b163a68663 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 9 Jan 2021 23:10:17 +0100 Subject: [PATCH] Corner detection feature: tests, bug fixes, enhancements (inclusive/exclusive angle constraints) --- src/db/db/dbRegionProcessors.cc | 18 ++++--- src/db/db/dbRegionProcessors.h | 11 +++-- src/db/db/gsiDeclDbCompoundOperation.cc | 12 ++--- src/db/db/gsiDeclDbRegion.cc | 21 +++++---- src/db/unit_tests/dbCompoundOperationTests.cc | 4 +- src/db/unit_tests/dbDeepRegionTests.cc | 10 ++-- src/db/unit_tests/dbRegionTests.cc | 14 ++++-- .../drc/built-in-macros/_drc_complex_ops.rb | 47 +++++++++++-------- .../built-in-macros/_drc_cop_integration.rb | 11 ++++- src/drc/unit_tests/drcGenericTests.cc | 10 ++++ testdata/ruby/dbRegionTest.rb | 16 +++---- 11 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/db/db/dbRegionProcessors.cc b/src/db/db/dbRegionProcessors.cc index 4fba2731a..c2cf6c8a7 100644 --- a/src/db/db/dbRegionProcessors.cc +++ b/src/db/db/dbRegionProcessors.cc @@ -30,11 +30,14 @@ namespace db // ----------------------------------------------------------------------------------- // CornerDetectorCore implementation -CornerDetectorCore::CornerDetectorCore (double angle_start, double angle_end) +CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end) { m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ()); m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ()); + m_include_start = include_angle_start; + m_include_end = include_angle_end; + m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0; m_all = (angle_end - angle_start - db::epsilon) > 360.0; } @@ -64,15 +67,18 @@ void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPo db::DVector v1 = m_t_start * vin; db::DVector v2 = m_t_end * vin; - bool vp1 = db::vprod_sign (v1, vout) >= 0; - bool vp2 = db::vprod_sign (v2, vout) <= 0; + int vps1 = db::vprod_sign (v1, vout); + int vps2 = db::vprod_sign (v2, vout); + bool opp1 = vps1 == 0 && (db::sprod_sign (v1, vout) < 0); + bool opp2 = vps2 == 0 && (db::sprod_sign (v2, vout) < 0); + + bool vp1 = !opp1 && (m_include_start ? (db::vprod_sign (v1, vout) >= 0) : (db::vprod_sign (v1, vout) > 0)); + bool vp2 = !opp2 && (m_include_end ? (db::vprod_sign (v2, vout) <= 0) : (db::vprod_sign (v2, vout) < 0)); if (m_big_angle && (vp1 || vp2)) { delivery.make_point (pt); } else if (! m_big_angle && vp1 && vp2) { - if (db::sprod_sign (v1, vout) > 0 && db::sprod_sign (v2, vout) > 0) { - delivery.make_point (pt); - } + delivery.make_point (pt); } } diff --git a/src/db/db/dbRegionProcessors.h b/src/db/db/dbRegionProcessors.h index 6a0c8b99c..4f9a4f206 100644 --- a/src/db/db/dbRegionProcessors.h +++ b/src/db/db/dbRegionProcessors.h @@ -91,13 +91,14 @@ private: class DB_PUBLIC CornerDetectorCore { public: - CornerDetectorCore (double angle_start, double angle_end); + CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end); virtual ~CornerDetectorCore () { } void detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const; private: db::CplxTrans m_t_start, m_t_end; + bool m_include_start, m_include_end; bool m_big_angle, m_all; }; @@ -108,8 +109,8 @@ class DB_PUBLIC CornersAsRectangles : public db::PolygonProcessorBase, private CornerDetectorCore { public: - CornersAsRectangles (double angle_start, double angle_end, db::Coord dim = 1) - : CornerDetectorCore (angle_start, angle_end), m_dim (dim) + CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1) + : CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end), m_dim (dim) { // .. nothing yet .. } @@ -137,8 +138,8 @@ class DB_PUBLIC CornersAsDots : public db::PolygonToEdgeProcessorBase, private CornerDetectorCore { public: - CornersAsDots (double angle_start, double angle_end) - : CornerDetectorCore (angle_start, angle_end) + CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end) + : CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end) { // .. nothing yet .. } diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 8248259d4..9ade51e65 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -214,16 +214,16 @@ static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOper return new db::CompoundRegionCountFilterNode (input, invert, min_count, max_count); } -static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1) +static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1) { check_non_null (input, "input"); - return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/); + return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/); } -static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, double angle_end) +static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end) { check_non_null (input, "input"); - return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, angle_end), input, true /*processor is owned*/); + return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/); } static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e) @@ -584,10 +584,10 @@ Class decl_CompoundRegionOperationNode ("db", " gsi::constructor ("new_count_filter", &new_count_filter, gsi::arg ("inputs"), gsi::arg ("invert", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits::max ()), "@brief Creates a node selecting results but their shape count.\n" ) + - gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), gsi::arg ("dim"), + gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"), "@brief Creates a node turning corners into rectangles.\n" ) + - gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), + gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), "@brief Creates a node turning corners into dots (single-point edges).\n" ) + gsi::constructor ("new_extents", &new_extents, gsi::arg ("input"), gsi::arg ("e", 0), diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index f74fdda5a..5b23694a2 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -112,14 +112,14 @@ static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss return new db::Region (r->texts_as_boxes (pat, pattern, enl, dss)); } -static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end) +static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end) { - return r->processed (db::CornersAsDots (angle_start, angle_end)); + return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end)); } -static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim) +static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end) { - return r->processed (db::CornersAsRectangles (angle_start, angle_end, dim)); + return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim)); } static db::Region *new_si (const db::RecursiveShapeIterator &si) @@ -1121,11 +1121,14 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "@hide\n" "This method is provided for DRC implementation.\n" ) + - method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("dim", 1), + method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), "@brief This method will select all corners whose attached edges satisfy the angle condition.\n" "\n" "The angle values specify a range of angles: all corners whose attached edges form an angle " - "between angle_start and angle_end will be reported boxes with 2*dim x 2*dim dimension. The default dimension is 2x2 DBU.\n" + "between angle_min and angle_max will be reported boxes with 2*dim x 2*dim dimension. The default dimension is 2x2 DBU.\n" + "\n" + "If 'include_angle_min' is true, the angle condition is >= min. angle, otherwise it is > min. angle. " + "Same for 'include_angle_,ax' and the max. angle.\n" "\n" "The angle is measured " "between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left " @@ -1134,14 +1137,14 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "A similar function that reports corners as point-like edges is \\corners_dots.\n" "\n" - "This function has been introduced in version 0.25.\n" + "This function has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n" ) + - method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), + method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), "@brief This method will select all corners whose attached edges satisfy the angle condition.\n" "\n" "This method is similar to \\corners, but delivers an \\Edges collection with dot-like edges for each corner.\n" "\n" - "This function has been introduced in version 0.25.\n" + "This function has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n" ) + method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge, "@brief Merge the region\n" diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc index c37786e1c..dde3ea383 100644 --- a/src/db/unit_tests/dbCompoundOperationTests.cc +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -835,10 +835,10 @@ void run_test15 (tl::TestBase *_this, bool deep) db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode (); - db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, 180.0, 1), primary, true /*processor is owned*/); + db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, 1), primary, true /*processor is owned*/); db::CompoundRegionCountFilterNode count1 (corners1, false, 5, 10000); - db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, 180.0), primary, true /*processor is owned*/); + db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true), primary, true /*processor is owned*/); db::CompoundRegionCountFilterNode count2 (corners2, true, 5, 10000); EXPECT_EQ (count1.result_type () == db::CompoundRegionJoinOperationNode::Region, true); diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index c4fee897e..9a4a90708 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1220,13 +1220,13 @@ TEST(21_Processors) target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, 180.0))); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, 180.0))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true))); db::Region ext; - r1.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 1000, 1000, 2000, 2000); + r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 1000, 1000, 2000, 2000); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, 180.0, 2000))); - target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, 180.0, 2000))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000))); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor (0, 0))); target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor (1000, 2000))); diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 24addb47d..4df6ad260 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -1979,13 +1979,17 @@ TEST(100_Processors) r.insert (db::Box (db::Point (0, 300), db::Point (200, 400))); r.insert (db::Box (db::Point (100, 300), db::Point (200, 500))); - EXPECT_EQ (r.processed (db::CornersAsDots (-180.0, 180.0)).to_string (), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"); - EXPECT_EQ (r.processed (db::CornersAsDots (0.0, 180.0)).to_string (), "(100,400;100,400)"); + EXPECT_EQ (r.processed (db::CornersAsDots (-180.0, true, 180.0, true)).to_string (), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"); + EXPECT_EQ (r.processed (db::CornersAsDots (0.0, true, 180.0, true)).to_string (), "(100,400;100,400)"); + EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, true, 90.0, true)).to_string (), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"); + EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, true)).to_string (), "(100,400;100,400)"); + EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, true, 90.0, false)).to_string (), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,500;100,500);(200,500;200,500)"); + EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false)).to_string (), ""); db::Region ext; - r.processed (db::CornersAsDots (0.0, 180.0)).extended (ext, 10, 10, 20, 20); + r.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 10, 10, 20, 20); EXPECT_EQ (ext.to_string (), "(90,380;90,420;110,420;110,380)"); - EXPECT_EQ (r.processed (db::CornersAsRectangles (-180.0, 180.0, 2)).to_string (), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"); - EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, 180.0, 2)).to_string (), "(98,398;98,402;102,402;102,398)"); + EXPECT_EQ (r.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2)).to_string (), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"); + EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2)).to_string (), "(98,398;98,402;102,402;102,398)"); EXPECT_EQ (r.processed (db::extents_processor (0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)"); EXPECT_EQ (r.processed (db::extents_processor (10, 20)).to_string (), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)"); diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 655bcbbba..6c02a7a13 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -455,7 +455,7 @@ CODE else raise("Invalid argument (#{as_dots.inspect}) for 'corners' method") end - DRCOpNodeCornersFilter::new(@engine, self, as_dots) + DRCOpNodeCornersFilter::new(@engine, as_dots, self) end end @@ -536,12 +536,12 @@ CODE end if as_edges - return DRCOpNodeRelativeExtents::new(self, true, *f) + return DRCOpNodeRelativeExtents::new(@engine, true, self, *f) else # add oversize for point- and edge-like regions zero_area = (f[0] - f[2]).abs < 1e-7 || (f[1] - f[3]).abs < 1e-7 f += [ zero_area ? 1 : 0 ] * 2 - return DRCOpNodeRelativeExtents::new(self, false, *f) + return DRCOpNodeRelativeExtents::new(@engine, false, self, *f) end end @@ -1207,7 +1207,7 @@ class DRCOpNodeCountFilter < DRCOpNodeWithCompare args = [ self.input.create_node(cache), self.inverse ] args << (self.gt ? @engine._make_numeric_value(self.gt) + 1 : (self.ge ? @engine._make_numeric_value(self.ge) : 0)) if self.lt || self.le - args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) - 1) + args << (self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) + 1) end RBA::CompoundRegionOperationNode::new_count_filter(*args) end @@ -1240,7 +1240,7 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare args = [ self.input.create_node(cache), self.inverse ] args << (self.gt ? @engine._make_area_value(self.gt) + 1 : (self.ge ? @engine._make_area_value(self.ge) : 0)) if self.lt || self.le - args << (self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) - 1) + args << (self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) + 1) end RBA::CompoundRegionOperationNode::new_area_filter(*args) end @@ -1281,7 +1281,7 @@ class DRCOpNodeEdgeLengthFilter < DRCOpNodeWithCompare args = [ n, self.inverse ] args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0)) if self.lt || self.le - args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1) + args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1) end RBA::CompoundRegionOperationNode::new_edge_length_filter(*args) @@ -1324,7 +1324,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare args = [ n, self.inverse ] angle_delta = 1e-6 args << (self.gt ? self.gt + angle_delta : (self.ge ? self.ge : -180.0)) - args << (self.lt ? self.lt : (self.le ? self.le - angle_delta : 180.0)) + args << (self.lt ? self.lt : (self.le ? self.le + angle_delta : 180.0)) RBA::CompoundRegionOperationNode::new_edge_orientation_filter(*args) @@ -1358,7 +1358,7 @@ class DRCOpNodePerimeterFilter < DRCOpNodeWithCompare args = [ self.input.create_node(cache), self.inverse ] args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0)) if self.lt || self.le - args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1) + args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1) end RBA::CompoundRegionOperationNode::new_perimeter_filter(*args) end @@ -1390,7 +1390,7 @@ class DRCOpNodeInteractingWithCount < DRCOpNodeWithCompare args = [ self.a.create_node(cache), self.b.create_node(cache), self.inverse ] args << (self.gt ? self.gt + 1 : (self.ge ? self.ge : 0)) if self.lt || self.le - args << (self.lt ? self.lt : self.le - 1) + args << (self.lt ? self.lt : self.le + 1) end factory = { :covering => :new_enclosing, :overlapping => :new_overlapping, @@ -1549,7 +1549,7 @@ class DRCOpNodeBBoxParameterFilter < DRCOpNodeWithCompare args = [ self.input.create_node(cache), self.inverse ] args << (self.gt ? @engine._make_value(self.gt) + 1 : (self.ge ? @engine._make_value(self.ge) : 0)) if self.lt || self.le - args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) - 1) + args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1) end RBA::CompoundRegionOperationNode::new_perimeter_filter(*args) end @@ -1565,8 +1565,7 @@ end class DRCOpNodeCornersFilter < DRCOpNodeWithCompare attr_accessor :input - attr_accessor :parameter - attr_accessor :inverse + attr_accessor :as_dots def initialize(engine, as_dots, input) super(engine) @@ -1577,14 +1576,15 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare def do_create_node(cache) args = [ self.input.create_node(cache) ] - angle_delta = 1e-6 - args << (self.gt ? self.gt + angle_delta : (self.ge ? self.ge : -180.0)) - args << (self.lt ? self.lt : (self.le ? self.le - angle_delta : 180.0)) + args << (self.gt ? self.gt : (self.ge ? self.ge : -180.0)) + args << (self.gt ? false : true) + args << (self.lt ? self.lt : (self.le ? self.le : 180.0)) + args << (self.lt ? false : true) if self.as_dots - RBA::CompoundRegionOperationNode::new_corners_as_dots_node(*args) + RBA::CompoundRegionOperationNode::new_corners_as_dots(*args) else args << 2 # dimension is 2x2 DBU - RBA::CompoundRegionOperationNode::new_corners_as_rectangles_node(*args) + RBA::CompoundRegionOperationNode::new_corners_as_rectangles(*args) end end @@ -1595,11 +1595,17 @@ class DRCOpNodeRelativeExtents < DRCOpNode attr_accessor :input attr_accessor :as_edges, :fx1, :fx2, :fy1, :fy2, :dx, :dy - def initialize(engine, input, as_edges, fx1, fx2, fy1, fy2, dx = 0, dy = 0) + def initialize(engine, as_edges, input, fx1, fx2, fy1, fy2, dx = 0, dy = 0) super(engine) self.input = input self.as_edges = as_edges self.description = "extents" + self.fx1 = fx1 + self.fx2 = fx2 + self.fy1 = fy1 + self.fy2 = fy2 + self.dx = dx + self.dy = dy end def dump(indent) @@ -1611,10 +1617,11 @@ class DRCOpNodeRelativeExtents < DRCOpNode end def do_create_node(cache) + node = self.input.create_node(cache) if !self.as_edges - RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(self.input, self.fx1, self.fx2, self.fy1, self.fy2, self.dx, self.dy) + RBA::CompoundRegionOperationNode::new_relative_extents(node, self.fx1, self.fx2, self.fy1, self.fy2, self.dx, self.dy) else - RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(self.input, self.fx1, self.fx2, self.fy1, self.fy2) + RBA::CompoundRegionOperationNode::new_relative_extents_as_edges(node, self.fx1, self.fx2, self.fy1, self.fy2) end end diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb index a039a3f62..949e04e57 100644 --- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb +++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb @@ -429,13 +429,20 @@ CODE # %DRC% # @name corners # @brief Selects all polygons which are rectilinear - # @synopsis corners (in condition) - # @synopsis corners(layer) + # @synopsis corners([ options ]) (in condition) + # @synopsis corners(layer [, options ]) # # This function can be used with a layer argument in which case it # is equivalent to "layer.corners" (see \Layer#corners). Without a layer # argument, "corners" represents the corner generator/filter in primary shapes for # \DRC# expressions (see \Layer#drc and \DRC#corners for more details). + # + # Like the layer-based version, the "corners" operator accepts the + # output type option: "as_dots" for dot-like edges and "as_boxes" for + # small (2x2 DBU) box markers. + # + # The "corners" operator can be put into a condition which means it's + # applied to coners meeting a particular angle constraint. def _cop_corners(as_dots = DRCAsDots::new(false)) # NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here. diff --git a/src/drc/unit_tests/drcGenericTests.cc b/src/drc/unit_tests/drcGenericTests.cc index a0314f298..a6af5916c 100644 --- a/src/drc/unit_tests/drcGenericTests.cc +++ b/src/drc/unit_tests/drcGenericTests.cc @@ -118,3 +118,13 @@ TEST(5d) { run_test (_this, "5", true); } + +TEST(6) +{ + run_test (_this, "6", false); +} + +TEST(6d) +{ + run_test (_this, "6", true); +} diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index caca68b22..0400da263 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -470,13 +470,13 @@ class DBRegion_TestClass < TestBase assert_equal(r3a.separation_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "") assert_equal(r3a.separation_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(-10,10;-10,0)/(0,0;0,10)") - assert_equal(r3b.overlap_check(r1, 15).to_s, "(10,10;10,-10)/(0,0;0,21);(-10,10;10,10)/(21,0;0,0)") - assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)") - assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, nil, nil, nil).to_s, "(10,10;10,-10)/(0,0;0,200);(-10,10;10,10)/(100,0;0,0)") + assert_equal(r3b.overlap_check(r1, 15).to_s, "(-10,10;10,10)/(21,0;0,0);(10,10;10,-10)/(0,0;0,21)") + assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, nil, nil).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)") + assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, nil, nil, nil).to_s, "(-10,10;10,10)/(100,0;0,0);(10,10;10,-10)/(0,0;0,200)") assert_equal(r3b.overlap_check(r1, 15, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "") - assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 500).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)") + assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 500).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)") assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "") - assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(10,10;10,0)/(0,0;0,10);(0,10;10,10)/(10,0;0,0)") + assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)") assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)/(100,395;100,5)") assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(100,380;100,20)") @@ -497,9 +497,9 @@ class DBRegion_TestClass < TestBase assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)/(50,220;10,220)") assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, 40).to_s, "") - assert_equal((r1 | r2).merged.space_check(25).to_s, "(0,200;50,200)/(50,220;10,220);(100,395;100,5)/(120,20;120,380)") - assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)/(50,220;10,220);(100,380;100,20)/(120,20;120,380)") - assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)/(50,220;10,220);(100,400;100,0)/(120,20;120,380)") + assert_equal((r1 | r2).merged.space_check(25).to_s, "(100,395;100,5)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(100,380;100,20)/(120,20;120,380);(10,200;50,200)/(50,220;10,220)") + assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(100,400;100,0)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)") assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "") assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(100,400;100,0)/(120,20;120,380)") assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)/(50,220;10,220)")