19#include "libmesh/libmesh_config.h"
21#ifdef LIBMESH_HAVE_POLY2TRI
25#include "libmesh/enforce_ieee754.h"
28#include "libmesh/poly2tri_triangulator.h"
30#include "libmesh/boundary_info.h"
31#include "libmesh/elem.h"
32#include "libmesh/enum_elem_type.h"
33#include "libmesh/function_base.h"
34#include "libmesh/hashing.h"
35#include "libmesh/libmesh_logging.h"
36#include "libmesh/mesh_serializer.h"
37#include "libmesh/mesh_smoother_laplace.h"
38#include "libmesh/mesh_triangle_holes.h"
39#include "libmesh/unstructured_mesh.h"
40#include "libmesh/utility.h"
43#include "libmesh/ignore_warnings.h"
44#include "poly2tri/poly2tri.h"
45#include "libmesh/restore_warnings.h"
54 bool operator()(
const p2t::Point & a,
const p2t::Point &
b)
const
56 return a.x <
b.x || (a.x ==
b.x && a.y <
b.y);
65 "Poly2TriTriangulator only supports point sets in the XY plane");
68 return {double(p(0)), double(p(1))};
71Real distance_from_circumcircle(
const Elem & elem,
84bool in_circumcircle(
const Elem & elem,
88 return (distance_from_circumcircle(elem, p) < tol);
104std::pair<bool, unsigned short>
105can_delaunay_swap(
const Elem & elem,
113 unsigned short nn = 0;
119 if (neigh_node == elem.
node_ptr(0) ||
126 if (in_circumcircle(elem, *neigh_node, tol))
133 const unsigned short n = (side+2)%3;
144 if (mid*right < left*right ||
145 left*mid < left*right)
152[[maybe_unused]]
void libmesh_assert_locally_delaunay(
const Elem & elem)
164template <
typename Container>
166void libmesh_assert_delaunay(
MeshBase & libmesh_dbg_var(
mesh),
167 Container & new_elems)
171 LOG_SCOPE(
"libmesh_assert_delaunay()",
"Poly2TriTriangulator");
173 for (
auto & elem :
mesh.element_ptr_range())
174 libmesh_assert_locally_delaunay(*elem);
176 for (
auto & [raw_elem, unique_elem] : new_elems)
179 libmesh_assert_locally_delaunay(*raw_elem);
188template <
typename Container>
190void restore_delaunay(Container & check_delaunay_on,
193 LOG_SCOPE(
"restore_delaunay()",
"Poly2TriTriangulator");
195 while (!check_delaunay_on.empty())
197 Elem & elem = **check_delaunay_on.begin();
198 check_delaunay_on.erase(&elem);
204 auto [can_swap, nn] =
212 const unsigned short n = (s+2)%3;
214 const std::array<Node *,4> nodes {elem.
node_ptr(n),
234 std::vector<boundary_id_type> bcids;
239 boundary_info.
add_side(neigh, (nn+1)%3, bcids);
246 boundary_info.
add_side(&elem, (n+1)%3, bcids);
250 neigh->
set_node((nn+2)%3, nodes[0]);
283unsigned int segment_intersection(
const Elem & elem,
285 const Point & target,
286 unsigned int source_side)
288 libmesh_assert_equal_to(elem.
dim(), 2);
290 const auto ns = elem.
n_sides();
295 if (s == source_side)
303 const Real raydx = target(0)-source(0),
304 raydy = target(1)-source(1),
305 edgedx = v1(0)-v0(0),
306 edgedy = v1(1)-v0(1);
307 const Real denom = edgedx * raydy - edgedy * raydx;
313 const Real one_over_denom = 1 / denom;
315 const Real targetsdx = v1(0)-target(0),
316 targetsdy = v1(1)-target(1);
318 const Real t_num = targetsdx * raydy -
320 const Real t = t_num * one_over_denom;
325 const Real u_num = targetsdx * edgedy - targetsdy * edgedx;
326 const Real u = u_num * one_over_denom;
339 const Real ray_fraction = (1-u);
341 source(0) += raydx * ray_fraction;
342 source(1) += raydy * ray_fraction;
361 _n_boundary_nodes(n_boundary_nodes),
362 _refine_bdy_allowed(true)
373 LOG_SCOPE(
"triangulate()",
"Poly2TriTriangulator");
387 libmesh_not_implemented();
391 libmesh_not_implemented();
398 libmesh_not_implemented();
429 libmesh_not_implemented();
474 std::vector<boundary_id_type> bcids;
478 libmesh_assert_equal_to(bcids.size(), 1);
488 libmesh_assert_less(hole_num, this->
_holes->size());
489 const Hole * hole = (*this->
_holes)[hole_num];
496 LOG_SCOPE(
"triangulate_current_points()",
"Poly2TriTriangulator");
499 const std::size_t n_holes =
_holes !=
nullptr ?
_holes->size() : 0;
503 std::map<const p2t::Point, Node *, P2TPointCompare> point_node_map;
509 std::vector<p2t::Point> outer_boundary_points;
510 std::vector<std::vector<p2t::Point>> inner_hole_points(n_holes);
514 (!nn,
"Poly2TriTriangulator cannot triangulate an empty mesh!");
521 "Poly2TriTriangulator needs contiguous node ids or explicit segments!");
527 std::set<p2t::Point, P2TPointCompare> steiner_points;
535 std::distance(
_mesh.nodes_begin(),
550 for (
auto & node :
_mesh.node_ptr_range())
552 const p2t::Point pt = to_p2t(*node);
557 outer_boundary_points.push_back(pt);
559 steiner_points.insert(pt);
562 if (point_node_map.count(pt))
563 libmesh_not_implemented();
565 point_node_map.emplace(pt, node);
576 for (
auto [segment_start, segment_end] : this->
segments)
579 libmesh_error_msg_if(segment_start != last_id,
580 "Disconnected triangulator segments");
581 last_id = segment_end;
585 libmesh_error_msg_if(!node,
586 "Triangulator segments reference nonexistent node id " <<
589 outer_boundary_points.emplace_back(
double((*node)(0)),
double((*node)(1)));
590 p2t::Point * pt = &outer_boundary_points.back();
593 if (point_node_map.count(*pt))
594 libmesh_not_implemented_msg
595 (
"Triangulating overlapping boundary nodes is unsupported");
597 point_node_map.emplace(*pt, node);
600 libmesh_error_msg_if(last_id != this->
segments[0].first,
601 "Non-closed-loop triangulator segments");
605 for (
auto & node :
_mesh.node_ptr_range())
607 const p2t::Point pt = to_p2t(*node);
608 if (
const auto it = point_node_map.find(pt);
609 it == point_node_map.end())
611 steiner_points.insert(pt);
612 point_node_map.emplace(pt, node);
615 libmesh_assert_equal_to(it->second, node);
629 std::unordered_map<std::pair<dof_id_type,dof_id_type>,
633 const std::size_t n_outer = outer_boundary_points.size();
638 libmesh_map_find(point_node_map, outer_boundary_points[i]),
640 libmesh_map_find(point_node_map, outer_boundary_points[(i+1)%n_outer]);
642 side_boundary_id.emplace(std::make_pair(node1->
id(),
648 std::vector<p2t::Point *> outer_boundary_pointers(n_outer);
649 std::transform(outer_boundary_points.begin(),
650 outer_boundary_points.end(),
651 outer_boundary_pointers.begin(),
652 [](p2t::Point & p) { return &p; });
659 std::vector<std::vector<p2t::Point *>> inner_hole_pointers(n_holes);
661 p2t::CDT cdt{outer_boundary_pointers};
666 const Hole * initial_hole = (*_holes)[h];
668 const Hole & our_hole =
670 *initial_hole : *it->second;
671 auto & poly2tri_hole = inner_hole_points[h];
676 poly2tri_hole.emplace_back(to_p2t(p));
678 const auto & pt = poly2tri_hole.back();
681 steiner_points.erase(pt);
687 if (point_node_map.count(pt))
689 libmesh_assert_equal_to
696 point_node_map[pt] = node;
701 const std::size_t n_inner = poly2tri_hole.size();
706 libmesh_map_find(point_node_map, poly2tri_hole[i]),
708 libmesh_map_find(point_node_map, poly2tri_hole[(i+1)%n_inner]);
710 side_boundary_id.emplace(std::make_pair(node1->
id(),
715 auto & poly2tri_ptrs = inner_hole_pointers[h];
716 poly2tri_ptrs.resize(n_inner);
718 std::transform(poly2tri_hole.begin(),
720 poly2tri_ptrs.begin(),
721 [](p2t::Point & p) { return &p; });
723 cdt.AddHole(poly2tri_ptrs);
731 std::vector<p2t::Point> steiner_vector(steiner_points.begin(), steiner_points.end());
732 steiner_points.clear();
733 for (
auto & p : steiner_vector)
740 std::vector<p2t::Triangle *> triangles = cdt.GetTriangles();
746 boundary_info.
clear();
749 for (
auto ptri_ptr : triangles)
751 p2t::Triangle & ptri = *ptri_ptr;
758 const p2t::Point & vertex = *ptri.GetPoint(v);
760 Node * node = libmesh_map_find(point_node_map, vertex);
773 & node2 = added_elem->
node_ref((v+1)%3);
775 auto it = side_boundary_id.find(std::make_pair(node1.
id(), node2.id()));
776 if (it == side_boundary_id.end())
777 it = side_boundary_id.find(std::make_pair(node2.id(), node1.
id()));
778 if (it != side_boundary_id.end())
779 boundary_info.
add_side(added_elem, v, it->second);
788 LOG_SCOPE(
"insert_refinement_points()",
"Poly2TriTriangulator");
791 libmesh_not_implemented();
822 bool operator()(
Elem * a,
Elem *
b)
const {
824 return (a->
id() <
b->id());
828 std::map<Elem *, std::unique_ptr<Elem>,
decltype(comp)> new_elems(comp);
840 std::set<
Elem *,
decltype(comp)> all_elems
841 {
mesh.elements_begin(),
mesh.elements_end(), comp };
843 restore_delaunay(all_elems, boundary_info);
845 libmesh_assert_delaunay(
mesh, new_elems);
853 std::unordered_map<Point, Node *> next_boundary_node;
863 std::unordered_set<Point> mesh_points;
864 for (
const Node * node :
mesh.node_ptr_range())
867 mesh_points.insert(*node);
871 auto add_point = [&
mesh,
875 &nn](
const Point & p)
879 mesh_points.insert(p);
884 for (
auto & elem :
mesh.element_ptr_range())
891 libmesh_assert_equal_to(elem->
level(), 0u);
892 libmesh_assert_equal_to(elem->
type(),
TRI3);
903 Node * new_node =
nullptr;
908 Elem * cavity_elem = elem;
911 auto boundary_refine = [
this, &next_boundary_node,
912 &cavity_elem, &new_node]
920 * old_segment_end = cavity_elem->
node_ptr((side+1)%3);
926 if (
auto it = next_boundary_node.find(*old_segment_start);
927 it != next_boundary_node.end())
930 it->second = new_node;
938 (old_segment_end->id() ==
939 old_segment_start->
id() + 1));
940 next_boundary_node[*old_segment_start] = new_node;
943 next_boundary_node[*new_node] = old_segment_end;
957 side = segment_intersection(*cavity_elem, ray_start, new_pt, source_side);
971 new_node = add_point(new_pt);
972 boundary_refine(side);
992 new_node = add_point(new_pt);
1003 cavity_elem = neigh;
1020 Real ax = cavity_elem->
point(s)(0) - new_pt(0),
1021 ay = cavity_elem->
point(s)(1) - new_pt(1),
1022 bx = cavity_elem->
point((s+1)%3)(0) - new_pt(0),
1023 by = cavity_elem->
point((s+1)%3)(1) - new_pt(1);
1024 const Real my_cos = (ax*bx+ay*by) /
1025 std::sqrt(ax*ax+ay*ay) /
1026 std::sqrt(bx*bx+by*by);
1028 if (my_cos < worst_cos)
1037 if (worst_cos < -0.6)
1046 new_pt = (cavity_elem->
point(side) +
1047 cavity_elem->
point((side+1)%3)) / 2;
1048 new_node = add_point(new_pt);
1049 boundary_refine(side);
1054 new_node = add_point(new_pt);
1062 new_node = add_point(new_pt);
1068 std::set<
Elem *,
decltype(comp)> cavity(comp);
1070 std::set<
Elem *,
decltype(comp)> unchecked_cavity ({cavity_elem}, comp);
1071 while (!unchecked_cavity.empty())
1073 std::set<
Elem *,
decltype(comp)> checking_cavity(comp);
1074 checking_cavity.swap(unchecked_cavity);
1075 for (
Elem * checking_elem : checking_cavity)
1080 if (!neigh || checking_cavity.count(neigh) || cavity.count(neigh))
1084 unchecked_cavity.insert(neigh);
1096 std::set<
Elem *,
decltype(comp)> check_delaunay_on(comp);
1100 std::unordered_map<Node *, std::pair<Elem *, boundary_id_type>>
1101 neighbors_CCW, neighbors_CW;
1103 for (
Elem * old_elem : cavity)
1108 if (!neigh || !cavity.count(neigh))
1110 Node * node_CW = old_elem->node_ptr(s),
1111 * node_CCW = old_elem->node_ptr((s+1)%3);
1113 auto set_neighbors =
1114 [&neighbors_CW, &neighbors_CCW, &node_CW,
1115 &node_CCW, &boundary_info]
1119 if (
const auto CW_it = neighbors_CW.find(node_CW);
1120 CW_it == neighbors_CW.end())
1123 neighbors_CCW[node_CW] = std::make_pair(new_neigh, bcid);
1127 Elem * neigh_CW = CW_it->second.first;
1133 boundary_info.
add_side(new_neigh, 0, bcid_CW);
1140 boundary_info.
add_side(neigh_CW, 2, bcid);
1142 neighbors_CW.erase(CW_it);
1146 if (
const auto CCW_it = neighbors_CCW.find(node_CCW);
1147 CCW_it == neighbors_CCW.end())
1150 neighbors_CW[node_CCW] = std::make_pair(new_neigh, bcid);
1154 Elem * neigh_CCW = CCW_it->second.first;
1160 boundary_info.
add_side(new_neigh, 2, bcid_CCW);
1166 boundary_info.
add_side(neigh_CCW, 0, bcid);
1168 neighbors_CCW.erase(CCW_it);
1175 if (old_elem == cavity_elem &&
1178 std::vector<boundary_id_type> bcids;
1180 libmesh_assert_equal_to(bcids.size(), 1);
1181 set_neighbors(
nullptr, bcids[0]);
1186 new_elem->set_node(0, new_node);
1187 new_elem->set_node(1, node_CW);
1188 new_elem->set_node(2, node_CCW);
1192 new_elem->set_neighbor(1, neigh);
1195 const unsigned int neigh_s =
1201 std::vector<boundary_id_type> bcids;
1203 boundary_info.
add_side(new_elem.get(), 1, bcids);
1211 Elem * new_elem_ptr = new_elem.get();
1212 new_elems.emplace(new_elem_ptr, std::move(new_elem));
1214 check_delaunay_on.insert(new_elem_ptr);
1218 boundary_info.
remove(old_elem);
1224 for (
Elem * old_elem : cavity)
1226 if (
const auto it = new_elems.find(old_elem);
1227 it == new_elems.end())
1230 new_elems.erase(it);
1241 restore_delaunay(check_delaunay_on, boundary_info);
1245 libmesh_assert_delaunay(
mesh, new_elems);
1252 if (!next_boundary_node.empty())
1254 auto checked_emplace = [
this](
dof_id_type new_first,
1258 for (
auto [first, second] : this->
segments)
1260 libmesh_assert_not_equal_to(first, new_first);
1261 libmesh_assert_not_equal_to(second, new_second);
1264 libmesh_assert_equal_to(this->
segments.back().second, new_first);
1266 libmesh_assert_not_equal_to(new_first, new_second);
1268 this->
segments.emplace_back (new_first, new_second);
1277 for (
auto node_it =
_mesh.nodes_begin(),
1278 node_end =
_mesh.nodes_end();
1279 node_it != node_end;)
1281 Node & node = **node_it;
1293 last_id = this->
segments.back().second;
1297 checked_emplace(last_id, node_id);
1302 Node * this_node = &node;
1303 auto it = next_boundary_node.find(*this_node);
1304 while (it != next_boundary_node.end())
1307 Node * next_node = it->second;
1310 if (node_it != node_end &&
1311 next_node == *node_it)
1314 checked_emplace(this_node->
id(), next_node->
id());
1316 this_node = next_node;
1317 if (this_node->
id() == this->segments.front().first)
1320 it = next_boundary_node.find(*this_node);
1325 if (this->
segments.back().second != this->segments.front().first)
1326 checked_emplace(this->
segments.back().second,
1327 this->segments.front().first);
1331 std::vector<std::pair<unsigned int, unsigned int>> old_segments;
1334 auto old_it = old_segments.begin();
1337 const Node *
const first_node = node;
1342 if (
const auto it = next_boundary_node.find(*node);
1343 it == next_boundary_node.end())
1345 while (node_id != old_it->first)
1357 checked_emplace(node_id, node->
id());
1359 while (node != first_node);
1371 bool hole_point_insertion =
false;
1373 if (next_boundary_node.count(hole->point(p)))
1375 hole_point_insertion =
true;
1378 if (hole_point_insertion)
1380 (hole, std::make_unique<ArbitraryHole>(*hole));
1395 bool point_inserted =
false;
1397 if (next_boundary_node.count(point))
1399 point_inserted =
true;
1403 if (!point_inserted)
1407 std::vector<Point> new_points;
1423 auto push_back_new_point = [&new_points](
const Point & p) {
1426 new_points.back() != p);
1429 for (
auto old_p : new_points)
1430 libmesh_assert_not_equal_to(old_p, p);
1432 new_points.push_back(p);
1435 for (
auto point_it = arb.
get_points().rbegin(),
1437 point_it != point_end;)
1439 Point point = *point_it;
1442 if (new_points.empty() ||
1443 (point != new_points.back() &&
1444 point != new_points.front()))
1445 push_back_new_point(point);
1447 auto it = next_boundary_node.find(point);
1448 while (it != next_boundary_node.end())
1450 point = *it->second;
1451 if (point == new_points.front())
1453 if (point_it != point_end &&
1456 push_back_new_point(point);
1457 it = next_boundary_node.find(point);
1461 std::reverse(new_points.begin(), new_points.end());
1469 for (
auto & [raw_elem, unique_elem] : new_elems)
1471 libmesh_assert_equal_to(raw_elem, unique_elem.get());
1478 return !new_elems.empty();
1489 area_func !=
nullptr ||
1497 return (area > min_area_target);
1499 libmesh_warning(
"WARNING: both desired are function and automatic area function are set. Using automatic area function.");
1508 const Real local_area_target = (*area_func)(elem.
point(v));
1509 libmesh_error_msg_if
1510 (local_area_target <= 0,
1511 "Non-positive desired element areas are unachievable");
1512 if (area > local_area_target)
1518 if (!min_area_target)
1521 libmesh_not_implemented_msg
1522 (
"Combining a minimum desired_area with an area function isn't yet supported.");
1531#include "libmesh/restore_ieee754.h"
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
std::size_t n_boundary_ids() const
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
void clear()
Clears the underlying data structures and restores the object to a pristine state with no data stored...
static const boundary_id_type invalid_id
Number used for internal use.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
void remove_side(const Elem *elem, const unsigned short int side)
Removes all boundary conditions associated with side side of element elem, if any exist.
void remove(const Node *node)
Removes the boundary conditions associated with node node, if any exist.
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
This is the base class from which all geometric element types are derived.
virtual Node *& set_node(const unsigned int i)
virtual Point quasicircumcenter() const
virtual unsigned int n_vertices() const =0
const Point & point(const unsigned int i) const
const Node & node_ref(const unsigned int i) const
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem's ...
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
virtual bool is_flipped() const =0
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
virtual unsigned short dim() const =0
unsigned int level() const
const Node * node_ptr(const unsigned int i) const
virtual Real volume() const
virtual ElemType type() const =0
virtual unsigned int n_sides() const =0
const Elem * neighbor_ptr(unsigned int i) const
Point vertex_average() const
Base class for functors that can be evaluated at a point and (optionally) time.
virtual std::unique_ptr< FunctionBase< Output > > clone() const =0
This class defines the data structures necessary for Laplace smoothing.
virtual void smooth() override
Redefinition of the smooth function from the base class.
This is the MeshBase class.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual const Node * node_ptr(const dof_id_type i) const =0
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.
virtual dof_id_type n_nodes() const =0
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
virtual dof_id_type max_node_id() const =0
virtual const Node * query_node_ptr(const dof_id_type i) const =0
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual dof_id_type max_elem_id() const =0
virtual void clear_elems()=0
Deletes all the element data that is currently stored.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
A Node is like a Point, but with more information.
const Parallel::Communicator & comm() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
virtual FunctionBase< Real > * get_desired_area_function() override
Get the function giving desired triangle area as a function of position, or nullptr if no such functi...
virtual void set_desired_area_function(FunctionBase< Real > *desired) override
Set a function giving desired triangle area as a function of position.
bool is_refine_boundary_allowed(const BoundaryInfo &boundary_info, const Elem &elem, unsigned int side)
Is refining this element's boundary side allowed?
std::map< const Hole *, std::unique_ptr< ArbitraryHole > > replaced_holes
We might have to replace the user-provided holes with refined versions.
std::unique_ptr< FunctionBase< Real > > _desired_area_func
Location-dependent area requirements.
virtual void triangulate() override
Internally, this calls the poly2tri triangulation code in a loop, inserting our owner Steiner points ...
virtual ~Poly2TriTriangulator()
Empty destructor.
Poly2TriTriangulator(UnstructuredMesh &mesh, dof_id_type n_boundary_nodes=DofObject::invalid_id)
The constructor.
bool should_refine_elem(Elem &elem)
Returns true if the given element ought to be refined according to current criteria.
virtual bool refine_boundary_allowed() const override
Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interio...
bool insert_refinement_points()
Add Steiner points as new mesh nodes, as necessary to refine an existing trangulation.
void triangulate_current_points()
Triangulate the current mesh and hole points.
dof_id_type _n_boundary_nodes
Keep track of how many mesh nodes are boundary nodes.
Another concrete instantiation of the hole, this one should be sufficiently general for most non-poly...
const std::vector< Point > & get_points() const
void set_points(std::vector< Point > points)
An abstract class for defining a 2-dimensional hole.
virtual bool refine_boundary_allowed() const
Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interio...
virtual Point point(const unsigned int n) const =0
Return the nth point defining the hole.
virtual unsigned int n_points() const =0
The number of geometric points which define the hole.
void increase_triangle_order()
Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.
ElemType _elem_type
The type of elements to generate.
void nodes_to_segments(dof_id_type max_node_id)
Helper function to create PSLG segments from our node ordering, up to the maximum node id,...
void elems_to_segments()
Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges,...
Real & minimum_angle()
Sets and/or gets the minimum desired angle.
bool _smooth_after_generating
Flag which tells whether we should smooth the mesh after it is generated.
void insert_any_extra_boundary_points()
Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.
@ PSLG
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
const std::vector< Hole * > * _holes
A pointer to a vector of Hole*s.
const std::vector< int > * _markers
Boundary markers.
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 ...
bool has_auto_area_function()
Whether or not an auto area function has been set.
const std::vector< Region * > * _regions
A pointer to a vector of Regions*s.
UnstructuredMesh & _mesh
Reference to the mesh which is to be created by triangle.
Real & desired_area()
Sets and/or gets the desired triangle area.
TriangulationType _triangulation_type
The type of triangulation to perform: choices are: convex hull PSLG.
FunctionBase< Real > * get_auto_area_function()
Get the auto area function.
The UnstructuredMesh class is derived from the MeshBase class.
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.
The libMesh namespace provides an interface to certain functionality in the library.
void libmesh_ignore(const Args &...)
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
void libmesh_merge_move(T &target, T &source)
static constexpr Real TOLERANCE
TypeVector< T > circumcenter(const TypeVector< T > &p0, const TypeVector< T > &p1, const TypeVector< T > &p2)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...