From 153289b5d8296a9a0a0c52841c96f02e0a603b0f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 6 Dec 2020 16:33:10 +0100 Subject: [PATCH] WIP: rectangle error pattern filter implemented. --- src/db/db/dbPolygon.h | 8 +++ src/db/db/dbRegionLocalOperations.cc | 66 ++++++++++++++++++++++- src/db/db/dbRegionLocalOperations.h | 23 +++++--- src/db/db/gsiDeclDbRegion.cc | 5 +- src/db/unit_tests/dbRegionTests.cc | 80 +++++++++++++++++++++++++++- 5 files changed, 172 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 52af3b00e..c0ca15f90 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -3218,6 +3218,14 @@ public: return this->obj ().perimeter (); } + /** + * @brief Returns a value indicating whether the polygon is a box + */ + bool is_box () const + { + return this->obj ().is_box (); + } + /** * @brief Return the transformed object * diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index cc44a3d6c..584ef8da1 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -312,10 +312,72 @@ check_local_operation::compute_local (db::Layout *layout, const shape_in } - // implements filtering on rectangles + // implements error filtering on rectangles if (m_rect_filter != RectFilter::NoSideAllowed && ! result.empty ()) { - // @@@ TODO: implement @@@ + std::unordered_set waived; + + for (typename shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const TS &subject = interactions.subject_shape (i->first); + if (! subject.is_box ()) { + continue; + } + + unsigned int p = 1; + std::map edges_with_errors; + for (typename TS::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end (); ++e) { + edges_with_errors [*e] = p; + p <<= 1; + } + + unsigned int error_pattern = 0; + for (std::unordered_set::const_iterator ep = result.begin (); ep != result.end (); ++ep) { + std::map::iterator i = edges_with_errors.find (ep->first ()); + if (i != edges_with_errors.end ()) { + if ((error_pattern & i->second) == 0) { + error_pattern |= i->second; + } + } + } + + if (error_pattern != 0) { + + bool can_be_waived = false; + + // decode pattern: consider each group of 4 bits and match them against the error pattern in their four rotation variants + uint32_t p32 = (uint32_t) m_rect_filter; + while (p32 != 0 && ! can_be_waived) { + + uint32_t p4 = p32 & 0xf; + p32 >>= 4; + + for (unsigned int r = 0; r < 4 && ! can_be_waived; ++r) { + can_be_waived = (error_pattern == p4); + p4 = ((p4 << 1) & 0xf) | ((p4 & 0x8) >> 3); + } + + } + + if (can_be_waived) { + + for (std::unordered_set::const_iterator ep = result.begin (); ep != result.end (); ++ep) { + if (edges_with_errors.find (ep->first ()) != edges_with_errors.end ()) { + waived.insert (*ep); + } + } + + } + + } + + } + + if (! waived.empty ()) { + for (std::unordered_set::const_iterator i = waived.begin (); i != waived.end (); ++i) { + result.erase (*i); + } + } } } diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h index 9c23d6673..95cefa485 100644 --- a/src/db/db/dbRegionLocalOperations.h +++ b/src/db/db/dbRegionLocalOperations.h @@ -34,38 +34,49 @@ namespace db /** * @brief Specifies an error filter on rectangular shapes + * + * There are actually more combinations possible. The bit pattern of the enum value consists + * of groups of 4 bits each specifying an allowed pattern. Rotation is implicit, so it's just + * required to give on incarnation. + * + * For example: 0x1953 would be one- or two-sided. */ enum RectFilter { /** * @brief No filter */ - NoSideAllowed, + NoSideAllowed = 0, /** * @brief Allow errors on one side */ - OneSideAllowed, + OneSideAllowed = 0x1, /** * @brief Allow errors on two sides (not specified which) */ - TwoSidesAllowed, + TwoSidesAllowed = 0x953, /** * @brief Allow errors on two sides ("L" configuration) */ - TwoConnectedSidesAllowed, + TwoConnectedSidesAllowed = 0x3, /** * @brief Allow errors on two opposite sides */ - TwoOppositeSidesAllowed, + TwoOppositeSidesAllowed = 0x5, /** * @brief Allow errors on three sides */ - ThreeSidesAllowed + ThreeSidesAllowed = 0x7, + + /** + * @brief Allow errors when on all sides + */ + FourSidesAllowed = 0xf }; /** diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 1bbbcff0b..68e9ad177 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -2527,7 +2527,10 @@ gsi::EnumIn decl_Region_RectFilter ("db", "RectFilte "@brief Allow errors on two opposite sides" ) + gsi::enum_const ("ThreeSidesAllowed", db::RectFilter::ThreeSidesAllowed, - "@brief Allow errors on three sides" + "@brief Allow errors when on three sides" + ) + + gsi::enum_const ("FourSidesAllowed", db::RectFilter::FourSidesAllowed, + "@brief Allow errors when on all sides" ), "@brief This class represents the error filter mode on rectangles for \\Region#separation and related checks.\n" "\n" diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 561e2c32b..d6d15ed26 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -661,7 +661,6 @@ TEST(15h) { // opposite_filter with internal shielding - // shielding within opposite error detection db::Region r2; r2.insert (db::Box (db::Point (0, 0), db::Point (90, 100))); r2.insert (db::Box (db::Point (0, 200), db::Point (90, 300))); @@ -689,6 +688,85 @@ TEST(15h) "(200,100;200,0)/(210,0;210,100);(100,0;100,100)/(90,100;90,0)"); } +TEST(15i) +{ + // rectangle error filter + + db::Region r; + r.insert (db::Box (db::Point (-90, -90), db::Point (90, 90))); + + db::Region rl; + rl.insert (db::Box (db::Point (-200, -100), db::Point (-100, 100))); + + db::Region rr; + rr.insert (db::Box (db::Point (100, -100), db::Point (200, 100))); + + db::Region rb; + rb.insert (db::Box (db::Point (-100, -200), db::Point (100, -100))); + + db::Region rt; + rt.insert (db::Box (db::Point (-100, 100), db::Point (100, 200))); + + db::RegionCheckOptions options; + options.metrics = db::Projection; + options.rect_filter = db::OneSideAllowed; + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90);(90,90;90,-90)/(100,-90;100,90)"); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100);(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); + + options.rect_filter = db::TwoSidesAllowed; + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100)"); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); + + options.rect_filter = db::TwoOppositeSidesAllowed; + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100);(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100)"); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); + + options.rect_filter = db::TwoConnectedSidesAllowed; + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90);(90,90;90,-90)/(100,-90;100,90)"); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100)"); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); + + options.rect_filter = db::ThreeSidesAllowed; + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90);(90,90;90,-90)/(100,-90;100,90)"); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100);(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90)"); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), "(-90,90;90,90)/(90,100;-90,100)"); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), ""); + + options.rect_filter = db::RectFilter (0x9531); // one and two sides allowed + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); + + options.rect_filter = db::RectFilter (0x31); // one and two connected sides allowed + + EXPECT_EQ (r.separation_check (rl + rr, 40, options).to_string (), "(-90,-90;-90,90)/(-100,90;-100,-90);(90,90;90,-90)/(100,-90;100,90)"); + EXPECT_EQ (r.separation_check (rl + rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rr + rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rl, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt, 40, options).to_string (), ""); + EXPECT_EQ (r.separation_check (rt + rr + rb, 40, options).to_string (), "(90,-90;-90,-90)/(-90,-100;90,-100);(90,90;90,-90)/(100,-90;100,90);(-90,90;90,90)/(90,100;-90,100)"); +} + TEST(16) { db::Region a;