WIP: Shapes#break_polygons, Layout#break_polygons, Region#break_polygons (as alias)

This commit is contained in:
Matthias Koefferlein 2024-07-17 00:27:06 +02:00
parent 7146db4762
commit a89e295349
6 changed files with 176 additions and 2 deletions

View File

@ -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<db::Polygon> new_polygons;
std::vector<db::Shape> to_delete;
for (auto s = shapes.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
std::vector<db::Polygon> polygons;
polygons.push_back (db::Polygon ());
s->instantiate (polygons.back ());
bool first = true;
while (! polygons.empty ()) {
std::vector<db::Polygon> 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);
}
}
}
}
}
}

View File

@ -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

View File

@ -32,6 +32,7 @@ namespace db
// Recursive shape iterator implementation
RecursiveShapeIterator::RecursiveShapeIterator (const RecursiveShapeIterator &d)
: gsi::ObjectBase (d)
{
operator= (d);
}

View File

@ -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<db::Layout> 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<db::Layout> 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"

View File

@ -2895,7 +2895,7 @@ Class<db::Region> 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<db::Region> 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"

View File

@ -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<db::Shapes> 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<db::Box>, 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"