From d69c60a5c534cf2608e94d0e0865b5ca42dbda1b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 19 Sep 2019 00:13:14 +0200 Subject: [PATCH] Enabled net tracing for heavily decomposed polygons --- src/db/db/dbHierarchyBuilder.cc | 15 +++++-- src/db/db/dbPolygon.h | 70 +++++++++++++++++++++++++++++---- src/db/db/gsiDeclDbPolygon.cc | 34 ++++++++++++++++ src/db/unit_tests/dbPolygon.cc | 10 +++++ 4 files changed, 119 insertions(+), 10 deletions(-) diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index a9e239d88..c43685c4b 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -571,7 +571,12 @@ void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape if (! trans.is_unity ()) { poly.transform (trans); } - target->insert (db::PolygonRef (poly, mp_layout->shape_repository ())); + + // NOTE: as this is a specialized receiver for the purpose of building region + // representations we don't need empty polygons here + if (poly.area2 () > 0) { + target->insert (db::PolygonRef (poly, mp_layout->shape_repository ())); + } } else if (shape.is_text () && m_text_enlargement >= 0) { @@ -598,12 +603,16 @@ void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { - target->insert (db::PolygonRef (db::Polygon (shape.transformed (trans)), mp_layout->shape_repository ())); + if (shape.area () > 0) { + target->insert (db::PolygonRef (db::Polygon (shape.transformed (trans)), mp_layout->shape_repository ())); + } } void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) { - target->insert (db::PolygonRef (shape.transformed (trans), mp_layout->shape_repository ())); + if (shape.area2 () > 0) { + target->insert (db::PolygonRef (shape.transformed (trans), mp_layout->shape_repository ())); + } } // --------------------------------------------------------------------------------------------- diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index d05b51cb2..827e083d4 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -758,6 +758,16 @@ public: * @brief The area of the contour */ area_type area () const + { + return area2 () / 2; + } + + /** + * @brief The area of the contour times 2 + * For integer area types, this is the more precise value as the division + * by 2 might round off. + */ + area_type area2 () const { size_type n = size (); if (n < 3) { @@ -771,10 +781,10 @@ public: a += db::vprod (pp - point_type (), pl - point_type ()); pl = pp; } - return a / 2; + return a; } - /** + /** * @brief The perimeter of the contour */ perimeter_type perimeter () const @@ -1682,7 +1692,13 @@ public: */ double area_ratio () const { - return double (box ().area ()) / double (area ()); + area_type a = area2 (); + 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); + } } /** @@ -2135,7 +2151,21 @@ public: return a; } - /** + /** + * @brief The area of the polygon times 2 + * For integer area types, this is the more precise value as the division + * by 2 might round off. + */ + area_type area2 () const + { + area_type a = 0; + for (typename contour_list_type::const_iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) { + a += h->area2 (); + } + return a; + } + + /** * @brief The perimeter of the polygon */ perimeter_type perimeter () const @@ -2861,7 +2891,17 @@ public: return m_hull.area (); } - /** + /** + * @brief The area of the polygon times 2 + * For integer area types, this is the more precise value as the division + * by 2 might round off. + */ + area_type area2 () const + { + return m_hull.area2 (); + } + + /** * @brief The perimeter of the polygon */ perimeter_type perimeter () const @@ -2977,7 +3017,13 @@ public: */ double area_ratio () const { - return double (box ().area ()) / double (area ()); + area_type a = area2 (); + 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 @@ -3154,7 +3200,17 @@ public: return this->obj ().area (); } - /** + /** + * @brief The area of the polygon times 2 + * For integer area types, this is the more precise value as the division + * by 2 might round off. + */ + area_type area2 () const + { + return this->obj ().area2 (); + } + + /** * @brief The perimeter of the polygon */ perimeter_type perimeter () const diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index 6e896f212..6ff51ab23 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -184,6 +184,16 @@ struct simple_polygon_defs return poly->area (); } +#if defined(HAVE_64BIT_COORD) + // workaround for missing 128bit binding of GSI + static double area2 (const C *poly) +#else + static area_type area2 (const C *poly) +#endif + { + return poly->area2 (); + } + static std::vector extract_rad (const C *sp) { db::polygon p, pnew; @@ -513,6 +523,13 @@ struct simple_polygon_defs "@brief Gets the area of the polygon\n" "The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise." ) + + method_ext ("area2", &area2, + "@brief Gets the double area of the polygon\n" + "This method is provided because the area for an integer-type polygon is a multiple of 1/2. " + "Hence the double area can be expresses precisely as an integer for these types.\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + 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." @@ -1022,6 +1039,16 @@ struct polygon_defs return poly->area (); } +#if defined(HAVE_64BIT_COORD) + // workaround for missing 128bit binding of GSI + static double area2 (const C *poly) +#else + static area_type area2 (const C *poly) +#endif + { + return poly->area2 (); + } + static std::vector extract_rad (const C *p) { C pnew; @@ -1492,6 +1519,13 @@ struct polygon_defs "The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise." "Orientation is ensured automatically in most cases.\n" ) + + method_ext ("area2", &area2, + "@brief Gets the double area of the polygon\n" + "This method is provided because the area for an integer-type polygon is a multiple of 1/2. " + "Hence the double area can be expresses precisely as an integer for these types.\n" + "\n" + "This method has been introduced in version 0.26.1\n" + ) + 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/db/unit_tests/dbPolygon.cc b/src/db/unit_tests/dbPolygon.cc index b9c03fe41..6261e3d1f 100644 --- a/src/db/unit_tests/dbPolygon.cc +++ b/src/db/unit_tests/dbPolygon.cc @@ -79,6 +79,8 @@ TEST(1) b = p.box (); EXPECT_EQ (p.holes (), size_t (0)); EXPECT_EQ (p.area (), 1000*100); + EXPECT_EQ (p.area2 (), 2*1000*100); + EXPECT_EQ (tl::to_string (p.area_ratio ()), "1"); EXPECT_EQ (p.perimeter (), db::Polygon::perimeter_type (2200)); EXPECT_EQ (p.is_box (), true); @@ -103,6 +105,8 @@ TEST(1) EXPECT_EQ (ip.vertices (), size_t (12)); EXPECT_EQ (p.area (), 1000*100-2*380*80); + EXPECT_EQ (p.area2 (), 2*(1000*100-2*380*80)); + EXPECT_EQ (tl::to_string (p.area_ratio (), 6), "2.55102"); EXPECT_EQ (p.perimeter (), db::Polygon::perimeter_type (2000+200+4*(380+80))); EXPECT_EQ (p.is_box (), false); EXPECT_EQ (p.box (), b); @@ -121,6 +125,7 @@ TEST(1) pp.insert_hole (c2.begin (), c2.end ()); pp.assign_hull (c1.begin (), c1.end ()); EXPECT_EQ (pp.area (), 1000*100-2*380*80); + EXPECT_EQ (pp.area2 (), 2*(1000*100-2*380*80)); EXPECT_EQ (pp.box (), b); EXPECT_EQ (p, pp); @@ -163,6 +168,8 @@ TEST(2) b = p.box (); EXPECT_EQ (p.holes (), size_t (0)); EXPECT_EQ (p.area (), 1000*100); + EXPECT_EQ (p.area2 (), 2*1000*100); + EXPECT_EQ (tl::to_string (p.area_ratio ()), "1"); EXPECT_EQ (p.perimeter (), db::SimplePolygon::perimeter_type (2000+200)); EXPECT_EQ (p.is_box (), true); @@ -460,8 +467,11 @@ TEST(5) } EXPECT_EQ (p.area (), 100*1000-10*100); + EXPECT_EQ (p.area2 (), 2*(100*1000-10*100)); + EXPECT_EQ (tl::to_string (p.area_ratio (), 6), "1.0101"); EXPECT_EQ (p.perimeter (), db::Polygon::perimeter_type (200+2000+20+200)); EXPECT_EQ (pref.area (), 100*1000-10*100); + EXPECT_EQ (pref.area2 (), 2*(100*1000-10*100)); EXPECT_EQ (pref.perimeter (), db::Polygon::perimeter_type (200+2000+20+200)); }