libMesh
mesh_triangulation.C
Go to the documentation of this file.
1 #include <libmesh/boundary_info.h>
2 #include <libmesh/elem.h>
3 #include <libmesh/mesh.h>
4 #include <libmesh/mesh_generation.h>
5 #include <libmesh/mesh_modification.h>
6 #include <libmesh/mesh_triangle_holes.h>
7 #include <libmesh/mesh_triangle_interface.h>
8 #include <libmesh/parallel_implementation.h> // max()
9 #include <libmesh/parsed_function.h>
10 #include <libmesh/point.h>
11 #include <libmesh/poly2tri_triangulator.h>
12 
13 #include "test_comm.h"
14 #include "libmesh_cppunit.h"
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <regex>
19 
20 
21 using namespace libMesh;
22 
23 class MeshTriangulationTest : public CppUnit::TestCase
24 {
29 public:
30  LIBMESH_CPPUNIT_TEST_SUITE( MeshTriangulationTest );
31 
32  CPPUNIT_TEST( testTriangleHoleArea );
33  CPPUNIT_TEST( testTriangleHoleContains );
34 
35 #ifdef LIBMESH_HAVE_POLY2TRI
36  CPPUNIT_TEST( testPoly2Tri );
37  CPPUNIT_TEST( testPoly2TriHalfDomain );
38  CPPUNIT_TEST( testPoly2TriHalfDomainEdge3 );
39  CPPUNIT_TEST( testPoly2TriInterp );
40  CPPUNIT_TEST( testPoly2TriInterp2 );
41  CPPUNIT_TEST( testPoly2TriHoles );
42  CPPUNIT_TEST( testPoly2TriMeshedHoles );
43 # ifdef LIBMESH_ENABLE_AMR
44  CPPUNIT_TEST( testPoly2TriRoundHole );
45 # endif
46  CPPUNIT_TEST( testPoly2TriEdges );
47  CPPUNIT_TEST( testPoly2TriEdge3s );
48  CPPUNIT_TEST( testPoly2TriBadEdges );
49  CPPUNIT_TEST( testPoly2TriBad1DMultiBoundary );
50  CPPUNIT_TEST( testPoly2TriBad2DMultiBoundary );
51  CPPUNIT_TEST( testPoly2TriEdgesRefined );
52  CPPUNIT_TEST( testPoly2TriSegments );
53  CPPUNIT_TEST( testPoly2TriRefined );
54  CPPUNIT_TEST( testPoly2TriNonRefined );
55  CPPUNIT_TEST( testPoly2TriExtraRefined );
56  CPPUNIT_TEST( testPoly2TriHolesRefined );
57  CPPUNIT_TEST( testPoly2TriHolesInterpRefined );
58  CPPUNIT_TEST( testPoly2TriHolesInteriorRefined );
59  CPPUNIT_TEST( testPoly2TriHolesInteriorExtraRefined );
60  // This covers an old poly2tri collinearity-tolerance bug
61  CPPUNIT_TEST( testPoly2TriHolesExtraRefined );
62 
63  CPPUNIT_TEST( testPoly2TriNonUniformRefined );
64  CPPUNIT_TEST( testPoly2TriHolesNonUniformRefined );
65 #endif
66 
67 #ifdef LIBMESH_HAVE_TRIANGLE
68  CPPUNIT_TEST( testTriangle );
69  CPPUNIT_TEST( testTriangleHalfDomain );
70  CPPUNIT_TEST( testTriangleInterp );
71  CPPUNIT_TEST( testTriangleInterp2 );
72  CPPUNIT_TEST( testTriangleHoles );
73  CPPUNIT_TEST( testTriangleMeshedHoles );
74 # ifdef LIBMESH_ENABLE_AMR
75  CPPUNIT_TEST( testTriangleRoundHole );
76 # endif
77  CPPUNIT_TEST( testTriangleEdges );
78  CPPUNIT_TEST( testTriangleSegments );
79 #endif
80 
81  CPPUNIT_TEST_SUITE_END();
82 
83 public:
84  void setUp() {}
85 
86  void tearDown() {}
87 
88  void commonSettings (TriangulatorInterface & triangulator)
89  {
90  // Use the point order to define the boundary, because our
91  // Poly2Tri implementation doesn't do convex hulls yet, even when
92  // that would give the same answer.
94 
95  // Don't try to insert points unless we're requested to later
96  triangulator.desired_area() = 1000;
97  triangulator.minimum_angle() = 0;
98  triangulator.smooth_after_generating() = false;
99  triangulator.set_verify_hole_boundaries(true);
100  }
101 
103  TriangulatorInterface & triangulator,
104  const char * re)
105  {
106 #ifdef LIBMESH_ENABLE_EXCEPTIONS
107  // We can't just CPPUNIT_ASSERT_THROW, because we want to make
108  // sure we were thrown from the right place with the right error
109  // message!
110  bool threw_desired_exception = false;
111  try {
112  this->testTriangulatorBase(mesh, triangulator);
113  }
114  catch (libMesh::LogicError & e) {
115  std::regex msg_regex(re);
116  CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
117  threw_desired_exception = true;
118  }
119  catch (CppUnit::Exception & e) {
120  throw e;
121  }
122  catch (...) {
123  CPPUNIT_ASSERT_MESSAGE("Unexpected exception type thrown", false);
124  }
125  CPPUNIT_ASSERT(threw_desired_exception);
126 #endif
127  }
128 
129 
131  {
132  LOG_UNIT_TEST;
133 
134  // Using center=(1,0), radius=2 for the heck of it
135  Point center{1};
136  Real radius = 2;
137  std::vector<TriangulatorInterface::PolygonHole> polyholes;
138 
139  // Line
140  polyholes.emplace_back(center, radius, 2);
141  // Triangle
142  polyholes.emplace_back(center, radius, 3);
143  // Square
144  polyholes.emplace_back(center, radius, 4);
145  // Pentagon
146  polyholes.emplace_back(center, radius, 5);
147  // Hexagon
148  polyholes.emplace_back(center, radius, 6);
149 
150  for (int i=0; i != 5; ++i)
151  {
152  const int n_sides = i+2;
153  const TriangulatorInterface::Hole & hole = polyholes[i];
154 
155  const Real computed_area = hole.area();
156  const Real theta = pi/n_sides;
157  const Real half_side_length = radius*std::cos(theta);
158  const Real apothem = radius*std::sin(theta);
159  const Real area = n_sides * apothem * half_side_length;
160 
161  LIBMESH_ASSERT_FP_EQUAL(computed_area, area, TOLERANCE*TOLERANCE);
162  }
163 
164  TriangulatorInterface::ArbitraryHole arbhole {center, {{0,-1},{2,-1},{2,1},{0,2}}};
165  LIBMESH_ASSERT_FP_EQUAL(arbhole.area(), Real(5), TOLERANCE*TOLERANCE);
166 
167 #ifdef LIBMESH_HAVE_TRIANGLE
168  // Make sure we're compatible with the old naming structure too
169  TriangleInterface::PolygonHole square(center, radius, 4);
170  LIBMESH_ASSERT_FP_EQUAL(square.area(), 2*radius*radius, TOLERANCE*TOLERANCE);
171 #endif
172  }
173 
174 
176  {
177  LOG_UNIT_TEST;
178 
179  // Using center=(1,2), radius=2 for the heck of it
180  Point center{1,2};
181  Real radius = 2;
182  std::vector<TriangulatorInterface::PolygonHole> polyholes;
183 
184  auto check_corners = [center, radius]
185  (const TriangulatorInterface::Hole & hole,
186  unsigned int np)
187  {
188  CPPUNIT_ASSERT_EQUAL(np, hole.n_points());
189  for (auto i : make_range(np))
190  {
191  const Real theta = i * 2 * libMesh::pi / np;
192  const Real xin = center(0) + radius * .99 * std::cos(theta);
193  const Real xout = center(0) + radius * 1.01 * std::cos(theta);
194  const Real yin = center(1) + radius * .99 * std::sin(theta);
195  const Real yout = center(1) + radius * 1.01 * std::sin(theta);
196 
197  CPPUNIT_ASSERT(hole.contains(Point(xin, yin)));
198  CPPUNIT_ASSERT(!hole.contains(Point(xout, yout)));
199  }
200  };
201 
202  const TriangulatorInterface::PolygonHole triangle(center, radius, 3);
203  check_corners(triangle, 3);
204  const TriangulatorInterface::PolygonHole diamond(center, radius, 4);
205  check_corners(diamond, 4);
206  const TriangulatorInterface::PolygonHole hexagon(center, radius, 6);
207  check_corners(hexagon, 6);
208 
210  {{1,0}, {{0,-1},{2,-1},{2,1},{1.75,-.5},{1.5,1},{1.25,-.5},
211  {1,1},{.75,-.5},{.5,1},{.25,-.5},{0,1}}};
212 
213  CPPUNIT_ASSERT(jaggy.contains({.1,-.3}));
214  CPPUNIT_ASSERT(jaggy.contains({.5,.9}));
215  CPPUNIT_ASSERT(jaggy.contains({.9,-.3}));
216  CPPUNIT_ASSERT(jaggy.contains({1,0}));
217  CPPUNIT_ASSERT(jaggy.contains({1.1,-.4}));
218  CPPUNIT_ASSERT(jaggy.contains({1.5,.9}));
219  CPPUNIT_ASSERT(jaggy.contains({1.9,-.3}));
220 
221  CPPUNIT_ASSERT(jaggy.contains({1.9,-.5}));
222  CPPUNIT_ASSERT(jaggy.contains({1.6,-.5}));
223  CPPUNIT_ASSERT(jaggy.contains({1.1,-.5}));
224  CPPUNIT_ASSERT(jaggy.contains({.5,-.5}));
225  CPPUNIT_ASSERT(jaggy.contains({.2,-.5}));
226 
227  CPPUNIT_ASSERT(!jaggy.contains({.1,.7}));
228  CPPUNIT_ASSERT(!jaggy.contains({.5,1.1}));
229  CPPUNIT_ASSERT(!jaggy.contains({.9,.7}));
230  CPPUNIT_ASSERT(!jaggy.contains({1,-1.1}));
231  CPPUNIT_ASSERT(!jaggy.contains({1.1,.8}));
232  CPPUNIT_ASSERT(!jaggy.contains({1.5,1.1}));
233  CPPUNIT_ASSERT(!jaggy.contains({1.9,.9}));
234 
235  CPPUNIT_ASSERT(!jaggy.contains({1.9,1}));
236  CPPUNIT_ASSERT(!jaggy.contains({1.4,1}));
237  CPPUNIT_ASSERT(!jaggy.contains({.9,1}));
238  CPPUNIT_ASSERT(!jaggy.contains({.4,1}));
239  CPPUNIT_ASSERT(!jaggy.contains({-.2,1}));
240  CPPUNIT_ASSERT(!jaggy.contains({-.2,0}));
241  CPPUNIT_ASSERT(!jaggy.contains({1.2,0}));
242 
244  {{1,0}, {{-.25,-1},{2,-1},{2,1},{1.75,1},{1.75,-.5},{1.5,-.5},
245  {1.5,1},{1.25,1},{1.25,-.5},{1,-.5},{1,1},{.75,1},
246  {.75,-.5},{.5,-.5},{.5,1},{.25,1},{.25,-.5},{0,-.5},
247  {0,1},{-.25,1}}};
248 
249  CPPUNIT_ASSERT(square_jaggy.contains({-.1,-.3}));
250  CPPUNIT_ASSERT(square_jaggy.contains({.4,.9}));
251  CPPUNIT_ASSERT(square_jaggy.contains({.9,-.3}));
252  CPPUNIT_ASSERT(square_jaggy.contains({.9,0}));
253  CPPUNIT_ASSERT(square_jaggy.contains({1.1,-.6}));
254  CPPUNIT_ASSERT(square_jaggy.contains({1.4,.9}));
255  CPPUNIT_ASSERT(square_jaggy.contains({1.9,-.3}));
256 
257  CPPUNIT_ASSERT(!square_jaggy.contains({.1,-.3}));
258  CPPUNIT_ASSERT(!square_jaggy.contains({.6,.9}));
259  CPPUNIT_ASSERT(!square_jaggy.contains({1.1,-.3}));
260  CPPUNIT_ASSERT(!square_jaggy.contains({1.1,0}));
261  CPPUNIT_ASSERT(!square_jaggy.contains({1.1,-1.6}));
262  CPPUNIT_ASSERT(!square_jaggy.contains({1.6,.9}));
263  CPPUNIT_ASSERT(!square_jaggy.contains({2.1,-.3}));
264 
265  CPPUNIT_ASSERT(square_jaggy.contains({-.1,-.5}));
266  CPPUNIT_ASSERT(square_jaggy.contains({.3,-.5}));
267  CPPUNIT_ASSERT(square_jaggy.contains({.9,-.5}));
268  CPPUNIT_ASSERT(square_jaggy.contains({1.3,-.5}));
269  CPPUNIT_ASSERT(square_jaggy.contains({1.9,-.5}));
270 
271  CPPUNIT_ASSERT(!square_jaggy.contains({-.3,1}));
272  CPPUNIT_ASSERT(!square_jaggy.contains({.2,1}));
273  CPPUNIT_ASSERT(!square_jaggy.contains({.6,1}));
274  CPPUNIT_ASSERT(!square_jaggy.contains({1.1,1}));
275  CPPUNIT_ASSERT(!square_jaggy.contains({1.6,1}));
276  CPPUNIT_ASSERT(!square_jaggy.contains({2.1,1}));
277  }
278 
279 
281  TriangulatorInterface & triangulator)
282  {
283  commonSettings(triangulator);
284 
285  triangulator.triangulate();
286 
287  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), static_cast<dof_id_type>(2));
288  for (const auto & elem : mesh.element_ptr_range())
289  {
290  CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);
291 
292  // Make sure we're not getting any inverted elements
293  auto cross_prod =
294  (elem->point(1) - elem->point(0)).cross
295  (elem->point(2) - elem->point(0));
296 
297  CPPUNIT_ASSERT_GREATER(Real(0), cross_prod(2));
298 
299  bool found_triangle = false;
300  for (const auto & node : elem->node_ref_range())
301  {
302  const Point & point = node;
303  if (point == Point(0,0))
304  {
305  found_triangle = true;
306  CPPUNIT_ASSERT((elem->point(0) == Point(0,0) &&
307  elem->point(1) == Point(1,0) &&
308  elem->point(2) == Point(0,1)) ||
309  (elem->point(1) == Point(0,0) &&
310  elem->point(2) == Point(1,0) &&
311  elem->point(0) == Point(0,1)) ||
312  (elem->point(2) == Point(0,0) &&
313  elem->point(0) == Point(1,0) &&
314  elem->point(1) == Point(0,1)));
315  }
316  if (point == Point(1,2))
317  {
318  found_triangle = true;
319  CPPUNIT_ASSERT((elem->point(0) == Point(0,1) &&
320  elem->point(1) == Point(1,0) &&
321  elem->point(2) == Point(1,2)) ||
322  (elem->point(1) == Point(0,1) &&
323  elem->point(2) == Point(1,0) &&
324  elem->point(0) == Point(1,2)) ||
325  (elem->point(2) == Point(0,1) &&
326  elem->point(0) == Point(1,0) &&
327  elem->point(1) == Point(1,2)));
328  }
329  }
330  CPPUNIT_ASSERT(found_triangle);
331  }
332  }
333 
334 
336  TriangulatorInterface & triangulator)
337  {
338  // A non-square quad, so we don't have ambiguity about which
339  // diagonal a Delaunay algorithm will pick.
340  // Manually-numbered points, so we can use the point numbering as
341  // a segment ordering even on DistributedMesh.
342  mesh.add_point(Point(0,0), 0);
343  mesh.add_point(Point(1,0), 1);
344  mesh.add_point(Point(1,2), 2);
345  mesh.add_point(Point(0,1), 3);
346 
347  this->testTriangulatorBase(mesh, triangulator);
348  }
349 
350 
352  {
353  // A non-square quad, so we don't have ambiguity about which
354  // diagonal a Delaunay algorithm will pick.
355  // Manually-numbered points, so we can use the point numbering as
356  // a segment ordering even on DistributedMesh.
357  mesh.add_point(Point(0,0), 0);
358  mesh.add_point(Point(1,0), 1);
359  mesh.add_point(Point(1,2), 2);
360  mesh.add_point(Point(0,1), 3);
361  }
362 
363 
365  TriangulatorInterface & triangulator,
366  int interpolate_boundary_points,
367  dof_id_type n_expected_elem,
368  Real expected_total_area = 1.5,
369  Real desired_area = 1000)
370  {
371  commonSettings(triangulator);
372 
373  if (!mesh.n_nodes())
374  testTriangulatorTrapMesh(mesh);
375 
376  // Interpolate points!
377  triangulator.set_interpolate_boundary_points(interpolate_boundary_points);
378 
379  // Try to insert points?
380  triangulator.desired_area() = desired_area;
381 
382  triangulator.triangulate();
383 
384  if (n_expected_elem)
385  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), n_expected_elem);
386 
387  Real area = 0;
388  for (const auto & elem : mesh.active_local_element_ptr_range())
389  {
390  CPPUNIT_ASSERT_EQUAL(elem->level(), 0u);
391  CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);
392 
393  area += elem->volume();
394  }
395 
396  mesh.comm().sum(area);
397 
398  LIBMESH_ASSERT_FP_EQUAL(area, expected_total_area, TOLERANCE*TOLERANCE);
399  }
400 
401 
403  const std::vector<Point> & expected_centers)
404  {
405  std::vector<bool> found_centers(expected_centers.size(), false);
406 
407  for (const auto & elem : mesh.element_ptr_range())
408  {
409  CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);
410 
411  // Make sure we're not getting any inverted elements
412  auto cross_prod =
413  (elem->point(1) - elem->point(0)).cross
414  (elem->point(2) - elem->point(0));
415 
416  CPPUNIT_ASSERT_GREATER(Real(0), cross_prod(2));
417 
418  // Make sure we're finding all the elements we expect
419  Point center = elem->vertex_average();
420 
421  bool found_mine = false;
422  for (auto i : index_range(expected_centers))
423  {
424  Point possible = expected_centers[i];
425 
426  if (possible.absolute_fuzzy_equals(center, TOLERANCE*TOLERANCE))
427  {
428  found_mine = true;
429  found_centers[i] = true;
430  }
431  }
432  CPPUNIT_ASSERT(found_mine);
433  }
434 
435  mesh.comm().max(found_centers);
436 
437  for (auto found_it : found_centers)
438  CPPUNIT_ASSERT(found_it);
439  }
440 
441 
443  TriangulatorInterface & triangulator)
444  {
445  // A square quad; we'll put a diamond hole in the middle to make
446  // the Delaunay selection unambiguous.
447  mesh.add_point(Point(-1,-1), 0);
448  mesh.add_point(Point(1,-1), 1);
449  mesh.add_point(Point(1,1), 2);
450  mesh.add_point(Point(-1,1), 3);
451 
452  commonSettings(triangulator);
453 
454  // Add a diamond hole in the center
455  TriangulatorInterface::PolygonHole diamond(Point(0), std::sqrt(2_R)/2, 4);
456  const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
457  triangulator.attach_hole_list(&holes);
458 
459  triangulator.triangulate();
460 
461  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), static_cast<dof_id_type>(8));
462 
463  // Center coordinates for all the elements we expect
464  Real r2p2o6 = (std::sqrt(2_R)+2)/6;
465  Real r2p4o6 = (std::sqrt(2_R)+4)/6;
466 
467  std::vector <Point> expected_centers
468  { {r2p2o6,r2p2o6}, {r2p2o6,-r2p2o6},
469  {-r2p2o6,r2p2o6}, {-r2p2o6,-r2p2o6},
470  {0,r2p4o6}, {r2p4o6, 0},
471  {0,-r2p4o6}, {-r2p4o6, 0}
472  };
473 
474  testFoundCenters(mesh, expected_centers);
475  }
476 
477 
479  TriangulatorInterface & triangulator)
480  {
481  // A square quad; we'll put a square hole in the middle. Offset
482  // this to catch a potential bug I missed on the first try.
483  mesh.add_point(Point(19,19), 0);
484  mesh.add_point(Point(21,19), 1);
485  mesh.add_point(Point(21,21), 2);
486  mesh.add_point(Point(19,21), 3);
487 
488  commonSettings(triangulator);
489 
490  // Add a square meshed hole in the center
491  Mesh centermesh { mesh.comm() };
492  MeshTools::Generation::build_square (centermesh, 2, 2, 19.5, 20.5, 19.5, 20.5, QUAD4);
493 
494  TriangulatorInterface::MeshedHole centerhole { centermesh };
495 
496  CPPUNIT_ASSERT_EQUAL(centerhole.n_points(), 8u);
497  CPPUNIT_ASSERT_EQUAL(centerhole.area(), Real(1));
498  Point inside = centerhole.inside();
499  CPPUNIT_ASSERT_EQUAL(inside(0), Real(20));
500  CPPUNIT_ASSERT_EQUAL(inside(1), Real(20));
501 
502  const std::vector<TriangulatorInterface::Hole*> holes { &centerhole };
503  triangulator.attach_hole_list(&holes);
504 
505  triangulator.triangulate();
506 
507  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), static_cast<dof_id_type>(12));
508 
509  // Center coordinates for all the elements we expect
510  std::vector <Point> expected_centers
511  { {-0.5, Real(2)/3}, {0, Real(5)/6},
512  {0.5, Real(2)/3},
513  {Real(2)/3, -0.5}, {Real(5)/6, 0},
514  {Real(2)/3, 0.5},
515  {-0.5, -Real(2)/3}, {0, -Real(5)/6},
516  {0.5, -Real(2)/3},
517  {-Real(2)/3, -0.5}, {-Real(5)/6, 0},
518  {-Real(2)/3, 0.5} };
519 
520  // With the same offset
521  for (auto & p : expected_centers)
522  p += Point(20,20);
523 
524  testFoundCenters(mesh, expected_centers);
525  }
526 
527 
528 #ifdef LIBMESH_ENABLE_AMR
530  TriangulatorInterface & triangulator)
531  {
532  // A square quad; we'll put a round hole in the middle.
533  mesh.add_point(Point(19,19), 0);
534  mesh.add_point(Point(21,19), 1);
535  mesh.add_point(Point(21,21), 2);
536  mesh.add_point(Point(19,21), 3);
537 
538  commonSettings(triangulator);
539 
540  // Add a square meshed hole in the center
541  const Real radius = 0.5;
542  const Point center{20,20};
543 
544  Mesh centermesh { mesh.comm() };
546  MeshTools::Modification::translate(centermesh, center(0), center(1));
547 
548  TriangulatorInterface::MeshedHole centerhole { centermesh };
549 
550  CPPUNIT_ASSERT_EQUAL(centerhole.n_points(), 8u);
551  Point inside = centerhole.inside();
552  CPPUNIT_ASSERT_EQUAL(inside(0), Real(20));
553  CPPUNIT_ASSERT_EQUAL(inside(1), Real(20));
554 
555  const std::vector<TriangulatorInterface::Hole*> holes { &centerhole };
556  triangulator.attach_hole_list(&holes);
557  triangulator.elem_type() = TRI6;
558 
559  triangulator.triangulate();
560 
561  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), static_cast<dof_id_type>(12));
562  CPPUNIT_ASSERT_EQUAL(mesh.n_nodes(), static_cast<dof_id_type>(36));
563 
564  // Make sure we didn't screw up the outer sides. We should
565  // have exact values for the outer vertices, so we can use
566  // those for a map.
567  std::map<std::pair<Real, Real>, Point> outer_midpoints
568  {{{19, 19}, {20, 19}},
569  {{21, 19}, {21, 20}},
570  {{21, 21}, {20, 21}},
571  {{19, 21}, {19, 20}}
572  };
573 
574  for (const auto & elem : mesh.active_local_element_ptr_range())
575  for (const auto n : make_range(elem->n_sides()))
576  {
577  if (elem->neighbor_ptr(n))
578  continue;
579 
580  auto it =
581  outer_midpoints.find(std::make_pair(elem->point(n)(0),
582  elem->point(n)(1)));
583  if (it != outer_midpoints.end())
584  {
585  const Point error = it->second - elem->point(n+3);
586  CPPUNIT_ASSERT_LESS(TOLERANCE*TOLERANCE,
587  error.norm_sq());
588  }
589  else
590  {
591  const Point radius1 = elem->point(n) - center;
592  CPPUNIT_ASSERT_LESS(TOLERANCE*TOLERANCE,
593  std::abs(radius1.norm()-radius));
594 
595  const Point radius2 = elem->point((n+1)%3) - center;
596  CPPUNIT_ASSERT_LESS(TOLERANCE*TOLERANCE,
597  std::abs(radius2.norm()-radius));
598 
599  const Point radius3 = elem->point(n+3) - center;
600  CPPUNIT_ASSERT_LESS(TOLERANCE*TOLERANCE,
601  std::abs(radius3.norm()-radius));
602  }
603  }
604  }
605 #endif // LIBMESH_ENABLE_AMR
606 
607 
609  TriangulatorInterface & triangulator)
610  {
611  // The same quad as testTriangulator, but out of order
612  mesh.add_point(Point(0,0), 0);
613  mesh.add_point(Point(1,2), 1);
614  mesh.add_point(Point(1,0), 2);
615  mesh.add_point(Point(0,1), 3);
616 
617  // Segments to put them in order
618  triangulator.segments = {{0,2},{2,1},{1,3},{3,0}};
619 
620  this->testTriangulatorBase(mesh, triangulator);
621  }
622 
623 
624  void testEdgesMesh(MeshBase & mesh, ElemType elem_type)
625  {
626  // The same quad as testTriangulator, but out of order
627  auto node0 = mesh.add_point(Point(0,0), 0);
628  auto node1 = mesh.add_point(Point(1,2), 1);
629  auto node2 = mesh.add_point(Point(1,0), 2);
630  auto node3 = mesh.add_point(Point(0,1), 3);
631 
632  // Edges, also out of order, but enough to put them in order
633  auto edge13 = mesh.add_elem(Elem::build(elem_type));
634  edge13->set_node(0, node1);
635  edge13->set_node(1, node3);
636  auto edge02 = mesh.add_elem(Elem::build(elem_type));
637  edge02->set_node(0, node0);
638  edge02->set_node(1, node2);
639  auto edge30 = mesh.add_elem(Elem::build(elem_type));
640  edge30->set_node(0, node3);
641  edge30->set_node(1, node0);
642  auto edge21 = mesh.add_elem(Elem::build(elem_type));
643  edge21->set_node(0, node2);
644  edge21->set_node(1, node1);
645 
646  // Add mid-edge nodes if asked to
647  if (elem_type == EDGE3)
648  {
649  auto node4 = mesh.add_point(Point(.5,1.5), 4);
650  edge13->set_node(2, node4);
651  auto node5 = mesh.add_point(Point(.5,0), 5);
652  edge02->set_node(2, node5);
653  auto node6 = mesh.add_point(Point(0,.5), 6);
654  edge30->set_node(2, node6);
655  auto node7 = mesh.add_point(Point(1,1), 7);
656  edge21->set_node(2, node7);
657  }
658  else
659  libmesh_assert(elem_type == EDGE2);
660 
662  }
663 
664 
666  TriangulatorInterface & triangulator,
667  ElemType elem_type)
668  {
669  // We might have 4 or 8 nodes on the outer boundary, depending on
670  // whether it has mid-edge nodes
671  const dof_id_type off = (elem_type == EDGE3)*4;
672 
673  // A pentagon we'll avoid via subdomain ids
674  auto node4 = mesh.add_point(Point(2,0), 4+off);
675  auto node5 = mesh.add_point(Point(3,0), 5+off);
676  auto node6 = mesh.add_point(Point(3,2), 6+off);
677  auto node7 = mesh.add_point(Point(2,2), 7+off);
678  auto node8 = mesh.add_point(Point(2,1), 8+off);
679 
680  auto edge45 = mesh.add_elem(Elem::build(elem_type));
681  edge45->set_node(0, node4);
682  edge45->set_node(1, node5);
683  edge45->subdomain_id() = 1;
684  auto edge56 = mesh.add_elem(Elem::build(elem_type));
685  edge56->set_node(0, node5);
686  edge56->set_node(1, node6);
687  edge56->subdomain_id() = 1;
688  auto edge67 = mesh.add_elem(Elem::build(elem_type));
689  edge67->set_node(0, node6);
690  edge67->set_node(1, node7);
691  edge67->subdomain_id() = 1;
692  auto edge78 = mesh.add_elem(Elem::build(elem_type));
693  edge78->set_node(0, node7);
694  edge78->set_node(1, node8);
695  edge78->subdomain_id() = 1;
696  auto edge84 = mesh.add_elem(Elem::build(elem_type));
697  edge84->set_node(0, node8);
698  edge84->set_node(1, node4);
699  edge84->subdomain_id() = 1;
700 
701  if (elem_type == EDGE3)
702  {
703  auto node9 = mesh.add_point(Point(2.5,0), 9+off);
704  edge45->set_node(2, node9);
705  auto node10 = mesh.add_point(Point(3,1), 10+off);
706  edge56->set_node(2, node10);
707  auto node11 = mesh.add_point(Point(2.5,2), 11+off);
708  edge67->set_node(2, node11);
709  auto node12 = mesh.add_point(Point(2,1.5), 12+off);
710  edge78->set_node(2, node12);
711  auto node13 = mesh.add_point(Point(2,.5), 13+off);
712  edge84->set_node(2, node13);
713  }
714  else
715  libmesh_assert(elem_type == EDGE2);
716 
717  testEdgesMesh(mesh, elem_type);
718 
719  std::set<std::size_t> bdy_ids {0};
720  triangulator.set_outer_boundary_ids(bdy_ids);
721 
722  this->testTriangulatorBase(mesh, triangulator);
723  }
724 
725 
726 #ifdef LIBMESH_HAVE_TRIANGLE
728  {
729  LOG_UNIT_TEST;
730 
732  TriangleInterface triangle(mesh);
733  testTriangulator(mesh, triangle);
734  }
735 
736 
738  {
739  LOG_UNIT_TEST;
740 
742  TriangleInterface triangle(mesh);
743  testHalfDomain(mesh, triangle, EDGE2);
744  }
745 
746 
748  {
749  LOG_UNIT_TEST;
750 
752  TriangleInterface triangle(mesh);
753  testTriangulatorInterp(mesh, triangle, 1, 6);
754  }
755 
756 
758  {
759  LOG_UNIT_TEST;
760 
762  TriangleInterface triangle(mesh);
763  testTriangulatorInterp(mesh, triangle, 2, 10);
764  }
765 
766 
768  {
769  LOG_UNIT_TEST;
770 
772  TriangleInterface triangle(mesh);
773  testTriangulatorHoles(mesh, triangle);
774  }
775 
776 
778  {
779  LOG_UNIT_TEST;
780 
782  TriangleInterface triangle(mesh);
783  testTriangulatorMeshedHoles(mesh, triangle);
784  }
785 
786 
787 #ifdef LIBMESH_ENABLE_AMR
789  {
790  LOG_UNIT_TEST;
791 
793  TriangleInterface triangle(mesh);
794  testTriangulatorRoundHole(mesh, triangle);
795  }
796 #endif // LIBMESH_ENABLE_AMR
797 
798 
800  {
801  LOG_UNIT_TEST;
802 
804  TriangleInterface triangulator(mesh);
805  testEdgesMesh(mesh, EDGE2);
806 
807  this->testTriangulatorBase(mesh, triangulator);
808  }
809 
810 
812  {
813  LOG_UNIT_TEST;
814 
816  TriangleInterface triangle(mesh);
817  testTriangulatorSegments(mesh, triangle);
818  }
819 #endif // LIBMESH_HAVE_TRIANGLE
820 
821 
822 #ifdef LIBMESH_HAVE_POLY2TRI
824  {
825  LOG_UNIT_TEST;
826 
828  Poly2TriTriangulator p2t_tri(mesh);
829  testTriangulator(mesh, p2t_tri);
830  }
831 
832 
834  {
835  LOG_UNIT_TEST;
836 
838  Poly2TriTriangulator p2t_tri(mesh);
839  testHalfDomain(mesh, p2t_tri, EDGE2);
840  }
841 
842 
844  {
845  LOG_UNIT_TEST;
846 
848  Poly2TriTriangulator p2t_tri(mesh);
849  testHalfDomain(mesh, p2t_tri, EDGE3);
850  }
851 
852 
854  {
855  LOG_UNIT_TEST;
856 
858  Poly2TriTriangulator p2t_tri(mesh);
859  testTriangulatorInterp(mesh, p2t_tri, 1, 6);
860  }
861 
862 
864  {
865  LOG_UNIT_TEST;
866 
868  Poly2TriTriangulator p2t_tri(mesh);
869  testTriangulatorInterp(mesh, p2t_tri, 2, 10);
870  }
871 
872 
874  {
875  LOG_UNIT_TEST;
876 
878  Poly2TriTriangulator p2t_tri(mesh);
879  testTriangulatorHoles(mesh, p2t_tri);
880  }
881 
882 
884  {
885  LOG_UNIT_TEST;
886 
888  Poly2TriTriangulator p2t_tri(mesh);
889  testTriangulatorMeshedHoles(mesh, p2t_tri);
890  }
891 
892 
893 #ifdef LIBMESH_ENABLE_AMR
895  {
896  LOG_UNIT_TEST;
897 
899  Poly2TriTriangulator p2t_tri(mesh);
900  testTriangulatorRoundHole(mesh, p2t_tri);
901  }
902 #endif // LIBMESH_ENABLE_AMR
903 
904 
906  {
907  LOG_UNIT_TEST;
908 
910  Poly2TriTriangulator triangulator(mesh);
911  testEdgesMesh(mesh, EDGE2);
912 
913  this->testTriangulatorBase(mesh, triangulator);
914  }
915 
916 
918  {
919  LOG_UNIT_TEST;
920 
922  Poly2TriTriangulator triangulator(mesh);
923  testEdgesMesh(mesh, EDGE3);
924 
925  this->testTriangulatorBase(mesh, triangulator);
926  }
927 
928 
930  {
931  LOG_UNIT_TEST;
932 
934  Poly2TriTriangulator triangulator(mesh);
935 
936  // The same quad as testTriangulator, but out of order
937  auto node0 = mesh.add_point(Point(0,0), 0);
938  auto node1 = mesh.add_point(Point(1,2), 1);
939  auto node2 = mesh.add_point(Point(1,0), 2);
940  auto node3 = mesh.add_point(Point(0,1), 3);
941 
942  // Edges, but not enough to complete the quad
943  auto edge13 = mesh.add_elem(Elem::build(EDGE2));
944  edge13->set_node(0, node1);
945  edge13->set_node(1, node3);
946  auto edge02 = mesh.add_elem(Elem::build(EDGE2));
947  edge02->set_node(0, node0);
948  edge02->set_node(1, node2);
949  auto edge30 = mesh.add_elem(Elem::build(EDGE2));
950  edge30->set_node(0, node3);
951  edge30->set_node(1, node0);
952 
954 
955  testExceptionBase(mesh, triangulator, "Bad edge topology");
956  }
957 
958 
960  {
961  LOG_UNIT_TEST;
962 
964  Poly2TriTriangulator triangulator(mesh);
965 
966  // Two separate triangles
967  auto node0 = mesh.add_point(Point(0,0), 0);
968  auto node1 = mesh.add_point(Point(0,1), 1);
969  auto node2 = mesh.add_point(Point(1,0), 2);
970 
971  auto node3 = mesh.add_point(Point(2,0), 3);
972  auto node4 = mesh.add_point(Point(2,1), 4);
973  auto node5 = mesh.add_point(Point(3,0), 5);
974 
975  auto edge01 = mesh.add_elem(Elem::build(EDGE2));
976  edge01->set_node(0, node0);
977  edge01->set_node(1, node1);
978  auto edge12 = mesh.add_elem(Elem::build(EDGE2));
979  edge12->set_node(0, node1);
980  edge12->set_node(1, node2);
981  auto edge20 = mesh.add_elem(Elem::build(EDGE2));
982  edge20->set_node(0, node2);
983  edge20->set_node(1, node0);
984 
985  auto edge34 = mesh.add_elem(Elem::build(EDGE2));
986  edge34->set_node(0, node3);
987  edge34->set_node(1, node4);
988  auto edge45 = mesh.add_elem(Elem::build(EDGE2));
989  edge45->set_node(0, node4);
990  edge45->set_node(1, node5);
991  auto edge53 = mesh.add_elem(Elem::build(EDGE2));
992  edge53->set_node(0, node5);
993  edge53->set_node(1, node3);
994 
996 
997  testExceptionBase(mesh, triangulator, "multiple loops of Edge");
998  }
999 
1001  {
1002  LOG_UNIT_TEST;
1003 
1005  Poly2TriTriangulator triangulator(mesh);
1006 
1007  // Two separate triangles
1008  auto node0 = mesh.add_point(Point(0,0), 0);
1009  auto node1 = mesh.add_point(Point(1,0), 1);
1010  auto node2 = mesh.add_point(Point(0,1), 2);
1011 
1012  auto node3 = mesh.add_point(Point(2,0), 3);
1013  auto node4 = mesh.add_point(Point(3,0), 4);
1014  auto node5 = mesh.add_point(Point(2,1), 5);
1015 
1016  auto tri012 = mesh.add_elem(Elem::build(TRI3));
1017  tri012->set_node(0, node0);
1018  tri012->set_node(1, node1);
1019  tri012->set_node(2, node2);
1020  auto tri345 = mesh.add_elem(Elem::build(TRI3));
1021  tri345->set_node(0, node3);
1022  tri345->set_node(1, node4);
1023  tri345->set_node(2, node5);
1024 
1026 
1027  testExceptionBase(mesh, triangulator, "cannot choose one");
1028  }
1029 
1030 
1032  {
1033  LOG_UNIT_TEST;
1034 
1036  Poly2TriTriangulator triangulator(mesh);
1037  testEdgesMesh(mesh, EDGE2);
1038  testPoly2TriRefinementBase(mesh, nullptr, 1.5, 14);
1039  }
1040 
1041 
1043  {
1044  LOG_UNIT_TEST;
1045 
1047  Poly2TriTriangulator p2t_tri(mesh);
1048  testTriangulatorSegments(mesh, p2t_tri);
1049  }
1050 
1051  void testPoly2TriRefinementBase
1053  const std::vector<TriangulatorInterface::Hole*> * holes,
1054  Real expected_total_area,
1055  dof_id_type n_original_elem,
1056  Real desired_area = 0.1,
1057  FunctionBase<Real> * area_func = nullptr)
1058  {
1059  Poly2TriTriangulator triangulator(mesh);
1060 
1061  commonSettings(triangulator);
1062 
1063  if (holes)
1064  triangulator.attach_hole_list(holes);
1065 
1066  // Try to insert points!
1067  triangulator.desired_area() = desired_area;
1068  triangulator.set_desired_area_function(area_func);
1069 
1070  triangulator.triangulate();
1071 
1072  // If refinement should have increased our element count, check it
1073  if (desired_area || area_func)
1074  CPPUNIT_ASSERT_GREATER(n_original_elem, mesh.n_elem()); // n_elem+++
1075  else
1076  CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), n_original_elem);
1077 
1078  Real area = 0;
1079  for (const auto & elem : mesh.active_local_element_ptr_range())
1080  {
1081  CPPUNIT_ASSERT_EQUAL(elem->level(), 0u);
1082  CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);
1083 
1084  const Real my_area = elem->volume();
1085 
1086  // my_area <= desired_area, wow this macro ordering hurts
1087  if (desired_area != 0)
1088  CPPUNIT_ASSERT_LESSEQUAL(desired_area, my_area);
1089 
1090  if (area_func != nullptr)
1091  for (auto v : make_range(elem->n_vertices()))
1092  {
1093  const Real local_desired_area =
1094  (*area_func)(elem->point(v));
1095  CPPUNIT_ASSERT_LESSEQUAL(local_desired_area, my_area);
1096  }
1097 
1098  area += my_area;
1099  }
1100 
1101  mesh.comm().sum(area);
1102 
1103  LIBMESH_ASSERT_FP_EQUAL(area, expected_total_area, TOLERANCE*TOLERANCE);
1104  }
1105 
1107  {
1108  LOG_UNIT_TEST;
1109 
1111  testTriangulatorTrapMesh(mesh);
1112  testPoly2TriRefinementBase(mesh, nullptr, 1.5, 15);
1113  }
1114 
1116  {
1117  LOG_UNIT_TEST;
1118 
1120  testTriangulatorTrapMesh(mesh);
1121  // Make sure we see 0 as "don't refine", not "infinitely refine"
1122  testPoly2TriRefinementBase(mesh, nullptr, 1.5, 2, 0);
1123  }
1124 
1125 
1127  {
1128  LOG_UNIT_TEST;
1129 
1131  testTriangulatorTrapMesh(mesh);
1132  testPoly2TriRefinementBase(mesh, nullptr, 1.5, 150, 0.01);
1133  }
1134 
1136  {
1137 #ifdef LIBMESH_HAVE_FPARSER
1138  ParsedFunction<Real> var_area {"0.002*(1+2*x)*(1+2*y)"};
1140  testTriangulatorTrapMesh(mesh);
1141  testPoly2TriRefinementBase(mesh, nullptr, 1.5, 150, 0, &var_area);
1142 #endif // LIBMESH_HAVE_FPARSER
1143  }
1144 
1146  {
1147  LOG_UNIT_TEST;
1148 
1149  // Add a diamond hole
1150  TriangulatorInterface::PolygonHole diamond(Point(0.5,0.5), std::sqrt(2_R)/4, 4);
1151  const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
1152 
1154  testTriangulatorTrapMesh(mesh);
1155  testPoly2TriRefinementBase(mesh, &holes, 1.25, 13);
1156  }
1157 
1159  {
1160  LOG_UNIT_TEST;
1161 
1163  testTriangulatorTrapMesh(mesh);
1164  Poly2TriTriangulator p2t_tri(mesh);
1165 
1166  Real total_area = 1.5;
1167 
1168  // Try a narrower point
1169  mesh.node_ref(2)(1) = 3;
1170  total_area += 0.5;
1171 
1172  // Add a bunch of tiny diamond holes
1173  const int N=3, M=3;
1174  TriangulatorInterface::PolygonHole diamond(Point(), std::sqrt(2_R)/20, 4);
1175 
1176  std::vector<TriangulatorInterface::AffineHole> hole_data;
1177  // Reserve so we don't invalidate pointers
1178  hole_data.reserve(M*N);
1179  std::vector<TriangulatorInterface::Hole*> holes;
1180  for (int i : make_range(M))
1181  for (int j : make_range(N))
1182  {
1183  Point shift(Real(i+1)/(M+1),Real(j+1)/(N+1));
1184  hole_data.emplace_back(diamond, 0, shift);
1185  holes.push_back(&hole_data.back());
1186  total_area -= hole_data.back().area();
1187  }
1188 
1189  p2t_tri.attach_hole_list(&holes);
1190 
1191  p2t_tri.set_refine_boundary_allowed(false);
1192 
1193  testTriangulatorInterp(mesh, p2t_tri, 4, 0, total_area, 0.03_R);
1194  }
1195 
1196  void testPoly2TriHolesInteriorRefinedBase
1197  (dof_id_type n_original_elem,
1198  Real desired_area)
1199  {
1200  // Add a diamond hole, disallowing refinement of it
1201  TriangulatorInterface::PolygonHole diamond(Point(0.5,0.5), std::sqrt(2_R)/4, 4);
1202 
1203  CPPUNIT_ASSERT_EQUAL(diamond.refine_boundary_allowed(), true);
1204 
1205  diamond.set_refine_boundary_allowed(false);
1206 
1207  const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
1208 
1209  // Doing extra refinement here to ensure that we had the
1210  // *opportunity* to refine the hole boundaries.
1212  testTriangulatorTrapMesh(mesh);
1213  testPoly2TriRefinementBase(mesh, &holes, 1.25, n_original_elem, desired_area);
1214 
1215  // Checking that we have more outer boundary sides than we started
1216  // with, and exactly the 4 hole boundary sides we started with.
1217  auto side_bcs = mesh.get_boundary_info().build_side_list();
1218 
1219  int n_outer_sides = std::count_if(side_bcs.begin(), side_bcs.end(),
1220  [](auto t){return std::get<2>(t) == 0;});
1221  CPPUNIT_ASSERT_GREATER(4, n_outer_sides); // n_outer_sides > 4
1222  int n_hole_sides = std::count_if(side_bcs.begin(), side_bcs.end(),
1223  [](auto t){return std::get<2>(t) == 1;});
1224  CPPUNIT_ASSERT_EQUAL(n_hole_sides, 4);
1225  }
1226 
1227 
1229  {
1230  LOG_UNIT_TEST;
1231  testPoly2TriHolesInteriorRefinedBase(25, 0.05);
1232  }
1233 
1234 
1236  {
1237  LOG_UNIT_TEST;
1238  // 0.01 creates slivers triggering a poly2tri exception for me - RHS
1239  testPoly2TriHolesInteriorRefinedBase(60, 0.02);
1240  }
1241 
1242 
1244  {
1245  // Add a diamond hole
1246  TriangulatorInterface::PolygonHole diamond(Point(0.5,0.5), std::sqrt(2_R)/4, 4);
1247  const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
1248 
1250  testTriangulatorTrapMesh(mesh);
1251  testPoly2TriRefinementBase(mesh, &holes, 1.25, 125, 0.01);
1252  }
1253 
1255  {
1256 #ifdef LIBMESH_HAVE_FPARSER
1257  // Add a diamond hole
1258  TriangulatorInterface::PolygonHole diamond(Point(0.5,0.5), std::sqrt(2_R)/4, 4);
1259  const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
1260 
1261  ParsedFunction<Real> var_area {"0.002*(0.25+2*x)*(0.25+2*y)"};
1263  testTriangulatorTrapMesh(mesh);
1264  testPoly2TriRefinementBase(mesh, &holes, 1.25, 150, 0, &var_area);
1265 #endif // LIBMESH_HAVE_FPARSER
1266  }
1267 
1268 
1269 #endif // LIBMESH_HAVE_POLY2TRI
1270 
1271 };
1272 
1273 
void testTriangulatorTrapMesh(UnstructuredMesh &mesh)
ElemType
Defines an enum for geometric element types.
void build_sphere(UnstructuredMesh &mesh, const Real rad=1, const unsigned int nr=2, const ElemType type=INVALID_ELEM, const unsigned int n_smooth=2, const bool flat=true)
Meshes a spherical or mapped-spherical domain.
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
const Real radius
virtual void triangulate()=0
This is the main public interface for this function.
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:907
virtual void set_refine_boundary_allowed(bool refine_bdy_allowed) override
Set whether or not the triangulation is allowed to refine the mesh boundary when refining the interio...
A Function generated (via FParser) by parsing a mathematical expression.
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
static constexpr Real TOLERANCE
An abstract class for defining a 2-dimensional hole.
void set_verify_hole_boundaries(bool v)
Verifying that hole boundaries don&#39;t cross the outer boundary or each other is something like O(N_bdy...
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:759
void sum(T &r) const
void testTriangulatorSegments(MeshBase &mesh, TriangulatorInterface &triangulator)
Real area() const
Return the area of the hole.
MeshBase & mesh
const Parallel::Communicator & comm() const
void set_interpolate_boundary_points(int n_points)
Complicated setter, for compatibility with insert_extra_points()
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
void set_outer_boundary_ids(std::set< std::size_t > bdy_ids)
A set of ids to allow on the outer boundary loop: interpreted as boundary ids of 2D elements and/or s...
The libMesh namespace provides an interface to certain functionality in the library.
ElemType & elem_type()
Sets and/or gets the desired element type.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
void testTriangulatorHoles(MeshBase &mesh, TriangulatorInterface &triangulator)
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
void testHalfDomain(MeshBase &mesh, TriangulatorInterface &triangulator, ElemType elem_type)
This is the MeshBase class.
Definition: mesh_base.h:75
void build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
Creates a list of element numbers, sides, and ids for those sides.
TriangulationType & triangulation_type()
Sets and/or gets the desired triangulation type.
void commonSettings(TriangulatorInterface &triangulator)
auto norm_sq() const -> decltype(std::norm(T()))
Definition: type_vector.h:926
void attach_hole_list(const std::vector< Hole *> *holes)
Attaches a vector of Hole* pointers which will be meshed around.
virtual void set_desired_area_function(FunctionBase< Real > *desired) override
Set a function giving desired triangle area as a function of position.
The UnstructuredMesh class is derived from the MeshBase class.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:444
Real & minimum_angle()
Sets and/or gets the minimum desired angle.
libmesh_assert(ctx)
CPPUNIT_TEST_SUITE_REGISTRATION(MeshTriangulationTest)
void testTriangulatorInterp(UnstructuredMesh &mesh, TriangulatorInterface &triangulator, int interpolate_boundary_points, dof_id_type n_expected_elem, Real expected_total_area=1.5, Real desired_area=1000)
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:972
void translate(MeshBase &mesh, const Real xt=0., const Real yt=0., const Real zt=0.)
Translates the mesh.
virtual bool refine_boundary_allowed() const
Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interio...
virtual void triangulate() override
Internally, this calls the poly2tri triangulation code in a loop, inserting our owner Steiner points ...
Real & desired_area()
Sets and/or gets the desired triangle area.
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< std::pair< unsigned int, unsigned int > > segments
When constructing a PSLG, if the node numbers do not define the desired boundary segments implicitly ...
void testTriangulatorRoundHole(MeshBase &mesh, TriangulatorInterface &triangulator)
void max(const T &r, T &o, Request &req) const
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
Another concrete instantiation of the hole, as general as ArbitraryHole, but based on an existing 1D ...
virtual void set_refine_boundary_allowed(bool refine_bdy_allowed)
Set whether or not a triangulator is allowed to refine the hole boundary when refining the mesh inter...
A concrete instantiation of the Hole class that describes polygonal (triangular, square, pentagonal, ...) holes.
void testTriangulatorBase(MeshBase &mesh, TriangulatorInterface &triangulator)
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
void testTriangulator(MeshBase &mesh, TriangulatorInterface &triangulator)
void testEdgesMesh(MeshBase &mesh, ElemType elem_type)
Another concrete instantiation of the hole, this one should be sufficiently general for most non-poly...
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:596
A C++ interface between LibMesh and the poly2tri library, with custom code for Steiner point insertio...
virtual dof_id_type n_elem() const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
A C++ interface between LibMesh and the Triangle library written by J.R.
void testTriangulatorMeshedHoles(MeshBase &mesh, TriangulatorInterface &triangulator)
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:117
virtual dof_id_type n_nodes() const =0
void testExceptionBase(MeshBase &mesh, TriangulatorInterface &triangulator, const char *re)
bool & smooth_after_generating()
Sets/gets flag which tells whether to do two steps of Laplace mesh smoothing after generating the gri...
void testFoundCenters(const MeshBase &mesh, const std::vector< Point > &expected_centers)
uint8_t dof_id_type
Definition: id_types.h:67
const Real pi
.
Definition: libmesh.h:299