Wildmeshing Toolkit
triangle_insertion.cpp
Go to the documentation of this file.
1 #include "triangle_insertion.hpp"
2 
3 
8 
10 
11 #include <wmtk/Mesh.hpp>
12 #include <wmtk/Scheduler.hpp>
13 #include <wmtk/TetMesh.hpp>
14 #include <wmtk/TriMesh.hpp>
16 #include <wmtk/simplex/Simplex.hpp>
17 #include <wmtk/utils/Logger.hpp>
18 #include <wmtk/utils/Rational.hpp>
19 
20 
21 // this should change! make a util?
23 
24 
26 
27 std::tuple<std::shared_ptr<wmtk::TetMesh>, ChildMeshes> triangle_insertion(
28  const TetMesh& bg_mesh,
29  const std::string& bg_position,
30  const TriMesh& mesh_in,
31  const std::string& in_position,
32  std::vector<attribute::MeshAttributeHandle>& pass_through,
33  bool round,
34  bool track_submeshes,
35  bool make_child_free)
36 {
38  mesh_in.serialize(writer);
39 
41  bg_mesh.serialize(writer_bg);
42 
43  Eigen::MatrixXd V;
44  writer.get_double_matrix(in_position, PrimitiveType::Vertex, V);
45 
46  Eigen::MatrixX<int64_t> F;
47  writer.get_FV_matrix(F);
48 
49  Eigen::MatrixXd Vbg;
50  writer_bg.get_double_matrix(bg_position, PrimitiveType::Vertex, Vbg);
51 
52  Eigen::MatrixX<int64_t> Fbg;
53  writer_bg.get_TV_matrix(Fbg);
54 
55 
56  /* new code for nonmanifold substructure and open boundaries*/
57 
58  constexpr static PrimitiveType PV = PrimitiveType::Vertex;
59  constexpr static PrimitiveType PE = PrimitiveType::Edge;
60  constexpr static PrimitiveType PF = PrimitiveType::Triangle;
61  constexpr static PrimitiveType PT = PrimitiveType::Tetrahedron;
62 
63  auto [tetmesh, tet_face_on_input_surface] =
65 
66  /* -------------rounding------------ */
67 
68  if (round) {
69  auto rounding_pt_attribute =
70  tetmesh->get_attribute_handle_typed<Rational>(in_position, PrimitiveType::Vertex);
71 
72  std::shared_ptr<Mesh> m_ptr = tetmesh;
73 
74  auto rounding = std::make_shared<wmtk::operations::Rounding>(*m_ptr, rounding_pt_attribute);
75  rounding->add_invariant(
76  std::make_shared<SimplexInversionInvariant<Rational>>(*m_ptr, rounding_pt_attribute));
77 
78  Scheduler scheduler;
79  auto stats = scheduler.run_operation_on_all(*rounding);
80 
81  logger().info(
82  "Executed rounding, {} ops (S/F) {}/{}. Time: collecting: {}, sorting: {}, "
83  "executing: {}",
84  stats.number_of_performed_operations(),
85  stats.number_of_successful_operations(),
86  stats.number_of_failed_operations(),
87  stats.collecting_time,
88  stats.sorting_time,
89  stats.executing_time);
90  }
91 
92  ChildMeshes child_meshes;
93 
94  if (track_submeshes) {
95  /* -----------input surface--------- */
96 
97  logger().trace("Registering input surface from tag surface");
98  auto surface_handle =
99  tetmesh->register_attribute<int64_t>("surface", PrimitiveType::Triangle, 1);
100  auto surface_accessor = tetmesh->create_accessor<int64_t>(surface_handle);
101 
102  // register surface tag
103 
104  const auto& tets = tetmesh->get_all(PrimitiveType::Tetrahedron);
105  assert(tets.size() == tet_face_on_input_surface.size());
106 
107  logger().info("Assigning surface tags");
108  for (int64_t i = 0; i < tets.size(); ++i) {
109  const auto& t = tets[i]; // local face 2
110  std::array<Tuple, 4> fs = {
111  {tetmesh->switch_tuples(t, {PV, PE, PF}),
112  tetmesh->switch_tuples(t, {PE, PF}),
113  t,
114  tetmesh->switch_tuples(t, {PF})}};
115 
116  for (int64_t k = 0; k < 4; ++k) {
117  if (tet_face_on_input_surface[i][k]) {
118  surface_accessor.scalar_attribute(fs[k]) = 1;
119  } else {
120  surface_accessor.scalar_attribute(fs[k]) = 0;
121  }
122  }
123  }
124 
125  pass_through.push_back(surface_handle);
126 
127 
128  // get multimesh from tag
129 
130  if (make_child_free) {
131  logger().info("Making free child surface mesh");
132  child_meshes.surface_mesh =
134  *tetmesh,
135  surface_handle.as<int64_t>(),
136  1,
137  /*free = */ true);
138 
139  } else {
140  logger().info("Making child surface mesh");
141  internal::MultiMeshFromTag SurfaceMeshFromTag(*tetmesh, surface_handle, 1);
142  SurfaceMeshFromTag.compute_substructure_mesh();
143 
144  child_meshes.surface_mesh = tetmesh->get_child_meshes().back();
145 
146  SurfaceMeshFromTag.remove_soup();
147  }
148 
149  /* -----------open boundary and nonmanifold edges in input surface--------- */
150 
151  logger().info("Going through open/nonmanifold stuff");
152  auto open_boundary_handle =
153  tetmesh->register_attribute<int64_t>("open_boundary", PrimitiveType::Edge, 1);
154  auto open_boundary_accessor = tetmesh->create_accessor<int64_t>(open_boundary_handle);
155 
156  auto nonmanifold_edge_handle =
157  tetmesh->register_attribute<int64_t>("nonmanifold_edge", PrimitiveType::Edge, 1);
158  auto nonmanifold_edge_accessor = tetmesh->create_accessor<int64_t>(nonmanifold_edge_handle);
159 
160  pass_through.push_back(open_boundary_handle);
161  pass_through.push_back(nonmanifold_edge_handle);
162 
163  // register edge tags
164  bool has_openboundary = false;
165  bool has_nonmanifold_edge = false;
166 
167  logger().info("Looping edges for open/nonmanifold ones");
168  for (const auto& e : child_meshes.surface_mesh->get_all(PrimitiveType::Edge)) {
169  const auto surface_edge = simplex::Simplex::edge(*child_meshes.surface_mesh, e);
170  if (!child_meshes.surface_mesh->is_boundary(surface_edge)) continue;
171 
172  const auto& parent_e = child_meshes.surface_mesh->map_to_parent(surface_edge);
173  const auto& child_e =
174  tetmesh->map_to_child_tuples(*child_meshes.surface_mesh, parent_e);
175 
176  assert(child_e.size() > 0);
177 
178  if (child_e.size() == 1) {
179  // if edge is a boundary on the surface mesh and only appears once,
180  // then it is an open boundary
181  open_boundary_accessor.scalar_attribute(parent_e.tuple()) = 1;
182  has_openboundary = true;
183  } else {
184  // else it is a nonmanifold edge in the input surface
185  nonmanifold_edge_accessor.scalar_attribute(parent_e.tuple()) = 1;
186  has_nonmanifold_edge = true;
187  }
188  }
189 
190  const bool process_nonmanifold_edges = !make_child_free && has_nonmanifold_edge;
191 
192  // get multimeshes from tag
193 
194  if (has_openboundary) {
195  if (make_child_free) {
196  logger().error("Creating free open boundary child mesh");
197  child_meshes.open_boundary_mesh =
199  *tetmesh,
200  open_boundary_handle.as<int64_t>(),
201  1,
202  /*free = */ true);
203 
204  } else {
205  logger().error("Creating open boundary child mesh");
206  internal::MultiMeshFromTag OpenBoundaryFromTag(*tetmesh, open_boundary_handle, 1);
207  OpenBoundaryFromTag.compute_substructure_mesh();
208 
209  child_meshes.open_boundary_mesh = tetmesh->get_child_meshes().back();
210  OpenBoundaryFromTag.remove_soup();
211  }
212  }
213 
214  if (process_nonmanifold_edges) {
215  logger().info("Creating nonmanifold edge mesh");
216  internal::MultiMeshFromTag NonmanifoldEdgeFromTag(*tetmesh, nonmanifold_edge_handle, 1);
217  NonmanifoldEdgeFromTag.compute_substructure_mesh();
218 
219  child_meshes.nonmanifold_edge_mesh = tetmesh->get_child_meshes().back();
220  NonmanifoldEdgeFromTag.remove_soup();
221  }
222 
223  /* ---------------------bounding box-------------------------*/
224  auto bbox_handle = tetmesh->register_attribute<int64_t>("bbox", PrimitiveType::Triangle, 1);
225  auto bbox_accessor = tetmesh->create_accessor<int64_t>(bbox_handle);
226 
227  pass_through.push_back(bbox_handle);
228 
229  logger().info("Annotating bounding box boundary");
230  for (const auto& f : tetmesh->get_all(PrimitiveType::Triangle)) {
231  bbox_accessor.scalar_attribute(f) =
232  tetmesh->is_boundary(PrimitiveType::Triangle, f) ? 1 : 0;
233  }
234 
235  internal::MultiMeshFromTag NonmanifoldEdgeFromTag(*tetmesh, bbox_handle, 1);
236  NonmanifoldEdgeFromTag.compute_substructure_mesh();
237 
238  child_meshes.bbox_mesh = tetmesh->get_child_meshes().back();
239  NonmanifoldEdgeFromTag.remove_soup();
240 
241 
242  /* -----------nonmanifold vertices in input surface--------- */
243 
244  logger().info("Nonmanifold vertices");
245  auto nonmanifold_vertex_handle =
246  tetmesh->register_attribute<int64_t>("nonmanifold_vertex", PrimitiveType::Vertex, 1);
247  auto nonmanifold_vertex_accessor =
248  tetmesh->create_accessor<int64_t>(nonmanifold_vertex_handle);
249 
250  pass_through.push_back(nonmanifold_vertex_handle);
251 
252  for (const auto& v : tetmesh->get_all(PrimitiveType::Vertex)) {
253  int64_t on_open_boundary_cnt = 0;
254  int64_t on_nonmanifold_edge_cnt = 0;
255 
256  if (has_openboundary) {
257  on_open_boundary_cnt = tetmesh
258  ->map_to_child(
259  *child_meshes.open_boundary_mesh,
260  simplex::Simplex::vertex(*tetmesh, v))
261  .size();
262  }
263  if (process_nonmanifold_edges) {
264  on_nonmanifold_edge_cnt = tetmesh
265  ->map_to_child(
266  *child_meshes.nonmanifold_edge_mesh,
267  simplex::Simplex::vertex(*tetmesh, v))
268  .size();
269  }
270 
271  if (on_open_boundary_cnt + on_open_boundary_cnt > 1) {
272  // if on the edgemeshes and more than 1 copy
273  nonmanifold_vertex_accessor.scalar_attribute(v) = 1;
274  } else if (
275  // not on the edgemeshes and more than 1 copy on the surface mesh
276  on_open_boundary_cnt + on_nonmanifold_edge_cnt == 0 &&
277  tetmesh->map_to_child(
278  *child_meshes.surface_mesh,
279  simplex::Simplex::vertex(*tetmesh, v))
280  .size() > 1) {
281  nonmanifold_vertex_accessor.scalar_attribute(v) = 1;
282  }
283  }
284 
285  // TODO: register as child mesh
286 
287  // remove all soups
288  // NonmanifoldEdgeFromTag.remove_soup();
289  // OpenBoundaryFromTag.remove_soup();
290  // SurfaceMeshFromTag.remove_soup();
291 
292 
293  /* ------------------ post processing -------------------*/
294 
295  logger().info("Propagating position to child meshes");
296  // propagate position to all child meshes
297  auto pt_attribute =
298  tetmesh->get_attribute_handle<Rational>(in_position, PrimitiveType::Vertex);
299 
300  for (auto child : tetmesh->get_child_meshes()) {
301  auto child_position_handle = child->register_attribute<Rational>(
302  in_position,
304  tetmesh->get_attribute_dimension(pt_attribute.as<Rational>()));
305 
306  auto propagate_to_child_position =
307  [](const Eigen::MatrixX<Rational>& P) -> Eigen::VectorX<Rational> { return P; };
308  auto update_child_positon = std::make_shared<
310  child_position_handle,
311  pt_attribute,
312  propagate_to_child_position);
313  update_child_positon->run_on_all();
314  }
315 
316  // send to cache
317 
318  logger().info(
319  "TetMesh created: {} tets, {} faces, {} edges, {} vertices",
320  tetmesh->capacity(PrimitiveType::Tetrahedron),
321  tetmesh->capacity(PrimitiveType::Triangle),
322  tetmesh->capacity(PrimitiveType::Edge),
323  tetmesh->capacity(PrimitiveType::Vertex));
324 
325  logger().info("Surface child TriMesh registered");
326 
327  if (has_openboundary) {
328  logger().info("Open boundary child EdgeMesh registered");
329  }
330  if (process_nonmanifold_edges) {
331  logger().info("Nonmanifold edge child EdgeMesh registered");
332  }
333 
334  logger().info("Bbox child TriMesh registered");
335  }
336 
337  return std::make_tuple(tetmesh, child_meshes);
338 }
339 
340 } // namespace wmtk::components::triangle_insertion
void serialize(MeshWriter &writer, const Mesh *local_root=nullptr) const
Definition: Mesh.cpp:93
SchedulerStats run_operation_on_all(operations::Operation &op)
Definition: Scheduler.cpp:33
This class generates a multi-mesh from a mesh where the substructure is represented by a tag.
void remove_soup()
Remove the substructure soup from the multimesh.
void compute_substructure_mesh()
Create a manifold mesh from the substructure.
static Simplex edge(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:61
static Simplex vertex(const Mesh &m, const Tuple &t)
Definition: Simplex.hpp:56
void get_TV_matrix(MatrixX< int64_t > &matrix)
void get_FV_matrix(MatrixX< int64_t > &matrix)
void get_double_matrix(const std::string &name, const PrimitiveType type, MatrixX< double > &matrix)
constexpr wmtk::PrimitiveType PT
constexpr wmtk::PrimitiveType PF
std::tuple< std::shared_ptr< wmtk::TetMesh >, ChildMeshes > triangle_insertion(const TetMesh &bg_mesh, const std::string &bg_position, const TriMesh &mesh_in, const std::string &in_position, std::vector< attribute::MeshAttributeHandle > &pass_through, bool round, bool track_submeshes, bool make_child_free)
std::shared_ptr< Mesh > extract_and_register_child_mesh_from_tag_handle(Mesh &m, const wmtk::attribute::TypedAttributeHandle< int64_t > &tag_handle, const int64_t tag_value, bool child_is_free)
extract a child mesh based on the tag handle and the tag value, and register it to the input (parent)...
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...
constexpr PrimitiveType PV
spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:58
constexpr PrimitiveType PE