Skip to content

Commit e98bc0c

Browse files
committed
More Poly2TriTriangulator robustness fixes
Our interpretation of number of interpolation points didn't match our documentation or intentions, so some unit tests here had to be changed along with the code. Other than that, this just refactors us to be more robust to use cases like incoming meshes with weird node numberings. Poly2Tri is now passing all the tests I can throw at this in both MOOSE and libMesh.
1 parent 613426e commit e98bc0c

5 files changed

Lines changed: 87 additions & 41 deletions

File tree

include/mesh/triangulator_interface.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,17 @@ class TriangulatorInterface
234234
protected:
235235
/**
236236
* Helper function to create PSLG segments from our other
237-
* boundary-defining options (nodal ordering, 1D mesh edges, 2D mesh
237+
* boundary-defining options (1D mesh edges, 2D mesh
238238
* boundary sides), if no segments already exist.
239239
*/
240240
void elems_to_segments();
241241

242+
/**
243+
* Helper function to create PSLG segments from our node ordering,
244+
* up to the maximum node id, if no segments already exist.
245+
*/
246+
void nodes_to_segments(dof_id_type max_node_id);
247+
242248
/**
243249
* Helper function to add extra points (midpoints of initial
244250
* segments) to a PSLG triangulation

src/mesh/mesh_triangle_interface.C

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,16 @@ void TriangleInterface::triangulate()
6060
// Will the triangulation have holes?
6161
const bool have_holes = ((_holes != nullptr) && (!_holes->empty()));
6262

63+
unsigned int n_hole_points = this->total_hole_points();
64+
65+
// If we're doing PSLG without segments, construct them from all our
66+
// mesh nodes
67+
this->nodes_to_segments(_mesh.max_node_id());
68+
6369
// Insert additional new points in between existing boundary points,
6470
// if that is requested and reasonable
6571
this->insert_any_extra_boundary_points();
6672

67-
unsigned int n_hole_points = this->total_hole_points();
68-
6973
// Regardless of whether we added additional points, the set of points to
7074
// triangulate is now sitting in the mesh.
7175

@@ -339,6 +343,8 @@ void TriangleInterface::triangulate()
339343
}
340344

341345

346+
_mesh.set_mesh_dimension(2);
347+
342348

343349
// To the naked eye, a few smoothing iterations usually looks better,
344350
// so we do this by default unless the user says not to.

src/mesh/poly2tri_triangulator.C

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,14 @@ void Poly2TriTriangulator::triangulate()
189189
_elem_type != TRI7)
190190
libmesh_not_implemented();
191191

192+
// If we have no explicit segments defined, we may get them from
193+
// mesh elements
194+
this->elems_to_segments();
195+
196+
// If we *still* have no explicit segments defined, we get them from
197+
// the order of nodes.
198+
this->nodes_to_segments(_n_boundary_nodes);
199+
192200
// Insert additional new points in between existing boundary points,
193201
// if that is requested and reasonable
194202
this->insert_any_extra_boundary_points();
@@ -204,6 +212,8 @@ void Poly2TriTriangulator::triangulate()
204212
if (_markers)
205213
libmesh_not_implemented();
206214

215+
_mesh.set_mesh_dimension(2);
216+
207217
// To the naked eye, a few smoothing iterations usually looks better,
208218
// so we do this by default unless the user says not to.
209219
if (this->_smooth_after_generating)
@@ -307,10 +317,6 @@ void Poly2TriTriangulator::triangulate_current_points()
307317
// Prepare poly2tri points for our nodes, sorted into outer boundary
308318
// points and interior Steiner points.
309319

310-
// If we have no explicit segments defined, we may get them from
311-
// mesh elements
312-
this->elems_to_segments();
313-
314320
if (this->segments.empty())
315321
{
316322
// If we have no segments even after taking elems into account,
@@ -586,6 +592,7 @@ bool Poly2TriTriangulator::insert_refinement_points()
586592
// In cases where we've been working with contiguous node id ranges;
587593
// let's keep it that way.
588594
dof_id_type nn = _mesh.max_node_id();
595+
dof_id_type ne = _mesh.max_elem_id();
589596

590597
for (auto & elem : mesh.element_ptr_range())
591598
{
@@ -855,7 +862,7 @@ bool Poly2TriTriangulator::insert_refinement_points()
855862
continue;
856863
}
857864

858-
auto new_elem = Elem::build(TRI3);
865+
auto new_elem = Elem::build_with_id(TRI3, ne++);
859866
new_elem->set_node(0) = new_node;
860867
new_elem->set_node(1) = node_CW;
861868
new_elem->set_node(2) = node_CCW;

src/mesh/triangulator_interface.C

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,35 @@ void TriangulatorInterface::elems_to_segments()
128128

129129

130130

131+
void TriangulatorInterface::nodes_to_segments(dof_id_type max_node_id)
132+
{
133+
// Don't try to override manually specified segments, or try to add
134+
// segments if we're doing a convex hull
135+
if (!this->segments.empty() || _triangulation_type != PSLG)
136+
return;
137+
138+
for (auto node_it = _mesh.nodes_begin(),
139+
node_end = _mesh.nodes_end();
140+
node_it != node_end;)
141+
{
142+
Node * node = *node_it;
143+
144+
// If we're out of boundary nodes, the rest are going to be
145+
// Steiner points or hole points
146+
if (node->id() >= max_node_id)
147+
break;
148+
149+
++node_it;
150+
151+
Node * next_node = (node_it == node_end) ?
152+
*_mesh.nodes_begin() : *node_it;
153+
154+
this->segments.emplace_back(node->id(), next_node->id());
155+
}
156+
}
157+
158+
159+
131160
void TriangulatorInterface::insert_any_extra_boundary_points()
132161
{
133162
// If the initial PSLG is really simple, e.g. an L-shaped domain or
@@ -141,40 +170,38 @@ void TriangulatorInterface::insert_any_extra_boundary_points()
141170
const int n_interpolated = this->get_interpolate_boundary_points();
142171
if ((_triangulation_type==PSLG) && n_interpolated)
143172
{
144-
// Make a copy of the original points from the Mesh
145-
std::vector<Point> original_points;
146-
original_points.reserve (_mesh.n_nodes());
147-
for (auto & node : _mesh.node_ptr_range())
148-
original_points.push_back(*node);
173+
std::vector<std::pair<unsigned int, unsigned int>> old_segments =
174+
std::move(this->segments);
149175

150-
// Clear out the mesh
151-
_mesh.clear();
176+
// We expect to have converted any elems and/or nodes into
177+
// segments by now.
178+
libmesh_assert(!old_segments.empty());
152179

153-
// Make sure the new Mesh will be 2D
154-
_mesh.set_mesh_dimension(2);
180+
this->segments.clear();
155181

156-
// Insert a new point on each PSLG at evenly spaced locations
182+
// Insert a new point on each segment at evenly spaced locations
157183
// between existing boundary points.
158-
// np=index into new points vector, also an explicit node index
159-
// (to avoid the stride in automatic DistributedMesh indexing)
184+
// np=index into new points vector
160185
// n =index into original points vector
161-
for (std::size_t np=0, n=0, tops=n_interpolated*original_points.size(); np<tops; ++np)
186+
for (auto old_segment : old_segments)
162187
{
163-
int offset = np % n_interpolated;
164-
165-
// Some entries are the original points
166-
if (!offset)
167-
_mesh.add_point(original_points[n++], np);
168-
169-
else // the odd entries are equispaced along the original PSLG segments
188+
Node * begin_node = _mesh.node_ptr(old_segment.first);
189+
Node * end_node = _mesh.node_ptr(old_segment.second);
190+
dof_id_type current_id = begin_node->id();
191+
for (auto i : make_range(n_interpolated))
170192
{
171-
libmesh_assert_less(n-1, original_points.size());
172-
const std::size_t next_n = n % original_points.size();
193+
// new points are equispaced along the original segments
173194
const Point new_point =
174-
(offset*original_points[next_n] +
175-
(n_interpolated-offset)*original_points[n-1])/n_interpolated;
176-
_mesh.add_point(new_point, np);
195+
((n_interpolated-i) * *(Point *)(begin_node) +
196+
(i+1) * *(Point *)(end_node)) /
197+
(n_interpolated + 1);
198+
Node * next_node = _mesh.add_point(new_point);
199+
this->segments.emplace_back(current_id,
200+
next_node->id());
201+
current_id = next_node->id();
177202
}
203+
this->segments.emplace_back(current_id,
204+
end_node->id());
178205
}
179206
}
180207
}

tests/mesh/mesh_triangulation.C

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public:
3232
#ifdef LIBMESH_HAVE_POLY2TRI
3333
CPPUNIT_TEST( testPoly2Tri );
3434
CPPUNIT_TEST( testPoly2TriInterp );
35-
CPPUNIT_TEST( testPoly2TriInterp3 );
35+
CPPUNIT_TEST( testPoly2TriInterp2 );
3636
CPPUNIT_TEST( testPoly2TriHoles );
3737
CPPUNIT_TEST( testPoly2TriMeshedHoles );
3838
CPPUNIT_TEST( testPoly2TriEdges );
@@ -54,7 +54,7 @@ public:
5454
#ifdef LIBMESH_HAVE_TRIANGLE
5555
CPPUNIT_TEST( testTriangle );
5656
CPPUNIT_TEST( testTriangleInterp );
57-
CPPUNIT_TEST( testTriangleInterp3 );
57+
CPPUNIT_TEST( testTriangleInterp2 );
5858
CPPUNIT_TEST( testTriangleHoles );
5959
CPPUNIT_TEST( testTriangleMeshedHoles );
6060
CPPUNIT_TEST( testTriangleSegments );
@@ -397,17 +397,17 @@ public:
397397

398398
Mesh mesh(*TestCommWorld);
399399
TriangleInterface triangle(mesh);
400-
testTriangulatorInterp(mesh, triangle, 2, 6);
400+
testTriangulatorInterp(mesh, triangle, 1, 6);
401401
}
402402

403403

404-
void testTriangleInterp3()
404+
void testTriangleInterp2()
405405
{
406406
LOG_UNIT_TEST;
407407

408408
Mesh mesh(*TestCommWorld);
409409
TriangleInterface triangle(mesh);
410-
testTriangulatorInterp(mesh, triangle, 3, 10);
410+
testTriangulatorInterp(mesh, triangle, 2, 10);
411411
}
412412

413413

@@ -459,17 +459,17 @@ public:
459459

460460
Mesh mesh(*TestCommWorld);
461461
Poly2TriTriangulator p2t_tri(mesh);
462-
testTriangulatorInterp(mesh, p2t_tri, 2, 6);
462+
testTriangulatorInterp(mesh, p2t_tri, 1, 6);
463463
}
464464

465465

466-
void testPoly2TriInterp3()
466+
void testPoly2TriInterp2()
467467
{
468468
LOG_UNIT_TEST;
469469

470470
Mesh mesh(*TestCommWorld);
471471
Poly2TriTriangulator p2t_tri(mesh);
472-
testTriangulatorInterp(mesh, p2t_tri, 3, 10);
472+
testTriangulatorInterp(mesh, p2t_tri, 2, 10);
473473
}
474474

475475

0 commit comments

Comments
 (0)