Enhancing polygon splitting

With this enhancement, the area ratio in DRC can
be configured as a negative value. This indicates
to take the outer manhattan approximation of the
polygons. This way, skinny diagonals are not
resolved into many small triangles.
This commit is contained in:
Matthias Koefferlein 2024-09-18 23:18:23 +02:00
parent ca9b1d779d
commit e2718c5a54
12 changed files with 272 additions and 12 deletions

View File

@ -405,7 +405,7 @@ private:
// ----------------------------------------------------------------------------------
DeepShapeStoreState::DeepShapeStoreState ()
: m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16), m_reject_odd_polygons (false), m_text_property_name (), m_text_enlargement (-1), m_subcircuit_hierarchy_for_nets (false)
: m_threads (1), m_max_area_ratio (-3.0), m_max_vertex_count (16), m_reject_odd_polygons (false), m_text_property_name (), m_text_enlargement (-1), m_subcircuit_hierarchy_for_nets (false)
{
// .. nothing yet ..
}

View File

@ -654,7 +654,7 @@ ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, db::prop
// NOTE: only halfmanhattan polygons are guaranteed not to generate grid snap artefacts when splitting.
// This is important to maintain the connection integrity of shape clusters.
if (poly.is_halfmanhattan () && ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio))) {
if (poly.is_halfmanhattan () && db::suggest_split_polygon (poly, m_max_vertex_count, m_area_ratio)) {
std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);

View File

@ -689,8 +689,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
static bool split_polygon (bool first, db::Polygon &poly, size_t max_vertex_count, double max_area_ratio, std::vector<db::Polygon> &parts)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
if (db::suggest_split_polygon (poly, max_vertex_count, max_area_ratio)) {
std::vector<db::Polygon> sp;
db::split_polygon (poly, sp);

View File

@ -58,7 +58,7 @@ PolygonSplitter::PolygonSplitter (PolygonSink &sink, double max_area_ratio, size
void
PolygonSplitter::put (const db::Polygon &poly)
{
if ((m_max_vertex_count > 0 && poly.vertices () > m_max_vertex_count) || (m_max_area_ratio > 0.0 && poly.area_ratio () > m_max_area_ratio)) {
if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) {
std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);

View File

@ -785,6 +785,14 @@ public:
return area2 () / 2;
}
/**
* @brief The upper bound area for a manhattan approximation of the contour times
*/
area_type area_upper_manhattan_bound () const
{
return area_upper_manhattan_bound2 () / 2;
}
/**
* @brief The area of the contour times 2
* For integer area types, this is the more precise value as the division
@ -807,6 +815,52 @@ public:
return a;
}
/**
* @brief The upper bound area for a manhattan approximation of the contour times 2
* This area takes non-manhattan edges as being manhattan-interpolated to the outside.
*/
area_type area_upper_manhattan_bound2 () const
{
size_type n = size ();
if (n < 3) {
return 0;
}
area_type a = 0;
point_type pl = (*this) [n - 1];
for (size_type p = 0; p < n; ++p) {
point_type pp = (*this) [p];
int sdx = pp.x () < pl.x () ? -1 : (pp.x () == pl.x () ? 0 : 1);
int sdy = pp.y () < pl.y () ? -1 : (pp.y () == pl.y () ? 0 : 1);
if (sdx != 0 && sdy != 0) {
point_type pm;
// determine an interpolation point
if (sdx * sdy < 0) {
pm = point_type (pp.x (), pl.y ());
} else {
pm = point_type (pl.x (), pp.y ());
}
a += db::vprod (pm - point_type (), pl - point_type ());
a += db::vprod (pp - point_type (), pm - point_type ());
} else {
a += db::vprod (pp - point_type (), pl - point_type ());
}
pl = pp;
}
return a;
}
/**
* @brief The perimeter of the contour
*/
@ -1747,6 +1801,26 @@ public:
}
}
/**
* @brief Returns the area ratio between the polygon's bounding box and upper manhattan approximation bound
*
* This number is a measure how well the polygon is approximated by the bounding box,
* while assuming an outer manhattan approximation is a good measure for the polygon's
* area.
* Values are bigger than 1 for well-formed polygons. Bigger values mean worse
* approximation.
*/
double area_upper_manhattan_bound_ratio () const
{
area_type a = this->area_upper_manhattan_bound2 ();
if (a == 0) {
// By our definition, an empty polygon has an area ratio of 0
return 0.0;
} else {
return double (box ().area ()) / (0.5 * a);
}
}
/**
* @brief The hull "begin" point iterator
*
@ -2193,6 +2267,21 @@ public:
return a;
}
/**
* @brief The area of the polygon - upper manhattan bound
*
* This gives the upper area bound for a manhattan approximation of the
* polygon.
*/
area_type area_upper_manhattan_bound () const
{
area_type a = 0;
for (typename contour_list_type::const_iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) {
a += h->area_upper_manhattan_bound ();
}
return a;
}
/**
* @brief The area of the polygon times 2
* For integer area types, this is the more precise value as the division
@ -2207,6 +2296,21 @@ public:
return a;
}
/**
* @brief The area of the polygon - upper manhattan bound times 2
*
* This gives the upper area bound for a manhattan approximation of the
* polygon.
*/
area_type area_upper_manhattan_bound2 () const
{
area_type a = 0;
for (typename contour_list_type::const_iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) {
a += h->area_upper_manhattan_bound2 ();
}
return a;
}
/**
* @brief The perimeter of the polygon
*/
@ -2966,6 +3070,17 @@ public:
return m_hull.area ();
}
/**
* @brief The area of the polygon - upper manhattan bound
*
* This gives the upper area bound for a manhattan approximation of the
* polygon.
*/
area_type area_upper_manhattan_bound () const
{
return m_hull.area_upper_manhattan_bound ();
}
/**
* @brief The area of the polygon times 2
* For integer area types, this is the more precise value as the division
@ -2976,6 +3091,17 @@ public:
return m_hull.area2 ();
}
/**
* @brief The area of the polygon - upper manhattan bound times 2
*
* This gives the upper area bound for a manhattan approximation of the
* polygon.
*/
area_type area_upper_manhattan_bound2 () const
{
return m_hull.area_upper_manhattan_bound2 ();
}
/**
* @brief The perimeter of the polygon
*/
@ -3101,6 +3227,26 @@ public:
}
}
/**
* @brief Returns the area ratio between the polygon's bounding box and upper manhattan approximation bound
*
* This number is a measure how well the polygon is approximated by the bounding box,
* while assuming an outer manhattan approximation is a good measure for the polygon's
* area.
* Values are bigger than 1 for well-formed polygons. Bigger values mean worse
* approximation.
*/
double area_upper_manhattan_bound_ratio () const
{
area_type a = this->area_upper_manhattan_bound2 ();
if (a == 0) {
// By our definition, an empty polygon has an area ratio of 0
return 0.0;
} else {
return double (box ().area ()) / (0.5 * a);
}
}
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const
{
db::mem_stat (stat, purpose, cat, m_hull, no_self, parent);

View File

@ -633,6 +633,32 @@ template<> DB_PUBLIC void cut_polygon_internal (const db::DSimplePolygon &polygo
}
// -------------------------------------------------------------------------
// Implementation of suggest_split_polygon
template <class PolygonType>
bool
suggest_split_polygon (const PolygonType &polygon, size_t max_vertex_count, double max_area_ratio)
{
size_t v = polygon.vertices ();
if (v <= 4) {
return false;
} else if (max_vertex_count > 0 && v > max_vertex_count) {
return true;
} else if (max_area_ratio > 0 && polygon.area_ratio () > max_area_ratio) {
return true;
} else if (max_area_ratio < 0 && polygon.area_upper_manhattan_bound_ratio () > -max_area_ratio) {
return true;
} else {
return false;
}
}
template DB_PUBLIC bool suggest_split_polygon<> (const db::Polygon &polygon, size_t max_vertex_count, double max_area_ratio);
template DB_PUBLIC bool suggest_split_polygon<> (const db::SimplePolygon &polygon, size_t max_vertex_count, double max_area_ratio);
template DB_PUBLIC bool suggest_split_polygon<> (const db::DPolygon &polygon, size_t max_vertex_count, double max_area_ratio);
template DB_PUBLIC bool suggest_split_polygon<> (const db::DSimplePolygon &polygon, size_t max_vertex_count, double max_area_ratio);
// -------------------------------------------------------------------------
// Implementation of split_polygon

View File

@ -129,6 +129,21 @@ void cut_polygon (const PolygonType &input, const typename PolygonType::edge_typ
template <class PolygonType>
void DB_PUBLIC split_polygon (const PolygonType &polygon, std::vector<PolygonType> &output);
/**
* @brief Determines whether a polygon needs to be split according to the given max_vertex and area_ratio criteron
*
* If max_vertex is 0, there is no vertex limit.
* If max_vertex is >0, the function returns true, if the vertex limit is exceeded.
*
* If area_ratio is 0, there is no area ratio limit.
* If area_ratio is >0, the function returns true, if the bounding box area is larger than area_ratio times the polygon area.
* If area_ratio is <0, the function returns true, if the bounding box area is larger than -area_ratio times the polygon
* manhattan approximation upper area bound.
* (the latter definition is useful to prevent splitting of thin diagonal lines).
*/
template <class PolygonType>
bool DB_PUBLIC suggest_split_polygon (const PolygonType &polygon, size_t max_vertex, double area_ratio);
/**
* @brief Determines whether a polygon and a box interact
*

View File

@ -266,8 +266,7 @@ void TrapezoidDecomposition::process (const db::Polygon &poly, std::vector<db::P
void PolygonBreaker::process (const db::Polygon &poly, std::vector<db::Polygon> &result) const
{
if ((m_max_vertex_count > 0 && poly.vertices () > m_max_vertex_count) ||
(m_max_area_ratio > 0 && poly.area_ratio () > m_max_area_ratio)) {
if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) {
std::vector<db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);

View File

@ -42,8 +42,7 @@ static std::vector<C> split_poly (const C *p)
template <class C>
static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector<C> &result)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
if (db::suggest_split_polygon (poly, max_vertex_count, max_area_ratio)) {
std::vector<C> split_polygons;
db::split_polygon (poly, split_polygons);
@ -222,6 +221,26 @@ struct simple_polygon_defs
return poly->area2 ();
}
#if defined(HAVE_64BIT_COORD)
// workaround for missing 128bit binding of GSI
static double area_upper_manhattan_bound (const C *poly)
#else
static area_type area_upper_manhattan_bound (const C *poly)
#endif
{
return poly->area_upper_manhattan_bound ();
}
#if defined(HAVE_64BIT_COORD)
// workaround for missing 128bit binding of GSI
static double area_upper_manhattan_bound2 (const C *poly)
#else
static area_type area_upper_manhattan_bound2 (const C *poly)
#endif
{
return poly->area_upper_manhattan_bound2 ();
}
static std::vector<tl::Variant> extract_rad (const C *sp)
{
db::polygon<coord_type> p, pnew;
@ -572,6 +591,12 @@ struct simple_polygon_defs
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method_ext ("area_upper_manhattan_bound", &area_upper_manhattan_bound,
"@hide" // too special
) +
method_ext ("area_upper_manhattan_bound2", &area_upper_manhattan_bound2,
"@hide" // too special
) +
method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the polygon\n"
"The perimeter is sum of the lengths of all edges making up the polygon."
@ -1091,6 +1116,26 @@ struct polygon_defs
return poly->area2 ();
}
#if defined(HAVE_64BIT_COORD)
// workaround for missing 128bit binding of GSI
static double area_upper_manhattan_bound (const C *poly)
#else
static area_type area_upper_manhattan_bound (const C *poly)
#endif
{
return poly->area_upper_manhattan_bound ();
}
#if defined(HAVE_64BIT_COORD)
// workaround for missing 128bit binding of GSI
static double area_upper_manhattan_bound2 (const C *poly)
#else
static area_type area_upper_manhattan_bound2 (const C *poly)
#endif
{
return poly->area_upper_manhattan_bound2 ();
}
static std::vector<tl::Variant> extract_rad (const C *p)
{
C pnew;
@ -1592,6 +1637,12 @@ struct polygon_defs
"\n"
"This method has been introduced in version 0.26.1\n"
) +
method_ext ("area_upper_manhattan_bound", &area_upper_manhattan_bound,
"@hide" // too special
) +
method_ext ("area_upper_manhattan_bound2", &area_upper_manhattan_bound2,
"@hide" // too special
) +
method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the polygon\n"
"The perimeter is sum of the lengths of all edges making up the polygon.\n"

View File

@ -1298,7 +1298,26 @@ module DRC
# In deep mode, polygons with a bounding box to polygon area ratio bigger than the given number
# will be split into smaller chunks to optimize performance (which gets better if the polygon's
# bounding boxes do not cover a lot of empty space).
# The default threshold is 3.0 which means fairly compact polygons. Use this method with a numeric
#
# The area ratio is a signed value. Negative values indicate a area ratio, taking the outer
# manhattan approximation of the polygons for the area ratio.
# The sign of the value indicates the mode (manhattan approximation or real polygon) - the actual area
# ratio checked is the absolute value.
#
# For manhattan polygons, an area ratio of -3.0 gives the same results than a positive 3.0.
# For non-manhattan polygons, the area used for the polygon is larger than
# the actual polygon area. So splitting is less likely in these cases. This avoids degeneration
# of the split polygon which can otherwise happen for thin diagonal lines. These are often
# resolved into a large number of small triangles which does not provide any benefit for
# the algorithms.
#
# With a negative area ratio, triangles are equivalent to their bounding box and always
# have an area ratio of 1.0.
#
# The default threshold is -3.0 which gives fairly compact polygons and using their outer
# manhattan approximation. Skinny diagonals will be maintained.
#
# Use this method with a numeric
# argument to set the value and without an argument to get the current maximum area ratio.
# Set the value to zero to disable splitting by area ratio.
#

View File

@ -1978,3 +1978,8 @@ TEST(131d_edge_pair_interactions)
{
run_test (_this, "131", true);
}
TEST(132d_sensitive_breaking)
{
run_test (_this, "132", true);
}

View File

@ -1451,7 +1451,7 @@ NetTracer::determine_interactions (const db::Polygon &seed, const NetTracerShape
{
int area_ratio = 2;
db::Polygon::area_type poly_area = seed.area ();
db::Polygon::area_type poly_area = seed.area_upper_manhattan_bound ();
db::Polygon::area_type box_area = seed.box ().area ();
if (poly_area == box_area && seed.vertices () == 4) {