Wildmeshing Toolkit
Loading...
Searching...
No Matches
VolumeRemesherTriangleInsertion.cpp
Go to the documentation of this file.
1
3#include <set>
4#include <wmtk/Mesh.hpp>
5#include <wmtk/TetMesh.hpp>
10#include <wmtk/utils/orient.hpp>
11
12
13// clang-format off
14#include <VolumeRemesher/embed.h>
15// clang-format on
16
17#include <numeric>
18
19#include <polysolve/Utils.hpp>
20
21
22namespace wmtk::utils {
23
24std::tuple<std::shared_ptr<wmtk::TetMesh>, std::vector<std::array<bool, 4>>>
26 const RowVectors3d& V,
27 const RowVectors3l& F,
28 const RowVectors3d& background_V,
29 const RowVectors4l& background_TV)
30{
31 polysolve::StopWatch timer("tri insertion", logger());
32
33 // prepare data for volume remesher
34 // inputs
35 std::vector<double> tri_vrt_coords(V.rows() * 3);
36 std::vector<uint32_t> triangle_indices(F.rows() * 3);
37 std::vector<double> tet_vrt_coords(background_V.rows() * 3);
38 std::vector<uint32_t> tet_indices(background_TV.rows() * 4);
39
40 for (int64_t i = 0; i < V.rows(); ++i) {
41 tri_vrt_coords[i * 3 + 0] = V(i, 0);
42 tri_vrt_coords[i * 3 + 1] = V(i, 1);
43 tri_vrt_coords[i * 3 + 2] = V(i, 2);
44 }
45
46 for (int64_t i = 0; i < F.rows(); ++i) {
47 triangle_indices[i * 3 + 0] = F(i, 0);
48 triangle_indices[i * 3 + 1] = F(i, 1);
49 triangle_indices[i * 3 + 2] = F(i, 2);
50 }
51
52 for (int64_t i = 0; i < background_V.rows(); ++i) {
53 tet_vrt_coords[i * 3 + 0] = background_V(i, 0);
54 tet_vrt_coords[i * 3 + 1] = background_V(i, 1);
55 tet_vrt_coords[i * 3 + 2] = background_V(i, 2);
56 }
57
58 for (int64_t i = 0; i < background_TV.rows(); ++i) {
59 tet_indices[i * 4 + 0] = background_TV(i, 0);
60 tet_indices[i * 4 + 1] = background_TV(i, 1);
61 tet_indices[i * 4 + 2] = background_TV(i, 2);
62 tet_indices[i * 4 + 3] = background_TV(i, 3);
63 }
64
65 // outputs
66 std::vector<vol_rem::bigrational> embedded_vertices;
67 std::vector<uint32_t> embedded_facets;
68 std::vector<uint32_t> embedded_cells;
69 std::vector<uint32_t> embedded_facets_on_input;
70 std::vector<std::array<uint32_t, 4>> tets_final; // final tets
71 std::vector<uint32_t> final_tets_parent;
72 std::vector<bool> cells_with_faces_on_input;
73 std::vector<std::vector<uint32_t>> final_tets_parent_faces;
74 timer.start();
75 // run volume remesher
76 vol_rem::embed_tri_in_poly_mesh(
77 tri_vrt_coords,
78 triangle_indices,
79 tet_vrt_coords,
80 tet_indices,
81 embedded_vertices,
82 embedded_facets,
83 embedded_cells,
84 tets_final,
85 final_tets_parent,
86 embedded_facets_on_input,
87 cells_with_faces_on_input,
88 final_tets_parent_faces,
89 wmtk::logger().level() < spdlog::level::info);
90 timer.stop();
91 assert(tets_final.size() == final_tets_parent.size());
92
93 wmtk::logger().info(
94 "volume remesher finished {}s, polycell mesh generated, #vertices: {}, #cells: {}, #tets "
95 "{}",
96 timer.getElapsedTimeInSec(),
97 embedded_vertices.size() / 3,
98 embedded_cells.size(),
99 tets_final.size());
100
101 // convert to double and readable format
102 std::vector<Vector3r> v_coords; // vertex coordinates
103 std::vector<std::array<int64_t, 3>> polygon_faces; // index of vertices
104 std::vector<bool> polygon_faces_on_input; // whether the face is on input surface
105 std::vector<std::array<bool, 4>> tet_face_on_input_surface; // tet local face on input surface
106
107
108 wmtk::logger().info("Converting vertices...");
109 int64_t round_cnt = 0;
110 for (int64_t i = 0; i < embedded_vertices.size() / 3; ++i) {
111#ifdef USE_GNU_GMP_CLASSES
112 v_coords.emplace_back();
113 v_coords.back()[0].init(embedded_vertices[3 * i + 0].get_mpq_t());
114 v_coords.back()[1].init(embedded_vertices[3 * i + 1].get_mpq_t());
115 v_coords.back()[2].init(embedded_vertices[3 * i + 2].get_mpq_t());
116#else
117 v_coords.emplace_back();
118 v_coords.back()[0].init_from_binary(embedded_vertices[3 * i + 0].get_str());
119 v_coords.back()[1].init_from_binary(embedded_vertices[3 * i + 1].get_str());
120 v_coords.back()[2].init_from_binary(embedded_vertices[3 * i + 2].get_str());
121#endif
122
123
124 bool round = true;
125 for (int64_t j = 0; j < 3; ++j) {
126 if (!v_coords.back()[j].can_be_rounded()) {
127 round = false;
128 break;
129 }
130 }
131
132 if (round) {
133 round_cnt++;
134 for (int64_t j = 0; j < 3; ++j) v_coords.back()[j].round();
135 }
136 }
137 wmtk::logger().info("done, {} rounded vertices over {}", round_cnt, v_coords.size());
138
139 wmtk::logger().info("Facets loop...");
140 for (int64_t i = 0; i < embedded_facets.size(); ++i) {
141 int64_t polysize = embedded_facets[i];
142 assert(polysize == 3);
143 std::array<int64_t, 3> polygon;
144 for (int64_t j = i + 1; j <= i + polysize; ++j) {
145 polygon[j - (i + 1)] = embedded_facets[j];
146 }
147 polygon_faces.push_back(polygon);
148 i += polysize; // dangerous behavior, but working now
149 }
150 wmtk::logger().info("done");
151
152 wmtk::logger().info("Tags loop...");
153 polygon_faces_on_input.resize(polygon_faces.size(), false);
154 for (int64_t i = 0; i < embedded_facets_on_input.size(); ++i) {
155 polygon_faces_on_input[embedded_facets_on_input[i]] = true;
156 }
157 wmtk::logger().info("done");
158
159
160 wmtk::logger().info("tracking surface starting...");
161 timer.start();
162 assert(final_tets_parent_faces.size() == tets_final.size());
163 for (int64_t i = 0; i < tets_final.size(); ++i) {
164 const auto& tetra = tets_final[i];
165 const uint32_t tetra_parent = final_tets_parent[i];
166
167 if (!cells_with_faces_on_input[tetra_parent]) {
168 tet_face_on_input_surface.push_back({{false, false, false, false}});
169 continue;
170 }
171
172 // vector of std array and sort
173 std::array<int64_t, 3> local_f0{{tetra[1], tetra[2], tetra[3]}};
174 std::sort(local_f0.begin(), local_f0.end());
175 std::array<int64_t, 3> local_f1{{tetra[0], tetra[2], tetra[3]}};
176 std::sort(local_f1.begin(), local_f1.end());
177 std::array<int64_t, 3> local_f2{{tetra[0], tetra[1], tetra[3]}};
178 std::sort(local_f2.begin(), local_f2.end());
179 std::array<int64_t, 3> local_f3{{tetra[0], tetra[1], tetra[2]}};
180 std::sort(local_f3.begin(), local_f3.end());
181
182 // track surface
183 std::array<bool, 4> tet_face_on_input{{false, false, false, false}};
184 for (auto f : final_tets_parent_faces[i]) {
185 assert(polygon_faces[f].size() == 3);
186
187 auto f_vs = polygon_faces[f];
188 std::sort(f_vs.begin(), f_vs.end());
189
190 int64_t local_f_idx = -1;
191
192 // decide which face it is
193
194 if (f_vs == local_f0) {
195 local_f_idx = 0;
196 } else if (f_vs == local_f1) {
197 local_f_idx = 1;
198 } else if (f_vs == local_f2) {
199 local_f_idx = 2;
200 } else {
201 local_f_idx = 3;
202 }
203 assert(local_f_idx >= 0);
204
205 tet_face_on_input[local_f_idx] = polygon_faces_on_input[f];
206 }
207
208 tet_face_on_input_surface.push_back(tet_face_on_input);
209 }
210 timer.stop();
211 wmtk::logger().info("took: {}", timer.getElapsedTimeInSec());
212
213 wmtk::logger().info("removing unreferenced vertices...");
214 timer.start();
215 std::vector<bool> v_is_used_in_tet(v_coords.size(), false);
216 for (const auto& t : tets_final) {
217 for (const auto& v : t) {
218 v_is_used_in_tet[v] = true;
219 }
220 }
221 std::vector<int64_t> v_map(v_coords.size(), -1);
222 std::vector<Vector3r> v_coords_final;
223
224 for (int64_t i = 0; i < v_coords.size(); ++i) {
225 if (v_is_used_in_tet[i]) {
226 v_map[i] = v_coords_final.size();
227 v_coords_final.emplace_back(v_coords[i]);
228 }
229 }
230 for (auto& t : tets_final) {
231 for (int i = 0; i < 4; ++i) {
232 assert(v_map[t[i]] >= 0);
233 t[i] = v_map[t[i]];
234 }
235 }
236 timer.stop();
237 wmtk::logger().info("took: {}", timer.getElapsedTimeInSec());
238
239
240 // check tets
241 // for (auto& t : tets_final) {
242 // if (wmtk_orient3d(
243 // v_coords_final[t[0]],
244 // v_coords_final[t[1]],
245 // v_coords_final[t[2]],
246 // v_coords_final[t[3]]) <= 0) {
247 // Eigen::Matrix<Rational, 3, 3> tmp;
248 // tmp.col(0) = v_coords_final[t[1]] - v_coords_final[t[0]];
249 // tmp.col(1) = v_coords_final[t[2]] - v_coords_final[t[0]];
250 // tmp.col(2) = v_coords_final[t[3]] - v_coords_final[t[0]];
251 // log_and_throw_error(
252 // "flipped tet=({},{},{},{}) crash vol={} orient={}",
253 // t[0],
254 // t[1],
255 // t[2],
256 // t[3],
257 // tmp.determinant().serialize(),
258 // wmtk_orient3d(
259 // v_coords_final[t[0]],
260 // v_coords_final[t[1]],
261 // v_coords_final[t[2]],
262 // v_coords_final[t[3]]));
263 // }
264 // }
265
266 wmtk::logger().info("convert to eigen...");
267 // transfer v_coords_final to V matrix and tets_final to TV matrix
268 RowVectors3r V_final_rational(v_coords_final.size(), 3);
269 RowVectors4l TV_final(tets_final.size(), 4);
270
271 for (int64_t i = 0; i < v_coords_final.size(); ++i) {
272 V_final_rational.row(i) = v_coords_final[i];
273 }
274
275 for (int64_t i = 0; i < tets_final.size(); ++i) {
276 assert(tets_final[i][0] < V_final_rational.rows());
277 assert(tets_final[i][1] < V_final_rational.rows());
278 assert(tets_final[i][2] < V_final_rational.rows());
279 assert(tets_final[i][3] < V_final_rational.rows());
280
281 assert(tets_final[i][0] != tets_final[i][1]);
282 assert(tets_final[i][0] != tets_final[i][2]);
283 assert(tets_final[i][0] != tets_final[i][3]);
284
285 assert(tets_final[i][1] != tets_final[i][2]);
286 assert(tets_final[i][1] != tets_final[i][3]);
287
288 assert(tets_final[i][2] != tets_final[i][3]);
289
290 TV_final.row(i) << tets_final[i][0], tets_final[i][1], tets_final[i][2], tets_final[i][3];
291 }
292 wmtk::logger().info("done");
293
294 wmtk::logger().info("init tetmesh...");
295 // initialize tetmesh
296 std::shared_ptr<wmtk::TetMesh> m = std::make_shared<wmtk::TetMesh>();
297 m->initialize(TV_final);
298 // mesh_utils::set_matrix_attribute(V_final, "vertices", PrimitiveType::Vertex, *m);
299 mesh_utils::set_matrix_attribute(V_final_rational, "vertices", PrimitiveType::Vertex, *m);
300
301 wmtk::logger().info("init tetmesh finished.");
302
303 if (!m->is_connectivity_valid()) {
304 wmtk::logger().error("invalid tetmesh connectivity after insertion");
305 throw std::runtime_error("invalid tetmesh connectivity by insertion");
306 }
307 return std::make_tuple(m, tet_face_on_input_surface);
308}
309
310
311} // namespace wmtk::utils
attribute::MeshAttributeHandle set_matrix_attribute(const Mat &data, const std::string &name, const PrimitiveType &type, Mesh &mesh)
Definition mesh_utils.hpp:9
std::tuple< std::shared_ptr< wmtk::TetMesh >, std::vector< std::array< bool, 4 > > > generate_raw_tetmesh_from_input_surface(const RowVectors3d &V, const RowVectors3l &F, const RowVectors3d &background_V, const RowVectors4l &background_TV)
input a triangle surface mesh, embed it into a background tet mesh, track the input surfaces on the t...
RowVectors< int64_t, 3 > RowVectors3l
Definition Types.hpp:47
RowVectors< int64_t, 4 > RowVectors4l
Definition Types.hpp:48
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
RowVectors< double, 3 > RowVectors3d
Definition Types.hpp:51
RowVectors< Rational, 3 > RowVectors3r
Definition Types.hpp:53