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,
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.
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 created (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.
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.
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.
The libMesh namespace provides an interface to certain functionality in the library.
virtual void smooth() override
Redefinition of the smooth function from the base class.
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.
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
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...
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
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
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