Fixing issue #1996: Providing a more robust triangulation

This commit is contained in:
Matthias Koefferlein 2025-03-22 21:47:22 +01:00
parent a727ed0b1d
commit 6228668fa1
3 changed files with 57 additions and 57 deletions

View File

@ -363,21 +363,33 @@ Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3)
}
mp_v[2] = mp_e[1]->other (mp_v[1]);
// establish link to edges
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = mp_e[i];
int side_of = e->side_of (*mp_v[i == 0 ? 2 : i - 1]);
// NOTE: in the degenerated case, the triangle is not attached to an edge!
if (side_of < 0) {
e->set_left (this);
} else if (side_of > 0) {
e->set_right (this);
}
// enforce clockwise orientation
int s = db::vprod_sign (*mp_v[2] - *mp_v[0], *mp_v[1] - *mp_v[0]);
if (s < 0) {
std::swap (mp_v[2], mp_v[1]);
} else if (s == 0) {
// Triangle is not orientable
tl_assert (false);
}
// enforce clockwise orientation
if (db::vprod_sign (*mp_v[2] - *mp_v[0], *mp_v[1] - *mp_v[0]) < 0) {
std::swap (mp_v[2], mp_v[1]);
// establish link to edges
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = mp_e[i];
unsigned int i1 = 0;
for ( ; e->v1 () != mp_v[i1] && i1 < 3; ++i1)
;
unsigned int i2 = 0;
for ( ; e->v2 () != mp_v[i2] && i2 < 3; ++i2)
;
if ((i1 + 1) % 3 == i2) {
e->set_right (this);
} else {
e->set_left (this);
}
}
}

View File

@ -364,12 +364,6 @@ Triangles::insert (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *n
// the new vertex is outside the domain
if (tris.empty ()) {
// @@@
if (m_is_constrained) {
dump("debug.gds"); // @@@
find_triangle_for_point (*vertex);
}
// @@@
tl_assert (! m_is_constrained);
insert_new_vertex (vertex, new_triangles);
return vertex;
@ -397,37 +391,7 @@ Triangles::insert (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *n
} else if (! on_edges.empty ()) {
tl_assert (on_edges.size () == size_t (1));
// @@@
auto v1 = on_edges.front()->v1();
auto v2 = on_edges.front()->v2();
unsigned int ns1 = 0, ns2 = 0;
for (auto e = v1->begin_edges (); e != v1->end_edges (); ++e) {
if ((*e)->is_segment()) { ++ns1; }
}
for (auto e = v2->begin_edges (); e != v2->end_edges (); ++e) {
if ((*e)->is_segment()) { ++ns2; }
}
std::string vs = vertex->to_string();
std::string es = on_edges.front()->to_string();
if (vs == "(-12.9999999999, 3.50126953125)" && es == "((-13, 3.5328125), (-12.9999999998, 3.4697265625))") {
printf("@@@ BANG!\n"); fflush(stdout);
}
// @@@
split_triangles_on_edge (vertex, on_edges.front (), new_triangles);
// @@@
unsigned int ns1p = 0, ns2p = 0;
for (auto e = v1->begin_edges (); e != v1->end_edges (); ++e) {
if ((*e)->is_segment()) { ++ns1p; }
}
for (auto e = v2->begin_edges (); e != v2->end_edges (); ++e) {
if ((*e)->is_segment()) { ++ns2p; }
}
if (ns1 != ns1p || ns2 != ns2p) {
printf("@@@ on '%s' '%s' - BANG!\n", vs.c_str(), es.c_str()); fflush(stdout);
}
tl_assert(ns1 == ns1p);
tl_assert(ns2 == ns2p);
// @@@
return vertex;
} else if (tris.size () == size_t (1)) {
@ -1638,7 +1602,6 @@ Triangles::refine (const TriangulateParameters &parameters)
if (tl::verbosity () >= parameters.base_verbosity + 10) {
tl::info << "Iteration " << nloop << " ..";
}
printf("@@@ iteration %d ..\n", (int)nloop); fflush(stdout);
std::list<tl::weak_ptr<db::Triangle> > to_consider;
for (auto t = new_triangles.begin (); t != new_triangles.end (); ++t) {
@ -1667,7 +1630,28 @@ Triangles::refine (const TriangulateParameters &parameters)
auto cr = (*t)->circumcircle();
auto center = cr.first;
if ((*t)->contains (center) >= 0) {
int s = (*t)->contains (center);
if (s >= 0) {
if (s > 0) {
double snap = 1e-3;
// Snap the center to a segment center if "close" to it.
// This avoids generating very skinny triangles that can't be fixed as the
// segment cannot be flipped. This a part of the issue #1996 problem.
for (unsigned int i = 0; i < 3; ++i) {
if ((*t)->edge (i)->is_segment ()) {
auto e = (*t)->edge (i)->edge ();
auto c = e.p1 () + e.d () * 0.5;
if (c.distance (center) < e.length () * 0.5 * snap - db::epsilon) {
center = c;
break;
}
}
}
}
if (tl::verbosity () >= parameters.base_verbosity + 20) {
tl::info << "Inserting in-triangle center " << center.to_string () << " of " << (*t)->to_string (true);
@ -1677,7 +1661,7 @@ Triangles::refine (const TriangulateParameters &parameters)
} else {
db::Vertex *vstart = 0;
for (int i = 0; i < 3; ++i) {
for (unsigned int i = 0; i < 3; ++i) {
db::TriangleEdge *edge = (*t)->edge (i);
vstart = (*t)->opposite (edge);
if (edge->side_of (*vstart) * edge->side_of (center) < 0) {

View File

@ -700,6 +700,9 @@ TEST(triangulate_basic)
EXPECT_GT (tri.num_triangles (), size_t (100));
EXPECT_LT (tri.num_triangles (), size_t (150));
// for debugging:
// tri.dump ("debug.gds");
param.min_b = 1.0;
param.max_area = 0.1;
@ -914,8 +917,8 @@ TEST(triangulate_problematic)
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GT (tri.num_triangles (), size_t (470));
EXPECT_LT (tri.num_triangles (), size_t (490));
EXPECT_GT (tri.num_triangles (), size_t (540));
EXPECT_LT (tri.num_triangles (), size_t (560));
}
TEST(triangulate_thin)
@ -978,7 +981,7 @@ TEST(triangulate_issue1996)
db::Triangles::TriangulateParameters param;
param.min_b = 0.5;
param.max_area = 500.0 * dbu * dbu;
param.max_area = 5000.0 * dbu * dbu;
TestableTriangles tri;
db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ()));
@ -990,9 +993,10 @@ TEST(triangulate_issue1996)
// tri.dump ("debug.gds");
for (auto t = tri.begin (); t != tri.end (); ++t) {
EXPECT_LE (t->area (), param.max_area);
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GT (tri.num_triangles (), size_t (13000));
EXPECT_LT (tri.num_triangles (), size_t (13200));
EXPECT_GT (tri.num_triangles (), size_t (128000));
EXPECT_LT (tri.num_triangles (), size_t (132000));
}