diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 5873ed3c5..6148e5db7 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -858,6 +858,7 @@ do_extract_rad_from_contour (typename db::polygon::polygon_contour_iterator f typename db::polygon::polygon_contour_iterator p2 = p1; const double cos_thr = 0.8; + const double acute_cos_thr = -0.8; const double circle_segment_thr = 2.5; // search for the first circle segment (where cos(a) > cos_thr) @@ -1031,7 +1032,7 @@ do_extract_rad_from_contour (typename db::polygon::polygon_contour_iterator f if (in_corner) { std::pair > cp = elast.cut_point (e); - if (! cp.first) { + if (! cp.first || db::sprod (elast, e) < acute_cos_thr * elast.double_length () * e.double_length ()) { // We have a full 180 degree bend without a stop (actually two corners). // Use the segment in between that is perpendicular to the start and end segment as stop edge. @@ -1048,7 +1049,7 @@ do_extract_rad_from_contour (typename db::polygon::polygon_contour_iterator f } e = db::edge (*pp1, *pp2); - if (db::sprod_sign (elast, e) == 0) { + if (db::sprod_sign (elast, e) <= 0) { break; } @@ -1059,6 +1060,13 @@ do_extract_rad_from_contour (typename db::polygon::polygon_contour_iterator f } + ++nseg_part; + + if (nseg_part >= nseg) { + // not a valid rounded bend - skip this solution + return false; + } + cp = elast.cut_point (e); if (! cp.first) { return false; @@ -1068,8 +1076,6 @@ do_extract_rad_from_contour (typename db::polygon::polygon_contour_iterator f new_pts->push_back (cp.second); } - ++nseg_part; - asum -= asum_part; asum -= db::vprod (e.p1 () - db::point (), e.p2 () - db::point ()); nseg -= nseg_part; diff --git a/src/db/unit_tests/dbPolygonTools.cc b/src/db/unit_tests/dbPolygonToolsTests.cc similarity index 95% rename from src/db/unit_tests/dbPolygonTools.cc rename to src/db/unit_tests/dbPolygonToolsTests.cc index 5e6d4fb9b..9c9ebfd29 100644 --- a/src/db/unit_tests/dbPolygonTools.cc +++ b/src/db/unit_tests/dbPolygonToolsTests.cc @@ -1555,6 +1555,120 @@ TEST(204) EXPECT_EQ (pr.to_string (), "(0,0;0,40000;40000,40000;40000,0/10000,10000;30000,10000;30000,30000;10000,30000)"); } +// rounding +TEST(205_issue318) +{ + db::Point pattern [] = { + db::Point (0, 0), + db::Point (0, 420000), + db::Point (400000, 400000), + db::Point (400000, 0), + }; + + db::Polygon p; + p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); + + double rinner = 0.0, router = 0.0; + unsigned int n; + db::Polygon pr; + db::Polygon pp = compute_rounded (p, 100000, 200000, 64); + EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); + + EXPECT_EQ (tl::to_string (rinner), "0"); + EXPECT_EQ (tl::to_string (router), "200000"); + EXPECT_EQ (tl::to_string (n), "64"); + // slight rounding errors, but still a good approximation ... + EXPECT_EQ (pr.to_string (), "(0,0;0,419998;400000,400002;400000,0)"); + + pp = compute_rounded (p, 50000, 100000, 64); + EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); + + EXPECT_EQ (tl::to_string (rinner), "0"); + EXPECT_EQ (tl::to_string (router), "100000"); + EXPECT_EQ (tl::to_string (n), "64"); + // slight rounding issue due to ... + EXPECT_EQ (pr.to_string (), "(0,0;0,420001;400000,400000;400000,0)"); +} + +// rounding +TEST(206_issue318) +{ + db::Point pattern [] = { + db::Point (0, 0), + db::Point (0, 40000000), + db::Point (400000, 400000), + db::Point (400000, 0), + }; + + db::Polygon p; + p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); + + double rinner = 0.0, router = 0.0; + unsigned int n; + db::Polygon pr; + db::Polygon pp = compute_rounded (p, 100000, 200000, 64); + EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); + + EXPECT_EQ (tl::to_string (rinner), "0"); + EXPECT_EQ (tl::to_string (router), "199992"); + EXPECT_EQ (tl::to_string (n), "65"); + // good approximation of a top edge ... + EXPECT_EQ (pr.to_string (), "(0,0;0,618467;400000,581242;400000,0)"); + + pp = compute_rounded (p, 50000, 100000, 64); + EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); + + EXPECT_EQ (tl::to_string (rinner), "0"); + EXPECT_EQ (tl::to_string (router), "100000"); + EXPECT_EQ (tl::to_string (n), "64"); + // the acute corner is split into two parts + EXPECT_EQ (pr.to_string (), "(0,0;0,20309228;199083,20290710;400000,400000;400000,0)"); +} + +// rounding +TEST(207_issue318) +{ + db::Point pattern [] = { + db::Point(-2523825, -4693678), + db::Point(-2627783, -4676814), + db::Point(-2705532, -4629488), + db::Point(-2747861, -4559084), + db::Point(-2750596, -4499543), + db::Point(-2753284, -4335751), + db::Point(-2764621, -4271381), + db::Point(-2828260, -4154562), + db::Point(-2808940, -4144038), + db::Point(-2743579, -4264019), + db::Point(-2731316, -4333649), + db::Point(-2728604, -4498857), + db::Point(-2726139, -4552516), + db::Point(-2689468, -4613512), + db::Point(-2620017, -4655786), + db::Point(-2529175, -4670522), + db::Point(-2468652, -4627768), + db::Point(-2437469, -4536777), + db::Point(-2434902, -4384723), + db::Point(-2436252, -4320529), + db::Point(-2395450, -4234678), + db::Point(-2338494, -4144716), + db::Point(-2319906, -4156484), + db::Point(-2376150, -4245322), + db::Point(-2414148, -4325271), + db::Point(-2412898, -4384677), + db::Point(-2415531, -4540623), + db::Point(-2450148, -4641632) + }; + + db::Polygon p; + p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); + + double rinner = 0.0, router = 0.0; + unsigned int n; + db::Polygon pr; + // this polygon should not be recognized as rounded - it kind of looks like ... + EXPECT_EQ (extract_rad (p, rinner, router, n, &pr), false); +} + // is_convex TEST(300) { diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index f3e14367f..68b975953 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -37,7 +37,6 @@ SOURCES = \ dbPCells.cc \ dbPoint.cc \ dbPolygon.cc \ - dbPolygonTools.cc \ dbPropertiesRepository.cc \ dbRegion.cc \ dbShapeArray.cc \ @@ -72,7 +71,8 @@ SOURCES = \ dbDeepEdgePairsTests.cc \ dbNetlistCompareTests.cc \ dbNetlistReaderTests.cc \ - dbLayoutVsSchematicTests.cc + dbLayoutVsSchematicTests.cc \ + dbPolygonToolsTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC