14#include "libmesh/boundary_info.h"
15#include "libmesh/elem.h"
16#include "libmesh/enum_to_string.h"
17#include "libmesh/int_range.h"
18#include "libmesh/mesh_base.h"
19#include "libmesh/node.h"
20#include "libmesh/replicated_mesh.h"
21#include "libmesh/unstructured_mesh.h"
22#include "libmesh/utility.h"
38constexpr unsigned int n_frontal_tri_sides = 3;
44 return Point(point.
x, point.
y, 0.0);
49frontalPointLess(
const Point & first,
const Point & second)
51 return (first(0) != second(0)) ? first(0) < second(0) : first(1) < second(1);
63frontalCanonicalizeLoop(std::vector<Point> & loop)
66 std::reverse(loop.begin(), loop.end());
69 loop.begin(), std::min_element(loop.begin(), loop.end(), frontalPointLess), loop.end());
82frontalCircumradius(
const Point & first,
const Point & second,
const Point & third)
84 std::array<Point, 3> corners = {first, second, third};
85 std::sort(corners.begin(), corners.end(), frontalPointLess);
87 const Real twice_area = (corners[1](0) - corners[0](0)) * (corners[2](1) - corners[0](1)) -
88 (corners[1](1) - corners[0](1)) * (corners[2](0) - corners[0](0));
89 if (twice_area == 0.0)
90 return std::numeric_limits<Real>::max();
92 std::array<Real, 3>
sides = {(corners[1] - corners[0]).
norm(),
93 (corners[2] - corners[1]).
norm(),
94 (corners[0] - corners[2]).
norm()};
114frontalLinfCorner(
const Point & start,
116 const Point & normal,
118 const std::pair<Point, Point> & frame)
120 const Point & u = frame.first;
121 const Point & v = frame.second;
123 const Real start_u = start * u;
124 const Real start_v = start * v;
125 const Real end_u = end * u;
126 const Real end_v = end * v;
131 std::max({size, 0.5 * std::abs(end_u - start_u), 0.5 * std::abs(end_v - start_v)});
133 const Real low_u = std::max(start_u, end_u) - reach;
134 const Real high_u = std::min(start_u, end_u) + reach;
135 const Real low_v = std::max(start_v, end_v) - reach;
136 const Real high_v = std::min(start_v, end_v) + reach;
140 const bool same_end_larger = ((end_u >= start_u) == (end_v >= start_v));
141 const Point first = low_u * u + (same_end_larger ? high_v : low_v) * v;
142 const Point second = high_u * u + (same_end_larger ? low_v : high_v) * v;
144 return ((first - start) * normal > (second - start) * normal) ? first : second;
159 const std::vector<XYIncrementalDelaunay::Triangle> & triangles,
160 const std::size_t seed_start,
161 const std::size_t seed_end)
168 if (triangles[t].vertices[k] == seed_start &&
169 triangles[t].vertices[(k + 1) % n_frontal_tri_sides] == seed_end)
177 " of the outer boundary is not an edge of the triangulation, so the triangles that "
178 "lie in the domain cannot be found. A point placed exactly on that segment divides "
179 "it in two, which removes it.");
181 std::vector<bool> inside(triangles.size(),
false);
184 std::vector<std::size_t> pending{seed};
186 while (!pending.empty())
188 const auto current = pending.back();
191 const auto & triangle = triangles[current];
192 for (
const auto i :
make_range(n_frontal_tri_sides))
194 const auto neighbor = triangle.neighbors[i];
198 triangle.vertices[(i + 2) % n_frontal_tri_sides]))
201 inside[neighbor] =
true;
202 pending.push_back(neighbor);
217 MooseEnum orientation(
"BOUNDARY CROSS_FIELD",
"CROSS_FIELD");
219 params.
addParam<std::vector<Point>>(
222 "Interior node locations. Any point outside the surface will not be meshed.");
226 "The norm the target size is measured in when a point is placed ahead "
227 "of the front. 'L2' places points that make equilateral triangles. "
228 "'LINF' places points that make right isosceles triangles in the "
229 "local frame, the shape that recombines into good quadrilaterals.");
232 "Where the local frame the 'LINF' metric measures in comes from. "
233 "'CROSS_FIELD' solves for a cross field over the domain. 'BOUNDARY' "
234 "takes the frame of the nearest boundary segment, which needs no "
235 "solve. This parameter has no effect when metric is 'L2'.");
241 "Triangulates meshes within boundaries defined by input meshes by advancing a front, which "
242 "places points at a target size ahead of the triangles that are still too large.");
249 _bdy_ptr(getMesh(
"boundary")),
250 _hole_ptrs(getMeshes(
"holes")),
251 _add_nodes_per_boundary_segment(getParam<unsigned
int>(
"add_nodes_per_boundary_segment")),
252 _refine_bdy(getParam<bool>(
"refine_boundary")),
253 _stitch_holes(getParam<
std::vector<bool>>(
"stitch_holes")),
254 _refine_holes(getParam<
std::vector<bool>>(
"refine_holes")),
255 _desired_area(getParam<Real>(
"desired_area")),
256 _desired_area_func(getParam<
std::string>(
"desired_area_func")),
257 _interior_points(getParam<
std::vector<Point>>(
"interior_points")),
259 _orientation(getParam<
MooseEnum>(
"orientation")),
260 _background_mean_area(0.0),
269 paramError(
"orientation",
"This parameter only applies to the 'LINF' metric.");
272std::unique_ptr<MeshBase>
274 const MeshBase & boundary_mesh,
275 const std::vector<std::unique_ptr<MeshBase>> & holes,
292 std::vector<std::unique_ptr<MeshBase>> hole_clones;
293 for (
const auto & hole : holes)
294 hole_clones.push_back(hole->clone());
297 *
this, boundary_mesh.clone(), std::move(hole_clones), background_opts);
300std::map<dof_id_type, Real>
303 std::map<dof_id_type, std::complex<Real>> directions;
305 for (
const auto & elem :
mesh.element_ptr_range())
306 for (
const auto side : elem->side_index_range())
308 if (elem->neighbor_ptr(side))
311 const Node & start = elem->node_ref(side);
312 const Node & end = elem->node_ref((side + 1) % elem->n_sides());
316 const std::complex<Real> direction =
317 std::polar(1.0, 4.0 * std::atan2(end(1) - start(1), end(0) - start(0)));
318 directions[start.id()] += direction;
319 directions[end.id()] += direction;
322 std::map<dof_id_type, Real> angles;
323 for (
const auto & [node_id, direction] : directions)
324 angles[node_id] = std::arg(direction) / 4.0;
332 const unsigned int extra_nodes,
333 const boundary_id_type bcid,
334 std::vector<Point> & points,
335 std::vector<XYIncrementalDelaunay::Segment> & segments)
337 const std::size_t loop_start = points.size();
339 for (
const auto i : index_range(loop))
341 const Point & start = loop[i];
342 const Point & end = loop[(i + 1) % loop.size()];
345 unsigned int pieces = extra_nodes + 1;
351 pieces = std::max(pieces,
static_cast<unsigned int>(std::ceil((end - start).norm() / size)));
354 points.push_back(start);
355 for (
const auto piece : make_range(1u, pieces))
356 points.push_back(start + (Real(piece) / pieces) * (end - start));
359 for (
const auto vertex : make_range(loop_start, points.size()))
361 const std::size_t next = (vertex + 1 < points.size()) ? vertex + 1 : loop_start;
362 segments.emplace_back(vertex, next);
372 const Real area = (*_area_function)(point);
375 "The desired area must be positive everywhere in the meshed domain, but it is ",
388 const Elem *
const background_elem = (*_background_locator)(point);
398 return (
_metric ==
"L2") ? std::sqrt(4.0 * area / std::sqrt(3.0)) : std::sqrt(2.0 * area);
406 return (
_metric ==
"L2") ? size / std::sqrt(3.0) : size / std::sqrt(2.0);
412 return {
static_cast<long>(std::floor(point(0) / cell)),
413 static_cast<long>(std::floor(point(1) / cell))};
420 "The boundary was seeded before the grid over it is built.");
422 Real min_x = std::numeric_limits<Real>::max();
423 Real max_x = std::numeric_limits<Real>::lowest();
427 for (
const auto & corner : {start, end})
429 min_x = std::min(min_x, corner(0));
430 max_x = std::max(max_x, corner(0));
431 min_y = std::min(min_y, corner(1));
432 max_y = std::max(max_y, corner(1));
438 const Real extent = (max_x - min_x) * (max_y - min_y);
449 std::max(std::size_t(1),
450 static_cast<std::size_t
>(std::ceil(2.0 * (end - start).norm() /
_boundary_cell)));
451 for (
const auto step : make_range(steps + 1))
457 if (bucket.empty() || bucket.back() != segment)
458 bucket.push_back(segment);
463std::pair<Point, Point>
470 "The grid over the boundary segments is built before any frame is taken from them.");
477 Real nearest = std::numeric_limits<Real>::max();
478 std::size_t nearest_segment = std::numeric_limits<std::size_t>::max();
479 const auto search = [&](
const long i,
const long j)
485 for (
const auto segment : bucket->second)
489 if (
distance < nearest || (
distance == nearest && segment < nearest_segment))
492 nearest_segment = segment;
500 for (
long span = 0;; ++span)
503 search(center_i, center_j);
506 for (
long i = center_i - span; i <= center_i + span; ++i)
508 search(i, center_j - span);
509 search(i, center_j + span);
511 for (
long j = center_j - span + 1; j <= center_j + span - 1; ++j)
513 search(center_i - span, j);
514 search(center_i + span, j);
519 if (nearest < covered * covered)
524 const Point tangent = (end - start).unit();
526 return {tangent, Point(-tangent(1), tangent(0), 0.0)};
531 const Point & second,
532 const std::pair<Point, Point> & frame)
const
534 const Point offset = first - second;
536 return offset.norm();
538 return std::max(std::abs(offset * frame.first), std::abs(offset * frame.second));
548 if (outline->contains(point))
564 const std::pair<Point, Point> & frame)
const
569 const long span =
static_cast<long>(std::ceil(reach /
_grid_cell));
576 for (
long i = center_i - span; i <= center_i + span; ++i)
577 for (
auto bucket =
_vertex_grid.lower_bound({i, center_j - span});
578 bucket !=
_vertex_grid.end() && bucket->first.first == i &&
579 bucket->first.second <= center_j + span;
581 for (
const auto vertex : bucket->second)
593 const Point start = frontalToPoint(delaunay.
point(edge.
start));
594 const Point end = frontalToPoint(delaunay.
point(edge.
end));
595 const Point midpoint = 0.5 * (start + end);
601 const Point along = end - start;
602 const Real length = along.norm();
603 const Point normal(-along(1) / length, along(0) / length, 0.0);
606 const std::pair<Point, Point> world_frame(Point(1.0, 0.0, 0.0), Point(0.0, 1.0, 0.0));
607 const std::pair<Point, Point> frame = (
_metric ==
"L2") ? world_frame :
localFrame(midpoint);
613 const Real half_length = 0.5 * length;
614 point = midpoint + std::sqrt(std::max(size * size - half_length * half_length,
615 half_length * half_length)) *
619 point = frontalLinfCorner(start, end, normal, size, frame);
629std::vector<XYFrontalDelaunayGenerator::FrontEdge>
632 const std::vector<XYIncrementalDelaunay::Triangle> & triangles,
633 const std::vector<bool> & inside)
const
637 std::vector<Real> excess(triangles.size(), 0.0);
638 for (
const auto t : index_range(triangles))
643 const Point first = frontalToPoint(delaunay.
point(triangles[t].vertices[0]));
644 const Point second = frontalToPoint(delaunay.
point(triangles[t].vertices[1]));
645 const Point third = frontalToPoint(delaunay.
point(triangles[t].vertices[2]));
646 const Point centroid = (first + second + third) / 3.0;
648 excess[t] = frontalCircumradius(first, second, third) /
652 std::vector<FrontEdge> front;
653 for (
const auto t : index_range(triangles))
658 const auto & triangle = triangles[t];
659 for (
const auto i : make_range(n_frontal_tri_sides))
662 const auto neighbor = triangle.neighbors[i];
667 front.push_back({triangle.vertices[(i + 1) % n_frontal_tri_sides],
668 triangle.vertices[(i + 2) % n_frontal_tri_sides],
675 std::sort(front.begin(),
679 if (a.excess > b.excess)
681 if (b.excess > a.excess)
684 return XYIncrementalDelaunay::makeSegment(a.start, a.end) <
685 XYIncrementalDelaunay::makeSegment(b.start, b.end);
693 const std::size_t vertex)
697 std::vector<std::size_t> ends;
699 if (second == vertex)
700 ends.push_back(first);
702 mooseAssert(ends.size() == 2,
703 "A split replaces the segment the new vertex landed on by the two halves that vertex "
713 const boundary_id_type bcid = recorded->second;
725 bool placed_any =
true;
733 const auto inside = frontalInsideTriangles(delaunay, triangles, 0, 1);
735 for (
const auto & edge :
collectFront(delaunay, triangles, inside))
741 const auto vertices_before = delaunay.
numPoints();
743 const auto vertex = delaunay.
insertPoint({point(0), point(1)});
744 if (delaunay.
numPoints() == vertices_before)
758std::unique_ptr<MeshBase>
764 const auto inside = frontalInsideTriangles(delaunay, triangles, 0, 1);
770 std::set<std::size_t> used_vertices;
771 for (
const auto t : index_range(triangles))
773 used_vertices.insert(triangles[t].vertices.begin(), triangles[t].vertices.end());
775 std::map<std::size_t, Node *> nodes;
776 for (
const auto vertex : used_vertices)
777 nodes[vertex] =
mesh->add_point(frontalToPoint(delaunay.
point(vertex)));
779 auto & boundary_info =
mesh->get_boundary_info();
780 for (
const auto t : index_range(triangles))
785 const auto & triangle = triangles[t];
786 Elem *
const elem =
mesh->add_elem(Elem::build(libMesh::ElemType::TRI3));
787 for (
const auto k : make_range(n_frontal_tri_sides))
788 elem->set_node(k, libmesh_map_find(nodes, triangle.vertices[k]));
789 elem->subdomain_id() = 0;
791 for (
const auto side : make_range(n_frontal_tri_sides))
795 const auto neighbor = triangle.neighbors[(side + 2) % n_frontal_tri_sides];
799 const auto first = triangle.vertices[side];
800 const auto second = triangle.vertices[(side + 1) % n_frontal_tri_sides];
804 mooseError(
"A side of the triangulation lies on the boundary of the domain without lying "
805 "on any of the input boundaries, which happens when a point of "
806 "'interior_points' falls on the outer boundary or on a hole boundary.");
808 boundary_info.add_side(elem, side, bcid->second);
812 mesh->prepare_for_use();
817std::unique_ptr<MeshBase>
820 std::unique_ptr<MeshBase> boundary_mesh = std::move(
_bdy_ptr);
822 std::vector<std::unique_ptr<MeshBase>> hole_meshes(
_hole_ptrs.size());
823 for (
const auto hole_i : index_range(
_hole_ptrs))
824 hole_meshes[hole_i] = std::move(*
_hole_ptrs[hole_i]);
828 if (!boundary_mesh->is_replicated())
829 mooseError(
"XYFrontalDelaunayGenerator is not implemented for distributed meshes");
832 if (!boundary_mesh->is_prepared())
833 boundary_mesh->prepare_for_use();
835 for (
const auto & elem : boundary_mesh->element_ptr_range())
842 " element. Only first order boundary elements are supported, because this mesh "
843 "generator produces TRI3 elements.");
848 _outer_outline = std::make_unique<libMesh::TriangulatorInterface::MeshedHole>(
851 std::vector<bool> holes_with_midpoints(hole_meshes.size());
853 for (
const auto hole_i : index_range(hole_meshes))
855 if (!hole_meshes[hole_i]->is_prepared())
856 hole_meshes[hole_i]->prepare_for_use();
859 std::make_unique<libMesh::TriangulatorInterface::MeshedHole>(*hole_meshes[hole_i]));
860 holes_with_midpoints[hole_i] =
_hole_outlines.back()->n_midpoints();
864 "Cannot stitch a quadratic element hole to the first order triangles this mesh "
865 "generator produces. Please reduce the order of the hole inputs.");
873 Real background_area = 0.0;
875 background_area += elem->volume();
883 _grid_cell = std::numeric_limits<Real>::max();
896 std::vector<Point> outer_loop;
899 frontalCanonicalizeLoop(outer_loop);
901 std::vector<Point> points;
902 std::vector<XYIncrementalDelaunay::Segment> segments;
907 std::vector<Point> hole_loop;
908 for (
const auto i : make_range(
_hole_outlines[hole_i]->n_points()))
910 frontalCanonicalizeLoop(hole_loop);
913 appendLoop(hole_loop, refine, 0,
static_cast<boundary_id_type
>(hole_i + 1), points, segments);
925 points.push_back(interior_point);
927 std::vector<XYIncrementalDelaunay::Point2D> plane_points;
928 plane_points.reserve(points.size());
929 for (
const auto & point : points)
930 plane_points.push_back({point(0), point(1)});
935 for (
const auto vertex : make_range(delaunay.numPoints()))
936 addToGrid(vertex, frontalToPoint(delaunay.point(vertex)));
938 advanceFront(delaunay);
940 auto mesh = buildTriangleMesh(delaunay);
943 *
this,
dynamic_cast<UnstructuredMesh &
>(*mesh), hole_meshes, holes_with_midpoints, opts);
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
for(PetscInt i=0;i< nvars;++i)
if(!dmm->_nl) SETERRQ(PETSC_COMM_WORLD
registerMooseObject("MooseApp", XYFrontalDelaunayGenerator)
void ErrorVector unsigned int
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
Build a replicated mesh.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Base class for Delaunay mesh generators applied to a surface.
void checkInteriorPoints(const std::vector< Point > &interior_points) const
Errors if a point was given twice as an interior point, which the triangulation cannot honor.
static InputParameters validParams()
void fillDelaunayOptions(MeshTriangulationUtils::XYDelaunayOptions &opts) const
Fills the triangulation options that follow from the parameters boundaryAndHolesParams() adds,...
static InputParameters boundaryAndHolesParams()
The parameters that select the outer boundary to triangulate within and the holes to leave out of the...
void checkBoundaryAndHolesParams(const std::vector< std::unique_ptr< MeshBase > * > &hole_ptrs) const
Errors if the parameters boundaryAndHolesParams() adds contradict each other or the holes they refer ...
Generates a triangulation in the XY plane by advancing a front, based on an input mesh defining the o...
static constexpr Real _size_tolerance
How far the circumradius of a triangle may exceed the target before the advance refines it.
const std::vector< bool > _refine_holes
Whether to allow automatically refining each hole boundary.
std::map< XYIncrementalDelaunay::Segment, boundary_id_type > _segment_boundary_ids
Boundary id of each seed segment, keyed on its two vertices with the smaller id first.
const std::string _desired_area_func
Desired triangle area as a (fparser-compatible) function of x,y.
std::unique_ptr< MeshBase > buildTriangleMesh(const XYIncrementalDelaunay &delaunay)
static constexpr Real _rejection_factor
How close to an existing vertex, as a fraction of the target size, a new point may not come.
Real _boundary_cell
Side of the buckets the boundary segments are sorted into so that the frame search stays local.
std::pair< Point, Point > localFrame(const Point &point) const
void recordSplitBoundaryIds(const XYIncrementalDelaunay &delaunay, std::size_t vertex)
Moves the boundary id recorded for the constrained segment an insertion split onto the two halves tha...
const std::vector< std::unique_ptr< MeshBase > * > _hole_ptrs
Holds pointers to the pointers to input meshes defining holes.
Real _grid_cell
Side of the buckets the vertices are sorted into so that the rejection rule stays local.
Real targetSize(Real area) const
void appendLoop(const std::vector< Point > &loop, bool refine, unsigned int extra_nodes, boundary_id_type bcid, std::vector< Point > &points, std::vector< XYIncrementalDelaunay::Segment > &segments)
Adds one closed loop of the input boundary to the points the triangulation is seeded with and to the ...
static std::map< dof_id_type, Real > boundaryTangentAngles(const MeshBase &mesh)
void advanceFront(XYIncrementalDelaunay &delaunay)
Advances the front over the whole domain, inserting points into the triangulation.
std::vector< FrontEdge > collectFront(const XYIncrementalDelaunay &delaunay, const std::vector< XYIncrementalDelaunay::Triangle > &triangles, const std::vector< bool > &inside) const
bool hasVertexWithin(const XYIncrementalDelaunay &delaunay, const Point &point, Real distance, const std::pair< Point, Point > &frame) const
std::unique_ptr< MeshBase > buildBackgroundMesh(const MeshBase &boundary_mesh, const std::vector< std::unique_ptr< MeshBase > > &holes, const MeshTriangulationUtils::XYDelaunayOptions &opts)
Triangulates the domain with the existing Delaunay triangulator at _background_area_factor times the ...
Real metricDistance(const Point &first, const Point &second, const std::pair< Point, Point > &frame) const
std::map< std::pair< long, long >, std::vector< std::size_t > > _vertex_grid
Vertex ids of the triangulation, bucketed by position.
static InputParameters validParams()
const MooseEnum _metric
Norm the target size is measured in when a point is placed ahead of the front.
const Real _desired_area
Desired (maximum) triangle area.
std::map< std::pair< long, long >, std::vector< std::size_t > > _boundary_segment_grid
Indices into _boundary_segments, bucketed by the cells each of those segments passes through.
Real targetCircumradius(Real size) const
XYFrontalDelaunayGenerator(const InputParameters ¶meters)
std::vector< std::unique_ptr< libMesh::TriangulatorInterface::MeshedHole > > _hole_outlines
Outlines of the holes, which the advance stays outside.
Real targetArea(const Point &point) const
std::unique_ptr< MeshBase > _background_mesh
Coarse triangulation of the domain the cross field is solved on.
std::unique_ptr< libMesh::ParsedFunction< Real > > _area_function
Desired area as a function of position, built only when 'desired_area_func' is set.
std::unique_ptr< MeshBase > & _bdy_ptr
Input mesh defining the boundary to triangulate within.
std::unique_ptr< libMesh::TriangulatorInterface::MeshedHole > _outer_outline
Outline of the outer boundary, which the advance stays inside.
std::pair< long, long > gridKey(const Point &point, Real cell) const
void addToGrid(std::size_t vertex, const Point &point)
Records a vertex in the grid the rejection rule searches.
static constexpr Real _background_area_factor
How much coarser in area the background triangulation is than the mesh being generated.
void buildBoundarySegmentGrid()
Sorts the boundary segments into the buckets the BOUNDARY frame searches, so that a search only has t...
Real _background_mean_area
Mean area of the background elements, the target where the background locator finds nothing.
const std::vector< Point > _interior_points
Desired interior node locations.
bool placePoint(const XYIncrementalDelaunay &delaunay, const FrontEdge &edge, Point &point) const
Computes where the advance would place a point ahead of a front edge and applies the rejection rule t...
std::vector< std::pair< Point, Point > > _boundary_segments
Segments of the outer boundary and of the holes, whose tangents give the BOUNDARY frame.
const std::vector< bool > _stitch_holes
Whether to stitch to the mesh defining each hole.
std::unique_ptr< XYCrossFieldSolver > _cross_field
Cross field over the domain, built only when the LINF metric asks for the CROSS_FIELD frame.
std::unique_ptr< libMesh::PointLocatorBase > _background_locator
Locates the background element whose area is the target where no area limit was given.
const MooseEnum _orientation
Where the local frame the LINF metric measures in comes from.
bool insideDomain(const Point &point) const
const unsigned int _add_nodes_per_boundary_segment
How many more nodes to add in each outer boundary segment.
const bool _refine_bdy
Whether to allow automatically refining the outer boundary.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
Constrained Delaunay triangulation of a set of points in the plane, built one point at a time.
const std::set< Segment > & constrainedSegments() const
void initialize(const std::vector< Point2D > &points, const std::vector< Segment > &segments)
Triangulates points and recovers every entry of segments as an edge of the result.
std::size_t numPoints() const
std::size_t insertPoint(const Point2D &p)
Inserts a point, restoring the constrained Delaunay property around it.
bool isConstrainedSegment(std::size_t v0, std::size_t v1) const
static Segment makeSegment(std::size_t v0, std::size_t v1)
const Point2D & point(std::size_t id) const
static constexpr std::size_t invalid_index
Sentinel for a vertex, triangle or neighbor that does not exist.
std::vector< Triangle > getTriangles() const
void finalizeTriangulation(MeshGenerator &mg, UnstructuredMesh &mesh, std::vector< std::unique_ptr< MeshBase > > &holes, const std::vector< bool > &holes_with_midpoints, const XYDelaunayOptions &opts)
Performs the subdomain and boundary naming, the boundary id remapping (outer boundary to 0 and hole i...
std::unique_ptr< MeshBase > triangulateWithDelaunay(MeshGenerator &mg, std::unique_ptr< MeshBase > boundary_mesh, std::vector< std::unique_ptr< MeshBase > > hole_meshes, const XYDelaunayOptions &xyd_opts)
Performs a 2D Delaunay triangulation (via libMesh::Poly2TriTriangulator) inside a closed boundary mes...
std::set< std::size_t > outerBoundaryIds(MeshGenerator &mg, MeshBase &boundary_mesh, const XYDelaunayOptions &opts)
Resolves the outer-boundary selection of the options into the set of ids that define it: the ids of '...
Real pointSegmentDistanceSq(const Point &point, const Point &a, const Point &b)
Compute the squared distance from a point to a 3-D line segment.
libMesh::Real signedArea2D(const libMesh::Point &pt1, const libMesh::Point &pt2, const libMesh::Point &pt3)
Twice the signed area of a triangle in the xy plane, which is positive when its corners are ordered c...
std::string enum_to_string(const T e)
auto index_range(const T &sizable)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
Bundle of inputs for triangulateWithDelaunay.
std::vector< BoundaryName > hole_boundaries
std::vector< bool > stitch_holes
bool has_output_subdomain_name
std::string desired_area_func
An edge of the front, which separates the triangles that meet the target size from the triangles that...
std::size_t start
Vertex at the start of the edge, which has the triangle that misses the target on its left.
std::size_t end
Vertex at the end of the edge.
A point of the triangulation, held as plain coordinates.
Real distance(const Point &p)