libMesh
Loading...
Searching...
No Matches
triangulator_interface.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19#include "libmesh/libmesh_config.h"
20
21// We'd like reproduceability here even when different FP rounding can
22// lead to different triangle splitting decisions
23#include "libmesh/enforce_ieee754.h"
24
25// libmesh includes
26#include "libmesh/mesh_triangle_interface.h"
27#include "libmesh/unstructured_mesh.h"
28#include "libmesh/face_tri3.h"
29#include "libmesh/face_tri6.h"
30#include "libmesh/mesh_generation.h"
31#include "libmesh/mesh_smoother_laplace.h"
32#include "libmesh/boundary_info.h"
33#include "libmesh/mesh_triangle_holes.h"
34#include "libmesh/mesh_triangle_wrapper.h"
35#include "libmesh/enum_elem_type.h"
36#include "libmesh/enum_order.h"
37#include "libmesh/enum_to_string.h"
38#include "libmesh/utility.h"
39
40#include "libmesh/meshfree_interpolation.h"
41
42// C/C++ includes
43#include <limits>
44#include <sstream>
45
46
47namespace libMesh
48{
49//
50// Function definitions for the AutoAreaFunction class
51//
52
53// Constructor
55 const unsigned int num_nearest_pts,
56 const unsigned int power,
57 const Real background_value,
58 const Real background_eff_dist):
59 _comm(comm),
60 _num_nearest_pts(num_nearest_pts),
61 _power(power),
62 _background_value(background_value),
63 _background_eff_dist(background_eff_dist),
64 _auto_area_mfi(std::make_unique<InverseDistanceInterpolation<3>>(_comm, _num_nearest_pts, _power, _background_value, _background_eff_dist))
65{
66 this->_initialized = false;
67 this->_is_time_dependent = false;
68}
69
70// Destructor
72
73void AutoAreaFunction::init_mfi (const std::vector<Point> & input_pts,
74 const std::vector<Real> & input_vals)
75{
76 std::vector<std::string> field_vars{"f"};
77 _auto_area_mfi->set_field_variables(field_vars);
78 _auto_area_mfi->get_source_points() = input_pts;
79#ifdef LIBMESH_USE_COMPLEX_NUMBERS
80 std::vector<Number> input_complex_vals;
81 for (const auto & input_val : input_vals)
82 input_complex_vals.push_back(Complex (input_val, 0.0));
83 _auto_area_mfi->get_source_vals() = input_complex_vals;
84#else
85 _auto_area_mfi->get_source_vals() = input_vals;
86#endif
87 _auto_area_mfi->prepare_for_use();
88 this->_initialized = true;
89}
90
92 const Real /*time*/)
93{
95
96 std::vector<Point> target_pts;
97 std::vector<Number> target_vals;
98
99 target_pts.push_back(p);
100 target_vals.resize(1);
101
102 _auto_area_mfi->interpolate_field_data(_auto_area_mfi->field_variables(), target_pts, target_vals);
103
104 return libmesh_real(target_vals.front());
105}
106
107//
108// Function definitions for the TriangulatorInterface class
109//
110
111// Constructor
113 : _mesh(mesh),
114 _holes(nullptr),
115 _markers(nullptr),
116 _regions(nullptr),
117 _elem_type(TRI3),
118 _desired_area(0.1),
119 _minimum_angle(20.0),
120 _triangulation_type(GENERATE_CONVEX_HULL),
121 _insert_extra_points(false),
122 _smooth_after_generating(true),
123 _quiet(true),
124 _fixup_tri7_center_nodes(false),
125 _auto_area_function(nullptr)
126{}
127
128
130{
131 // Maybe we'll reserve a meaning for negatives later?
132 libmesh_assert(n_points >= 0);
133
135
136 // backwards compatibility - someone (including us) might want to
137 // query this via the old API.
138 _insert_extra_points = n_points;
139}
140
141
142
144{
145 // backwards compatibility - someone might have turned this off via
146 // the old API
148 return 0;
149
151}
152
153
154
156{
157 // Don't try to override manually specified segments
158 if (!this->segments.empty())
159 return;
160
161 // If we have edges, they should form the polyline with the ordering
162 // we want. Let's turn them into segments for later use, because
163 // we're going to delete the original elements to replace with our
164 // triangulation.
165 if (_mesh.n_elem())
166 {
167 // Mapping from points to node ids, to back those out from
168 // MeshedHole results later
169 std::map<Point, dof_id_type> point_id_map;
170
171 for (Node * node : _mesh.node_ptr_range())
172 {
173 // We're not going to support overlapping nodes on the boundary
174 libmesh_error_msg_if
175 (point_id_map.count(*node),
176 "TriangulatorInterface does not support overlapping nodes found at "
177 << static_cast<Point&>(*node));
178
179 point_id_map.emplace(*node, node->id());
180 }
181
182 // We don't support directly generating Tri6, so for
183 // compatibility with future stitching we need to be working
184 // with first-order elements. Let's get rid of any non-vertex
185 // nodes we just added.
186 for (Elem * elem : _mesh.element_ptr_range())
187 for (auto n : make_range(elem->n_vertices(), elem->n_nodes()))
188 point_id_map.erase(elem->point(n));
189
190 // We'll steal the ordering calculation from
191 // the MeshedHole code
193
194 // If we've specified only a subset of the mesh as our outer
195 // boundary, then we may have nodes that don't actually fall
196 // inside that boundary. Triangulator code doesn't like Steiner
197 // points that aren't inside the triangulation domain, so we
198 // need to get rid of them.
199 //
200 // Also, if we're using Edge3 elements to define our outer
201 // boundary, we're only dealing with their 2 end nodes and we'll
202 // need to get rid of their central nodes.
203 std::unordered_set<Node *> nodes_to_delete;
204
205 for (Elem * elem : _mesh.element_ptr_range())
206 for (auto n : make_range(elem->n_vertices(), elem->n_nodes()))
207 nodes_to_delete.insert(elem->node_ptr(n));
208
209 if (!this->_bdy_ids.empty())
210 {
211 for (auto & node : _mesh.node_ptr_range())
212 if (!mh.contains(*node))
213 nodes_to_delete.insert(node);
214 }
215
216 // And now we're done with elements. Delete them lest they have
217 // dangling pointers to nodes we'll be deleting.
219
220 // Make segments from boundary nodes; also make sure we don't
221 // delete them.
222 const std::size_t np = mh.n_points();
223 for (auto i : make_range(np))
224 {
225 const Point pt = mh.point(i);
226 const dof_id_type id0 = libmesh_map_find(point_id_map, pt);
227 nodes_to_delete.erase(_mesh.node_ptr(id0));
228 const Point next_pt = mh.point((np+i+1)%np);
229 const dof_id_type id1 = libmesh_map_find(point_id_map, next_pt);
230 this->segments.emplace_back(id0, id1);
231 for (auto m : make_range(mh.n_midpoints()))
232 {
233 this->segment_midpoints.emplace_back(mh.midpoint(m, i));
234 this->segment_midpoints_keys.emplace_back(pt);
235 }
236 }
237
238 for (Node * node : nodes_to_delete)
239 _mesh.delete_node(node);
240
241 if (this->_verify_hole_boundaries && _holes)
242 this->verify_holes(mh);
243 }
244}
245
246
247
249{
250 // Don't try to override manually specified segments, or try to add
251 // segments if we're doing a convex hull
252 if (!this->segments.empty() || _triangulation_type != PSLG)
253 return;
254
255 for (auto node_it = _mesh.nodes_begin(),
256 node_end = _mesh.nodes_end();
257 node_it != node_end;)
258 {
259 Node * node = *node_it;
260
261 // If we're out of boundary nodes, the rest are going to be
262 // Steiner points or hole points
263 if (node->id() >= max_node_id)
264 break;
265
266 ++node_it;
267
268 Node * next_node = (node_it == node_end) ?
269 *_mesh.nodes_begin() : *node_it;
270
271 this->segments.emplace_back(node->id(), next_node->id());
272 }
273
274 if (this->_verify_hole_boundaries && _holes)
275 {
276 std::vector<Point> outer_pts;
277 for (auto segment : this->segments)
278 outer_pts.push_back(_mesh.point(segment.first));
279
280 ArbitraryHole ah(outer_pts);
281 this->verify_holes(ah);
282 }
283}
284
285
286
288{
289 // If the initial PSLG is really simple, e.g. an L-shaped domain or
290 // a square/rectangle, the resulting triangulation may be very
291 // "structured" looking. Sometimes this is a problem if your
292 // intention is to work with an "unstructured" looking grid. We can
293 // attempt to work around this limitation by inserting midpoints
294 // into the original PSLG. Inserting additional points into a
295 // set of points meant to be a convex hull usually makes less sense.
296
297 const int n_interpolated = this->get_interpolate_boundary_points();
298 if ((_triangulation_type==PSLG) && n_interpolated)
299 {
300 // If we were lucky enough to start with contiguous node ids,
301 // let's keep them that way.
303
304 std::vector<std::pair<unsigned int, unsigned int>> old_segments =
305 std::move(this->segments);
306
307 // We expect to have converted any elems and/or nodes into
308 // segments by now.
309 libmesh_assert(!old_segments.empty());
310
311 this->segments.clear();
312
313 // Insert a new point on each segment at evenly spaced locations
314 // between existing boundary points.
315 // np=index into new points vector
316 // n =index into original points vector
317 for (auto old_segment : old_segments)
318 {
319 Node * begin_node = _mesh.node_ptr(old_segment.first);
320 Node * end_node = _mesh.node_ptr(old_segment.second);
321 dof_id_type current_id = begin_node->id();
322 for (auto i : make_range(n_interpolated))
323 {
324 // new points are equispaced along the original segments
325 const Point new_point =
326 ((n_interpolated-i) * *(Point *)(begin_node) +
327 (i+1) * *(Point *)(end_node)) /
328 (n_interpolated + 1);
329 Node * next_node = _mesh.add_point(new_point, nn++);
330 this->segments.emplace_back(current_id,
331 next_node->id());
332 current_id = next_node->id();
333 }
334 this->segments.emplace_back(current_id,
335 end_node->id());
336 }
337 }
338}
339
340
342{
343 switch (_elem_type)
344 {
345 case TRI3:
346 // Nothing to do if we're not requested to increase order
347 return;
348 case TRI6:
350 break;
351 case TRI7:
353 break;
354 default:
355 libmesh_not_implemented();
356 }
357
358 // If we have any midpoint location data, we'll want to look it up
359 // by point. all_midpoints[{p, m}] will be the mth midpoint
360 // location following after point p (when traversing a triangle
361 // counter-clockwise)
362 std::map<std::pair<Point, unsigned int>, Point> all_midpoints;
363 unsigned int n_midpoints =
364 this->segment_midpoints.size() / this->segments.size();
365 libmesh_assert_equal_to(this->segments.size() * n_midpoints,
366 this->segment_midpoints.size());
367 for (auto m : make_range(n_midpoints))
368 for (auto i : make_range(this->segments.size()))
369 {
370 const Point & p = segment_midpoints_keys[i*n_midpoints+m];
371 all_midpoints[{p,m}] =
372 this->segment_midpoints[i*n_midpoints+m];
373 }
374
375 if (_holes)
376 for (const Hole * hole : *_holes)
377 {
378 if (!hole->n_midpoints())
379 continue;
380 if (!n_midpoints)
381 n_midpoints = hole->n_midpoints();
382 else if (hole->n_midpoints() != n_midpoints)
383 libmesh_not_implemented_msg
384 ("Differing boundary midpoint counts " <<
385 hole->n_midpoints() << " and " << n_midpoints);
386
387 // Our inner holes are expected to have points in
388 // counter-clockwise order, which is backwards from how we
389 // want to traverse them when iterating in counter-clockwise
390 // order over a triangle, so we'll need to reverse our maps
391 // carefully here.
392 const auto n_hole_points = hole->n_points();
393 libmesh_assert(n_hole_points);
394 for (auto m : make_range(n_midpoints))
395 {
396 for (auto i : make_range(n_hole_points-1))
397 {
398 const Point & p = hole->point(i+1);
399 all_midpoints[{p,m}] = hole->midpoint(n_midpoints-m-1, i);
400 }
401 const Point & p = hole->point(0);
402 all_midpoints[{p,m}] = hole->midpoint(n_midpoints-m-1, n_hole_points-1);
403 }
404 }
405
406 // The n_midpoints > 1 case is for future proofing, but in the
407 // present we have EDGE4 and no TRI10 yet.
408 if (n_midpoints > 1)
409 libmesh_not_implemented_msg
410 ("Cannot construct triangles with more than 1 midpoint per edge");
411
412 if (!n_midpoints)
413 return;
414
415 for (Elem * elem : _mesh.element_ptr_range())
416 {
417 // This should only be called right after we've finished
418 // converting a triangulation to higher order
419 libmesh_assert_equal_to(elem->n_vertices(), 3);
420 libmesh_assert_not_equal_to(elem->default_order(), FIRST);
421
422 for (auto n : make_range(3))
423 {
424 // Only hole/outer boundary segments need adjusted midpoints
425 if (elem->neighbor_ptr(n))
426 continue;
427
428 const Point & p = elem->point(n);
429
430 if (const auto it = all_midpoints.find({p,0});
431 it != all_midpoints.end())
432 elem->point(n+3) = it->second;
433 }
434 }
435
436 // Moving boundary mid-edge nodes can displace the TRI7 interior node
437 // and tangle the element map. Repositioning the interior node is
438 // opt-in (off by default); the validity check always runs.
441
443}
444
445
447{
448 libmesh_assert_equal_to(_elem_type, TRI7);
449
450 // Place the interior node at the image of the reference centroid
451 // (xi, eta) = (1/3, 1/3) under the curved Tri6 map, using the Tri6
452 // shape function values there as weights: -1/9 on the vertices and
453 // 4/9 on the mid-edges. This reduces to the straight-edge centroid
454 // when no boundary midpoint has moved.
455 static const Real wv = -Real(1)/9;
456 static const Real wm = Real(4)/9;
457
458 for (Elem * elem : _mesh.element_ptr_range())
459 {
460 libmesh_assert_equal_to(elem->n_vertices(), 3);
461 libmesh_assert_equal_to(elem->n_nodes(), 7u);
462
463 elem->point(6) = wv * (elem->point(0) +
464 elem->point(1) +
465 elem->point(2)) +
466 wm * (elem->point(3) +
467 elem->point(4) +
468 elem->point(5));
469 }
470}
471
472
474{
475 if (_elem_type != TRI6 && _elem_type != TRI7)
476 return;
477
478 // Once fixup_tri7_center_nodes() has placed node 6, the TRI6 and TRI7
479 // mappings coincide and this Tri6 formula serves both.
480 static const Real xi_samples[7] = {Real(0), Real(1), Real(0),
481 Real(1)/2, Real(1)/2, Real(0),
482 Real(1)/3};
483 static const Real eta_samples[7] = {Real(0), Real(0), Real(1),
484 Real(0), Real(1)/2, Real(1)/2,
485 Real(1)/3};
486
487 for (Elem * elem : _mesh.element_ptr_range())
488 {
489 libmesh_assert_equal_to(elem->n_vertices(), 3);
490 libmesh_assert_greater_equal(elem->n_nodes(), 6u);
491
492 const Point & x0 = elem->point(0);
493 const Point & x1 = elem->point(1);
494 const Point & x2 = elem->point(2);
495 const Point & x3 = elem->point(3);
496 const Point & x4 = elem->point(4);
497 const Point & x5 = elem->point(5);
498
499 // Tri6 mapping derivative coefficients (see Tri6::volume()):
500 // dx/dxi = xi*a1 + eta*b1 + c1, dx/deta = xi*b1 + eta*b2 + c2.
501 const Point a1 = 4*x0 + 4*x1 - 8*x3;
502 const Point b1 = 4*x0 - 4*x3 + 4*x4 - 4*x5;
503 const Point c1 = -3*x0 - 1*x1 + 4*x3;
504 const Point b2 = 4*x0 + 4*x2 - 8*x5;
505 const Point c2 = -3*x0 - 1*x2 + 4*x5;
506
507 // Scale the tolerance by the straight-edge triangle area, which
508 // is strictly positive for the valid TRI3 poly2tri input.
509 const Real ref_area = 0.5 * cross_norm(x1 - x0, x2 - x0);
510 const Real jac_tol = TOLERANCE * ref_area;
511
512 Real min_jac = std::numeric_limits<Real>::max();
513 unsigned int worst_sample = 0;
514 for (unsigned int s = 0; s != 7; ++s)
515 {
516 const Real xi = xi_samples[s];
517 const Real eta = eta_samples[s];
518 const Point dxi = xi*a1 + eta*b1 + c1;
519 const Point deta = xi*b1 + eta*b2 + c2;
520 // z-component of the cross product; the elements are planar.
521 const Real jac = dxi(0)*deta(1) - dxi(1)*deta(0);
522 if (jac < min_jac)
523 {
524 min_jac = jac;
525 worst_sample = s;
526 }
527 }
528
529 if (min_jac > jac_tol)
530 continue;
531
532 // Build a diagnostic naming every snapped boundary side on this
533 // element so the user can immediately see which curved-boundary
534 // input caused the tangle.
535 std::ostringstream sides;
536 for (unsigned int n = 0; n != 3; ++n)
537 if (!elem->neighbor_ptr(n))
538 {
539 const Point straight =
540 0.5 * (elem->point(n) + elem->point((n+1) % 3));
541 sides << " (boundary side " << n
542 << ": straight midpoint " << straight
543 << ", snapped midpoint " << elem->point(n+3) << ")";
544 }
545
546 libmesh_error_msg(
547 "TriangulatorInterface: snapping a boundary midpoint produced a "
548 "tangled quadratic triangle (element " << elem->id()
549 << ", non-positive Jacobian " << min_jac
550 << " at reference sample (" << xi_samples[worst_sample] << ", "
551 << eta_samples[worst_sample] << "); reference triangle area "
552 << ref_area << ")." << sides.str()
553 << " Refine the boundary discretization so that recorded "
554 "midpoints lie closer to their straight-line midpoints, "
555 "then retry.");
556 }
557}
558
559
561{
562 for (const Hole * hole : *_holes)
563 {
564 for (const Hole * hole2 : *_holes)
565 {
566 if (hole == hole2)
567 continue;
568
569 for (auto i : make_range(hole2->n_points()))
570 if (hole->contains(hole2->point(i)))
571 libmesh_error_msg
572 ("Found point " << hole2->point(i) <<
573 " on one hole boundary and another's interior");
574 }
575
576 for (auto i : make_range(hole->n_points()))
577 if (!outer_bdy.contains(hole->point(i)))
578 libmesh_error_msg
579 ("Found point " << hole->point(i) <<
580 " on hole boundary but outside outer boundary");
581 }
582}
583
584
586{
587 // If the holes vector is non-nullptr (and non-empty) we need to determine
588 // the number of additional points which the holes will add to the
589 // triangulation.
590 // Note that the number of points is always equal to the number of segments
591 // that form the holes.
592 unsigned int n_hole_points = 0;
593
594 if (_holes)
595 for (const auto & hole : *_holes)
596 {
597 n_hole_points += hole->n_points();
598 // A hole at least has one enclosure.
599 // Points on enclosures are ordered so that we can add segments implicitly.
600 // Elements in segment_indices() indicates the starting points of all enclosures.
601 // The last element in segment_indices() is the number of total points.
602 libmesh_assert_greater(hole->segment_indices().size(), 1);
603 libmesh_assert_equal_to(hole->segment_indices().back(), hole->n_points());
604 }
605
606 return n_hole_points;
607}
608
610 const unsigned int num_nearest_pts,
611 const unsigned int power,
612 const Real background_value,
613 const Real background_eff_dist)
614{
615 _auto_area_function = std::make_unique<AutoAreaFunction>(comm, num_nearest_pts, power, background_value, background_eff_dist);
616}
617
619{
620 if (!_auto_area_function->initialized())
621 {
622 // Points and target element sizes for the interpolation
623 std::vector<Point> function_points;
624 std::vector<Real> function_sizes;
625 calculate_auto_desired_area_samples(function_points, function_sizes);
626 _auto_area_function->init_mfi(function_points, function_sizes);
627 }
628 return _auto_area_function.get();
629}
630
631void TriangulatorInterface::calculate_auto_desired_area_samples(std::vector<Point> & function_points,
632 std::vector<Real> & function_sizes,
633 const Real & area_factor)
634{
635 // Get the hole mesh of the outer boundary
636 // Holes should already be attached if applicable when this function is called
637 const TriangulatorInterface::MeshedHole bdry_mh { _mesh, this->_bdy_ids };
638 // Collect all the centroid points of the outer boundary segments
639 // and the corresponding element sizes
640 for (unsigned int i = 0; i < bdry_mh.n_points(); i++)
641 {
642 function_points.push_back((bdry_mh.point(i) + bdry_mh.point((i + 1) % bdry_mh.n_points())) /
643 Real(2.0));
644 function_sizes.push_back(
645 (bdry_mh.point(i) - bdry_mh.point((i + 1) % bdry_mh.n_points())).norm());
646 }
647 // If holes are present, do the same for the hole boundaries
648 if(_holes)
649 for (const Hole * hole : *_holes)
650 {
651 for (unsigned int i = 0; i < hole->n_points(); i++)
652 {
653 function_points.push_back(
654 (hole->point(i) + hole->point((i + 1) % hole->n_points())) / Real(2.0));
655 function_sizes.push_back(
656 (hole->point(i) - hole->point((i + 1) % hole->n_points())).norm());
657 }
658 }
659
660 std::for_each(
661 function_sizes.begin(), function_sizes.end(), [&area_factor](Real & a) { a = a * a * area_factor * std::sqrt(3.0) / 4.0; });
662
663}
664} // namespace libMesh
665
666
667// Unnecessary at end of file, *except* maybe we'll do a unity build
668// someday, and in the meantime test coverage is nice.
669#include "libmesh/restore_ieee754.h"
AutoAreaFunction(const Parallel::Communicator &comm, const unsigned int num_nearest_pts, const unsigned int power, const Real background_value, const Real background_eff_dist)
void init_mfi(const std::vector< Point > &input_pts, const std::vector< Real > &input_vals)
std::unique_ptr< InverseDistanceInterpolation< 3 > > _auto_area_mfi
virtual Real operator()(const Point &p, const Real) override
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
Base class for functors that can be evaluated at a point and (optionally) time.
bool _initialized
When init() was called so that everything is ready for calls to operator() (...), then this bool is t...
bool _is_time_dependent
Cache whether or not this function is actually time-dependent.
virtual const Point & point(const dof_id_type i) const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh.
Definition mesh_base.C:1803
virtual void delete_node(Node *n)=0
Removes the Node n from the mesh.
virtual dof_id_type max_node_id() const =0
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.
virtual void clear_elems()=0
Deletes all the element data that is currently stored.
virtual void all_complete_order()
Calls the range-based version of this function with a range consisting of all elements in the mesh.
Definition mesh_base.C:1808
A Node is like a Point, but with more information.
Definition node.h:55
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
Another concrete instantiation of the hole, this one should be sufficiently general for most non-poly...
An abstract class for defining a 2-dimensional hole.
bool contains(Point p) const
Return true iff p lies inside the hole.
Another concrete instantiation of the hole, as general as ArbitraryHole, but based on an existing 1D ...
void increase_triangle_order()
Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.
bool _verify_hole_boundaries
Flag which tells if we want to check hole geometry.
ElemType _elem_type
The type of elements to generate.
void nodes_to_segments(dof_id_type max_node_id)
Helper function to create PSLG segments from our node ordering, up to the maximum node id,...
std::set< std::size_t > _bdy_ids
A set of ids to allow on the outer boundary loop.
void elems_to_segments()
Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges,...
void fixup_tri7_center_nodes()
Helper called at the end of increase_triangle_order() for TRI7 to reposition the interior node to the...
int _interpolate_boundary_points
Flag which tells how many additional nodes should be inserted between each pair of original mesh poin...
void insert_any_extra_boundary_points()
Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.
unsigned int total_hole_points()
Helper function to count points in and verify holes.
@ PSLG
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
const std::vector< Hole * > * _holes
A pointer to a vector of Hole*s.
TriangulatorInterface(UnstructuredMesh &mesh)
The constructor.
bool _fixup_tri7_center_nodes
Flag which tells if we want to relocate TRI7 interior nodes to the curved-mapping centroid after snap...
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 ...
UnstructuredMesh & _mesh
Reference to the mesh which is to be created by triangle.
int get_interpolate_boundary_points() const
Complicated getter, for compatibility with insert_extra_points()
void verify_holes(const Hole &outer_bdy)
Helper function to check holes for intersections if requested.
void calculate_auto_desired_area_samples(std::vector< Point > &function_points, std::vector< Real > &function_sizes, const Real &area_factor=1.5)
The external boundary and all hole boundaries are collected.
std::vector< Point > segment_midpoints
When constructing a second-order triangulation from a second-order boundary, we may do the triangulat...
TriangulationType _triangulation_type
The type of triangulation to perform: choices are: convex hull PSLG.
std::vector< Point > segment_midpoints_keys
When saving the midpoint location data, we need to save the corresponding segment information too.
void verify_quadratic_elements()
Helper called at the end of increase_triangle_order() to verify that no boundary-midpoint snap has ta...
std::unique_ptr< AutoAreaFunction > _auto_area_function
The auto area function based on the spacing of boundary points.
bool _insert_extra_points
Flag which tells whether or not to insert additional nodes before triangulation.
void set_auto_area_function(const Parallel::Communicator &comm, const unsigned int num_nearest_pts, const unsigned int power, const Real background_value, const Real background_eff_dist)
Generate an auto area function based on spacing of boundary points.
FunctionBase< Real > * get_auto_area_function()
Get the auto area function.
void set_interpolate_boundary_points(int n_points)
Complicated setter, for compatibility with insert_extra_points()
The UnstructuredMesh class is derived from the MeshBase class.
MeshBase & mesh
The libMesh namespace provides an interface to certain functionality in the library.
std::complex< Real > Complex
T libmesh_real(T a)
libmesh_assert(ctx)
T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176