Wildmeshing Toolkit
VolumeRemesherTriangleInsertion.cpp
Go to the documentation of this file.
1 
3 #include <set>
4 #include <wmtk/Mesh.hpp>
5 #include <wmtk/TetMesh.hpp>
7 #include <wmtk/utils/Logger.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 
22 namespace wmtk::utils {
23 
24 std::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