From 128efd45e41a33929ad063d2f9f0452656beee71 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 25 Jun 2024 18:21:21 +0200 Subject: [PATCH] WIP: Implementing flat mode for sized inside/outside --- src/db/db/dbAsIfFlatRegion.cc | 80 +++++++++++++++++++++------- src/db/db/dbDeepRegion.cc | 3 +- src/db/db/dbRegionLocalOperations.cc | 8 ++- src/db/db/dbRegionLocalOperations.h | 3 +- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 14c4c0f71..63686cb65 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -1386,7 +1386,8 @@ AsIfFlatRegion::sized_inside (const Region &inside, bool outside, coord_type d, RegionDelegate * AsIfFlatRegion::sized_inside (const Region &inside, bool outside, coord_type dx, coord_type dy, int steps, unsigned int mode) const { - // @@@ TODO: restrict max. number of steps in "outside" mode like for DeepRegion + // empirical value + const int max_steps = 25; if (steps <= 0 || empty ()) { // Nothing to do - NOTE: don't return EmptyRegion because we want to @@ -1398,27 +1399,68 @@ 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"))); } - std::unique_ptr output (new FlatRegion ()); - std::vector results; - results.push_back (&output->raw_polygons ()); - - // NOTE: as we merge the inside region in the inside case, we can use distance 0 - db::Coord dist = outside ? std::max (dx, dy) : 0; - bool inside_is_merged = outside ? inside.is_merged () : true; - db::sized_inside_local_operation op (dx, dy, steps, mode, dist, outside, inside_is_merged, true /*split after*/); - - db::local_processor proc; - proc.set_base_verbosity (base_verbosity ()); - proc.set_description (progress_desc ()); - proc.set_report_progress (report_progress ()); - - std::vector > others; // NOTE: it does not provide benefits to merge the outside region, so just don't - others.push_back (outside ? inside.begin () : inside.begin_merged ()); + auto inside_polygons = outside ? inside.begin () : inside.begin_merged (); + bool inside_polygons_is_merged = outside ? inside.is_merged () : true; - proc.run_flat (begin_merged (), others, std::vector (), &op, results); + auto polygons = begin_merged (); - return output.release (); + std::unique_ptr res (new FlatRegion ()); + std::unique_ptr prev; + + int steps_from = 0; + + while (steps > 0) { + + db::Coord dx_chunk = dx, dy_chunk = dy; + int steps_chunk = steps; + + // We perform at most max_steps in one chunk. + // This is supposed to limit the search range and merge shapes instead of creating + // heavily overlapping ones. + if (steps > max_steps) { + steps_chunk = max_steps; + dx_chunk = db::coord_traits::rounded (dx * max_steps / double (steps)); + dy_chunk = db::coord_traits::rounded (dy * max_steps / double (steps)); + } + + steps -= steps_chunk; + dx -= dx_chunk; + dy -= dy_chunk; + + // NOTE: as we merge the inside region in the inside case, we can use distance 0 + db::Coord dist = outside ? std::max (dx_chunk, dy_chunk) : 0; + db::sized_inside_local_operation op (dx_chunk, dy_chunk, steps_chunk, mode, dist, outside, inside_polygons_is_merged); + + db::local_processor proc; + proc.set_base_verbosity (base_verbosity ()); + proc.set_description (progress_desc ()); + proc.set_report_progress (report_progress ()); + + // indicate chunk in the progress description + proc.set_description (proc.description (&op) + tl::sprintf (tl::to_string (tr (" (steps %d..%d)")), steps_from + 1, steps_from + steps_chunk + 1)); + + std::vector > others; + others.push_back (inside_polygons); + + std::vector results; + results.push_back (&res->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); + 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); + } + + } + + return res.release (); } RegionDelegate * diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 95c4d0761..15e2074ce 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1839,8 +1839,7 @@ DeepRegion::sized_inside (const Region &inside, bool outside, coord_type dx, coo // NOTE: as we merge the inside region in the inside case, we can use distance 0 db::Coord dist = outside ? std::max (dx_chunk, dy_chunk) : 0; - bool split_after = (steps == 0); - db::sized_inside_local_operation op (dx_chunk, dy_chunk, steps_chunk, mode, dist, outside, inside_polygons_is_merged, split_after); + db::sized_inside_local_operation op (dx_chunk, dy_chunk, steps_chunk, mode, dist, outside, inside_polygons_is_merged); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &inside_polygons.layout (), &inside_polygons.initial_cell (), polygons.breakout_cells (), inside_polygons.breakout_cells ()); configure_proc (proc); diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index c475089ea..b69bd33ff 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -1948,8 +1948,8 @@ template class DB_PUBLIC two_bool_and_not_local_operation_with_properties -sized_inside_local_operation::sized_inside_local_operation (db::Coord dx, db::Coord dy, int steps, unsigned int mode, db::Coord dist, bool outside, bool inside_is_merged, bool split_after) - : m_dx (dx), m_dy (dy), m_dist (dist), m_steps (steps), m_mode (mode), m_outside (outside), m_inside_is_merged (inside_is_merged), m_split_after (split_after) +sized_inside_local_operation::sized_inside_local_operation (db::Coord dx, db::Coord dy, int steps, unsigned int mode, db::Coord dist, bool outside, bool inside_is_merged) + : m_dx (dx), m_dy (dy), m_dist (dist), m_steps (steps), m_mode (mode), m_outside (outside), m_inside_is_merged (inside_is_merged) { // .. nothing yet .. } @@ -2067,9 +2067,7 @@ sized_inside_local_operation::do_compute_local (db::Layout *layout, } db::PolygonContainer pc (subjects, true /*clear*/); - db::PolygonSplitter splitter (pc, proc->area_ratio (), proc->max_vertex_count ()); - // NOTE: we split in the last step if requested - db::PolygonGenerator pg ((! m_split_after || step + 1 < m_steps) ? (PolygonSink &) pc : (PolygonSink &) splitter, false /*don't resolve holes*/, false /*min. coherence*/); + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, false /*min. coherence*/); db::BooleanOp op (m_outside ? db::BooleanOp::ANotB : db::BooleanOp::And); ep_and.process (pg, op); diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h index c89bd8474..ba8129696 100644 --- a/src/db/db/dbRegionLocalOperations.h +++ b/src/db/db/dbRegionLocalOperations.h @@ -471,7 +471,7 @@ class DB_PUBLIC sized_inside_local_operation : public local_operation { public: - sized_inside_local_operation (db::Coord dx, db::Coord dy, int steps, unsigned int mode, db::Coord dist, bool outside, bool inside_is_merged, bool split_after); + sized_inside_local_operation (db::Coord dx, db::Coord dy, int steps, unsigned int mode, db::Coord dist, bool outside, bool inside_is_merged); virtual db::Coord dist () const; virtual OnEmptyIntruderHint on_empty_intruder_hint () const; @@ -491,7 +491,6 @@ private: unsigned int m_mode; bool m_outside; bool m_inside_is_merged; - bool m_split_after; db::MagnificationAndOrientationReducer m_vars_anisotropic; db::MagnificationReducer m_vars_isotropic; };