diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 63686cb65..d97e764ff 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1399,14 +1399,18 @@ AsIfFlatRegion::sized_inside (const Region &inside, bool outside, coord_type dx, throw tl::Exception (tl::to_string (tr ("'sized_inside' operation does not make sense with negative sizing"))); } + if (dx == 0 && dy == 0) { + steps = 1; + } + // NOTE: it does not provide benefits to merge the outside region, so just don't auto inside_polygons = outside ? inside.begin () : inside.begin_merged (); bool inside_polygons_is_merged = outside ? inside.is_merged () : true; auto polygons = begin_merged (); - std::unique_ptr res (new FlatRegion ()); - std::unique_ptr prev; + std::unique_ptr res (new FlatRegion ()); + std::unique_ptr prev; int steps_from = 0; @@ -1444,18 +1448,18 @@ AsIfFlatRegion::sized_inside (const Region &inside, bool outside, coord_type dx, others.push_back (inside_polygons); std::vector results; - results.push_back (&res->raw_polygons ()); + db::FlatRegion *res_flat = dynamic_cast (res.get ()); + tl_assert (res_flat != 0); + results.push_back (&res_flat->raw_polygons ()); proc.run_flat (prev.get () ? prev->begin () : polygons, others, std::vector (), &op, results); // NOTE: in the last step we apply a polygon breaker in addition to "merge" so the // result is granular for better deep mode performance if (steps > 0) { - prev.reset (dynamic_cast (res->merged ())); - tl_assert (prev.get () != 0); + prev.reset (res->merged ()); res.reset (new db::FlatRegion ()); } else { - res.reset (dynamic_cast (res->processed (db::PolygonBreaker (proc.max_vertex_count (), proc.area_ratio ())))); - tl_assert (res.get () != 0); + res.reset (res->processed (db::PolygonBreaker (proc.max_vertex_count (), proc.area_ratio ()))); } } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 15e2074ce..076e9f46b 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1803,9 +1803,13 @@ DeepRegion::sized_inside (const Region &inside, bool outside, coord_type dx, coo throw tl::Exception (tl::to_string (tr ("'sized_inside' operation does not make sense with negative sizing"))); } + if (dx == 0 && dy == 0) { + steps = 1; + } + const db::DeepRegion *inside_deep = dynamic_cast (inside.delegate ()); if (! inside_deep) { - return db::AsIfFlatRegion::sized_inside (inside, dx, dy, steps, mode); + return db::AsIfFlatRegion::sized_inside (inside, outside, dx, dy, steps, mode); } // NOTE: it does not provide benefits to merge the outside region, so just don't diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index b69bd33ff..d0bf5b91c 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -1965,7 +1965,7 @@ template OnEmptyIntruderHint sized_inside_local_operation::on_empty_intruder_hint () const { - return Drop; + return m_outside ? Ignore : Drop; } template diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index eaaee9e8c..2056f924f 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -2566,6 +2566,281 @@ TEST(56_RegionsFromShapes) EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5), false).area (), 10000); } +TEST(60_sized_inside) +{ + db::Region r, inside; + r.insert (db::Box (-10, 20, 20, 60)); + r.insert (db::Box (20, 20, 30, 60)); + inside.insert (db::Box (-10, 10, 100, 100)); + + EXPECT_EQ (db::Region ().sized_inside (db::Region (), false, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (db::Region (), false, 40, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (inside, false, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (inside, false, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 40, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 20, 10).to_string (), "(-10,10;-10,80;30,80;30,10)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 10, 20, 10).to_string (), "(-10,10;-10,80;40,80;40,10)"); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 40, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 20, 10).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 10, 20, 10).to_string (), ""); + + try { + // no negative sizing + r.sized_inside (inside, false, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (inside, false, -1, 1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (inside, false, 1, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } +} + +TEST(61_sized_outside) +{ + db::Region r, outside; + r.insert (db::Box (-10, 20, 20, 60)); + r.insert (db::Box (20, 20, 30, 60)); + outside.insert (db::Box (-20, 0, -10, 110)); + outside.insert (db::Box (100, 0, 110, 110)); + outside.insert (db::Box (-20, 0, 110, 10)); + outside.insert (db::Box (-20, 100, 110, 110)); + + EXPECT_EQ (db::Region ().sized_inside (db::Region (), true, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (db::Region (), true, 40, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (outside, true, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (outside, true, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 40, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 20, 10).to_string (), "(-10,10;-10,80;30,80;30,10)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 10, 20, 10).to_string (), "(-10,10;-10,80;40,80;40,10)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 40, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 20, 10).to_string (), "(-10,0;-10,80;30,80;30,0)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 10, 20, 10).to_string (), "(-20,0;-20,80;40,80;40,0)"); + + try { + // no negative sizing + r.sized_inside (outside, true, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (outside, true, -1, 1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (outside, true, 1, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } +} + +TEST(62_sized_inside_deep) +{ + db::DeepShapeStore dss ("TOP", 0.001); + db::Region r (dss), inside (dss), empty (dss); + + r.insert (db::Box (-10, 20, 20, 60)); + r.insert (db::Box (20, 20, 30, 60)); + inside.insert (db::Box (-10, 10, 100, 100)); + + EXPECT_EQ (db::Region ().sized_inside (db::Region (), false, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (db::Region (), false, 40, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (inside, false, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (inside, false, 40, 40).to_string (), ""); + + EXPECT_EQ (empty.sized_inside (empty, false, 0, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (empty, false, 40, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (inside, false, 0, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (inside, false, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 40, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (inside, false, 0, 20, 10).to_string (), "(-10,10;-10,80;30,80;30,10)"); + EXPECT_EQ (r.sized_inside (inside, false, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (inside, false, 10, 20, 10).to_string (), "(-10,10;-10,80;40,80;40,10)"); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 40, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (db::Region (), false, 0, 20, 10).to_string (), ""); + EXPECT_EQ (r.sized_inside (db::Region (), false, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), false, 10, 20, 10).to_string (), ""); + + EXPECT_EQ (r.sized_inside (empty, false, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (empty, false, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, false, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, false, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (empty, false, 0, 0, 40).to_string (), ""); + EXPECT_EQ (r.sized_inside (empty, false, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, false, 40, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (empty, false, 0, 20, 10).to_string (), ""); + EXPECT_EQ (r.sized_inside (empty, false, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, false, 10, 20, 10).to_string (), ""); + + try { + // no negative sizing + r.sized_inside (inside, false, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (inside, false, -1, 1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (inside, false, 1, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } +} + +TEST(63_sized_outside_deep) +{ + db::DeepShapeStore dss ("TOP", 0.001); + db::Region r (dss), outside (dss), empty (dss); + + r.insert (db::Box (-10, 20, 20, 60)); + r.insert (db::Box (20, 20, 30, 60)); + outside.insert (db::Box (-20, 0, -10, 110)); + outside.insert (db::Box (100, 0, 110, 110)); + outside.insert (db::Box (-20, 0, 110, 10)); + outside.insert (db::Box (-20, 100, 110, 110)); + + EXPECT_EQ (db::Region ().sized_inside (db::Region (), true, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (db::Region (), true, 40, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (outside, true, 0, 40).to_string (), ""); + EXPECT_EQ (db::Region ().sized_inside (outside, true, 40, 40).to_string (), ""); + + EXPECT_EQ (empty.sized_inside (empty, true, 0, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (empty, true, 40, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (outside, true, 0, 40).to_string (), ""); + EXPECT_EQ (empty.sized_inside (outside, true, 40, 40).to_string (), ""); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, -1).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 40, 40, 40).to_string (), "(-10,10;-10,100;70,100;70,10)"); + + EXPECT_EQ (r.sized_inside (outside, true, 0, 20, 10).to_string (), "(-10,10;-10,80;30,80;30,10)"); + EXPECT_EQ (r.sized_inside (outside, true, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (outside, true, 10, 20, 10).to_string (), "(-10,10;-10,80;40,80;40,10)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 40, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (db::Region (), true, 0, 20, 10).to_string (), "(-10,0;-10,80;30,80;30,0)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (db::Region (), true, 10, 20, 10).to_string (), "(-20,0;-20,80;40,80;40,0)"); + + EXPECT_EQ (r.sized_inside (empty, true, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, true, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, true, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (empty, true, 0, 0, 40).to_string (), "(-10,20;-10,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, true, 1, 1, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, true, 40, 40, 40).to_string (), "(-50,-20;-50,100;70,100;70,-20)"); + + EXPECT_EQ (r.sized_inside (empty, true, 0, 20, 10).to_string (), "(-10,0;-10,80;30,80;30,0)"); + EXPECT_EQ (r.sized_inside (empty, true, 1, 2, 0).to_string (), "(-10,20;-10,60;20,60;20,20);(20,20;20,60;30,60;30,20)"); + EXPECT_EQ (r.sized_inside (empty, true, 10, 20, 10).to_string (), "(-20,0;-20,80;40,80;40,0)"); + + try { + // no negative sizing + r.sized_inside (outside, true, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (outside, true, -1, 1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } + try { + // no negative sizing + r.sized_inside (outside, true, 1, -1, 1); + EXPECT_EQ (true, false); + } catch (...) { + } +} + TEST(100_Processors) { db::Region r;