diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index db052be3b..b4be6ee70 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -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 .. } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index f8476730d..cfb495af6 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -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 split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 4829e9131..631c03277 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -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 &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 sp; db::split_polygon (poly, sp); diff --git a/src/db/db/dbLocalOperationUtils.cc b/src/db/db/dbLocalOperationUtils.cc index eff3c1b14..9faf34c31 100644 --- a/src/db/db/dbLocalOperationUtils.cc +++ b/src/db/db/dbLocalOperationUtils.cc @@ -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 split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 550564174..40fa230d2 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -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 * @@ -2184,7 +2258,7 @@ public: /** * @brief The area of the polygon */ - area_type area () const + area_type area () const { area_type a = 0; for (typename contour_list_type::const_iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) { @@ -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); diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 4ccb7dd6b..b7a3fc6ac 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -633,6 +633,31 @@ template<> DB_PUBLIC void cut_polygon_internal (const db::DSimplePolygon &polygo } +// ------------------------------------------------------------------------- +// Implementation of suggest_split_polygon + +template +bool +suggest_split_polygon (const PolygonType &polygon, size_t max_vertex_count, double max_area_ratio) +{ + if (polygon.is_box () || polygon.vertices () <= 3) { + return false; + } else if (max_vertex_count > 0 && polygon.vertices () > 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 diff --git a/src/db/db/dbPolygonTools.h b/src/db/db/dbPolygonTools.h index 87497812f..cdcd1d2bf 100644 --- a/src/db/db/dbPolygonTools.h +++ b/src/db/db/dbPolygonTools.h @@ -129,6 +129,21 @@ void cut_polygon (const PolygonType &input, const typename PolygonType::edge_typ template void DB_PUBLIC split_polygon (const PolygonType &polygon, std::vector &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 +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 * diff --git a/src/db/db/dbRegionProcessors.cc b/src/db/db/dbRegionProcessors.cc index f432aec21..e3f3b854f 100644 --- a/src/db/db/dbRegionProcessors.cc +++ b/src/db/db/dbRegionProcessors.cc @@ -266,8 +266,7 @@ void TrapezoidDecomposition::process (const db::Polygon &poly, std::vector &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 split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index 9cfcb1cf6..f552ac1ff 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -42,8 +42,7 @@ static std::vector split_poly (const C *p) template static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector &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 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 extract_rad (const C *sp) { db::polygon 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 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" diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 176bf9aaa..6b98291d8 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -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. # diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 79122f690..04b9fb3df 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1978,3 +1978,8 @@ TEST(131d_edge_pair_interactions) { run_test (_this, "131", true); } + +TEST(132d_sensitive_breaking) +{ + run_test (_this, "132", true); +} diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc index 5e5fb1e54..b8b87521a 100644 --- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc +++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc @@ -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) { diff --git a/testdata/drc/drcSimpleTests_132.drc b/testdata/drc/drcSimpleTests_132.drc new file mode 100644 index 000000000..24aa34def --- /dev/null +++ b/testdata/drc/drcSimpleTests_132.drc @@ -0,0 +1,26 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l1.output(100, 0) + +max_area_ratio(0.0) + +l1 = input(1, 0) +l1.output(101, 0) + +max_area_ratio(3.0) + +l1 = input(1, 0) +l1.output(102, 0) + +max_area_ratio(-3.0) + +l1 = input(1, 0) +l1.output(103, 0) + diff --git a/testdata/drc/drcSimpleTests_132.gds b/testdata/drc/drcSimpleTests_132.gds new file mode 100644 index 000000000..31c8a3cb8 Binary files /dev/null and b/testdata/drc/drcSimpleTests_132.gds differ diff --git a/testdata/drc/drcSimpleTests_au132d.gds b/testdata/drc/drcSimpleTests_au132d.gds new file mode 100644 index 000000000..16b9e1dbf Binary files /dev/null and b/testdata/drc/drcSimpleTests_au132d.gds differ diff --git a/testdata/drc/drcSimpleTests_au47bd.gds b/testdata/drc/drcSimpleTests_au47bd.gds index ba8325cc3..284990144 100644 Binary files a/testdata/drc/drcSimpleTests_au47bd.gds and b/testdata/drc/drcSimpleTests_au47bd.gds differ