From c8f4c83c53e93f1aa181efdacfed6bd2763ab856 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 13 Mar 2021 18:01:43 +0100 Subject: [PATCH] Fill tool enhancement (GSI, db): glue box for fill cell array compatibility in tiling processor. --- src/db/db/dbFillTool.cc | 31 +++++++++++--------- src/db/db/dbFillTool.h | 24 ++++++++++++---- src/db/db/gsiDeclDbCell.cc | 58 ++++++++++++++++++++++++++++++-------- 3 files changed, 84 insertions(+), 29 deletions(-) diff --git a/src/db/db/dbFillTool.cc b/src/db/db/dbFillTool.cc index 2adaf5d41..e795c0f1b 100644 --- a/src/db/db/dbFillTool.cc +++ b/src/db/db/dbFillTool.cc @@ -196,7 +196,7 @@ private: static bool fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - std::vector *remaining_parts, const db::Vector &fill_margin) + std::vector *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box) { if (row_step.x () <= 0 || column_step.y () <= 0) { throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row step must have a positive x component while column step must have a positive y component"))); @@ -206,6 +206,11 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row_step x column_step vector vector product must be > 0"))); } + // disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box + if (enhanced_fill && ! glue_box.empty () && ! fp0.box ().enlarged (db::Vector (1, 1)).inside (glue_box)) { + enhanced_fill = false; + } + std::vector filled_regions; db::EdgeProcessor ep; @@ -346,25 +351,25 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f DB_PUBLIC bool fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - std::vector *remaining_parts, const db::Vector &fill_margin) + std::vector *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box) { - return fill_polygon_impl (cell, fp0, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin); + return fill_polygon_impl (cell, fp0, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box); } DB_PUBLIC bool fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill, - std::vector *remaining_parts, const db::Vector &fill_margin) + std::vector *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box) { if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) { throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)"))); } - return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox.p1 () - db::Point (), db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin); + return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox.p1 () - db::Point (), db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin, glue_box); } static void fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration) + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration, const db::Box &glue_box) { if (row_step.x () <= 0 || column_step.y () <= 0) { throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row step must have a positive x component while column step must have a positive y component"))); @@ -391,7 +396,7 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill tl::RelativeProgress progress (progress_title, n); for (db::Region::const_iterator p = fr.begin_merged (); !p.at_end (); ++p) { - if (! fill_polygon_impl (cell, *p, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin)) { + if (! fill_polygon_impl (cell, *p, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin, glue_box)) { if (remaining_polygons) { rem_poly.push_back (*p); } @@ -421,27 +426,27 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill DB_PUBLIC void fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { - fill_region_impl (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0); + fill_region_impl (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box); } DB_PUBLIC void fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) { throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)"))); } fill_region_impl (cell, fr, fill_cell_index, fc_bbox.p1 () - db::Point (), db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), - origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0); + origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box); } DB_PUBLIC void fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons) + const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box) { const db::Region *fill_region = &fr; @@ -455,7 +460,7 @@ fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fi ++iteration; remaining.clear (); - fill_region_impl (cell, *fill_region, fill_cell_index, kernel_origin, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration); + fill_region_impl (cell, *fill_region, fill_cell_index, kernel_origin, row_step, column_step, origin, true, &remaining, fill_margin, remaining_polygons, iteration, glue_box); new_fill_region.swap (remaining); fill_region = &new_fill_region; diff --git a/src/db/db/dbFillTool.h b/src/db/db/dbFillTool.h index ad2e22b4a..2e1bef33d 100644 --- a/src/db/db/dbFillTool.h +++ b/src/db/db/dbFillTool.h @@ -46,6 +46,7 @@ class Region; * * @param remaining_parts If non-null, this vector receives the parts of the polygons not covered by the tiling cells (plus the fill_margin) * @param fill_margin Only used if remaining_parts is not 0 (see there) + * @param glue_box Guarantees boundary compatibility * * Return value: true, if the polygon could be filled, false if no fill tile at all could be applied (remaining_parts will not be fed in that case) * @@ -77,15 +78,22 @@ class Region; * * As a practical consequence, if all fill cell geometries are within the kernel's boundary, they will also * be within the polygon to fill. + * + * If the glue box is non-empty, fill cells are guaranteed to use the global origin even in enhanced mode if + * unless they are entirely inside and not touching the boundary of the glue box. + * The glue box is useful to put the fill algorithm inside a tiling processor. In this case, the glue box + * is the tile box while the actual fill region can be larger to allow overlapping tiles. + * + * In enhanced fill mode, the origin is ignored unless a glue box is given. */ DB_PUBLIC bool fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill, - std::vector *remaining_parts = 0, const db::Vector &fill_margin = db::Vector ()); + std::vector *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ()); DB_PUBLIC bool fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - std::vector *remaining_parts = 0, const db::Vector &fill_margin = db::Vector ()); + std::vector *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ()); /** @@ -94,25 +102,31 @@ fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cel * remaining_parts (if non-null) will receive the non-filled parts of partially filled polygons. * fill_margin will specify the margin around the filled area when computing (through subtraction of the tiled area) the remaining_parts. * remaining_polygons (if non-null) will receive the polygons which could not be filled at all. + * + * In enhanced fill mode, the origin is ignored unless a glue box is given. */ DB_PUBLIC void fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0); + db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ()); DB_PUBLIC void fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0); + db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ()); /** * @brief An iterative version for enhanced fill * * This version operates like the region-based fill_region version, but repeates the fill step until no further fill cells can be placed. * The remaining parts will be placed inside "remaining_polygons" unless this pointer is null. + * + * This version implies enhanced_mode (see "fill_region"). + * + * The origin is ignored unless a glue box is given. */ DB_PUBLIC void fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons = 0); + const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Point &origin = db::Point (), const db::Box &glue_box = db::Box ()); } diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index daf6eb7a8..b33c7005b 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1298,23 +1298,23 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db:: static void fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { - db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons); + db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0 || !glue_box.empty (), remaining_parts, fill_margin, remaining_polygons, glue_box); } static void -fill_region_diamond (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) +fill_region_skew (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin, + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { - db::fill_region (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons); + db::fill_region (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin ? *origin : db::Point (), origin == 0 || !glue_box.empty (), remaining_parts, fill_margin, remaining_polygons, glue_box); } static void fill_region_multi (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons) + const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box) { - db::fill_region_repeat (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, fill_margin, remaining_polygons); + db::fill_region_repeat (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box); } static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t) @@ -1774,7 +1774,14 @@ Class decl_Cell ("db", "Cell", "\n" "This method has been introduced in version 0.23.\n" ) + - gsi::method_ext ("fill_region", &fill_region, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("fc_box"), gsi::arg ("origin", &default_origin, "(0, 0)"), gsi::arg ("remaining_parts", (db::Region *)0, "nil"), gsi::arg ("fill_margin", db::Vector ()), gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::method_ext ("fill_region", &fill_region, gsi::arg ("region"), + gsi::arg ("fill_cell_index"), + gsi::arg ("fc_box"), + gsi::arg ("origin", &default_origin, "(0, 0)"), + gsi::arg ("remaining_parts", (db::Region *)0, "nil"), + gsi::arg ("fill_margin", db::Vector ()), + gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::arg ("glue_box", db::Box ()), "@brief Fills the given region with cells of the given type (extended version)\n" "@param region The region to fill\n" "@param fill_cell_index The fill cell to place\n" @@ -1783,6 +1790,7 @@ Class decl_Cell ("db", "Cell", "@param remaining_parts See explanation below\n" "@param fill_margin See explanation below\n" "@param remaining_polygons See explanation below\n" + "@param glue_box Guarantees fill cell compatibility to neighbor regions in enhanced mode\n" "\n" "This method creates a regular pattern of fill cells to cover the interior of the given region as far as possible. " "This process is also known as tiling. This implementation supports rectangular (not necessarily square) tile cells. " @@ -1825,9 +1833,27 @@ Class decl_Cell ("db", "Cell", "end\n" "@/code\n" "\n" - "This method has been introduced in version 0.23 and generalized in version 0.27 with default values.\n" + "The glue box parameter supports fill cell array compatibility with neighboring regions. This is specifically useful when putting the fill_cell " + "method into a tiling processor. Fill cell array compatibility means that the fill cell array continues over tile boundaries. This is easy with an origin: " + "you can chose the origin identically over all tiles which is sufficient to guarantee fill cell array compatibility across the tiles. " + "However there is no freedom of choice of the origin then and fill cell placement may not be optimal. To enable the origin for the tile boundary only, " + "a glue box can given. The origin will then be used only when the polygons to fill not entirely inside and not at the border of the glue box. Hence, " + "while a certain degree of freedom is present for the placement of fill cells inside the glue box, the fill cells are guaranteed to be placed " + "at the raster implied by origin at the glue box border and beyond. To ensure fill cell compatibility inside the tiling processor, it is sufficient to use the tile " + "box as the glue box.\n" + "\n" + "This method has been introduced in version 0.23 and enhanced in version 0.27.\n" ) + - gsi::method_ext ("fill_region", &fill_region_diamond, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("kernel_origin"), gsi::arg ("row_step"), gsi::arg ("column_step"), gsi::arg ("origin", &default_origin, "(0, 0)"), gsi::arg ("remaining_parts", (db::Region *)0, "nil"), gsi::arg ("fill_margin", db::Vector ()), gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::method_ext ("fill_region", &fill_region_skew, gsi::arg ("region"), + gsi::arg ("fill_cell_index"), + gsi::arg ("kernel_origin"), + gsi::arg ("row_step"), + gsi::arg ("column_step"), + gsi::arg ("origin", &default_origin, "(0, 0)"), + gsi::arg ("remaining_parts", (db::Region *)0, "nil"), + gsi::arg ("fill_margin", db::Vector ()), + gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::arg ("glue_box", db::Box ()), "@brief Fills the given region with cells of the given type (skew step version)\n" "@param region The region to fill\n" "@param fill_cell_index The fill cell to place\n" @@ -1845,13 +1871,23 @@ Class decl_Cell ("db", "Cell", "\n" "This variant has been introduced in version 0.27.\n" ) + - gsi::method_ext ("fill_region_multi", &fill_region_multi, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("kernel_origin"), gsi::arg ("row_step"), gsi::arg ("column_step"), gsi::arg ("fill_margin", db::Vector ()), gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::method_ext ("fill_region_multi", &fill_region_multi, gsi::arg ("region"), + gsi::arg ("fill_cell_index"), + gsi::arg ("kernel_origin"), + gsi::arg ("row_step"), + gsi::arg ("column_step"), + gsi::arg ("fill_margin", db::Vector ()), + gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), + gsi::arg ("origin", db::Point ()), + gsi::arg ("glue_box", db::Box ()), "@brief Fills the given region with cells of the given type in enhanced mode with iterations\n" "This version operates like \\fill_region, but repeats the fill generation until no further fill cells can be placed. " "As the fill pattern origin changes between the iterations, narrow regions can be filled which cannot with a fixed fill pattern origin. " "The \\fill_margin parameter is important as it controls the distance between fill cells with a different origin and therefore " "introduces a safety distance between pitch-incompatible arrays.\n" "\n" + "The origin is ignored unless a glue box is given. See \\fill_region for a description of this concept.\n" + "\n" "This method has been introduced in version 0.27.\n" ) + gsi::method_ext ("begin_shapes_rec", &begin_shapes_rec, gsi::arg ("layer"),