18#include <lagrange/Edge.h>
19#include <lagrange/Mesh.h>
20#include <lagrange/MeshTrait.h>
21#include <lagrange/attributes/map_corner_attributes.h>
22#include <lagrange/common.h>
23#include <lagrange/legacy/inline.h>
24#include <lagrange/mesh_cleanup/detect_degenerate_triangles.h>
25#include <lagrange/mesh_cleanup/remove_short_edges.h>
26#include <lagrange/mesh_cleanup/split_triangle.h>
27#include <lagrange/utils/safe_cast.h>
45template <
typename MeshType>
46std::unique_ptr<MeshType> remove_degenerate_triangles(
const MeshType& mesh)
48 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
50 using Index =
typename MeshType::Index;
51 using Facet =
typename Eigen::Matrix<Index, 3, 1>;
57 detect_degenerate_triangles(*out_mesh);
59 const auto& is_degenerate = out_mesh->get_facet_attribute(
"is_degenerate");
60 const Index num_degenerate_faces = safe_cast<Index>(is_degenerate.sum());
61 if (num_degenerate_faces == 0) {
65 const Index dim = out_mesh->get_dim();
66 const auto& vertices = out_mesh->get_vertices();
67 const Index num_vertices = out_mesh->get_num_vertices();
68 const Index num_facets = out_mesh->get_num_facets();
69 const Index vertex_per_facet = out_mesh->get_vertex_per_facet();
71 const auto& facets = out_mesh->get_facets();
75 auto on_edge = [&vertices, dim](
const Edge& edge,
const Index pid) {
76 for (Index i = 0; i < dim; i++) {
77 double ep1 = vertices(edge[0], i);
78 double ep2 = vertices(edge[1], i);
79 double p = vertices(pid, i);
80 if (ep1 > p && ep2 < p)
82 else if (ep1 < p && ep2 > p)
84 else if (ep1 == p && ep2 == p)
90 throw std::runtime_error(
"Edge must be degenerated.");
95 std::unordered_set<Index> active_vertices;
96 std::unordered_set<Index> active_facets;
97 for (Index i = 0; i < num_facets; ++i) {
98 if (is_degenerate(i, 0)) {
99 active_facets.insert(i);
100 active_vertices.insert(facets(i, 0));
101 active_vertices.insert(facets(i, 1));
102 active_vertices.insert(facets(i, 2));
107 for (Index i = 0; i < num_facets; ++i) {
108 if (active_facets.find(i) == active_facets.end()) {
109 for (Index j = 0; j < vertex_per_facet; ++j) {
110 if (active_vertices.find(facets(i, j)) != active_vertices.end()) {
111 active_facets.insert(i);
116 auto edge_facet_map = compute_edge_facet_map_in_active_facets(*out_mesh, active_facets);
118 std::vector<bool> visited(num_facets,
false);
119 std::function<void(std::set<Index>&, EdgeSet<Index>&,
const Index)> get_collinear_pts;
121 [&edge_facet_map, &facets, &visited, vertex_per_facet, &get_collinear_pts, &is_degenerate](
122 std::set<Index>& collinear_pts,
123 EdgeSet<Index>& involved_edges,
125 if (visited[fid])
return;
127 if (!is_degenerate(fid, 0))
return;
130 for (Index i = 0; i < vertex_per_facet; i++) {
131 Index v = facets(fid, i);
132 collinear_pts.insert(v);
133 Edge e{{facets(fid, i), facets(fid, (i + 1) % vertex_per_facet)}};
134 involved_edges.insert(e);
138 for (Index i = 0; i < vertex_per_facet; i++) {
139 Edge edge{{facets(fid, i), facets(fid, (i + 1) % vertex_per_facet)}};
140 const auto itr = edge_facet_map.find(edge);
142 for (
const auto next_fid : itr->second) {
143 get_collinear_pts(collinear_pts, involved_edges, next_fid);
148 using SplittingPts = std::vector<Index>;
149 EdgeMap<Index, SplittingPts> splitting_points;
150 for (
const auto& item : edge_facet_map) {
152 const auto& adj_facets = item.second;
153 std::set<Index> collinear_pts;
154 EdgeSet<Index> involved_edges;
155 for (
const auto& fid : adj_facets) {
156 if (!is_degenerate(fid, 0))
continue;
157 get_collinear_pts(collinear_pts, involved_edges, fid);
161 for (
const auto& edge : involved_edges) {
163 for (
const auto vid : collinear_pts) {
164 if (on_edge(edge, vid)) {
168 splitting_points[edge] = pts;
172 const auto index_comp = [&vertices, dim](
const Index i,
const Index j) {
173 for (Index d = 0; d < dim; d++) {
174 if (vertices(i, d) == vertices(j, d))
177 return vertices(i, d) < vertices(j, d);
182 for (
auto& item : splitting_points) {
183 std::sort(item.second.begin(), item.second.end(), index_comp);
186 std::vector<Facet> splitted_facets;
187 std::vector<Index> facet_map;
189 for (Index i = 0; i < num_facets; i++) {
190 if (active_facets.find(i) == active_facets.end()) {
191 splitted_facets.emplace_back(facets.row(i));
192 facet_map.push_back(i);
194 }
else if (is_degenerate(i)) {
198 std::vector<Index> chain;
201 const Facet f = facets.row(i);
202 for (Index j = 0; j < 3; j++) {
203 Edge e{{f[j], f[(j + 1) % 3]}};
204 v[j] = safe_cast<Index>(chain.size());
205 chain.push_back(f[j]);
206 const auto itr = splitting_points.find(e);
207 if (itr != splitting_points.end()) {
208 const auto& pts = itr->second;
209 if (index_comp(e[0], e[1])) {
210 std::copy(pts.begin(), pts.end(), std::back_inserter(chain));
212 std::copy(pts.rbegin(), pts.rend(), std::back_inserter(chain));
217 if (chain.size() == 3) {
218 splitted_facets.emplace_back(facets.row(i));
219 facet_map.push_back(i);
221 auto new_facets =
split_triangle(vertices, chain, v[0], v[1], v[2]);
222 std::move(new_facets.begin(), new_facets.end(), std::back_inserter(splitted_facets));
223 facet_map.insert(facet_map.end(), new_facets.size(), i);
227 const auto num_out_facets = splitted_facets.size();
228 typename MeshType::FacetArray out_facets(num_out_facets, 3);
229 for (
auto i :
range(num_out_facets)) {
230 out_facets.row(i) = splitted_facets[i];
235 auto out_mesh2 =
create_mesh(vertices, out_facets);
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
@ Edge
Per-edge mesh attributes.
Definition: AttributeFwd.h:34
@ Facet
Per-facet mesh attributes.
Definition: AttributeFwd.h:31
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
void map_attributes(const SurfaceMesh< Scalar, Index > &source_mesh, SurfaceMesh< Scalar, Index > &target_mesh, span< const Index > mapping_data, span< const Index > mapping_offsets={}, const MapAttributesOptions &options={})
Map attributes from the source mesh to the target mesh.
Definition: map_attributes.cpp:26
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto create_mesh(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets)
This function create a new mesh given the vertex and facet arrays by copying data into the Mesh objec...
Definition: create_mesh.h:39
void split_triangle(size_t num_points, span< const Scalar > points, span< const Index > chain, span< Index > visited_buffer, std::vector< Index > &queue_buffer, const Index v0, const Index v1, const Index v2, span< Index > triangulation)
Split a triangle into smaller triangles based on the chain of splitting points on the edges.
Definition: split_triangle.cpp:27
void remove_short_edges(SurfaceMesh< Scalar, Index > &mesh, Scalar threshold=0)
Collapse all edges shorter than a given tolerance.
Definition: remove_short_edges.cpp:29