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.
This commit is contained in:
Matthias Koefferlein
2026-08-22 22:15:55 +02:00
parent 0c8a3387ee
commit 9fad2ff1fa
12 changed files with 105 additions and 40 deletions
+4 -4
View File
@@ -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<db::Layout> ly (to_layout (decompose_by_id));
std::unique_ptr<db::Layout> ly (to_layout (decompose_by_id, dbu));
tl::OutputStream stream (path);
+2 -2
View File
@@ -879,13 +879,13 @@ public:
* 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);
+32 -15
View File
@@ -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<tl::weak_ptr<Polygon> > *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<Edge *>
Triangulation::ensure_edge_inner (Vertex *from, Vertex *to)
{
auto crossed_edges = search_edges_crossing (from, to);
std::vector<Edge *> 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<std::vector<Vertex *> > &edge_contours)
{
edge_contours.push_back (std::vector<Vertex *> ());
// @@@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 &region, const CplxTrans &trans)
{
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (region.bbox ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
for (auto p = region.begin_merged (); ! p.at_end (); ++p) {
@@ -1416,6 +1415,9 @@ Triangulation::create_constrained_delaunay (const db::Region &region, const Cplx
void
Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTrans &trans)
{
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (p.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > 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<std::vector<Vertex *> > box_contours;
make_contours (db::DPolygon (p.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (p, trans, edge_contours);
@@ -1493,6 +1498,9 @@ Triangulation::triangulate (const db::Region &region, const std::vector<db::Poin
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (region.bbox ()), trans, box_contours);
std::vector<std::vector<Vertex *> > 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<db::Point
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
@@ -1547,6 +1558,9 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector<db::Point
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
@@ -1572,6 +1586,9 @@ Triangulation::triangulate (const db::DPolygon &poly, const std::vector<db::DPoi
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::DPolygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
+66 -18
View File
@@ -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));
}
EXPECT_GE (plc.num_polygons (), size_t (70));
EXPECT_LE (plc.num_polygons (), size_t (72));
{
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));
}
{
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)
@@ -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?
)
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.