19 #include "libmesh/libmesh_config.h" 21 #ifdef LIBMESH_HAVE_POLY2TRI 24 #include "libmesh/poly2tri_triangulator.h" 26 #include "libmesh/boundary_info.h" 27 #include "libmesh/elem.h" 28 #include "libmesh/enum_elem_type.h" 29 #include "libmesh/function_base.h" 30 #include "libmesh/hashing.h" 31 #include "libmesh/libmesh_logging.h" 32 #include "libmesh/mesh_serializer.h" 33 #include "libmesh/mesh_smoother_laplace.h" 34 #include "libmesh/mesh_triangle_holes.h" 35 #include "libmesh/unstructured_mesh.h" 36 #include "libmesh/utility.h" 39 #include "libmesh/ignore_warnings.h" 40 #include "poly2tri/poly2tri.h" 41 #include "libmesh/restore_warnings.h" 48 struct P2TPointCompare
50 bool operator()(
const p2t::Point & a,
const p2t::Point & b)
const 52 return a.x < b.x || (a.x == b.x && a.y < b.y);
61 "Poly2TriTriangulator only supports point sets in the XY plane");
64 return {double(p(0)), double(p(1))};
67 Real distance_from_circumcircle(
const Elem & elem,
74 const Real p_dist = (p - circumcenter).
norm();
80 bool in_circumcircle(
const Elem & elem,
84 return (distance_from_circumcircle(elem, p) < tol);
100 std::pair<bool, unsigned short>
101 can_delaunay_swap(
const Elem & elem,
109 unsigned short nn = 0;
115 if (neigh_node == elem.
node_ptr(0) ||
122 if (in_circumcircle(elem, *neigh_node, tol))
129 const unsigned short n = (side+2)%3;
140 if (mid*right < left*right ||
141 left*mid < left*right)
148 [[maybe_unused]]
void libmesh_assert_locally_delaunay(
const Elem & elem)
160 template <
typename Container>
162 void libmesh_assert_delaunay(
MeshBase & libmesh_dbg_var(
mesh),
163 Container & new_elems)
167 LOG_SCOPE(
"libmesh_assert_delaunay()",
"Poly2TriTriangulator");
169 for (
auto & elem :
mesh.element_ptr_range())
170 libmesh_assert_locally_delaunay(*elem);
172 for (
auto & [raw_elem, unique_elem] : new_elems)
175 libmesh_assert_locally_delaunay(*raw_elem);
184 template <
typename Container>
186 void restore_delaunay(Container & check_delaunay_on,
189 LOG_SCOPE(
"restore_delaunay()",
"Poly2TriTriangulator");
191 while (!check_delaunay_on.empty())
193 Elem & elem = **check_delaunay_on.begin();
194 check_delaunay_on.erase(&elem);
200 auto [can_swap, nn] =
208 const unsigned short n = (s+2)%3;
210 const std::array<Node *,4> nodes {elem.
node_ptr(n),
230 std::vector<boundary_id_type> bcids;
235 boundary_info.
add_side(neigh, (nn+1)%3, bcids);
242 boundary_info.
add_side(&elem, (n+1)%3, bcids);
246 neigh->
set_node((nn+2)%3, nodes[0]);
279 unsigned int segment_intersection(
const Elem & elem,
281 const Point & target,
282 unsigned int source_side)
284 libmesh_assert_equal_to(elem.
dim(), 2);
286 const auto ns = elem.
n_sides();
291 if (s == source_side)
299 const Real raydx = target(0)-source(0),
300 raydy = target(1)-source(1),
301 edgedx = v1(0)-v0(0),
302 edgedy = v1(1)-v0(1);
303 const Real denom = edgedx * raydy - edgedy * raydx;
309 const Real one_over_denom = 1 / denom;
311 const Real targetsdx = v1(0)-target(0),
312 targetsdy = v1(1)-target(1);
314 const Real t_num = targetsdx * raydy -
316 const Real t = t_num * one_over_denom;
321 const Real u_num = targetsdx * edgedy - targetsdy * edgedx;
322 const Real u = u_num * one_over_denom;
335 const Real ray_fraction = (1-u);
337 source(0) += raydx * ray_fraction;
338 source(1) += raydy * ray_fraction;
357 _n_boundary_nodes(n_boundary_nodes),
358 _refine_bdy_allowed(true)
369 LOG_SCOPE(
"triangulate()",
"Poly2TriTriangulator");
383 libmesh_not_implemented();
387 libmesh_not_implemented();
394 libmesh_not_implemented();
425 libmesh_not_implemented();
450 _desired_area_func = desired->
clone();
452 _desired_area_func.reset();
470 std::vector<boundary_id_type> bcids;
474 libmesh_assert_equal_to(bcids.size(), 1);
477 return this->refine_boundary_allowed();
484 libmesh_assert_less(hole_num, this->_holes->size());
485 const Hole * hole = (*this->_holes)[hole_num];
492 LOG_SCOPE(
"triangulate_current_points()",
"Poly2TriTriangulator");
495 const std::size_t n_holes =
_holes !=
nullptr ?
_holes->size() : 0;
499 std::map<const p2t::Point, Node *, P2TPointCompare> point_node_map;
505 std::vector<p2t::Point> outer_boundary_points;
506 std::vector<std::vector<p2t::Point>> inner_hole_points(n_holes);
510 (!nn,
"Poly2TriTriangulator cannot triangulate an empty mesh!");
517 "Poly2TriTriangulator needs contiguous node ids or explicit segments!");
523 std::set<p2t::Point, P2TPointCompare> steiner_points;
546 for (
auto & node :
_mesh.node_ptr_range())
548 const p2t::Point pt = to_p2t(*node);
553 outer_boundary_points.push_back(pt);
555 steiner_points.insert(pt);
558 if (point_node_map.count(pt))
559 libmesh_not_implemented();
561 point_node_map.emplace(pt, node);
572 for (
auto [segment_start, segment_end] : this->
segments)
575 libmesh_error_msg_if(segment_start != last_id,
576 "Disconnected triangulator segments");
577 last_id = segment_end;
581 libmesh_error_msg_if(!node,
582 "Triangulator segments reference nonexistent node id " <<
585 outer_boundary_points.emplace_back(
double((*node)(0)),
double((*node)(1)));
586 p2t::Point * pt = &outer_boundary_points.back();
589 if (point_node_map.count(*pt))
590 libmesh_not_implemented_msg
591 (
"Triangulating overlapping boundary nodes is unsupported");
593 point_node_map.emplace(*pt, node);
596 libmesh_error_msg_if(last_id != this->segments[0].first,
597 "Non-closed-loop triangulator segments");
601 for (
auto & node :
_mesh.node_ptr_range())
603 const p2t::Point pt = to_p2t(*node);
604 if (
const auto it = point_node_map.find(pt);
605 it == point_node_map.end())
607 steiner_points.insert(pt);
608 point_node_map.emplace(pt, node);
611 libmesh_assert_equal_to(it->second, node);
625 std::unordered_map<std::pair<dof_id_type,dof_id_type>,
629 const std::size_t n_outer = outer_boundary_points.size();
634 libmesh_map_find(point_node_map, outer_boundary_points[i]),
636 libmesh_map_find(point_node_map, outer_boundary_points[(i+1)%n_outer]);
638 side_boundary_id.emplace(std::make_pair(node1->
id(),
644 std::vector<p2t::Point *> outer_boundary_pointers(n_outer);
645 std::transform(outer_boundary_points.begin(),
646 outer_boundary_points.end(),
647 outer_boundary_pointers.begin(),
648 [](p2t::Point & p) {
return &p; });
655 std::vector<std::vector<p2t::Point *>> inner_hole_pointers(n_holes);
657 p2t::CDT cdt{outer_boundary_pointers};
662 const Hole * initial_hole = (*_holes)[h];
664 const Hole & our_hole =
666 *initial_hole : *it->second;
667 auto & poly2tri_hole = inner_hole_points[h];
672 poly2tri_hole.emplace_back(to_p2t(p));
674 const auto & pt = poly2tri_hole.back();
677 steiner_points.erase(pt);
683 if (point_node_map.count(pt))
685 libmesh_assert_equal_to
692 point_node_map[pt] = node;
697 const std::size_t n_inner = poly2tri_hole.size();
702 libmesh_map_find(point_node_map, poly2tri_hole[i]),
704 libmesh_map_find(point_node_map, poly2tri_hole[(i+1)%n_inner]);
706 side_boundary_id.emplace(std::make_pair(node1->
id(),
711 auto & poly2tri_ptrs = inner_hole_pointers[h];
712 poly2tri_ptrs.resize(n_inner);
714 std::transform(poly2tri_hole.begin(),
716 poly2tri_ptrs.begin(),
717 [](p2t::Point & p) {
return &p; });
719 cdt.AddHole(poly2tri_ptrs);
727 std::vector<p2t::Point> steiner_vector(steiner_points.begin(), steiner_points.end());
728 steiner_points.clear();
729 for (
auto & p : steiner_vector)
736 std::vector<p2t::Triangle *> triangles = cdt.GetTriangles();
742 boundary_info.
clear();
745 for (
auto ptri_ptr : triangles)
747 p2t::Triangle & ptri = *ptri_ptr;
754 const p2t::Point & vertex = *ptri.GetPoint(v);
756 Node * node = libmesh_map_find(point_node_map, vertex);
768 const Node & node1 = added_elem->node_ref(v),
769 & node2 = added_elem->node_ref((v+1)%3);
771 auto it = side_boundary_id.find(std::make_pair(node1.
id(), node2.id()));
772 if (it == side_boundary_id.end())
773 it = side_boundary_id.find(std::make_pair(node2.id(), node1.
id()));
774 if (it != side_boundary_id.end())
775 boundary_info.
add_side(added_elem, v, it->second);
784 LOG_SCOPE(
"insert_refinement_points()",
"Poly2TriTriangulator");
787 libmesh_not_implemented();
818 bool operator()(
Elem * a,
Elem * b)
const {
820 return (a->
id() < b->
id());
824 std::map<Elem *, std::unique_ptr<Elem>, decltype(comp)> new_elems(comp);
836 std::set<Elem *, decltype(comp)> all_elems
837 {
mesh.elements_begin(),
mesh.elements_end(), comp };
839 restore_delaunay(all_elems, boundary_info);
841 libmesh_assert_delaunay(
mesh, new_elems);
849 std::unordered_map<Point, Node *> next_boundary_node;
859 std::unordered_set<Point> mesh_points;
860 for (
const Node * node :
mesh.node_ptr_range())
863 mesh_points.insert(*node);
867 auto add_point = [&
mesh,
871 &nn](
const Point & p)
875 mesh_points.insert(p);
880 for (
auto & elem :
mesh.element_ptr_range())
887 libmesh_assert_equal_to(elem->
level(), 0u);
888 libmesh_assert_equal_to(elem->
type(),
TRI3);
899 Node * new_node =
nullptr;
904 Elem * cavity_elem = elem;
907 auto boundary_refine = [
this, &next_boundary_node,
908 &cavity_elem, &new_node]
915 Node * old_segment_start = cavity_elem->node_ptr(side),
916 * old_segment_end = cavity_elem->node_ptr((side+1)%3);
922 if (
auto it = next_boundary_node.find(*old_segment_start);
923 it != next_boundary_node.end())
926 it->second = new_node;
934 (old_segment_end->id() ==
935 old_segment_start->id() + 1));
936 next_boundary_node[*old_segment_start] = new_node;
939 next_boundary_node[*new_node] = old_segment_end;
951 while (!cavity_elem->contains_point(new_pt))
953 side = segment_intersection(*cavity_elem, ray_start, new_pt, source_side);
967 new_node = add_point(new_pt);
968 boundary_refine(side);
987 new_pt = cavity_elem->vertex_average();
988 new_node = add_point(new_pt);
1013 if (cavity_elem->neighbor_ptr(s))
1016 Real ax = cavity_elem->point(s)(0) - new_pt(0),
1017 ay = cavity_elem->point(s)(1) - new_pt(1),
1018 bx = cavity_elem->point((s+1)%3)(0) - new_pt(0),
1019 by = cavity_elem->point((s+1)%3)(1) - new_pt(1);
1020 const Real my_cos = (ax*bx+ay*by) /
1021 std::sqrt(ax*ax+ay*ay) /
1022 std::sqrt(bx*bx+by*by);
1024 if (my_cos < worst_cos)
1033 if (worst_cos < -0.6)
1042 new_pt = (cavity_elem->point(side) +
1043 cavity_elem->point((side+1)%3)) / 2;
1044 new_node = add_point(new_pt);
1045 boundary_refine(side);
1049 new_pt = cavity_elem->vertex_average();
1050 new_node = add_point(new_pt);
1058 new_node = add_point(new_pt);
1064 std::set<Elem *, decltype(comp)> cavity(comp);
1066 std::set<Elem *, decltype(comp)> unchecked_cavity ({cavity_elem}, comp);
1067 while (!unchecked_cavity.empty())
1069 std::set<Elem *, decltype(comp)> checking_cavity(comp);
1070 checking_cavity.swap(unchecked_cavity);
1071 for (
Elem * checking_elem : checking_cavity)
1076 if (!neigh || checking_cavity.count(neigh) || cavity.count(neigh))
1080 unchecked_cavity.insert(neigh);
1092 std::set<Elem *, decltype(comp)> check_delaunay_on(comp);
1096 std::unordered_map<Node *, std::pair<Elem *, boundary_id_type>>
1097 neighbors_CCW, neighbors_CW;
1099 for (
Elem * old_elem : cavity)
1104 if (!neigh || !cavity.count(neigh))
1106 Node * node_CW = old_elem->node_ptr(s),
1107 * node_CCW = old_elem->node_ptr((s+1)%3);
1109 auto set_neighbors =
1110 [&neighbors_CW, &neighbors_CCW, &node_CW,
1111 &node_CCW, &boundary_info]
1115 if (
const auto CW_it = neighbors_CW.find(node_CW);
1116 CW_it == neighbors_CW.end())
1119 neighbors_CCW[node_CW] = std::make_pair(new_neigh, bcid);
1123 Elem * neigh_CW = CW_it->second.first;
1129 boundary_info.
add_side(new_neigh, 0, bcid_CW);
1136 boundary_info.
add_side(neigh_CW, 2, bcid);
1138 neighbors_CW.erase(CW_it);
1142 if (
const auto CCW_it = neighbors_CCW.find(node_CCW);
1143 CCW_it == neighbors_CCW.end())
1146 neighbors_CW[node_CCW] = std::make_pair(new_neigh, bcid);
1150 Elem * neigh_CCW = CCW_it->second.first;
1156 boundary_info.
add_side(new_neigh, 2, bcid_CCW);
1162 boundary_info.
add_side(neigh_CCW, 0, bcid);
1164 neighbors_CCW.erase(CCW_it);
1171 if (old_elem == cavity_elem &&
1174 std::vector<boundary_id_type> bcids;
1176 libmesh_assert_equal_to(bcids.size(), 1);
1177 set_neighbors(
nullptr, bcids[0]);
1182 new_elem->set_node(0, new_node);
1183 new_elem->set_node(1, node_CW);
1184 new_elem->set_node(2, node_CCW);
1188 new_elem->set_neighbor(1, neigh);
1191 const unsigned int neigh_s =
1197 std::vector<boundary_id_type> bcids;
1199 boundary_info.
add_side(new_elem.get(), 1, bcids);
1207 Elem * new_elem_ptr = new_elem.get();
1208 new_elems.emplace(new_elem_ptr, std::move(new_elem));
1210 check_delaunay_on.insert(new_elem_ptr);
1214 boundary_info.
remove(old_elem);
1220 for (
Elem * old_elem : cavity)
1222 if (
const auto it = new_elems.find(old_elem);
1223 it == new_elems.end())
1226 new_elems.erase(it);
1237 restore_delaunay(check_delaunay_on, boundary_info);
1241 libmesh_assert_delaunay(
mesh, new_elems);
1248 if (!next_boundary_node.empty())
1250 auto checked_emplace = [
this](
dof_id_type new_first,
1254 for (
auto [first, second] : this->
segments)
1256 libmesh_assert_not_equal_to(first, new_first);
1257 libmesh_assert_not_equal_to(second, new_second);
1259 if (!this->segments.empty())
1260 libmesh_assert_equal_to(this->segments.back().second, new_first);
1262 libmesh_assert_not_equal_to(new_first, new_second);
1264 this->segments.emplace_back (new_first, new_second);
1273 for (
auto node_it =
_mesh.nodes_begin(),
1274 node_end =
_mesh.nodes_end();
1275 node_it != node_end;)
1277 Node & node = **node_it;
1289 last_id = this->
segments.back().second;
1293 checked_emplace(last_id, node_id);
1298 Node * this_node = &node;
1299 auto it = next_boundary_node.find(*this_node);
1300 while (it != next_boundary_node.end())
1303 Node * next_node = it->second;
1306 if (node_it != node_end &&
1307 next_node == *node_it)
1310 checked_emplace(this_node->
id(), next_node->id());
1312 this_node = next_node;
1313 if (this_node->id() == this->
segments.front().first)
1316 it = next_boundary_node.find(*this_node);
1322 checked_emplace(this->
segments.back().second,
1327 std::vector<std::pair<unsigned int, unsigned int>> old_segments;
1330 auto old_it = old_segments.begin();
1333 const Node *
const first_node = node;
1338 if (
const auto it = next_boundary_node.find(*node);
1339 it == next_boundary_node.end())
1341 while (node_id != old_it->first)
1353 checked_emplace(node_id, node->
id());
1355 while (node != first_node);
1367 bool hole_point_insertion =
false;
1369 if (next_boundary_node.count(hole->point(p)))
1371 hole_point_insertion =
true;
1374 if (hole_point_insertion)
1376 (hole, std::make_unique<ArbitraryHole>(*hole));
1381 for (
const Hole * hole : *this->_holes)
1391 bool point_inserted =
false;
1393 if (next_boundary_node.count(point))
1395 point_inserted =
true;
1399 if (!point_inserted)
1403 std::vector<Point> new_points;
1419 auto push_back_new_point = [&new_points](
const Point & p) {
1422 new_points.back() != p);
1425 for (
auto old_p : new_points)
1426 libmesh_assert_not_equal_to(old_p, p);
1428 new_points.push_back(p);
1431 for (
auto point_it = arb.
get_points().rbegin(),
1433 point_it != point_end;)
1435 Point point = *point_it;
1438 if (new_points.empty() ||
1439 (point != new_points.back() &&
1440 point != new_points.front()))
1441 push_back_new_point(point);
1443 auto it = next_boundary_node.find(point);
1444 while (it != next_boundary_node.end())
1446 point = *it->second;
1447 if (point == new_points.front())
1449 if (point_it != point_end &&
1452 push_back_new_point(point);
1453 it = next_boundary_node.find(point);
1457 std::reverse(new_points.begin(), new_points.end());
1465 for (
auto & [raw_elem, unique_elem] : new_elems)
1467 libmesh_assert_equal_to(raw_elem, unique_elem.get());
1474 return !new_elems.empty();
1485 area_func !=
nullptr ||
1493 return (area > min_area_target);
1495 libmesh_warning(
"WARNING: both desired are function and automatic area function are set. Using automatic area function.");
1504 const Real local_area_target = (*area_func)(elem.
point(v));
1505 libmesh_error_msg_if
1506 (local_area_target <= 0,
1507 "Non-positive desired element areas are unachievable");
1508 if (area > local_area_target)
1514 if (!min_area_target)
1517 libmesh_not_implemented_msg
1518 (
"Combining a minimum desired_area with an area function isn't yet supported.");
1530 #endif // LIBMESH_HAVE_POLY2TRI FunctionBase< Real > * get_auto_area_function()
Get the auto area function.
virtual Point quasicircumcenter() const
virtual Node *& set_node(const unsigned int i)
A Node is like a Point, but with more information.
virtual void smooth() override
Redefinition of the smooth function from the base class.
std::unique_ptr< FunctionBase< Real > > _desired_area_func
Location-dependent area requirements.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
void insert_any_extra_boundary_points()
Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.
static constexpr Real TOLERANCE
An abstract class for defining a 2-dimensional hole.
void libmesh_merge_move(T &target, T &source)
const std::vector< int > * _markers
Boundary markers.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
void remove(const Node *node)
Removes the boundary conditions associated with node node, if any exist.
const std::vector< Region * > * _regions
A pointer to a vector of Regions*s.
This is the base class from which all geometric element types are derived.
const Parallel::Communicator & comm() 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.
UnstructuredMesh & _mesh
Reference to the mesh which is to be created by triangle.
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true) override
Other functions from MeshBase requiring re-definition.
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Real distance(const Point &p)
virtual bool is_flipped() 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.
This is the MeshBase class.
std::size_t n_boundary_ids() const
void elems_to_segments()
Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges...
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...
This class defines the data structures necessary for Laplace smoothing.
void libmesh_ignore(const Args &...)
ElemType _elem_type
The type of elements to generate.
static const boundary_id_type invalid_id
Number used for internal use.
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
void triangulate_current_points()
Triangulate the current mesh and hole points.
virtual void set_desired_area_function(FunctionBase< Real > *desired) override
Set a function giving desired triangle area as a function of position.
The UnstructuredMesh class is derived from the MeshBase class.
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
Real & minimum_angle()
Sets and/or gets the minimum desired angle.
Poly2TriTriangulator(UnstructuredMesh &mesh, dof_id_type n_boundary_nodes=DofObject::invalid_id)
The constructor.
const std::vector< Hole * > * _holes
A pointer to a vector of Hole*s.
bool has_auto_area_function()
Whether or not an auto area function has been set.
virtual const Node * query_node_ptr(const dof_id_type i) const =0
std::map< const Hole *, std::unique_ptr< ArbitraryHole > > replaced_holes
We might have to replace the user-provided holes with refined versions.
bool insert_refinement_points()
Add Steiner points as new mesh nodes, as necessary to refine an existing trangulation.
virtual dof_id_type max_elem_id() const =0
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
void increase_triangle_order()
Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type...
const std::vector< Point > & get_points() const
void set_points(std::vector< Point > points)
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
void clear()
Clears the underlying data structures and restores the object to a pristine state with no data stored...
virtual bool refine_boundary_allowed() const
Get whether or not the triangulation is allowed to refine the mesh boundary when refining the interio...
virtual void triangulate() override
Internally, this calls the poly2tri triangulation code in a loop, inserting our owner Steiner points ...
Real & desired_area()
Sets and/or gets the desired triangle area.
virtual void clear_elems()=0
Deletes all the element data that is currently stored.
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
virtual unsigned int n_sides() const =0
const Elem * neighbor_ptr(unsigned int i) const
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...
unsigned int level() const
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< std::pair< unsigned int, unsigned int > > segments
When constructing a PSLG, if the node numbers do not define the desired boundary segments implicitly ...
void 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...
virtual unsigned short dim() const =0
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
const Node * node_ptr(const unsigned int i) const
bool is_refine_boundary_allowed(const BoundaryInfo &boundary_info, const Elem &elem, unsigned int side)
Is refining this element's boundary side allowed?
bool _smooth_after_generating
Flag which tells whether we should smooth the mesh after it is generated.
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 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...
virtual Real volume() const
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...
virtual ~Poly2TriTriangulator()
Empty destructor.
virtual std::unique_ptr< FunctionBase< Output > > clone() const =0
Another concrete instantiation of the hole, this one should be sufficiently general for most non-poly...
virtual Point point(const unsigned int n) const =0
Return the nth point defining the hole.
dof_id_type _n_boundary_nodes
Keep track of how many mesh nodes are boundary nodes.
bool should_refine_elem(Elem &elem)
Returns true if the given element ought to be refined according to current criteria.
virtual dof_id_type max_node_id() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
TriangulationType _triangulation_type
The type of triangulation to perform: choices are: convex hull PSLG.
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
const Point & point(const unsigned int i) const
virtual dof_id_type n_nodes() const =0
virtual unsigned int n_points() const =0
The number of geometric points which define the hole.
Point vertex_average() const