9#include <geogram/basic/file_system.h>
10#include <geogram/mesh/mesh_io.h>
11#include <geogram/mesh/mesh_geometry.h>
12#include <geogram/mesh/mesh_repair.h>
16#include <unordered_map>
21 using namespace utils;
27 assert(keep.size() ==
n_faces());
29 std::unordered_map<std::pair<int, int>, int,
utils::HashPair> old_edge_ids;
31 for (
int e = 0; e <
n_edges(); ++e)
40 auto filter_nodes = [&keep](
auto &nodes) {
41 if (nodes.size() != keep.size())
43 std::decay_t<
decltype(nodes)> filtered;
44 for (
int i = 0; i < keep.size(); ++i)
46 filtered.push_back(nodes[i]);
47 nodes = std::move(filtered);
53 GEO::vector<GEO::index_t> to_delete(
mesh_.facets.nb(), 0);
54 for (
int f = 0; f < keep.size(); ++f)
55 to_delete[f] = keep[f] ? 0 : 1;
56 mesh_.facets.delete_elements(to_delete);
62 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(
mesh_.facet_corners.attributes(),
"edge_id");
64 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(
mesh_.edges.attributes(),
"boundary_edge");
66 if (!old_edge_ids.empty())
69 for (
int e = 0; e <
n_edges(); ++e)
72 const auto it = old_edge_ids.find(key);
80 if (!old_edge_nodes.empty())
83 for (
int e = 0; e <
n_edges(); ++e)
86 const auto it = old_edge_nodes.find(key);
87 if (it != old_edge_nodes.end())
93 for (
int e = 0; e <
n_edges(); ++e)
101 if (n_refinement <= 0)
109 bool all_simplicial =
true;
115 for (
int i = 0; i < n_refinement; ++i)
124 mesh_.clear(
false,
false);
141 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(
mesh_.facet_corners.attributes(),
"edge_id");
143 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(
mesh_.edges.attributes(),
"boundary_edge");
157 for (
int e = 0; e < (int)
mesh_.edges.nb(); ++e)
159 for (
int lv = 0; lv < 2; ++lv)
172 const Eigen::MatrixXd &
V = data.
vertices;
173 const Eigen::MatrixXi &
F = data.
elements;
182 mesh_.clear(
false,
false);
183 mesh_.vertices.create_vertices(
V.rows());
184 for (
int i = 0; i <
V.rows(); ++i)
191 for (
int i = 0; i <
F.rows(); ++i)
193 std::vector<GEO::index_t> vertices;
194 vertices.reserve(
F.cols());
195 for (
int j = 0; j <
F.cols() &&
F(i, j) >= 0; ++j)
196 vertices.push_back(
F(i, j));
197 if (vertices.size() < 3)
199 mesh_.facets.create_polygon(vertices.size(), vertices.data());
205 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(
mesh_.facet_corners.attributes(),
"edge_id");
207 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(
mesh_.edges.attributes(),
"boundary_edge");
224 assert(nodes.size() ==
n_faces());
226 for (
int f = 0; f <
n_faces(); ++f)
230 const auto &nodes_ids = nodes[f];
232 if (nodes_ids.size() == 3)
238 else if (nodes_ids.size() == 6)
242 for (
int le = 0; le < 3; ++le)
247 if (n.nodes.size() <= 0)
253 if ((n.v1 == nodes_ids[0] && n.v2 == nodes_ids[1]) || (n.v2 == nodes_ids[0] && n.v1 == nodes_ids[1]))
255 else if ((n.v1 == nodes_ids[1] && n.v2 == nodes_ids[2]) || (n.v2 == nodes_ids[1] && n.v1 == nodes_ids[2]))
260 n.nodes.resize(1, 2);
261 n.nodes <<
V(nodes_ids[node_index], 0),
V(nodes_ids[node_index], 1);
262 n.nodes_ids.push_back(nodes_ids[node_index]);
268 else if (nodes_ids.size() == 10)
272 for (
int le = 0; le < 3; ++le)
277 if (n.nodes.size() <= 0)
284 if (n.v1 == nodes_ids[0] && n.v2 == nodes_ids[1])
289 else if (n.v2 == nodes_ids[0] && n.v1 == nodes_ids[1])
294 else if (n.v1 == nodes_ids[1] && n.v2 == nodes_ids[2])
299 else if (n.v2 == nodes_ids[1] && n.v1 == nodes_ids[2])
304 else if (n.v1 == nodes_ids[2] && n.v2 == nodes_ids[0])
311 assert(n.v2 == nodes_ids[2] && n.v1 == nodes_ids[0]);
316 n.nodes.resize(2, 2);
317 n.nodes.row(0) <<
V(nodes_ids[node_index1], 0),
V(nodes_ids[node_index1], 1);
318 n.nodes.row(1) <<
V(nodes_ids[node_index2], 0),
V(nodes_ids[node_index2], 1);
320 n.nodes_ids.push_back(nodes_ids[node_index1]);
321 n.nodes_ids.push_back(nodes_ids[node_index2]);
328 n.v1 =
mesh_.facets.vertex(f, 0);
329 n.v2 =
mesh_.facets.vertex(f, 1);
330 n.v3 =
mesh_.facets.vertex(f, 2);
331 n.nodes.resize(1, 2);
332 n.nodes <<
V(nodes_ids[9], 0),
V(nodes_ids[9], 1);
333 n.nodes_ids.push_back(nodes_ids[9]);
337 else if (nodes_ids.size() == 15)
361 const double t = i / (n_new_nodes + 1.0);
363 return std::make_pair((1 - t) * v1 + t * v2, -1);
368 return std::make_pair(n.nodes.row(i - 1), n.nodes_ids[i - 1]);
371 assert(n.v2 == index.
vertex);
372 return std::make_pair(n.nodes.row(n.nodes.rows() - i), n.nodes_ids[n.nodes_ids.size() - i]);
386 const double b2 = i / (n_new_nodes + 2.0);
387 const double b3 = j / (n_new_nodes + 2.0);
388 const double b1 = 1 - b3 - b2;
392 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
398 return std::make_pair(n.nodes.row(0), n.nodes_ids[0]);
410 const double b1 = i / (n_new_nodes + 1.0);
411 const double b2 = j / (n_new_nodes + 1.0);
413 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
422 GEO::vec3 min_corner, max_corner;
423 GEO::get_bbox(
mesh_, &min_corner[0], &max_corner[0]);
427 min(0) = min_corner.x;
428 min(1) = min_corner.y;
430 max(0) = max_corner.x;
431 max(1) = max_corner.y;
437 GEO::vec3 min_corner, max_corner;
438 GEO::get_bbox(
mesh_, &min_corner[0], &max_corner[0]);
439 GEO::vec3 extent = max_corner - min_corner;
440 double scaling = std::max(extent[0], std::max(extent[1], extent[2]));
442 const GEO::vec3 origin = min_corner;
443 for (GEO::index_t v = 0; v <
mesh_.vertices.nb(); ++v)
445 mesh_.vertices.point(v) = (
mesh_.vertices.point(v) - origin) / scaling;
447 Eigen::RowVector2d shift;
448 shift << origin[0], origin[1];
451 if (n.nodes.size() > 0)
452 n.nodes = (n.nodes.rowwise() - shift) / scaling;
456 if (n.nodes.size() > 0)
457 n.nodes = (n.nodes.rowwise() - shift) / scaling;
459 Eigen::Vector2d normalization_translation;
460 normalization_translation << -origin[0] / scaling, -origin[1] / scaling;
462 Eigen::Matrix2d::Identity() / scaling,
463 normalization_translation);
465 logger().debug(
"-- bbox before normalization:");
466 logger().debug(
" min : {} {}", min_corner[0], min_corner[1]);
467 logger().debug(
" max : {} {}", max_corner[0], max_corner[1]);
468 logger().debug(
" extent: {} {}", max_corner[0] - min_corner[0], max_corner[1] - min_corner[1]);
469 GEO::get_bbox(
mesh_, &min_corner[0], &max_corner[0]);
470 logger().debug(
"-- bbox after normalization:");
471 logger().debug(
" min : {} {}", min_corner[0], min_corner[1]);
472 logger().debug(
" max : {} {}", max_corner[0], max_corner[1]);
473 logger().debug(
" extent: {} {}", max_corner[0] - min_corner[0], max_corner[1] - min_corner[1]);
475 Eigen::MatrixXd p0, p1, p;
478 logger().debug(
"-- edge length after normalization:");
479 logger().debug(
" min: {}", p.rowwise().norm().minCoeff());
480 logger().debug(
" max: {}", p.rowwise().norm().maxCoeff());
481 logger().debug(
" avg: {}", p.rowwise().norm().mean());
486 const int v0 =
mesh_.edges.vertex(gid, 0);
487 const int v1 =
mesh_.edges.vertex(gid, 1);
494 mesh_.vertices.point(global_index).x = p(0);
495 mesh_.vertices.point(global_index).y = p(1);
500 const double *ptr =
mesh_.vertices.point_ptr(global_index);
596 const int v0 =
mesh_.edges.vertex(index, 0);
597 const int v1 =
mesh_.edges.vertex(index, 1);
618 for (
int e = 0; e <
n_edges(); ++e)
623 std::sort(vs.begin(), vs.end());
630 assert(
typeid(mesh) ==
typeid(
CMesh2D));
639 for (
int i = n_v; i < (int)
mesh_.vertices.nb(); ++i)
641 GEO::vec3 &p =
mesh_.vertices.point(i);
645 std::vector<GEO::index_t> indices;
646 for (
int i = 0; i < mesh2d.
n_faces(); ++i)
649 for (
int j = 0; j < mesh2d.
mesh_.facets.nb_vertices(i); ++j)
650 indices.push_back(mesh2d.
mesh_.facets.vertex(i, j) + n_v);
652 mesh_.facets.create_polygon(indices.size(), &indices[0]);
662 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(
mesh_.facet_corners.attributes(),
"edge_id");
664 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(
mesh_.edges.attributes(),
"boundary_edge");
670 int max_face_size = 0;
672 vertices.row(i) =
point(i);
673 for (
int i = 0; i <
n_faces(); ++i)
676 Eigen::MatrixXi
faces = Eigen::MatrixXi::Constant(
n_faces(), max_face_size, -1);
677 for (
int i = 0; i <
n_faces(); ++i)
681 std::unique_ptr<CMesh2D> copy_mesh = std::make_unique<CMesh2D>();
682 copy_mesh->build_topology(
MeshData(std::move(vertices), std::move(
faces)));
690 copy_mesh->orders_ = this->
orders_;
virtual RowVectorNd edge_barycenter(const int index) const override
edge barycenter
Navigation::Index switch_edge(Navigation::Index idx) const override
void normalize() override
normalize the mesh
void compute_elements_tag() override
compute element types, see ElementType
int n_faces() const override
number of faces
int n_face_vertices(const int f_id) const override
number of vertices of a face
int n_vertices() const override
number of vertices
int n_edges() const override
number of edges
bool is_boundary_element(const int element_global_id) const override
is cell boundary
double edge_length(const int gid) const override
edge length
std::unique_ptr< GEO::Attribute< bool > > boundary_edges_
std::pair< RowVectorNd, int > edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const override
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Navigation::Index switch_vertex(Navigation::Index idx) const override
int face_vertex(const int f_id, const int lv_id) const override
id of the face vertex
void compute_boundary_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &, bool)> &marker) override
computes boundary selections based on a function
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
bool build_topology(const MeshData &data) override
Construct only the dimension-specific topology.
bool is_boundary_edge(const int edge_global_id) const override
is edge boundary
std::unique_ptr< GEO::Attribute< GEO::index_t > > c2e_
std::unique_ptr< GEO::Attribute< bool > > boundary_vertices_
std::pair< RowVectorNd, int > face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const override
void append(const Mesh &mesh) override
appends a new mesh to the end of this
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Navigation::Index get_index_from_face(int f, int lv=0) const override
virtual void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
void refine(const int n_refinement, const double t) override
refine the mesh
void compute_body_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &)> &marker) override
computes boundary selections based on a function
virtual RowVectorNd point(const int global_index) const override
point coordinates
virtual void update_elements_tag() override
Update elements types.
RowVectorNd face_barycenter(const int index) const override
face barycenter
Navigation::Index next_around_face(Navigation::Index idx) const
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Class to store the high-order edge nodes.
Format-independent input used to construct a runtime Mesh.
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Eigen::MatrixXi orders_
list of geometry orders, one per cell
std::vector< ElementType > elements_tag_
list of element types
bool is_rational_
stores if the mesh is rational
bool has_boundary_ids() const
checks if surface selections are available
std::vector< std::vector< int > > higher_order_connectivity_
bool is_cube(const int el_id) const
checks if element is cube compatible
Eigen::MatrixXi in_ordered_faces_
Order of the input faces, TODO: change to std::vector of Eigen::Vector.
bool is_simplex(const int el_id) const
checks if element is simplex
std::vector< int > geometry_ids_
list of geometry labels, one per top-dimensional element
std::vector< int > boundary_ids_
list of surface labels
void clear_higher_order_data()
std::vector< int > node_ids_
list of node labels
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
std::vector< std::vector< double > > cell_weights_
weights associates to cells for rational polynomail meshes
Eigen::MatrixXd higher_order_nodes_
Canonical connectivity is retained because the runtime edge/face caches do not preserve the original ...
std::vector< int > element_vertices(const int el_id) const
list of vids of an element
std::vector< int > body_ids_
list of volume labels
virtual int get_default_boundary_id(const int primitive) const
Get the default boundary selection of an element (face in 3d, edge in 2d)
void transform_higher_order_data(const MatrixNd &A, const VectorNd &b)
std::vector< FaceNodes > face_nodes_
high-order nodes associates to faces
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
std::vector< std::vector< int > > faces() const
list of sorted faces.
void filter_element_data(const std::vector< bool > &keep)
Eigen::MatrixXi in_ordered_edges_
Order of the input edges.
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
bool has_explicit_polyhedral_topology_
Whether the source MeshData supplied explicit face/cell incidence.
Eigen::VectorXi in_ordered_vertices_
Order of the input vertices.
void prepare_mesh(GEO::Mesh &M)
SplitFunction catmul_clark_split_func()
SplitFunction polar_split_func(double t)
Helper function.
void refine_triangle_mesh(const GEO::Mesh &M_in, GEO::Mesh &M_out)
Refine a triangle mesh.
void orient_normals_2d(GEO::Mesh &M)
Orient facets of a 2D mesh so that each connected component has positive volume.
void generate_edges(GEO::Mesh &M)
assing edges to M
void refine_polygonal_mesh(const GEO::Mesh &M_in, GEO::Mesh &M_out, Polygons::SplitFunction split_func)
Refine a polygonal mesh.
void compute_element_tags(const GEO::Mesh &M, std::vector< ElementType > &element_tags)
Compute the type of each facet in a surface mesh.
spdlog::logger & logger()
Retrieves the current logger.
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd