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 () 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 .. // .. 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. // 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. // 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; std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, 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) 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) || if (db::suggest_split_polygon (poly, max_vertex_count, max_area_ratio)) {
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
std::vector<db::Polygon> sp; std::vector<db::Polygon> sp;
db::split_polygon (poly, sp); db::split_polygon (poly, sp);

View File

@ -58,7 +58,7 @@ PolygonSplitter::PolygonSplitter (PolygonSink &sink, double max_area_ratio, size
void void
PolygonSplitter::put (const db::Polygon &poly) 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; std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons); db::split_polygon (poly, split_polygons);

View File

@ -785,6 +785,14 @@ public:
return area2 () / 2; 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 * @brief The area of the contour times 2
* For integer area types, this is the more precise value as the division * For integer area types, this is the more precise value as the division
@ -807,6 +815,52 @@ public:
return a; 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 * @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 * @brief The hull "begin" point iterator
* *
@ -2193,6 +2267,21 @@ public:
return a; 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 * @brief The area of the polygon times 2
* For integer area types, this is the more precise value as the division * For integer area types, this is the more precise value as the division
@ -2207,6 +2296,21 @@ public:
return a; 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 * @brief The perimeter of the polygon
*/ */
@ -2966,6 +3070,17 @@ public:
return m_hull.area (); 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 * @brief The area of the polygon times 2
* For integer area types, this is the more precise value as the division * For integer area types, this is the more precise value as the division
@ -2976,6 +3091,17 @@ public:
return m_hull.area2 (); 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 * @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 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); 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 // Implementation of split_polygon

View File

@ -129,6 +129,21 @@ void cut_polygon (const PolygonType &input, const typename PolygonType::edge_typ
template <class PolygonType> template <class PolygonType>
void DB_PUBLIC split_polygon (const PolygonType &polygon, std::vector<PolygonType> &output); 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 * @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 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) || if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) {
(m_max_area_ratio > 0 && poly.area_ratio () > m_max_area_ratio)) {
std::vector<db::Polygon> split_polygons; std::vector<db::Polygon> split_polygons;
db::split_polygon (poly, 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> template <class C>
static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector<C> &result) 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) || if (db::suggest_split_polygon (poly, max_vertex_count, max_area_ratio)) {
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
std::vector<C> split_polygons; std::vector<C> split_polygons;
db::split_polygon (poly, split_polygons); db::split_polygon (poly, split_polygons);
@ -222,6 +221,26 @@ struct simple_polygon_defs
return poly->area2 (); 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) static std::vector<tl::Variant> extract_rad (const C *sp)
{ {
db::polygon<coord_type> p, pnew; db::polygon<coord_type> p, pnew;
@ -572,6 +591,12 @@ struct simple_polygon_defs
"\n" "\n"
"This method has been introduced in version 0.26.1\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, method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the polygon\n" "@brief Gets the perimeter of the polygon\n"
"The perimeter is sum of the lengths of all edges making up the polygon." "The perimeter is sum of the lengths of all edges making up the polygon."
@ -1091,6 +1116,26 @@ struct polygon_defs
return poly->area2 (); 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) static std::vector<tl::Variant> extract_rad (const C *p)
{ {
C pnew; C pnew;
@ -1592,6 +1637,12 @@ struct polygon_defs
"\n" "\n"
"This method has been introduced in version 0.26.1\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, method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the polygon\n" "@brief Gets the perimeter of the polygon\n"
"The perimeter is sum of the lengths of all edges making up 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 # 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 # 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). # 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. # 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. # 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); 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; 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 (); db::Polygon::area_type box_area = seed.box ().area ();
if (poly_area == box_area && seed.vertices () == 4) { if (poly_area == box_area && seed.vertices () == 4) {