libMesh
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes | Private Attributes | List of all members
libMesh::TriangleInterface Class Reference

A C++ interface between LibMesh and the Triangle library written by J.R. More...

#include <mesh_triangle_interface.h>

Inheritance diagram for libMesh::TriangleInterface:
[legend]

Public Types

enum  TriangulationType { GENERATE_CONVEX_HULL = 0 , PSLG = 1 , INVALID_TRIANGULATION_TYPE }
 The TriangulationType is used with the general triangulate function defined below. More...
 

Public Member Functions

 TriangleInterface (UnstructuredMesh &mesh)
 The constructor.
 
virtual ~TriangleInterface ()=default
 Empty destructor.
 
virtual void triangulate () override
 Internally, this calls Triangle's triangulate routine.
 
std::string & extra_flags ()
 Sets and/or gets additional flags to be passed to triangle.
 
ElemTypeelem_type ()
 Sets and/or gets the desired element type.
 
Realdesired_area ()
 Sets and/or gets the desired triangle area.
 
virtual void set_desired_area_function (FunctionBase< Real > *)
 Set a function giving desired triangle area as a function of position.
 
virtual FunctionBase< Real > * get_desired_area_function ()
 Get the function giving desired triangle area as a function of position, or nullptr if no such function has been set.
 
Realminimum_angle ()
 Sets and/or gets the minimum desired angle.
 
TriangulationTypetriangulation_type ()
 Sets and/or gets the desired triangulation type.
 
bool & insert_extra_points ()
 Sets and/or gets the flag for inserting add'l points.
 
void set_interpolate_boundary_points (int n_points)
 Complicated setter, for compatibility with insert_extra_points()
 
int get_interpolate_boundary_points () const
 Complicated getter, for compatibility with insert_extra_points()
 
virtual void set_refine_boundary_allowed (bool)
 Set whether or not the triangulation is allowed to refine the mesh boundary when refining the interior.
 
virtual bool refine_boundary_allowed () const
 Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interior.
 
bool & smooth_after_generating ()
 Sets/gets flag which tells whether to do two steps of Laplace mesh smoothing after generating the grid.
 
bool & quiet ()
 Whether not to silence internal messages to stdout.
 
void attach_hole_list (const std::vector< Hole * > *holes)
 Attaches a vector of Hole* pointers which will be meshed around.
 
void set_verify_hole_boundaries (bool v)
 Verifying that hole boundaries don't cross the outer boundary or each other is something like O(N_bdys^2*N_points_per_bdy^2), so we only do it if requested.
 
bool get_verify_hole_boundaries () const
 
void set_fixup_tri7_center_nodes (bool v)
 For TRI7 elements, after boundary mid-edge nodes have been snapped to a curved boundary in increase_triangle_order(), the interior node can be repositioned to the curved-mapping image of the reference centroid.
 
bool get_fixup_tri7_center_nodes () const
 
void attach_boundary_marker (const std::vector< int > *markers)
 Attaches boundary markers.
 
void attach_region_list (const std::vector< Region * > *regions)
 Attaches regions for using attribute to set subdomain IDs and better controlling the triangle sizes within the regions.
 
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.
 
bool has_auto_area_function ()
 Whether or not an auto area function has been set.
 
FunctionBase< Real > * get_auto_area_function ()
 Get the auto area function.
 
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.
 
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 subdomain ids of 1D edges.
 
const std::set< std::size_t > & get_outer_boundary_ids () const
 

Public Attributes

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 through the ordering of the points, you can use the segments vector to specify the segments explicitly, Ex: unit square numbered counter-clockwise starting from origin segments[0] = (0,1) segments[1] = (1,2) segments[2] = (2,3) segments[3] = (3,0) (For the above case you could actually use the implicit ordering!)
 
std::vector< Pointsegment_midpoints
 When constructing a second-order triangulation from a second-order boundary, we may do the triangulation using first-order elements, in which case we need to save midpoint location data in order to reconstruct curvature along boundaries.
 
std::vector< Pointsegment_midpoints_keys
 When saving the midpoint location data, we need to save the corresponding segment information too.
 

Protected Member Functions

void elems_to_segments ()
 Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges, 2D mesh boundary sides), if no segments already exist.
 
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, if no segments already exist.
 
void insert_any_extra_boundary_points ()
 Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.
 
void increase_triangle_order ()
 Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.
 
void fixup_tri7_center_nodes ()
 Helper called at the end of increase_triangle_order() for TRI7 to reposition the interior node to the curved-mapping image of the reference centroid after boundary midpoints have been snapped.
 
void verify_quadratic_elements ()
 Helper called at the end of increase_triangle_order() to verify that no boundary-midpoint snap has tangled a quadratic triangle, by sampling the signed element Jacobian at the reference nodes and centroid.
 
void verify_holes (const Hole &outer_bdy)
 Helper function to check holes for intersections if requested.
 
unsigned int total_hole_points ()
 Helper function to count points in and verify holes.
 

Protected Attributes

UnstructuredMesh_mesh
 Reference to the mesh which is to be created by triangle.
 
const std::vector< Hole * > * _holes
 A pointer to a vector of Hole*s.
 
const std::vector< int > * _markers
 Boundary markers.
 
const std::vector< Region * > * _regions
 A pointer to a vector of Regions*s.
 
std::set< std::size_t > _bdy_ids
 A set of ids to allow on the outer boundary loop.
 
ElemType _elem_type
 The type of elements to generate.
 
Real _desired_area
 The desired area for the elements in the resulting mesh.
 
Real _minimum_angle
 Minimum angle in triangles.
 
TriangulationType _triangulation_type
 The type of triangulation to perform: choices are: convex hull PSLG.
 
bool _insert_extra_points
 Flag which tells whether or not to insert additional nodes before triangulation.
 
int _interpolate_boundary_points
 Flag which tells how many additional nodes should be inserted between each pair of original mesh points.
 
bool _smooth_after_generating
 Flag which tells whether we should smooth the mesh after it is generated.
 
bool _quiet
 Flag which tells if we want to suppress stdout outputs.
 
bool _verify_hole_boundaries
 Flag which tells if we want to check hole geometry.
 
bool _fixup_tri7_center_nodes
 Flag which tells if we want to relocate TRI7 interior nodes to the curved-mapping centroid after snapping boundary midpoints.
 
std::unique_ptr< AutoAreaFunction_auto_area_function
 The auto area function based on the spacing of boundary points.
 

Private Attributes

std::string _extra_flags
 Additional flags to be passed to triangle.
 
MeshSerializer _serializer
 Triangle only operates on serial meshes.
 

Detailed Description

A C++ interface between LibMesh and the Triangle library written by J.R.

Shewchuk.

Author
John W. Peterson
Date
2011

Definition at line 41 of file mesh_triangle_interface.h.

Member Enumeration Documentation

◆ TriangulationType

The TriangulationType is used with the general triangulate function defined below.

Enumerator
GENERATE_CONVEX_HULL 

First generate a convex hull from the set of points passed in, and then triangulate this set of points.

This is probably the most common type of usage.

PSLG 

Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of the "points" vector: a straight line is assumed to lie between each successive pair of points, with an additional line joining the final and first points.

Explicitly telling the triangulator to add additional points may be important for this option.

INVALID_TRIANGULATION_TYPE 

Does nothing, used as a "null" value.

Definition at line 111 of file triangulator_interface.h.

112 {
119
130 PSLG = 1,
131
136 };
@ PSLG
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
@ INVALID_TRIANGULATION_TYPE
Does nothing, used as a "null" value.
@ GENERATE_CONVEX_HULL
First generate a convex hull from the set of points passed in, and then triangulate this set of point...

Constructor & Destructor Documentation

◆ TriangleInterface()

libMesh::TriangleInterface::TriangleInterface ( UnstructuredMesh mesh)
explicit

The constructor.

A reference to the mesh containing the points which are to be triangulated must be provided. Unless otherwise specified, a convex hull will be computed for the set of input points and the convex hull will be meshed.

Definition at line 48 of file mesh_triangle_interface.C.

50 _extra_flags(""),
52{}
MeshSerializer _serializer
Triangle only operates on serial meshes.
std::string _extra_flags
Additional flags to be passed to triangle.
TriangulatorInterface(UnstructuredMesh &mesh)
The constructor.
UnstructuredMesh & _mesh
Reference to the mesh which is to be created by triangle.
MeshBase & mesh

◆ ~TriangleInterface()

virtual libMesh::TriangleInterface::~TriangleInterface ( )
virtualdefault

Empty destructor.

Member Function Documentation

◆ attach_boundary_marker()

void libMesh::TriangulatorInterface::attach_boundary_marker ( const std::vector< int > *  markers)
inlineinherited

Attaches boundary markers.

If segments is set, the number of markers must be equal to the size of segments, otherwise, it is equal to the number of points.

Definition at line 313 of file triangulator_interface.h.

313{ _markers = markers; }
const std::vector< int > * _markers
Boundary markers.

References libMesh::TriangulatorInterface::_markers.

◆ attach_hole_list()

void libMesh::TriangulatorInterface::attach_hole_list ( const std::vector< Hole * > *  holes)
inlineinherited

◆ attach_region_list()

void libMesh::TriangulatorInterface::attach_region_list ( const std::vector< Region * > *  regions)
inlineinherited

Attaches regions for using attribute to set subdomain IDs and better controlling the triangle sizes within the regions.

Definition at line 319 of file triangulator_interface.h.

319{ _regions = regions; }
const std::vector< Region * > * _regions
A pointer to a vector of Regions*s.

References libMesh::TriangulatorInterface::_regions.

◆ calculate_auto_desired_area_samples()

void libMesh::TriangulatorInterface::calculate_auto_desired_area_samples ( std::vector< Point > &  function_points,
std::vector< Real > &  function_sizes,
const Real area_factor = 1.5 
)
inherited

The external boundary and all hole boundaries are collected.

The centroid of each EDGE element is used as the point position and the desired area is calculated as the area of the equilateral triangle with the edge length as the length of the EDGE element times an area_factor (default is 1.5).

Definition at line 631 of file triangulator_interface.C.

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}
std::set< std::size_t > _bdy_ids
A set of ids to allow on the outer boundary loop.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

References libMesh::TriangulatorInterface::_bdy_ids, libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::_mesh, and libMesh::Real.

Referenced by libMesh::TriangulatorInterface::get_auto_area_function().

◆ desired_area()

Real & libMesh::TriangulatorInterface::desired_area ( )
inlineinherited

Sets and/or gets the desired triangle area.

Set to zero to disable area constraint.

If a desired_area_function is set, then desired_area() should be used to set a minimum desired area; this will reduce "false negatives" by suggesting how finely to sample desired_area_function inside large triangles, where ideally the desired_area_function will be satisfied in the triangle interior and not just at the triangle vertices.

Definition at line 177 of file triangulator_interface.h.

177{return _desired_area;}
Real _desired_area
The desired area for the elements in the resulting mesh.

References libMesh::TriangulatorInterface::_desired_area.

Referenced by libMesh::MeshTools::Generation::build_delaunay_square(), MeshTriangulationTest::commonSettings(), libMesh::Poly2TriTriangulator::insert_refinement_points(), main(), libMesh::Poly2TriTriangulator::should_refine_elem(), MeshTriangulationTest::testPoly2TriRefinementBase(), MeshTriangulationTest::testTriangulatorHolePerturbed(), MeshTriangulationTest::testTriangulatorHoleTangentPerturbed(), MeshTriangulationTest::testTriangulatorInterp(), and triangulate_domain().

◆ elem_type()

ElemType & libMesh::TriangulatorInterface::elem_type ( )
inlineinherited

◆ elems_to_segments()

void libMesh::TriangulatorInterface::elems_to_segments ( )
protectedinherited

Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges, 2D mesh boundary sides), if no segments already exist.

Definition at line 155 of file triangulator_interface.C.

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
192 const TriangulatorInterface::MeshedHole mh { _mesh, this->_bdy_ids };
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}
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
virtual void clear_elems()=0
Deletes all the element data that is currently stored.
bool _verify_hole_boundaries
Flag which tells if we want to check hole geometry.
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 verify_holes(const Hole &outer_bdy)
Helper function to check holes for intersections if requested.
std::vector< Point > segment_midpoints
When constructing a second-order triangulation from a second-order boundary, we may do the triangulat...
std::vector< Point > segment_midpoints_keys
When saving the midpoint location data, we need to save the corresponding segment information too.
bool contains(std::string_view superstring, std::string_view substring)
Look for a substring within a string.
Definition utility.C:205
uint8_t dof_id_type
Definition id_types.h:67
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
const dof_id_type n_nodes
Definition tecplot_io.C:67

References libMesh::TriangulatorInterface::_bdy_ids, libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::_mesh, libMesh::TriangulatorInterface::_verify_hole_boundaries, libMesh::MeshBase::clear_elems(), libMesh::MeshBase::delete_node(), libMesh::make_range(), libMesh::MeshBase::n_elem(), libMesh::MeshBase::node_ptr(), libMesh::TriangulatorInterface::segment_midpoints, libMesh::TriangulatorInterface::segment_midpoints_keys, libMesh::TriangulatorInterface::segments, and libMesh::TriangulatorInterface::verify_holes().

Referenced by triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ extra_flags()

std::string & libMesh::TriangleInterface::extra_flags ( )
inline

Sets and/or gets additional flags to be passed to triangle.

Definition at line 66 of file mesh_triangle_interface.h.

66{return _extra_flags;}

References _extra_flags.

◆ fixup_tri7_center_nodes()

void libMesh::TriangulatorInterface::fixup_tri7_center_nodes ( )
protectedinherited

Helper called at the end of increase_triangle_order() for TRI7 to reposition the interior node to the curved-mapping image of the reference centroid after boundary midpoints have been snapped.

Safe to call unconditionally for TRI7.

Definition at line 446 of file triangulator_interface.C.

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}

References libMesh::TriangulatorInterface::_elem_type, libMesh::TriangulatorInterface::_mesh, libMesh::Real, and libMesh::TRI7.

Referenced by libMesh::TriangulatorInterface::increase_triangle_order().

◆ get_auto_area_function()

FunctionBase< Real > * libMesh::TriangulatorInterface::get_auto_area_function ( )
inherited

Get the auto area function.

Definition at line 618 of file triangulator_interface.C.

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}
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::unique_ptr< AutoAreaFunction > _auto_area_function
The auto area function based on the spacing of boundary points.

References libMesh::TriangulatorInterface::_auto_area_function, and libMesh::TriangulatorInterface::calculate_auto_desired_area_samples().

Referenced by libMesh::Poly2TriTriangulator::should_refine_elem().

◆ get_desired_area_function()

virtual FunctionBase< Real > * libMesh::TriangulatorInterface::get_desired_area_function ( )
inlinevirtualinherited

Get the function giving desired triangle area as a function of position, or nullptr if no such function has been set.

Reimplemented in libMesh::Poly2TriTriangulator.

Definition at line 193 of file triangulator_interface.h.

194 { return nullptr; }

◆ get_fixup_tri7_center_nodes()

bool libMesh::TriangulatorInterface::get_fixup_tri7_center_nodes ( ) const
inlineinherited

Definition at line 275 of file triangulator_interface.h.

bool _fixup_tri7_center_nodes
Flag which tells if we want to relocate TRI7 interior nodes to the curved-mapping centroid after snap...

References libMesh::TriangulatorInterface::_fixup_tri7_center_nodes.

◆ get_interpolate_boundary_points()

int libMesh::TriangulatorInterface::get_interpolate_boundary_points ( ) const
inherited

Complicated getter, for compatibility with insert_extra_points()

Definition at line 143 of file triangulator_interface.C.

144{
145 // backwards compatibility - someone might have turned this off via
146 // the old API
148 return 0;
149
151}
int _interpolate_boundary_points
Flag which tells how many additional nodes should be inserted between each pair of original mesh poin...
bool _insert_extra_points
Flag which tells whether or not to insert additional nodes before triangulation.

References libMesh::TriangulatorInterface::_insert_extra_points, and libMesh::TriangulatorInterface::_interpolate_boundary_points.

Referenced by libMesh::TriangulatorInterface::insert_any_extra_boundary_points().

◆ get_outer_boundary_ids()

const std::set< std::size_t > & libMesh::TriangulatorInterface::get_outer_boundary_ids ( ) const
inlineinherited

Definition at line 371 of file triangulator_interface.h.

371{ return _bdy_ids; }

References libMesh::TriangulatorInterface::_bdy_ids.

◆ get_verify_hole_boundaries()

bool libMesh::TriangulatorInterface::get_verify_hole_boundaries ( ) const
inlineinherited

◆ has_auto_area_function()

bool libMesh::TriangulatorInterface::has_auto_area_function ( )
inlineinherited

Whether or not an auto area function has been set.

Definition at line 348 of file triangulator_interface.h.

348{return _auto_area_function != nullptr;}

References libMesh::TriangulatorInterface::_auto_area_function.

Referenced by libMesh::Poly2TriTriangulator::insert_refinement_points(), and libMesh::Poly2TriTriangulator::should_refine_elem().

◆ increase_triangle_order()

void libMesh::TriangulatorInterface::increase_triangle_order ( )
protectedinherited

Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.

Should be called at the end of triangulate()

Definition at line 341 of file triangulator_interface.C.

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}
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 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
void fixup_tri7_center_nodes()
Helper called at the end of increase_triangle_order() for TRI7 to reposition the interior node to the...
void verify_quadratic_elements()
Helper called at the end of increase_triangle_order() to verify that no boundary-midpoint snap has ta...
libmesh_assert(ctx)

References libMesh::TriangulatorInterface::_elem_type, libMesh::TriangulatorInterface::_fixup_tri7_center_nodes, libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::_mesh, libMesh::MeshBase::all_complete_order(), libMesh::MeshBase::all_second_order(), libMesh::FIRST, libMesh::TriangulatorInterface::fixup_tri7_center_nodes(), libMesh::libmesh_assert(), libMesh::make_range(), libMesh::TriangulatorInterface::segment_midpoints, libMesh::TriangulatorInterface::segment_midpoints_keys, libMesh::TriangulatorInterface::segments, libMesh::TRI3, libMesh::TRI6, libMesh::TRI7, and libMesh::TriangulatorInterface::verify_quadratic_elements().

Referenced by triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ insert_any_extra_boundary_points()

void libMesh::TriangulatorInterface::insert_any_extra_boundary_points ( )
protectedinherited

Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.

Definition at line 287 of file triangulator_interface.C.

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}
dof_id_type id() const
Definition dof_object.h:819
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.
int get_interpolate_boundary_points() const
Complicated getter, for compatibility with insert_extra_points()
TriangulationType _triangulation_type
The type of triangulation to perform: choices are: convex hull PSLG.

References libMesh::TriangulatorInterface::_mesh, libMesh::TriangulatorInterface::_triangulation_type, libMesh::MeshBase::add_point(), libMesh::TriangulatorInterface::get_interpolate_boundary_points(), libMesh::DofObject::id(), libMesh::libmesh_assert(), libMesh::make_range(), libMesh::MeshBase::max_node_id(), libMesh::MeshBase::node_ptr(), libMesh::TriangulatorInterface::PSLG, and libMesh::TriangulatorInterface::segments.

Referenced by triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ insert_extra_points()

bool & libMesh::TriangulatorInterface::insert_extra_points ( )
inlineinherited

Sets and/or gets the flag for inserting add'l points.

Definition at line 210 of file triangulator_interface.h.

210{return _insert_extra_points;}

References libMesh::TriangulatorInterface::_insert_extra_points.

◆ minimum_angle()

Real & libMesh::TriangulatorInterface::minimum_angle ( )
inlineinherited

Sets and/or gets the minimum desired angle.

Set to zero to disable angle constraint.

Definition at line 200 of file triangulator_interface.h.

200{return _minimum_angle;}
Real _minimum_angle
Minimum angle in triangles.

References libMesh::TriangulatorInterface::_minimum_angle.

Referenced by MeshTriangulationTest::commonSettings(), libMesh::Poly2TriTriangulator::insert_refinement_points(), and main().

◆ nodes_to_segments()

void libMesh::TriangulatorInterface::nodes_to_segments ( dof_id_type  max_node_id)
protectedinherited

Helper function to create PSLG segments from our node ordering, up to the maximum node id, if no segments already exist.

Definition at line 248 of file triangulator_interface.C.

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}

References libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::_mesh, libMesh::TriangulatorInterface::_triangulation_type, libMesh::TriangulatorInterface::_verify_hole_boundaries, libMesh::DofObject::id(), libMesh::MeshBase::point(), libMesh::TriangulatorInterface::PSLG, libMesh::TriangulatorInterface::segments, and libMesh::TriangulatorInterface::verify_holes().

Referenced by triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ quiet()

bool & libMesh::TriangulatorInterface::quiet ( )
inlineinherited

Whether not to silence internal messages to stdout.

Definition at line 249 of file triangulator_interface.h.

249{return _quiet;}
bool _quiet
Flag which tells if we want to suppress stdout outputs.

References libMesh::TriangulatorInterface::_quiet.

◆ refine_boundary_allowed()

virtual bool libMesh::TriangulatorInterface::refine_boundary_allowed ( ) const
inlinevirtualinherited

Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interior.

True by default.

Reimplemented in libMesh::Poly2TriTriangulator.

Definition at line 237 of file triangulator_interface.h.

238 { return true; }

◆ set_auto_area_function()

void libMesh::TriangulatorInterface::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 
)
inherited

Generate an auto area function based on spacing of boundary points.

The external boundary as well as the hole boundaries are taken into consideration to generate the auto area function based on inverse distance interpolation. For each EDGE element on these boundaries, its centroid (midpoint) is used as the point position and the desired area is calculated as 1.5 times of the area of the equilateral triangle with the edge length as the length of the EDGE element. For a given position, the inverse distance interpolation only considers a number of nearest points (set by num_nearest_pts) to calculate the desired area. The weight of the value at each point is calculated as 1/distance^power.

In addition to these conventional inverse distance interpolation features, a concept of "background value" and "background effective distance" is introduced. The background value belongs to a virtual point located at a constant distance (background effective distance) from the given position. The weight of the value at this virtual point is calculated as 1/background_effective_distance^power. Effectively, the background value is the value when the given position is far away from the boundary points.

Definition at line 609 of file triangulator_interface.C.

614{
615 _auto_area_function = std::make_unique<AutoAreaFunction>(comm, num_nearest_pts, power, background_value, background_eff_dist);
616}

References libMesh::TriangulatorInterface::_auto_area_function.

◆ set_desired_area_function()

virtual void libMesh::TriangulatorInterface::set_desired_area_function ( FunctionBase< Real > *  )
inlinevirtualinherited

Set a function giving desired triangle area as a function of position.

Set this to nullptr to disable position-dependent area constraint (falling back on desired_area()).

This may not be implemented in all subclasses.

Reimplemented in libMesh::Poly2TriTriangulator.

Definition at line 186 of file triangulator_interface.h.

187 { libmesh_not_implemented(); }

◆ set_fixup_tri7_center_nodes()

void libMesh::TriangulatorInterface::set_fixup_tri7_center_nodes ( bool  v)
inlineinherited

For TRI7 elements, after boundary mid-edge nodes have been snapped to a curved boundary in increase_triangle_order(), the interior node can be repositioned to the curved-mapping image of the reference centroid.

This is off by default; enable it only if the consuming code wants the relocated interior node.

Definition at line 273 of file triangulator_interface.h.

References libMesh::TriangulatorInterface::_fixup_tri7_center_nodes.

Referenced by MeshTriangulationTest::testPoly2TriEdge3ToTri7CenterFixup().

◆ set_interpolate_boundary_points()

void libMesh::TriangulatorInterface::set_interpolate_boundary_points ( int  n_points)
inherited

Complicated setter, for compatibility with insert_extra_points()

Definition at line 129 of file triangulator_interface.C.

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}

References libMesh::TriangulatorInterface::_insert_extra_points, libMesh::TriangulatorInterface::_interpolate_boundary_points, and libMesh::libmesh_assert().

Referenced by MeshTriangulationTest::testTriangulatorInterp().

◆ set_outer_boundary_ids()

void libMesh::TriangulatorInterface::set_outer_boundary_ids ( std::set< std::size_t >  bdy_ids)
inlineinherited

A set of ids to allow on the outer boundary loop: interpreted as boundary ids of 2D elements and/or subdomain ids of 1D edges.

If this is empty, then the outer boundary may be constructed from boundary edges of any id!

Definition at line 370 of file triangulator_interface.h.

370{ _bdy_ids = std::move(bdy_ids); }

References libMesh::TriangulatorInterface::_bdy_ids.

Referenced by MeshTriangulationTest::testHalfDomain().

◆ set_refine_boundary_allowed()

virtual void libMesh::TriangulatorInterface::set_refine_boundary_allowed ( bool  )
inlinevirtualinherited

Set whether or not the triangulation is allowed to refine the mesh boundary when refining the interior.

This is true by default, but may be set to false to make the mesh boundary more predictable (and so easier to stitch to other meshes) later.

This may not be implemented in all subclasses.

Reimplemented in libMesh::Poly2TriTriangulator.

Definition at line 230 of file triangulator_interface.h.

231 { libmesh_not_implemented(); }

◆ set_verify_hole_boundaries()

void libMesh::TriangulatorInterface::set_verify_hole_boundaries ( bool  v)
inlineinherited

Verifying that hole boundaries don't cross the outer boundary or each other is something like O(N_bdys^2*N_points_per_bdy^2), so we only do it if requested.

Definition at line 262 of file triangulator_interface.h.

References libMesh::TriangulatorInterface::_verify_hole_boundaries.

Referenced by MeshTriangulationTest::commonSettings().

◆ smooth_after_generating()

bool & libMesh::TriangulatorInterface::smooth_after_generating ( )
inlineinherited

Sets/gets flag which tells whether to do two steps of Laplace mesh smoothing after generating the grid.

Definition at line 244 of file triangulator_interface.h.

bool _smooth_after_generating
Flag which tells whether we should smooth the mesh after it is generated.

References libMesh::TriangulatorInterface::_smooth_after_generating.

Referenced by MeshTriangulationTest::commonSettings(), and triangulate_domain().

◆ total_hole_points()

unsigned int libMesh::TriangulatorInterface::total_hole_points ( )
protectedinherited

Helper function to count points in and verify holes.

Definition at line 585 of file triangulator_interface.C.

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}

References libMesh::TriangulatorInterface::_holes.

Referenced by triangulate().

◆ triangulate()

void libMesh::TriangleInterface::triangulate ( )
overridevirtual

Internally, this calls Triangle's triangulate routine.

Implements libMesh::TriangulatorInterface.

Definition at line 58 of file mesh_triangle_interface.C.

59{
60 // Will the triangulation have holes?
61 const bool have_holes = ((_holes != nullptr) && (!_holes->empty()));
62
63 unsigned int n_hole_points = this->total_hole_points();
64
65 // If we have no explicit segments defined, we may get them from
66 // mesh elements
67 this->elems_to_segments();
68
69 // If we're doing PSLG without segments, construct them from all our
70 // mesh nodes
72
73 // Insert additional new points in between existing boundary points,
74 // if that is requested and reasonable
76
77 // Regardless of whether we added additional points, the set of points to
78 // triangulate is now sitting in the mesh.
79
80 // Triangle data structure for the mesh
81 TriangleWrapper::triangulateio initial;
82 TriangleWrapper::triangulateio final;
83 TriangleWrapper::triangulateio voronoi;
84
85 // Pseudo-Constructor for the triangle io structs
86 TriangleWrapper::init(initial);
88 TriangleWrapper::init(voronoi);
89
90 initial.numberofpoints = _mesh.n_nodes() + n_hole_points;
91 initial.pointlist = static_cast<REAL*>(std::malloc(initial.numberofpoints * 2 * sizeof(REAL)));
92
94 {
95 // Implicit segment ordering: One segment per point, including hole points
96 if (this->segments.empty())
97 initial.numberofsegments = initial.numberofpoints;
98
99 // User-defined segment ordering: One segment per entry in the segments vector
100 else
101 initial.numberofsegments = this->segments.size() + n_hole_points;
102 }
103
105 initial.numberofsegments = n_hole_points; // One segment for each hole point
106
107 // Allocate space for the segments (2 int per segment)
108 if (initial.numberofsegments > 0)
109 {
110 initial.segmentlist = static_cast<int *> (std::malloc(initial.numberofsegments * 2 * sizeof(int)));
111 if (_markers)
112 initial.segmentmarkerlist = static_cast<int *> (std::malloc(initial.numberofsegments * sizeof(int)));
113 }
114
115
116 // Copy all the holes' points and segments into the triangle struct.
117
118 // The hole_offset is a constant offset into the points vector which points
119 // past the end of the last hole point added.
120 unsigned int hole_offset=0;
121
122 if (have_holes)
123 for (const auto & hole : *_holes)
124 {
125 for (unsigned int ctr=0, h=0, i=0, hsism=hole->segment_indices().size()-1; i<hsism; ++i)
126 {
127 unsigned int begp = hole_offset + hole->segment_indices()[i];
128 unsigned int endp = hole->segment_indices()[i+1];
129
130 for (; h<endp; ctr+=2, ++h)
131 {
132 Point p = hole->point(h);
133
134 const unsigned int index0 = 2*hole_offset+ctr;
135 const unsigned int index1 = 2*hole_offset+ctr+1;
136
137 // Save the x,y locations in the triangle struct.
138 initial.pointlist[index0] = p(0);
139 initial.pointlist[index1] = p(1);
140
141 // Set the points which define the segments
142 initial.segmentlist[index0] = hole_offset+h;
143 initial.segmentlist[index1] = (h == endp - 1) ? begp : hole_offset + h + 1; // wrap around
144 if (_markers)
145 // 1 is reserved for boundaries of holes
146 initial.segmentmarkerlist[hole_offset+h] = 1;
147 }
148 }
149
150 // Update the hole_offset for the next hole
151 hole_offset += hole->n_points();
152 }
153
154
155 // Copy all the non-hole points and segments into the triangle struct.
156 std::vector<unsigned int> libmesh_id_to_pointlist_index(_mesh.max_node_id());
157 {
158 dof_id_type ctr=0;
159 for (auto & node : _mesh.node_ptr_range())
160 {
161 dof_id_type index = 2*hole_offset + ctr;
162
163 // Set x,y values in pointlist
164 initial.pointlist[index] = (*node)(0);
165 initial.pointlist[index+1] = (*node)(1);
166 libmesh_id_to_pointlist_index[node->id()] = ctr/2;
167
168 // If the user requested a PSLG, the non-hole points are also segments
170 {
171 // Use implicit ordering to define segments
172 if (this->segments.empty())
173 {
174 dof_id_type n = ctr/2; // ctr is always even
175 initial.segmentlist[index] = hole_offset+n;
176 initial.segmentlist[index+1] = (n==_mesh.n_nodes()-1) ? hole_offset : hole_offset+n+1; // wrap around
177 if (_markers)
178 initial.segmentmarkerlist[hole_offset + n] = (*_markers)[n];
179 }
180 }
181
182 ctr +=2;
183 }
184 }
185
186
187 // If the user provided it, use his ordering to define the segments
188 for (std::size_t ctr=0, s=0, ss=this->segments.size(); s<ss; ctr+=2, ++s)
189 {
190 const unsigned int index0 = 2*hole_offset+ctr;
191 const unsigned int index1 = 2*hole_offset+ctr+1;
192
193 initial.segmentlist[index0] = hole_offset +
194 libmesh_id_to_pointlist_index[this->segments[s].first];
195 initial.segmentlist[index1] = hole_offset +
196 libmesh_id_to_pointlist_index[this->segments[s].second];
197 if (_markers)
198 initial.segmentmarkerlist[hole_offset + s] = (*_markers)[s];
199 }
200
201
202
203 // Tell the input struct about the holes
204 if (have_holes)
205 {
206 initial.numberofholes = _holes->size();
207 initial.holelist = static_cast<REAL*>(std::malloc(initial.numberofholes * 2 * sizeof(REAL)));
208 for (std::size_t i=0, ctr=0, hs=_holes->size(); i<hs; ++i, ctr+=2)
209 {
210 Point inside_point = (*_holes)[i]->inside();
211 initial.holelist[ctr] = inside_point(0);
212 initial.holelist[ctr+1] = inside_point(1);
213 }
214 }
215
216 if (_regions)
217 {
218 initial.numberofregions = _regions->size();
219 initial.regionlist = static_cast<REAL*>(std::malloc(initial.numberofregions * 4 * sizeof(REAL)));
220 for (std::size_t i=0, ctr=0, rs=_regions->size(); i<rs; ++i, ctr+=4)
221 {
222 Point inside_point = (*_regions)[i]->inside();
223 initial.regionlist[ctr] = inside_point(0);
224 initial.regionlist[ctr+1] = inside_point(1);
225 initial.regionlist[ctr+2] = (*_regions)[i]->attribute();
226 initial.regionlist[ctr+3] = (*_regions)[i]->max_area();
227 }
228 }
229
230 // Set the triangulation flags.
231 // c ~ enclose convex hull with segments
232 // z ~ use zero indexing
233 // B ~ Suppresses boundary markers in the output
234 // Q ~ run in "quiet" mode
235 // p ~ Triangulates a Planar Straight Line Graph
236 // If the `p' switch is used, `segmentlist' must point to a list of
237 // segments, `numberofsegments' must be properly set, and
238 // `segmentmarkerlist' must either be set to nullptr (in which case all
239 // markers default to zero), or must point to a list of markers.
240 // D ~ Conforming Delaunay: use this switch if you want all triangles
241 // in the mesh to be Delaunay, and not just constrained Delaunay
242 // q ~ Quality mesh generation with no angles smaller than 20 degrees.
243 // An alternate minimum angle may be specified after the q
244 // a ~ Imposes a maximum triangle area constraint.
245 // -P Suppresses the output .poly file. Saves disk space, but you lose the ability to maintain
246 // constraining segments on later refinements of the mesh.
247 // -e Outputs (to an .edge file) a list of edges of the triangulation.
248 // -v Outputs the Voronoi diagram associated with the triangulation.
249 // Create the flag strings, depends on element type
250 std::ostringstream flags;
251
252 // Default flags always used
253 flags << "z";
254
255 if (_quiet)
256 flags << "QP";
257 else
258 flags << "V";
259
260 if (_markers)
261 flags << "ev";
262
263 // Flags which are specific to the type of triangulation
264 switch (_triangulation_type)
265 {
267 {
268 flags << "c";
269 break;
270 }
271
272 case PSLG:
273 {
274 flags << "p";
275 break;
276 }
277
279 libmesh_error_msg("ERROR: INVALID_TRIANGULATION_TYPE selected!");
280
281 default:
282 libmesh_error_msg("Unrecognized _triangulation_type");
283 }
284
285
286 // Flags specific to the type of element
287 switch (_elem_type)
288 {
289 case TRI3:
290 {
291 // do nothing.
292 break;
293 }
294
295 case TRI6:
296 {
297 flags << "o2";
298 break;
299 }
300
301 default:
302 libmesh_error_msg("ERROR: Unrecognized triangular element type == " << Utility::enum_to_string(_elem_type));
303 }
304
305
306 // If we do have holes and the user asked to GENERATE_CONVEX_HULL,
307 // need to add the p flag so the triangulation respects those segments.
308 if ((_triangulation_type==GENERATE_CONVEX_HULL) && (have_holes))
309 flags << "p";
310
311 // Finally, add the area constraint
313 flags << "a" << std::fixed << _desired_area;
314
315 // add minimum angle constraint
317 flags << "q" << std::fixed << _minimum_angle;
318
319 if (_regions)
320 flags << "Aa";
321
322 // add user provided extra flags
323 if (_extra_flags.size() > 0)
324 flags << _extra_flags;
325
326 // Refine the initial output to conform to the area constraint
327 if (_markers)
328 {
329 // need Voronoi to generate boundary information
330 TriangleWrapper::triangulate(const_cast<char *>(flags.str().c_str()),
331 &initial,
332 &final,
333 &voronoi);
334
335 // Send the information computed by Triangle to the Mesh.
337 _mesh,
339 &voronoi);
340 }
341 else
342 {
343 TriangleWrapper::triangulate(const_cast<char *>(flags.str().c_str()),
344 &initial,
345 &final,
346 nullptr);
347 // Send the information computed by Triangle to the Mesh.
349 _mesh,
350 _elem_type);
351 }
352
353
355
356 // The user might have requested TRI6 or higher instead of TRI3. If
357 // so then we'll need to get our neighbor pointers in order ahead of
358 // time for increase_triangle_order() to use.
359 if (_elem_type != TRI3)
360 {
363 }
364
365 // To the naked eye, a few smoothing iterations usually looks better,
366 // so we do this by default unless the user says not to.
367 if (this->_smooth_after_generating)
368 LaplaceMeshSmoother(_mesh, 2).smooth();
369
370 // Clean up.
374
375 // Prepare the mesh for use before returning. This ensures (among
376 // other things) that it is partitioned and therefore users can
377 // iterate over local elements, etc.
379}
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
Definition mesh_base.C:824
virtual dof_id_type n_nodes() const =0
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition mesh_base.h:423
void increase_triangle_order()
Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.
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,...
void elems_to_segments()
Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges,...
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.
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true) override
Other functions from MeshBase requiring re-definition.
void copy_tri_to_mesh(const triangulateio &triangle_data_input, UnstructuredMesh &mesh_output, const ElemType type, const triangulateio *voronoi=nullptr)
Copies triangulation data computed by triangle from a triangulateio object to a LibMesh mesh.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
void destroy(triangulateio &t, IO_Type)
Frees any memory which has been dynamically allocated by Triangle.
std::string enum_to_string(const T e)
static constexpr Real TOLERANCE

References libMesh::TriangulatorInterface::_desired_area, libMesh::TriangulatorInterface::_elem_type, _extra_flags, libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::_markers, libMesh::TriangulatorInterface::_mesh, libMesh::TriangulatorInterface::_minimum_angle, libMesh::TriangulatorInterface::_quiet, libMesh::TriangulatorInterface::_regions, libMesh::TriangulatorInterface::_smooth_after_generating, libMesh::TriangulatorInterface::_triangulation_type, libMesh::TriangleWrapper::copy_tri_to_mesh(), libMesh::TriangleWrapper::destroy(), libMesh::TriangulatorInterface::elems_to_segments(), libMesh::Utility::enum_to_string(), libMesh::UnstructuredMesh::find_neighbors(), libMesh::TriangulatorInterface::GENERATE_CONVEX_HULL, libMesh::TriangulatorInterface::increase_triangle_order(), libMesh::TriangleWrapper::init(), libMesh::TriangleWrapper::INPUT, libMesh::TriangulatorInterface::insert_any_extra_boundary_points(), libMesh::TriangulatorInterface::INVALID_TRIANGULATION_TYPE, libMesh::MeshBase::max_node_id(), libMesh::MeshBase::n_nodes(), libMesh::TriangulatorInterface::nodes_to_segments(), libMesh::TriangleWrapper::OUTPUT, libMesh::MeshBase::prepare_for_use(), libMesh::TriangulatorInterface::PSLG, libMesh::TriangulatorInterface::segments, libMesh::MeshBase::set_mesh_dimension(), libMesh::LaplaceMeshSmoother::smooth(), libMesh::TOLERANCE, libMesh::TriangulatorInterface::total_hole_points(), libMesh::TRI3, and libMesh::TRI6.

Referenced by libMesh::MeshTools::Generation::build_delaunay_square(), and triangulate_domain().

◆ triangulation_type()

TriangulationType & libMesh::TriangulatorInterface::triangulation_type ( )
inlineinherited

◆ verify_holes()

void libMesh::TriangulatorInterface::verify_holes ( const Hole outer_bdy)
protectedinherited

Helper function to check holes for intersections if requested.

Definition at line 560 of file triangulator_interface.C.

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}

References libMesh::TriangulatorInterface::_holes, libMesh::TriangulatorInterface::Hole::contains(), and libMesh::make_range().

Referenced by libMesh::TriangulatorInterface::elems_to_segments(), and libMesh::TriangulatorInterface::nodes_to_segments().

◆ verify_quadratic_elements()

void libMesh::TriangulatorInterface::verify_quadratic_elements ( )
protectedinherited

Helper called at the end of increase_triangle_order() to verify that no boundary-midpoint snap has tangled a quadratic triangle, by sampling the signed element Jacobian at the reference nodes and centroid.

Errors out with a diagnostic naming the bad element and side if the Jacobian is non-positive.

Definition at line 473 of file triangulator_interface.C.

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}
T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.

References libMesh::TriangulatorInterface::_elem_type, libMesh::TriangulatorInterface::_mesh, libMesh::cross_norm(), libMesh::Real, libMesh::TOLERANCE, libMesh::TRI6, and libMesh::TRI7.

Referenced by libMesh::TriangulatorInterface::increase_triangle_order().

Member Data Documentation

◆ _auto_area_function

std::unique_ptr<AutoAreaFunction> libMesh::TriangulatorInterface::_auto_area_function
protectedinherited

◆ _bdy_ids

std::set<std::size_t> libMesh::TriangulatorInterface::_bdy_ids
protectedinherited

◆ _desired_area

Real libMesh::TriangulatorInterface::_desired_area
protectedinherited

The desired area for the elements in the resulting mesh.

Definition at line 463 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::desired_area(), and triangulate().

◆ _elem_type

ElemType libMesh::TriangulatorInterface::_elem_type
protectedinherited

◆ _extra_flags

std::string libMesh::TriangleInterface::_extra_flags
private

Additional flags to be passed to triangle.

Definition at line 72 of file mesh_triangle_interface.h.

Referenced by extra_flags(), and triangulate().

◆ _fixup_tri7_center_nodes

bool libMesh::TriangulatorInterface::_fixup_tri7_center_nodes
protectedinherited

Flag which tells if we want to relocate TRI7 interior nodes to the curved-mapping centroid after snapping boundary midpoints.

Definition at line 513 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::get_fixup_tri7_center_nodes(), libMesh::TriangulatorInterface::increase_triangle_order(), and libMesh::TriangulatorInterface::set_fixup_tri7_center_nodes().

◆ _holes

const std::vector<Hole*>* libMesh::TriangulatorInterface::_holes
protectedinherited

◆ _insert_extra_points

bool libMesh::TriangulatorInterface::_insert_extra_points
protectedinherited

Flag which tells whether or not to insert additional nodes before triangulation.

This can sometimes be used to "de-regularize" the resulting triangulation.

This flag is supported for backwards compatibility; setting _interpolate_boundary_points = 1 is equivalent.

Definition at line 485 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::get_interpolate_boundary_points(), libMesh::TriangulatorInterface::insert_extra_points(), and libMesh::TriangulatorInterface::set_interpolate_boundary_points().

◆ _interpolate_boundary_points

int libMesh::TriangulatorInterface::_interpolate_boundary_points
protectedinherited

Flag which tells how many additional nodes should be inserted between each pair of original mesh points.

Definition at line 491 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::get_interpolate_boundary_points(), and libMesh::TriangulatorInterface::set_interpolate_boundary_points().

◆ _markers

const std::vector<int>* libMesh::TriangulatorInterface::_markers
protectedinherited

◆ _mesh

UnstructuredMesh& libMesh::TriangulatorInterface::_mesh
protectedinherited

◆ _minimum_angle

Real libMesh::TriangulatorInterface::_minimum_angle
protectedinherited

Minimum angle in triangles.

Definition at line 468 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::minimum_angle(), and triangulate().

◆ _quiet

bool libMesh::TriangulatorInterface::_quiet
protectedinherited

Flag which tells if we want to suppress stdout outputs.

Definition at line 502 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::quiet(), and triangulate().

◆ _regions

const std::vector<Region*>* libMesh::TriangulatorInterface::_regions
protectedinherited

A pointer to a vector of Regions*s.

If this is nullptr, there are no regions!

Definition at line 447 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::attach_region_list(), triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ _serializer

MeshSerializer libMesh::TriangleInterface::_serializer
private

Triangle only operates on serial meshes.

Definition at line 77 of file mesh_triangle_interface.h.

◆ _smooth_after_generating

bool libMesh::TriangulatorInterface::_smooth_after_generating
protectedinherited

Flag which tells whether we should smooth the mesh after it is generated.

True by default.

Definition at line 497 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::smooth_after_generating(), triangulate(), and libMesh::Poly2TriTriangulator::triangulate().

◆ _triangulation_type

TriangulationType libMesh::TriangulatorInterface::_triangulation_type
protectedinherited

◆ _verify_hole_boundaries

bool libMesh::TriangulatorInterface::_verify_hole_boundaries
protectedinherited

◆ segment_midpoints

std::vector<Point> libMesh::TriangulatorInterface::segment_midpoints
inherited

When constructing a second-order triangulation from a second-order boundary, we may do the triangulation using first-order elements, in which case we need to save midpoint location data in order to reconstruct curvature along boundaries.

Definition at line 298 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::elems_to_segments(), and libMesh::TriangulatorInterface::increase_triangle_order().

◆ segment_midpoints_keys

std::vector<Point> libMesh::TriangulatorInterface::segment_midpoints_keys
inherited

When saving the midpoint location data, we need to save the corresponding segment information too.

Here the first point of the segment is saved so that it can be used as a key to find the corresponding segment midpoint.

Definition at line 306 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::elems_to_segments(), and libMesh::TriangulatorInterface::increase_triangle_order().

◆ segments

std::vector<std::pair<unsigned int, unsigned int> > libMesh::TriangulatorInterface::segments
inherited

When constructing a PSLG, if the node numbers do not define the desired boundary segments implicitly through the ordering of the points, you can use the segments vector to specify the segments explicitly, Ex: unit square numbered counter-clockwise starting from origin segments[0] = (0,1) segments[1] = (1,2) segments[2] = (2,3) segments[3] = (3,0) (For the above case you could actually use the implicit ordering!)

Definition at line 290 of file triangulator_interface.h.

Referenced by libMesh::TriangulatorInterface::elems_to_segments(), libMesh::TriangulatorInterface::increase_triangle_order(), libMesh::TriangulatorInterface::insert_any_extra_boundary_points(), libMesh::Poly2TriTriangulator::insert_refinement_points(), libMesh::TriangulatorInterface::nodes_to_segments(), MeshTriangulationTest::testTriangulatorSegments(), triangulate(), and libMesh::Poly2TriTriangulator::triangulate_current_points().


The documentation for this class was generated from the following files: