From a89e295349c5f9ae422957155784684f50a85544 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 17 Jul 2024 00:27:06 +0200 Subject: [PATCH] WIP: Shapes#break_polygons, Layout#break_polygons, Region#break_polygons (as alias) --- src/db/db/dbLayoutUtils.cc | 83 +++++++++++++++++++++++++++ src/db/db/dbLayoutUtils.h | 27 +++++++++ src/db/db/dbRecursiveShapeIterator.cc | 1 + src/db/db/gsiDeclDbLayout.cc | 38 ++++++++++++ src/db/db/gsiDeclDbRegion.cc | 5 +- src/db/db/gsiDeclDbShapes.cc | 24 ++++++++ 6 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 2fe5174fb..a5d7b8518 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -683,5 +683,88 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db } } + +// ------------------------------------------------------------ +// break_polygons implementation + +void +break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio) +{ + std::vector new_polygons; + std::vector to_delete; + + for (auto s = shapes.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) { + + std::vector polygons; + polygons.push_back (db::Polygon ()); + s->instantiate (polygons.back ()); + + bool first = true; + while (! polygons.empty ()) { + + std::vector split_polygons; + + for (auto p = polygons.begin (); p != polygons.end (); ++p) { + if ((max_vertex_count > 0 && p->vertices () > max_vertex_count) || + (max_area_ratio > 0 && p->area_ratio () > max_area_ratio)) { + if (first) { + to_delete.push_back (*s); + } + db::split_polygon (*p, split_polygons); + } else if (! first) { + new_polygons.push_back (db::Polygon ()); + new_polygons.back ().swap (*p); + } + } + + first = false; + polygons.swap (split_polygons); + + } + + } + + shapes.erase_shapes (to_delete); + + for (auto p = new_polygons.begin (); p != new_polygons.end (); ++p) { + shapes.insert (*p); + } +} + +void +break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio) +{ + if (layout.is_valid_cell_index (cell_index) && layout.is_valid_layer (layer)) { + db::Cell &cell = layout.cell (cell_index); + break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio); + } +} + +void +break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio) +{ + for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) { + if (layout.is_valid_cell_index (ci)) { + db::Cell &cell = layout.cell (ci); + break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio); + } + } +} + +void +break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio) +{ + for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) { + if (layout.is_valid_cell_index (ci)) { + db::Cell &cell = layout.cell (ci); + for (unsigned int li = 0; li < layout.layers (); ++li) { + if (layout.is_valid_layer (li)) { + break_polygons (cell.shapes (li), max_vertex_count, max_area_ratio); + } + } + } + } +} + } diff --git a/src/db/db/dbLayoutUtils.h b/src/db/db/dbLayoutUtils.h index c4d06c239..d3a15c207 100644 --- a/src/db/db/dbLayoutUtils.h +++ b/src/db/db/dbLayoutUtils.h @@ -249,6 +249,33 @@ private: */ DB_PUBLIC void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d); +/** + * @brief Breaks polygons according to max_vertex_count and max_area_ratio + * + * This method will investigate all polygons on the given layer and cell and split them in case they + * have more than the specified vertices and an bounding-box area to polygon area ratio larget + * than the specified max_area_ratio. This serves optimization for algorithms needing a good + * bounding box approximation. + * + * Setting max_vertex_count or max_area_ratio to 0 disables the respective check. + */ +DB_PUBLIC void break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio); + +/** + * @brief Like "break_polygons" before, but applies it to all cells. + */ +DB_PUBLIC void break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio); + +/** + * @brief Like "break_polygons" before, but applies it to all cells and all layers. + */ +DB_PUBLIC void break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio); + +/** + * @brief Like "break_polygons" before, but applies it to the given Shapes container. + */ +DB_PUBLIC void break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio); + } // namespace db #endif diff --git a/src/db/db/dbRecursiveShapeIterator.cc b/src/db/db/dbRecursiveShapeIterator.cc index cc02f75a9..5c628def1 100644 --- a/src/db/db/dbRecursiveShapeIterator.cc +++ b/src/db/db/dbRecursiveShapeIterator.cc @@ -32,6 +32,7 @@ namespace db // Recursive shape iterator implementation RecursiveShapeIterator::RecursiveShapeIterator (const RecursiveShapeIterator &d) + : gsi::ObjectBase (d) { operator= (d); } diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index db8c78233..8b547d1b6 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -41,6 +41,7 @@ #include "dbLayerMapping.h" #include "dbCellMapping.h" #include "dbTechnology.h" +#include "dbLayoutUtils.h" #include "tlStream.h" #include "tlGlobPattern.h" @@ -1050,6 +1051,16 @@ static void set_properties (db::Layout *layout, unsigned int index, const db::La } } +void break_polygons2 (db::Layout *layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio) +{ + db::break_polygons (*layout, layer, max_vertex_count, max_area_ratio); +} + +void break_polygons1 (db::Layout *layout, size_t max_vertex_count, double max_area_ratio) +{ + db::break_polygons (*layout, max_vertex_count, max_area_ratio); +} + Class decl_Layout ("db", "Layout", gsi::constructor ("new", &layout_ctor_with_manager, gsi::arg ("manager"), "@brief Creates a layout object attached to a manager\n" @@ -1956,6 +1967,33 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.26.1.\n" ) + + gsi::method_ext ("break_polygons", &break_polygons1, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), + "@brief Breaks the polygons of the layout into smaller ones\n" + "\n" + "There are two criteria for splitting a polygon: a polygon is split into parts with less then " + "'max_vertex_count' points and an bounding box-to-polygon area ratio less than 'max_area_ratio'. " + "The area ratio is supposed to render polygons whose bounding box is a better approximation. " + "This applies for example to 'L' shape polygons.\n" + "\n" + "Using a value of 0 for either limit means that the respective limit isn't checked. " + "Breaking happens by cutting the polygons into parts at 'good' locations. The " + "algorithm does not have a specific goal to minimize the number of parts for example. " + "The only goal is to achieve parts within the given limits.\n" + "\n" + "Breaking also applies to paths if their polygon representation satisfies the breaking criterion. " + "In that case, paths are converted to polygons and broken into smaller parts.\n" + "\n" + "This variant applies breaking to all cells and layers.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + + gsi::method_ext ("break_polygons", &break_polygons2, gsi::arg ("layer"), gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), + "@brief Breaks the polygons of the layer into smaller ones\n" + "\n" + "This variant applies breaking to all cells and the given layer.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + gsi::method ("transform", (void (db::Layout::*) (const db::Trans &t)) &db::Layout::transform, gsi::arg ("trans"), "@brief Transforms the layout with the given transformation\n" "\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 8e98a9656..059dd4d67 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -2895,7 +2895,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "This method returns all polygons in self which are not rectilinear." "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + - method_ext ("break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), + method_ext ("break_polygons|#break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), "@brief Breaks the polygons of the region into smaller ones\n" "\n" "There are two criteria for splitting a polygon: a polygon is split into parts with less then " @@ -2908,7 +2908,8 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "algorithm does not have a specific goal to minimize the number of parts for example. " "The only goal is to achieve parts within the given limits.\n" "\n" - "This method has been introduced in version 0.26." + "This method has been introduced in version 0.26. The 'break_polygons' alias has been introduced " + "in version 0.29.5 to avoid issues with reserved keywords." ) + method_ext ("delaunay", &delaunay, "@brief Computes a constrained Delaunay triangulation from the given region\n" diff --git a/src/db/db/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index f2334f33b..7393f3a89 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -30,6 +30,7 @@ #include "dbRegion.h" #include "dbEdgePairs.h" #include "dbEdges.h" +#include "dbLayoutUtils.h" namespace gsi { @@ -441,6 +442,11 @@ static db::Layout *layout (db::Shapes *sh) } } +static void break_polygons (db::Shapes *sh, size_t max_vertex_count, double max_area_ratio) +{ + db::break_polygons (*sh, max_vertex_count, max_area_ratio); +} + static unsigned int s_all () { return db::ShapeIterator::All; } static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; } static unsigned int s_properties () { return db::ShapeIterator::Properties; } @@ -791,6 +797,24 @@ Class decl_Shapes ("db", "Shapes", "\n" "This method has been introduced in version 0.25.\n" ) + + gsi::method_ext ("break_polygons", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), + "@brief Breaks the polygons of the shape container into smaller ones\n" + "\n" + "There are two criteria for splitting a polygon: a polygon is split into parts with less then " + "'max_vertex_count' points and an bounding box-to-polygon area ratio less than 'max_area_ratio'. " + "The area ratio is supposed to render polygons whose bounding box is a better approximation. " + "This applies for example to 'L' shape polygons.\n" + "\n" + "Using a value of 0 for either limit means that the respective limit isn't checked. " + "Breaking happens by cutting the polygons into parts at 'good' locations. The " + "algorithm does not have a specific goal to minimize the number of parts for example. " + "The only goal is to achieve parts within the given limits.\n" + "\n" + "Breaking also applies to paths if their polygon representation satisfies the breaking criterion. " + "In that case, paths are converted to polygons and broken into smaller parts.\n" + "\n" + "This method has been introduced in version 0.29.5." + ) + gsi::method_ext ("replace", &replace, gsi::arg ("shape"), gsi::arg ("box"), "@brief Replaces the given shape with a box\n" "@return A reference to the new shape (a \\Shape object)\n"