16#include <lagrange/Edge.h>
17#include <lagrange/Mesh.h>
18#include <lagrange/attributes/attribute_utils.h>
19#include <lagrange/attributes/map_corner_attributes.h>
20#include <lagrange/attributes/rename_attribute.h>
21#include <lagrange/common.h>
22#include <lagrange/create_mesh.h>
23#include <lagrange/legacy/inline.h>
24#include <lagrange/mesh_cleanup/split_triangle.h>
25#include <lagrange/utils/safe_cast.h>
32template <
typename MeshType>
33std::unique_ptr<MeshType>
36 using Index =
typename MeshType::Index;
37 using Scalar =
typename MeshType::Scalar;
39 if (mesh.get_vertex_per_facet() != 3) {
40 throw "Only triangle is supported";
42 const Index dim = mesh.get_dim();
43 const Index num_vertices = mesh.get_num_vertices();
44 const Index num_facets = mesh.get_num_facets();
45 const auto& vertices = mesh.get_vertices();
46 const auto& facets = mesh.get_facets();
47 std::vector<typename MeshType::VertexType> additional_vertices;
48 EdgeMap<Index, std::vector<Index>> splitting_pts;
49 EdgeSet<Index> visited;
50 std::vector<std::tuple<Index, Index, Scalar>> vertex_mapping;
52 typename MeshType::AttributeArray active_facets;
53 const bool has_active_region = mesh.has_facet_attribute(
"__is_active");
54 if (has_active_region) {
55 mesh.export_facet_attribute(
"__is_active", active_facets);
57 active_facets.resize(num_facets, 1);
58 active_facets.setZero();
60 auto is_active = [&active_facets](Index fid) {
return active_facets(fid, 0) != 0; };
62 auto split_edge = [&vertices,
68 &vertex_mapping](
const Edge& edge) {
69 if (visited.find(edge) != visited.end())
return;
71 if (splitting_pts.find(edge) != splitting_pts.end())
return;
72 Scalar sq_length = (vertices.row(edge[0]) - vertices.row(edge[1])).squaredNorm();
73 if (sq_length <= sq_tol)
return;
75 const Scalar num_segments = std::ceil(sqrt(sq_length / sq_tol));
76 const auto v0 = vertices.row(edge[0]).eval();
77 const auto v1 = vertices.row(edge[1]).eval();
78 std::vector<Index> split_pts_indices;
79 split_pts_indices.push_back(edge[0]);
80 const Index base = safe_cast<Index>(additional_vertices.size()) + num_vertices;
81 for (Index i = 1; i < num_segments; i++) {
82 Scalar ratio = i / num_segments;
83 additional_vertices.push_back(v0 * (1.0f - ratio) + v1 * ratio);
84 vertex_mapping.emplace_back(edge[0], edge[1], 1.0f - ratio);
85 split_pts_indices.push_back(base + i - 1);
87 split_pts_indices.push_back(edge[1]);
88 splitting_pts.insert({edge, split_pts_indices});
91 for (Index i = 0; i < num_facets; i++) {
92 if (has_active_region && !is_active(i))
continue;
93 split_edge({{facets(i, 0), facets(i, 1)}});
94 split_edge({{facets(i, 1), facets(i, 2)}});
95 split_edge({{facets(i, 2), facets(i, 0)}});
99 const Index total_num_vertices = num_vertices + safe_cast<Index>(additional_vertices.size());
101 typename MeshType::VertexArray all_vertices(total_num_vertices, dim);
102 all_vertices.block(0, 0, num_vertices, dim) = vertices;
103 for (Index i = num_vertices; i < total_num_vertices; i++) {
104 all_vertices.row(i) = additional_vertices[i - num_vertices];
108 std::vector<Eigen::Matrix<Index, 3, 1>> out_facets;
109 std::vector<Index> facet_map;
110 for (Index i = 0; i < num_facets; i++) {
112 std::vector<Index> chain;
115 if (has_active_region && !is_active(i)) {
118 out_facets.push_back(facets.row(i));
119 facet_map.push_back(i);
123 for (Index j = 0; j < 3; j++) {
124 Edge e{{facets(i, j), facets(i, (j + 1) % 3)}};
125 corners[j] = safe_cast<Index>(chain.size());
126 chain.push_back(e[0]);
127 auto itr = splitting_pts.find(e);
128 if (itr != splitting_pts.end()) {
129 const auto& pts = itr->second;
131 if (pts[0] == e[0]) {
132 auto start = std::next(pts.cbegin());
133 auto end = std::prev(pts.cend());
134 chain.insert(chain.end(), start, end);
137 auto start = std::next(pts.crbegin());
138 auto end = std::prev(pts.crend());
139 chain.insert(chain.end(), start, end);
143 if (chain.size() == 3) {
147 out_facets.push_back(facets.row(i));
148 facet_map.push_back(i);
149 active_facets(i, 0) = 0;
151 auto additional_facets =
152 split_triangle(all_vertices, chain, corners[0], corners[1], corners[2]);
154 additional_facets.begin(),
155 additional_facets.end(),
156 std::back_inserter(out_facets));
157 facet_map.insert(facet_map.end(), additional_facets.size(), i);
158 active_facets(i, 0) = 1;
162 const Index num_out_facets = safe_cast<Index>(out_facets.size());
163 typename MeshType::FacetArray all_facets(num_out_facets, 3);
164 for (Index i = 0; i < num_out_facets; i++) {
167 all_facets.row(i) = out_facets[i];
171 if (has_active_region) {
172 mesh.import_facet_attribute(
"__is_active", active_facets);
174 mesh.add_facet_attribute(
"__is_active");
175 mesh.import_facet_attribute(
"__is_active", active_facets);
178 auto out_mesh =
create_mesh(all_vertices, all_facets);
181 auto vertex_attributes = mesh.get_vertex_attribute_names();
182 auto map_vertex_fn = [&](Eigen::Index i,
183 std::vector<std::pair<Eigen::Index, double>>& weights) {
185 if (i < num_vertices) {
186 weights.emplace_back(i, 1.0);
188 const auto& record = vertex_mapping[i - num_vertices];
189 Index v0 = std::get<0>(record);
190 Index v1 = std::get<1>(record);
191 Scalar ratio = std::get<2>(record);
192 weights.emplace_back(v0, ratio);
193 weights.emplace_back(v1, 1.0 - ratio);
197 for (
const auto& name : vertex_attributes) {
198 auto attr = mesh.get_vertex_attribute_array(name);
199 auto attr2 =
to_shared_ptr(attr->row_slice(total_num_vertices, map_vertex_fn));
200 out_mesh->add_vertex_attribute(name);
201 out_mesh->set_vertex_attribute_array(name, std::move(attr2));
205 auto facet_attributes = mesh.get_facet_attribute_names();
206 for (
const auto& name : facet_attributes) {
207 auto attr = mesh.get_facet_attribute_array(name);
209 out_mesh->add_facet_attribute(name);
210 out_mesh->set_facet_attribute_array(name, std::move(attr2));
214 map_corner_attributes(mesh, *out_mesh, facet_map);
217 const auto& indexed_attr_names = mesh.get_indexed_attribute_names();
218 typename MeshType::AttributeArray attr;
219 typename MeshType::IndexArray indices;
220 for (
const auto& attr_name : indexed_attr_names) {
221 std::tie(attr, indices) = mesh.get_indexed_attribute(attr_name);
222 assert(indices.rows() == facets.rows());
224 auto get_vertex_index_in_facet = [&facets](Index fid, Index vid) -> Index {
225 if (vid == facets(fid, 0))
227 else if (vid == facets(fid, 1))
230 assert(vid == facets(fid, 2));
235 typename MeshType::AttributeArray out_attr(num_out_facets * 3, attr.cols());
236 for (
auto i :
range(num_out_facets)) {
237 const auto old_fid = facet_map[i];
238 assert(old_fid < facets.rows());
240 for (Index j = 0; j < 3; j++) {
241 const auto vid = all_facets(i, j);
242 if (vid < num_vertices) {
243 const auto old_j = get_vertex_index_in_facet(old_fid, vid);
245 out_attr.row(i * 3 + j) = attr.row(indices(old_fid, old_j));
247 const auto& record = vertex_mapping[vid - num_vertices];
248 Index v0 = std::get<0>(record);
249 Index v1 = std::get<1>(record);
250 Scalar ratio = std::get<2>(record);
251 Index old_j0 = get_vertex_index_in_facet(old_fid, v0);
252 Index old_j1 = get_vertex_index_in_facet(old_fid, v1);
254 out_attr.row(i * 3 + j) = attr.row(indices(old_fid, old_j0)) * ratio +
255 attr.row(indices(old_fid, old_j1)) * (1.0f - ratio);
260 if (attr_name ==
"normal") {
261 for (
auto i :
range(num_out_facets * 3)) {
262 out_attr.row(i).stableNormalize();
266 const std::string tmp_name =
"__" + attr_name;
267 out_mesh->add_corner_attribute(tmp_name);
268 out_mesh->import_corner_attribute(tmp_name, out_attr);
269 map_corner_attribute_to_indexed_attribute(*out_mesh, tmp_name);
270 rename_indexed_attribute(*out_mesh, tmp_name, attr_name);
271 out_mesh->remove_corner_attribute(tmp_name);
274 if (recursive && total_num_vertices > num_vertices) {
@ Edge
Per-edge mesh attributes.
Definition: AttributeFwd.h:34
#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
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
std::shared_ptr< T > to_shared_ptr(std::unique_ptr< T > &&ptr)
Helper for automatic type deduction for unique_ptr to shared_ptr conversion.
Definition: common.h:88
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 split_long_edges(SurfaceMesh< Scalar, Index > &mesh, SplitLongEdgesOptions options={})
Split edges that are longer than options.max_edge_length.
Definition: split_long_edges.cpp:66