From e53ad06be0b4294236eac515795a8fe440c7816f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 21 Aug 2026 23:33:27 +0200 Subject: [PATCH 1/5] Bugfix: triangulation_max_area/min_b was not properly configured, hence ineffective. --- src/pex/pex/pexRNetExtractor.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pex/pex/pexRNetExtractor.cc b/src/pex/pex/pexRNetExtractor.cc index aa724090a..b17a7b32d 100644 --- a/src/pex/pex/pexRNetExtractor.cc +++ b/src/pex/pex/pexRNetExtractor.cc @@ -339,6 +339,8 @@ class ExtractingReceiver case RExtractorTechConductor::Tesselation: { pex::TriangulationRExtractor rex (m_dbu); + rex.triangulation_parameters ().max_area = mp_cond->triangulation_max_area; + rex.triangulation_parameters ().min_b = mp_cond->triangulation_min_b; rex.extract (poly, local_vertex_ports, local_polygon_ports, local_network); } break; From 0c8a3387eed1430ede29d625d9d4cbecb5055cdf Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 22 Aug 2026 17:35:25 +0200 Subject: [PATCH 2/5] WIP --- src/db/db/dbPLCTriangulation.cc | 96 +++++++++++--------- src/db/db/dbPLCTriangulation.h | 8 +- src/db/unit_tests/dbPLCTriangulationTests.cc | 5 +- 3 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/db/db/dbPLCTriangulation.cc b/src/db/db/dbPLCTriangulation.cc index f59ec1a68..dff58d45b 100644 --- a/src/db/db/dbPLCTriangulation.cc +++ b/src/db/db/dbPLCTriangulation.cc @@ -46,7 +46,7 @@ static inline bool is_equal (const db::DPoint &a, const db::DPoint &b) const double snap_to_edge_vertex = 1e-5; // distance of point to edge center to be considered "on edge center" relative to edge length involved -double snap_to_edge_center = 1e-3; +const double snap_to_edge_center = 1e-3; Triangulation::Triangulation (Graph *graph) @@ -224,84 +224,86 @@ Triangulation::find_points_around (Vertex *vertex, double radius) } Vertex * -Triangulation::insert_point (const db::DPoint &point, std::list > *new_triangles) +Triangulation::insert_point (const db::DPoint &point, std::list > *new_triangles, double snap) { - return insert (mp_graph->create_vertex (point), new_triangles); + return insert (mp_graph->create_vertex (point), new_triangles, snap); } Vertex * -Triangulation::insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles) +Triangulation::insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles, double snap) { - return insert (mp_graph->create_vertex (x, y), new_triangles); + return insert (mp_graph->create_vertex (x, y), new_triangles, snap); } Vertex * -Triangulation::insert (Vertex *vertex, std::list > *new_triangles) +Triangulation::insert (Vertex *vertex, std::list > *new_triangles, double snap) { - std::vector tris = find_triangle_for_point (*vertex); + Polygon *in_triangle = 0; + Edge *on_edge = 0; + + if (! find_triangle_for_point (*vertex, snap, in_triangle, on_edge)) { - // the new vertex is outside the domain - if (tris.empty ()) { + // the new vertex is outside the domain tl_assert (! m_is_constrained); insert_new_vertex (vertex, new_triangles); return vertex; - } - // check, if the new vertex is on an edge (may be edge between triangles or edge on outside) - Edge *on_edge = 0; - std::vector on_vertex; - for (int i = 0; i < 3; ++i) { + } - Edge *e = tris.front ()->edge (i); + if (on_edge) { - double snap_range = snap_to_edge_vertex * e->length (); + // double snap_range = std::max (db::epsilon, snap_to_edge_vertex * e->length ()); @@@ + double snap_range = std::max (db::epsilon, snap * on_edge->length ()); - if (std::abs (e->edge ().distance (*vertex)) < snap_range - db::epsilon) { - if (vertex->distance (*e->v1 ()) < snap_range + db::epsilon || vertex->distance (*e->v2 ()) < snap_range + db::epsilon) { - on_vertex.push_back (e); - } else if (! on_edge) { - on_edge = e; - } + if (snap > 0.0 ? vertex->distance (*on_edge->v1 ()) < snap_range : is_equal (*vertex, *on_edge->v1 ())) { + return on_edge->v1 (); + } else if (snap > 0.0 ? vertex->distance (*on_edge->v2 ()) < snap_range : is_equal (*vertex, *on_edge->v2 ())) { + return on_edge->v2 (); + } else { + split_triangles_on_edge (vertex, on_edge, new_triangles); + return vertex; } - } - - if (on_edge) { + } else if (in_triangle) { - split_triangles_on_edge (vertex, on_edge, new_triangles); + split_triangle (in_triangle, vertex, new_triangles); return vertex; - } else if (! on_vertex.empty ()) { - - tl_assert (on_vertex.size () == size_t (2)); - return on_vertex.front ()->common_vertex (on_vertex [1]); - - } else if (tris.size () == size_t (1)) { + } else { - // the new vertex is inside one triangle - split_triangle (tris.front (), vertex, new_triangles); - return vertex; + tl_assert (false); + return 0; } - - tl_assert (false); } -std::vector -Triangulation::find_triangle_for_point (const db::DPoint &point) +bool Triangulation::find_triangle_for_point (const db::DPoint &point, double snap, Polygon *&in_triangle, Edge *&on_edge) { Edge *edge = find_closest_edge (point); - std::vector res; if (edge) { - for (auto t = edge->begin_polygons (); t != edge->end_polygons (); ++t) { - if (t->contains (point) >= 0) { - res.push_back (t.operator-> ()); + + double snap_range = std::max (db::epsilon, snap * edge->length ()); + + if (snap > 0.0 ? std::abs (edge->edge ().distance (point)) < snap_range : edge->side_of (point) == 0) { + + on_edge = edge; + return true; + + } else { + + for (auto t = edge->begin_polygons (); t != edge->end_polygons (); ++t) { + if (t->contains (point) >= 0) { + in_triangle = t.operator-> (); + return true; + } } + } + } - return res; + return false; } Edge * @@ -1378,8 +1380,14 @@ void Triangulation::make_contours (const Poly &poly, const Trans &trans, std::vector > &edge_contours) { edge_contours.push_back (std::vector ()); +// @@@int id = 0; // @@@ for (auto pt = poly.begin_hull (); pt != poly.end_hull (); ++pt) { +// @@@if (id == 27) { // @@@ +// @@@tl::info << "@@@ BANG!"; // @@@ +// @@@} // @@@ + // @@@ edge_contours.back ().push_back (insert_point (trans * *pt, 0, snap_to_edge_vertex)); edge_contours.back ().push_back (insert_point (trans * *pt)); +// @@@++id; mp_graph->dump ("xxx" + tl::to_string(id) + ".gds"); tl::info << "@@@ xxx" << id; // @@@ } for (unsigned int h = 0; h < poly.holes (); ++h) { diff --git a/src/db/db/dbPLCTriangulation.h b/src/db/db/dbPLCTriangulation.h index 8bcb790af..75b92a33c 100644 --- a/src/db/db/dbPLCTriangulation.h +++ b/src/db/db/dbPLCTriangulation.h @@ -163,7 +163,7 @@ class DB_PUBLIC Triangulation * This method can be called after "triangulate" to add new points and adjust the triangulation. * Inserting new points will maintain the (constrained) Delaunay condition. */ - Vertex *insert_point (const db::DPoint &point, std::list > *new_triangles = 0); + Vertex *insert_point (const db::DPoint &point, std::list > *new_triangles = 0, double snap = 0.0); /** * @brief Finds the edge for two given points @@ -286,7 +286,7 @@ class DB_PUBLIC Triangulation * If "new_triangles" is not null, it will receive the list of new triangles created during * the remove step. */ - Vertex *insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles = 0); + Vertex *insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles = 0, double snap = 0.0); /** * @brief Removes the given vertex @@ -335,9 +335,9 @@ class DB_PUBLIC Triangulation void remove_inside_vertex (Vertex *vertex, std::list > *new_triangles_out = 0); std::vector fill_concave_corners (const std::vector &edges); void fix_triangles (const std::vector &tris, const std::vector &fixed_edges, std::list > *new_triangles); - std::vector find_triangle_for_point (const db::DPoint &point); + bool find_triangle_for_point (const db::DPoint &point, double snap, Polygon *&in_triangle, Edge *&on_edge); Edge *find_closest_edge (const db::DPoint &p, Vertex *vstart = 0, bool inside_only = false) const; - Vertex *insert (Vertex *vertex, std::list > *new_triangles = 0); + Vertex *insert (Vertex *vertex, std::list > *new_triangles = 0, double snap = 0.0); void split_triangle (Polygon *t, Vertex *vertex, std::list > *new_triangles_out); void split_triangles_on_edge (Vertex *vertex, Edge *split_edge, std::list > *new_triangles_out); void add_more_triangles (std::vector &new_triangles, diff --git a/src/db/unit_tests/dbPLCTriangulationTests.cc b/src/db/unit_tests/dbPLCTriangulationTests.cc index 44b90ff97..ac253a6a7 100644 --- a/src/db/unit_tests/dbPLCTriangulationTests.cc +++ b/src/db/unit_tests/dbPLCTriangulationTests.cc @@ -1078,7 +1078,7 @@ TEST(triangulate_issue1996) EXPECT_LT (plc.num_polygons (), size_t (132000)); } -TEST(triangulate_discussion_2883) +TEST(triangulate_issue_2429) { db::DPoint contour[] = { db::DPoint (-13025.428, -33338.541), @@ -1114,10 +1114,11 @@ TEST(triangulate_discussion_2883) db::DPolygon poly; poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); - double dbu = 0.001; + double dbu = 1.0; db::plc::TriangulationParameters param; param.min_b = 0.3; + param.max_area = 500.0; // @@@ db::plc::Graph plc; TestableTriangulation tri (&plc); From 9fad2ff1facfe166342055df8a65dc9a395b7aa8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 22 Aug 2026 22:15:55 +0200 Subject: [PATCH 3/5] Fixing issue #2429 by introducing a rectangular envelope for triangulation Previously the algorithm tried to dynamically build a convex envelope. However, in case of the #2429 polygon, this rendered extremely skinny triangles which could not be removed. These caused numerical issues. --- src/db/db/dbPLC.cc | 8 +- src/db/db/dbPLC.h | 4 +- src/db/db/dbPLCTriangulation.cc | 47 ++++++---- src/db/unit_tests/dbPLCTriangulationTests.cc | 84 ++++++++++++++---- .../pexTriangulationRExtractorTests.cc | 2 +- testdata/algo/hm_decomposition_au1.gds | Bin 1636 -> 1636 bytes testdata/algo/hm_decomposition_au2.gds | Bin 1946 -> 1884 bytes testdata/algo/hm_decomposition_au3.gds | Bin 1492 -> 1540 bytes testdata/algo/hm_decomposition_au4.gds | Bin 1850 -> 1788 bytes testdata/algo/hm_decomposition_au5.gds | Bin 1322 -> 1322 bytes testdata/algo/hm_decomposition_au6.gds | Bin 2760 -> 2760 bytes testdata/algo/hm_decomposition_au7.gds | Bin 14920 -> 14824 bytes 12 files changed, 105 insertions(+), 40 deletions(-) diff --git a/src/db/db/dbPLC.cc b/src/db/db/dbPLC.cc index 8d85580ba..28f70b706 100644 --- a/src/db/db/dbPLC.cc +++ b/src/db/db/dbPLC.cc @@ -903,10 +903,10 @@ Graph::bbox () const } db::Layout * -Graph::to_layout (bool decompose_by_id) const +Graph::to_layout (bool decompose_by_id, double dbu) const { db::Layout *layout = new db::Layout (); - layout->dbu (0.001); + layout->dbu (dbu); auto dbu_trans = db::CplxTrans (layout->dbu ()).inverted (); @@ -950,9 +950,9 @@ Graph::to_layout (bool decompose_by_id) const } void -Graph::dump (const std::string &path, bool decompose_by_id) const +Graph::dump (const std::string &path, bool decompose_by_id, double dbu) const { - std::unique_ptr ly (to_layout (decompose_by_id)); + std::unique_ptr ly (to_layout (decompose_by_id, dbu)); tl::OutputStream stream (path); diff --git a/src/db/db/dbPLC.h b/src/db/db/dbPLC.h index 6e098e81c..b1b479517 100644 --- a/src/db/db/dbPLC.h +++ b/src/db/db/dbPLC.h @@ -879,13 +879,13 @@ class DB_PUBLIC Graph * according to bit 0, 1 and 2 of the ID (useful with the 'mark_polygons' * flat in TriangulateParameters). */ - void dump (const std::string &path, bool decompose_by_id = false) const; + void dump (const std::string &path, bool decompose_by_id = false, double dbu = 0.001) const; /** * @brief Creates a new layout object representing the polygon graph * This method is for testing purposes mainly. */ - db::Layout *to_layout (bool decompose_by_id = false) const; + db::Layout *to_layout (bool decompose_by_id = false, double dbu = 0.001) const; protected: Vertex *create_vertex (double x, double y); diff --git a/src/db/db/dbPLCTriangulation.cc b/src/db/db/dbPLCTriangulation.cc index dff58d45b..63b77c981 100644 --- a/src/db/db/dbPLCTriangulation.cc +++ b/src/db/db/dbPLCTriangulation.cc @@ -42,9 +42,6 @@ static inline bool is_equal (const db::DPoint &a, const db::DPoint &b) std::abs (a.y () - b.y ()) < std::max (1.0, (std::abs (a.y ()) + std::abs (b.y ()))) * db::epsilon; } -// distance of point to vertex to be considered "on edge vertex" relative to edge length involved -const double snap_to_edge_vertex = 1e-5; - // distance of point to edge center to be considered "on edge center" relative to edge length involved const double snap_to_edge_center = 1e-3; @@ -252,7 +249,6 @@ Triangulation::insert (Vertex *vertex, std::list > *new_tr if (on_edge) { - // double snap_range = std::max (db::epsilon, snap_to_edge_vertex * e->length ()); @@@ double snap_range = std::max (db::epsilon, snap * on_edge->length ()); if (snap > 0.0 ? vertex->distance (*on_edge->v1 ()) < snap_range : is_equal (*vertex, *on_edge->v1 ())) { @@ -1142,17 +1138,23 @@ static bool is_touching (const db::DEdge &a, const db::DEdge &b) std::vector Triangulation::ensure_edge_inner (Vertex *from, Vertex *to) { - auto crossed_edges = search_edges_crossing (from, to); std::vector result; + // check if there is an edge already + Edge *already_there = find_edge_for_points (*from, *to); + if (already_there) { + result.push_back (already_there); + return result; + } + + auto crossed_edges = search_edges_crossing (from, to); + db::DEdge dedge (*from , *to); if (crossed_edges.empty ()) { // no crossing edge - there should be a edge already - Edge *res = find_edge_for_points (*from, *to); - tl_assert (res != 0); - result.push_back (res); + tl_assert (false); } else if (crossed_edges.size () == 1 && ! is_touching (dedge, crossed_edges.front ()->edge ())) { @@ -1173,7 +1175,7 @@ Triangulation::ensure_edge_inner (Vertex *from, Vertex *to) db::DPoint p = (*e)->intersection_point (dedge); double dp = fabs ((p - *from).sq_length () - l_half); if (d < 0.0 || dp < d) { - dp = d; + d = dp; split_point = p; split_edge = *e; } @@ -1380,14 +1382,8 @@ void Triangulation::make_contours (const Poly &poly, const Trans &trans, std::vector > &edge_contours) { edge_contours.push_back (std::vector ()); -// @@@int id = 0; // @@@ for (auto pt = poly.begin_hull (); pt != poly.end_hull (); ++pt) { -// @@@if (id == 27) { // @@@ -// @@@tl::info << "@@@ BANG!"; // @@@ -// @@@} // @@@ - // @@@ edge_contours.back ().push_back (insert_point (trans * *pt, 0, snap_to_edge_vertex)); edge_contours.back ().push_back (insert_point (trans * *pt)); -// @@@++id; mp_graph->dump ("xxx" + tl::to_string(id) + ".gds"); tl::info << "@@@ xxx" << id; // @@@ } for (unsigned int h = 0; h < poly.holes (); ++h) { @@ -1404,6 +1400,9 @@ template DB_PUBLIC void Triangulation::make_contours (const db::DPolygon &, cons void Triangulation::create_constrained_delaunay (const db::Region ®ion, const CplxTrans &trans) { + std::vector > box_contours; + make_contours (db::Polygon (region.bbox ()), trans, box_contours); + std::vector > edge_contours; for (auto p = region.begin_merged (); ! p.at_end (); ++p) { @@ -1416,6 +1415,9 @@ Triangulation::create_constrained_delaunay (const db::Region ®ion, const Cplx void Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTrans &trans) { + std::vector > box_contours; + make_contours (db::Polygon (p.box ()), trans, box_contours); + std::vector > edge_contours; make_contours (p, trans, edge_contours); @@ -1425,6 +1427,9 @@ Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTran void Triangulation::create_constrained_delaunay (const db::DPolygon &p, const DCplxTrans &trans) { + std::vector > box_contours; + make_contours (db::DPolygon (p.box ()), trans, box_contours); + std::vector > edge_contours; make_contours (p, trans, edge_contours); @@ -1493,6 +1498,9 @@ Triangulation::triangulate (const db::Region ®ion, const std::vector > box_contours; + make_contours (db::Polygon (region.bbox ()), trans, box_contours); + std::vector > edge_contours; for (auto p = region.begin_merged (); ! p.at_end (); ++p) { make_contours (*p, trans, edge_contours); @@ -1522,6 +1530,9 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector > box_contours; + make_contours (db::Polygon (poly.box ()), trans, box_contours); + std::vector > edge_contours; make_contours (poly, trans, edge_contours); @@ -1547,6 +1558,9 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector > box_contours; + make_contours (db::Polygon (poly.box ()), trans, box_contours); + std::vector > edge_contours; make_contours (poly, trans, edge_contours); @@ -1572,6 +1586,9 @@ Triangulation::triangulate (const db::DPolygon &poly, const std::vector > box_contours; + make_contours (db::DPolygon (poly.box ()), trans, box_contours); + std::vector > edge_contours; make_contours (poly, trans, edge_contours); diff --git a/src/db/unit_tests/dbPLCTriangulationTests.cc b/src/db/unit_tests/dbPLCTriangulationTests.cc index ac253a6a7..5a81b5ca1 100644 --- a/src/db/unit_tests/dbPLCTriangulationTests.cc +++ b/src/db/unit_tests/dbPLCTriangulationTests.cc @@ -896,8 +896,8 @@ TEST(triangulate_geo) } EXPECT_LT (n_skinny, size_t (20)); - EXPECT_GT (plc.num_polygons (), size_t (29000)); - EXPECT_LT (plc.num_polygons (), size_t (30000)); + EXPECT_GT (plc.num_polygons (), size_t (30000)); + EXPECT_LT (plc.num_polygons (), size_t (30200)); } TEST(triangulate_analytic) @@ -951,8 +951,8 @@ TEST(triangulate_analytic) EXPECT_GE (t->b (), param.min_b); } - EXPECT_GT (plc.num_polygons (), size_t (1250)); - EXPECT_LT (plc.num_polygons (), size_t (1300)); + EXPECT_GT (plc.num_polygons (), size_t (1300)); + EXPECT_LT (plc.num_polygons (), size_t (1340)); } TEST(triangulate_problematic) @@ -1116,26 +1116,74 @@ TEST(triangulate_issue_2429) double dbu = 1.0; - db::plc::TriangulationParameters param; - param.min_b = 0.3; - param.max_area = 500.0; // @@@ + { + db::plc::TriangulationParameters param; + param.min_b = 0.3; + param.max_area = 0.0; - db::plc::Graph plc; - TestableTriangulation tri (&plc); - db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ())); - tri.triangulate (trans * poly, param); + db::plc::Graph plc; + TestableTriangulation tri (&plc); + db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ())); + tri.triangulate (trans * poly, param); - EXPECT_EQ (tri.check (false), true); + EXPECT_EQ (tri.check (false), true); - // for debugging: - // tri.dump ("debug.gds"); + // for debugging: + // tri.dump ("debug.gds"); - for (auto t = plc.begin (); t != plc.end (); ++t) { - EXPECT_GE (t->b (), param.min_b); + for (auto t = plc.begin (); t != plc.end (); ++t) { + EXPECT_GE (t->b (), param.min_b); + } + + EXPECT_GE (plc.num_polygons (), size_t (65)); + EXPECT_LE (plc.num_polygons (), size_t (67)); + } + + { + db::plc::TriangulationParameters param; + param.min_b = 0.3; + param.max_area = 500.0; + + db::plc::Graph plc; + TestableTriangulation tri (&plc); + db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ())); + tri.triangulate (trans * poly, param); + + EXPECT_EQ (tri.check (false), true); + + // for debugging: + // tri.dump ("debug.gds"); + + for (auto t = plc.begin (); t != plc.end (); ++t) { + EXPECT_GE (t->b (), param.min_b); + } + + EXPECT_GE (plc.num_polygons (), size_t (94)); + EXPECT_LE (plc.num_polygons (), size_t (96)); } - EXPECT_GE (plc.num_polygons (), size_t (70)); - EXPECT_LE (plc.num_polygons (), size_t (72)); + { + db::plc::TriangulationParameters param; + param.min_b = 0.9; + param.max_area = 50.0; + + db::plc::Graph plc; + TestableTriangulation tri (&plc); + db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ())); + tri.triangulate (trans * poly, param); + + EXPECT_EQ (tri.check (false), true); + + // for debugging: + // tri.dump ("debug.gds"); + + for (auto t = plc.begin (); t != plc.end (); ++t) { + EXPECT_GE (t->b (), param.min_b); + } + + EXPECT_GE (plc.num_polygons (), size_t (670)); + EXPECT_LE (plc.num_polygons (), size_t (676)); + } } TEST(triangulate_with_vertexes) diff --git a/src/pex/unit_tests/pexTriangulationRExtractorTests.cc b/src/pex/unit_tests/pexTriangulationRExtractorTests.cc index d441c0ee1..9d1689deb 100644 --- a/src/pex/unit_tests/pexTriangulationRExtractorTests.cc +++ b/src/pex/unit_tests/pexTriangulationRExtractorTests.cc @@ -357,7 +357,7 @@ TEST(extraction_meander) rex.extract (poly, vertex_ports, polygon_ports, rn); EXPECT_EQ (rn.to_string (), - "R V0 V1 8.61417" // what is the "real" value? + "R V0 V1 8.60459" // what is the "real" value? ) } diff --git a/testdata/algo/hm_decomposition_au1.gds b/testdata/algo/hm_decomposition_au1.gds index dd04b81d925b3ab992d3ac34c8e92a3a3deff618..06bfe96bce771292da2a0f5c71cb183a37711afe 100644 GIT binary patch literal 1636 zcmb7^u};G<5QhIasT+`>K@`f+1&IkEbwNd4kU(7!MPdL6G52BM8CbgU3OoT%(1$>X zfq@aJ+}U>_GNg4fA_Czr3! zpQG{1VD@x>gMMoXXYKg*>Ka)N*bRdOcGCbjDpH^`qY*vMPJ!(Q`XE~j-EZ}0Tlk;% zv*b-&`sR6Of1R~_b$;?iK_-A&&O`jQd@)=szV|5a49p`&sUnXi775JB*})J1mk?HRQ&Kq=IuEOUY@L+o2)VEJIf>lCRnuZMp?A F`~VIcgh&7Y delta 349 zcmaFD^MoggfsKKQDS|{L4=vr&au&crL9pqI6m>C#Y*%-ip z`2~#BC5&Gf7?@v7PGHvI0;z;@&oCP>F{DgB z!E7-30t?6F92T=lEP8AZqbDz5F<|2`0a-FR2B@HpiGzuM0muZPS~D*G1rYmyLO}cY zgx^367487hlN(qKCx2$roqUhgj7$6qM5XW>u;vsNv&luQW*`@e0wtjSU=aj*fgOlh F7yy4pM`Hj0 diff --git a/testdata/algo/hm_decomposition_au2.gds b/testdata/algo/hm_decomposition_au2.gds index 279d6e3c44487a9b9a5775341f197837decceaf4..3c7853d9d28b9f0cad9b4590e657efbe0d4eacea 100644 GIT binary patch delta 285 zcmbQme}_+rfsKKQDS||Ifd1Xi^Bw@ih%*BDUVfWau18y>`u1SX3sjV#}KB#cnoPgk6M<9q0@e1_1jELtFp= delta 291 zcmZvWF-rqM6olWt-F>%gf{C7@g^h>lwg?iou)4G&Vk3x%m81yy2Z~r&1PkGu&O-77 z{0aFPsl>uMq)aXDMGy;LHO%*Bn2)uWRzX6{=d`Oho0Fq0TBi;*{_3je+$W?HHs3@8wwfprUGzS2h7y?76JFbJ6>JI%S7;qo>QeF0-;#7E*@y zuc_2m)Co;|g?b68s5(N**OrxfrU6y!Fd-H7qmc4NcikYQdh_2sy1F-_&Jy}c-S5@D qqT43)70nnS<*VUtu#k%8kd$)M!cDJ+RI>=pc~OJZd!tQLpui97@p!WU delta 304 zcmZqSxx%f)z{bGD6u}_F$i)7NfrCMmL6AX}fg71UQAt%8n{ZU5u!{gQ11dkT&CDe!;-N_=SOi`Nbq=9WE9h7;kb8 zvjG!B%H#}YgUJOf9Fuui%qA~j)?jLVBj!8q8TQ;F{)19%;-81W%2IhZ(1CI>L-z!bk@GT;O0WBkIv0I~wC*kJM`X1&QQtY%yY+a~j|>P*&Q zF`GPt#f(e9?En8i5)2FiW?*3jc2-uPef$eRCW9=v$C?Fp0?1V1H*hBuu$oOSVC7&E jzXDP?S%F<-G8c==WG}X?$*fss*8rIW2ly}uhy!aR1=vVg+p5{yF?;J3CHRTALw`Oux`A}-G|;eHq3>~#zbmDlnvq{hT2Ou th!SeNg}Y?OExyKZNQ`5j6TzpsL|6LQWs8x_U`28~iieX0sf70peF22yKP>w(PIh7RnEZ=T zX|ez-%j8+iMw6d0noZVXHk&NNWX2|bg@J+j-sCX$XLd}V9Wv*W@1@1If2<~vIwgf0AO$?&j0`b delta 184 zcmZ3*wTerLfsKKQDS|y<_5Sc8-a%A!uX0yq8EF6>n0Hp+2r2y5$ BDq{cu diff --git a/testdata/algo/hm_decomposition_au6.gds b/testdata/algo/hm_decomposition_au6.gds index 1c81106dcd6df06a52c94c0bc3bfbed5bd90d21c..88a0fac6564773cafcda97549853775b1e0c7c1c 100644 GIT binary patch delta 258 zcmX>hdO|dcfsKKQDS|{L4=vr&au%nZyO2 Q7t>p~PymhdO|dcfsKKQDS|{L4=vr&au z@3HDk=HcR)e1}zUa~Ycp<75Xmv(3BMH!x0Kz{xT>g-HOc0mx=zI59bo)nM{9&QAb8 CtUv|; diff --git a/testdata/algo/hm_decomposition_au7.gds b/testdata/algo/hm_decomposition_au7.gds index cae3d5cb19c454d231e00b4849f227b202c2f199..84854aa307107874c01767a05c60ce6c16b597ff 100644 GIT binary patch delta 1703 zcmZuxZD?C%6uwDwZ*G#_G->*oG-;MJS#$H9o7~*$DiOCCaluVt)S+cMklJ=7P{C~- zMFfA0>S%p%paorR#{@;|@~=u)=bu4m*(S)`hYZxA8yiI(ZC6=5_a>_j{PFTU=XuY2 z-gC}9?>+n4Z^J%@WAyqSrcI|e-eh>DiD_iI81BD(!WVG-pS-6HujmRB-}X!l?}SU2 zhu@ILtr`U*`U5EG&f-(98^sz4!|W`6<`hiVay#FEF__qcD3y0+SCh-)@s2dyi#D&CyKU-ewFzl`fbNO-Vc zId84=<9$aeoK|D37U(91Fh&?8bPzs6_#h)KLo8X{kn9R-8gh;u+PSLV$~yTU!ks#o zJ5RYs=w!8qjR=}2hU%Y1ks{32<*;mf!cvKHld>MeV^+Vr+KEaH|JJmsc}#rnM4~<^ zRIgaMKvx;@Q@yLP+Nh07H4lv1GT2v_N6AK?UZ7>qAzY{6N~;xLw#IR(Q36_eaI0aP z$9P+5*}a}p89|95ZRiJ`KJAtY^2F@C9$>XNramz6xsV)b66){YEUrHoQK1y zpwwJIXDdxpi=x|sEiD1I5~H^z1Ba^*mZm($XkBUTMjxf{w3DXB*@YW^AC_F#;dIAw zt&PVncZ}_)42Cf0P7341)ci`cBJjFHY=tem6Bu=y47VAE!%G>FRmnBH;7JNBu~Sq^ zGvQk}?+LLLcHfi4J04yaM?#EP`8aI{$Sut<>|GRP(Lh(6$Dlu9=8h0ur2RR>f+7|? z7G&F_;JjH(wrAk;$vEFGm$rCs=+NW)k)0#=Gx)46frOvuj7?-t!6u3L(BIFk{I2Cu z3@1%@iOrPDE9=?7i(2Q z!Xn{G*t{Z+1}%t-VcZKU=-WJ9dc5<7j=eyc25>GI!yZw=crc5yILKZmbvKs8G-kpQ zzDpUYS{k5}I4*|R3LA|i*~_H;fUDu8pv^87evW21i}64RzeX~sjmU6DW$W5@N}``u zGp&Pa5PT7l1`D8DxcVoc5vE@k_1Ej}gduy$ zS~1lJpnVEezM7S>yGw>5$;c~NIFt-Vl|gt(d%Npn*wQ9@<>edf3}c{}1_SdCt>EvJ delta 1742 zcmZuxZD>vcqfl%kvf;cy&unnzF5yoa}#q8wXcKTyKUY_&$ z+;h%7?|Wz0h21MSo--N?oX21^-{l0Zfve>Lob7ped__R~Kl4Tpe1`n^`2q$Ex$#}= zF=4y_**FaFy%=NNn5a@QW6ELCprUBVLFD(sX3k-T&*HbLDa^1unphUY6!)b`Mn6;W zms!PxWf0q|lUQrrhOm&ugtdS}<^qbs2Ar~GkhQ3IXrp-I>b9v6ttxievOx705Xe3t z2hg}YvbU(5luYhugkk8V)RC^U8(R-?K(fUf2w&es<(+oS?bS%{5U^w;;|Jz{EVk}=zob<=<1 zIP+B+Ymo3`!eNdR7~u#eWfx5D95y%af!~#Y8d`xt_neWR$EART5swWu{wQzWL79W- z^CawJB(0;PTc$lBc9k?94?JC_iVv^LA&2=s$MH8w(|t}Q#28slVxu?C3ymc1!vXTVJIkJuvNvctqNXj%@oD9KMXid zO6i54?ep}-A|;(BJcl7)i0RT{UmQLDo!HxMfww))KU$=qlZXdGxZf_IzdcrcfKmqO zrwkEN3ms?+*jS#Fh!*yFKww%3zK&MvG9ST~K-{`O#hZ(ib{9^+go8mFehkFyC&+r4 zmSGR!48}S`Oq2Ep<9HIXu#1&Ok(IVus9=5{-HIFgeG+;)RK$Y{c6S`Z_wDJTtMj&j z-JpmKaCF2FmsGq6Jb?K0zG zIKi}gNWKW9sEl=yG)_kp>+%{eG~#JW!p5i-=OQt_bby*TgG;wvjXMtqPI40$}1C4mN_JuA4JsMKvjn`*+rL>&908T$}%-lPbfoBjdQ zo*eWfHws)f`3RqN%lzBQCv^f^VE{b#Qh6dQ4sC` From a8669d35ce82358e837b3159eaa7c5dccb53001e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 22 Aug 2026 22:21:01 +0200 Subject: [PATCH 4/5] Cleanup --- src/db/db/dbPLCTriangulation.cc | 24 ++++++++++-------------- src/db/db/dbPLCTriangulation.h | 8 ++++---- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/db/db/dbPLCTriangulation.cc b/src/db/db/dbPLCTriangulation.cc index 63b77c981..28084ae89 100644 --- a/src/db/db/dbPLCTriangulation.cc +++ b/src/db/db/dbPLCTriangulation.cc @@ -221,24 +221,24 @@ Triangulation::find_points_around (Vertex *vertex, double radius) } Vertex * -Triangulation::insert_point (const db::DPoint &point, std::list > *new_triangles, double snap) +Triangulation::insert_point (const db::DPoint &point, std::list > *new_triangles) { - return insert (mp_graph->create_vertex (point), new_triangles, snap); + return insert (mp_graph->create_vertex (point), new_triangles); } Vertex * -Triangulation::insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles, double snap) +Triangulation::insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles) { - return insert (mp_graph->create_vertex (x, y), new_triangles, snap); + return insert (mp_graph->create_vertex (x, y), new_triangles); } Vertex * -Triangulation::insert (Vertex *vertex, std::list > *new_triangles, double snap) +Triangulation::insert (Vertex *vertex, std::list > *new_triangles) { Polygon *in_triangle = 0; Edge *on_edge = 0; - if (! find_triangle_for_point (*vertex, snap, in_triangle, on_edge)) { + if (! find_triangle_for_point (*vertex, in_triangle, on_edge)) { // the new vertex is outside the domain tl_assert (! m_is_constrained); @@ -249,11 +249,9 @@ Triangulation::insert (Vertex *vertex, std::list > *new_tr if (on_edge) { - double snap_range = std::max (db::epsilon, snap * on_edge->length ()); - - if (snap > 0.0 ? vertex->distance (*on_edge->v1 ()) < snap_range : is_equal (*vertex, *on_edge->v1 ())) { + if (is_equal (*vertex, *on_edge->v1 ())) { return on_edge->v1 (); - } else if (snap > 0.0 ? vertex->distance (*on_edge->v2 ()) < snap_range : is_equal (*vertex, *on_edge->v2 ())) { + } else if (is_equal (*vertex, *on_edge->v2 ())) { return on_edge->v2 (); } else { split_triangles_on_edge (vertex, on_edge, new_triangles); @@ -273,15 +271,13 @@ Triangulation::insert (Vertex *vertex, std::list > *new_tr } } -bool Triangulation::find_triangle_for_point (const db::DPoint &point, double snap, Polygon *&in_triangle, Edge *&on_edge) +bool Triangulation::find_triangle_for_point (const db::DPoint &point, Polygon *&in_triangle, Edge *&on_edge) { Edge *edge = find_closest_edge (point); if (edge) { - double snap_range = std::max (db::epsilon, snap * edge->length ()); - - if (snap > 0.0 ? std::abs (edge->edge ().distance (point)) < snap_range : edge->side_of (point) == 0) { + if (edge->side_of (point) == 0) { on_edge = edge; return true; diff --git a/src/db/db/dbPLCTriangulation.h b/src/db/db/dbPLCTriangulation.h index 75b92a33c..8c352514c 100644 --- a/src/db/db/dbPLCTriangulation.h +++ b/src/db/db/dbPLCTriangulation.h @@ -163,7 +163,7 @@ class DB_PUBLIC Triangulation * This method can be called after "triangulate" to add new points and adjust the triangulation. * Inserting new points will maintain the (constrained) Delaunay condition. */ - Vertex *insert_point (const db::DPoint &point, std::list > *new_triangles = 0, double snap = 0.0); + Vertex *insert_point (const db::DPoint &point, std::list > *new_triangles = 0); /** * @brief Finds the edge for two given points @@ -286,7 +286,7 @@ class DB_PUBLIC Triangulation * If "new_triangles" is not null, it will receive the list of new triangles created during * the remove step. */ - Vertex *insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles = 0, double snap = 0.0); + Vertex *insert_point (db::DCoord x, db::DCoord y, std::list > *new_triangles = 0); /** * @brief Removes the given vertex @@ -335,9 +335,9 @@ class DB_PUBLIC Triangulation void remove_inside_vertex (Vertex *vertex, std::list > *new_triangles_out = 0); std::vector fill_concave_corners (const std::vector &edges); void fix_triangles (const std::vector &tris, const std::vector &fixed_edges, std::list > *new_triangles); - bool find_triangle_for_point (const db::DPoint &point, double snap, Polygon *&in_triangle, Edge *&on_edge); + bool find_triangle_for_point (const db::DPoint &point, Polygon *&in_triangle, Edge *&on_edge); Edge *find_closest_edge (const db::DPoint &p, Vertex *vstart = 0, bool inside_only = false) const; - Vertex *insert (Vertex *vertex, std::list > *new_triangles = 0, double snap = 0.0); + Vertex *insert (Vertex *vertex, std::list > *new_triangles = 0); void split_triangle (Polygon *t, Vertex *vertex, std::list > *new_triangles_out); void split_triangles_on_edge (Vertex *vertex, Edge *split_edge, std::list > *new_triangles_out); void add_more_triangles (std::vector &new_triangles, From 88568c8983b44b1e95c2485947cc38e7946f5601 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 23 Aug 2026 10:05:43 +0200 Subject: [PATCH 5/5] Fixing unit tests --- testdata/ruby/dbPolygonTest.rb | 8 ++++---- testdata/ruby/dbSimplePolygonTest.rb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index 14e6f1983..b5df2cdef 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -1062,15 +1062,15 @@ def test_hm_decomposition assert_equal(sorted_polygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") assert_equal(sorted_polygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)") assert_equal(sorted_polygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") - assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)") - assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") + assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)") + assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") p = RBA::DPolygon::new([ [0, 0], [0, 100], [1000, 100], [1000, 1000], [1100, 1000], [1100, 100], [2200, 100], [2200, 0] ]) assert_equal(sorted_dpolygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") assert_equal(sorted_dpolygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)") assert_equal(sorted_dpolygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") - assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)") - assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") + assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)") + assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") end diff --git a/testdata/ruby/dbSimplePolygonTest.rb b/testdata/ruby/dbSimplePolygonTest.rb index eb1efd246..82441d769 100644 --- a/testdata/ruby/dbSimplePolygonTest.rb +++ b/testdata/ruby/dbSimplePolygonTest.rb @@ -452,15 +452,15 @@ def test_hm_decomposition assert_equal(sorted_polygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") assert_equal(sorted_polygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)") assert_equal(sorted_polygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") - assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)") - assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") + assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)") + assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") p = RBA::DSimplePolygon::new([ [0, 0], [0, 100], [1000, 100], [1000, 1000], [1100, 1000], [1100, 100], [2200, 100], [2200, 0] ]) assert_equal(sorted_dpolygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") assert_equal(sorted_dpolygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)") assert_equal(sorted_dpolygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)") - assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)") - assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") + assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)") + assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)") end end