Wildmeshing Toolkit
Loading...
Searching...
No Matches
TetWildMesh.h
1#pragma once
2
3#include <wmtk/MeshData.hpp>
4
5#include <igl/Timer.h>
6#include <wmtk/SurfaceTagAttributes.h>
7#include <wmtk/TetMesh.h>
8#include <wmtk/TetOptimizerMesh.h>
9#include <wmtk/utils/PartitionMesh.h>
10#include <algorithm>
11#include <wmtk/envelope/CompositeEnvelopes.hpp>
12#include <wmtk/envelope/Envelope.hpp>
13#include <wmtk/optimization/SmoothVertex.hpp>
14#include <wmtk/threading/concurrent_map.hpp>
15#include <wmtk/threading/enumerable_thread_specific.hpp>
16#include <wmtk/threading/parallel_for.hpp>
17
18#include "Parameters.h"
19
20// clang-format off
21#include <wmtk/utils/DisableWarnings.hpp>
22#include <fastenvelope/FastEnvelope.h>
23#include <wmtk/utils/EnableWarnings.hpp>
24// clang-format on
25
26#include <igl/remove_unreferenced.h>
27#include <memory>
28#include <set>
29#include <unordered_set>
30#include <utility>
31#include <wmtk/utils/EmbedTriangles.hpp>
32#include <wmtk/utils/SurfaceTopology.hpp>
33#include <wmtk/utils/partition_utils.hpp>
34
35namespace wmtk::components::tetwild {
36
38using VertexAttributes = wmtk::TetOptimizerMesh::VertexAttributes;
39using FaceAttributes = wmtk::TetOptimizerMesh::FaceAttributes;
40
43{
44public:
45 double m_quality;
46};
47
58{
59public:
60 double m_winding_number_input = 0; // winding number w.r.t. the input
61 double m_winding_number_tracked = 0; // winding number w.r.t. the tracked surface
62 std::vector<double> m_winding_number_per_input;
63 int part_id = -1; // flood fill ID
64};
65
67{
68public:
77 {
85 };
87
88 // The 0-dimensional features -- the input feature points, and the feature-curve
89 // endpoints (junctions too, when allow_junction_cleanup is off) -- are anchored by the
90 // base (TetOptimizerMesh's feature-point anchors), turned on in the constructor. The
91 // driver sets m_feature_eps alongside m_feature_envelope; init_from_Volumeremesher fills
92 // the anchors.
93
97
101 std::shared_ptr<Envelope> m_order2_envelope;
102
111
113 std::shared_ptr<Envelope> surface_envelope_for_face(
114 const std::array<size_t, 3>& vids,
115 const FaceAttributes& attr) const override
116 {
117 if (m_input_envelopes.empty()) return m_envelope;
118 return m_input_envelopes.containment(attr.input_set());
119 }
120
123 std::vector<std::string> m_input_names;
124
126 TetAttCol m_tet_attribute;
127
138 void enable_finalize_attributes()
139 {
140 if (m_tet_finalize_enabled) return;
141 m_tet_finalize.resize(m_tet_attribute.size());
142 m_tet_attr_group.add(&m_tet_finalize);
143 m_tet_finalize_enabled = true;
144 }
145 TetFinalizeAttributes& tet_finalize(const size_t tid)
146 {
147 enable_finalize_attributes();
148 return m_tet_finalize[tid];
149 }
150 const TetFinalizeAttributes& tet_finalize(const size_t tid) const
151 {
152 static const TetFinalizeAttributes defaults;
153 return m_tet_finalize_enabled ? m_tet_finalize[tid] : defaults;
154 }
157private:
159 wmtk::AttributeContainerGroup m_tet_attr_group;
160 bool m_tet_finalize_enabled = false;
161
162public:
163 double cell_quality(const size_t tid) const override { return m_tet_attribute[tid].m_quality; }
164 void set_cell_quality(const size_t tid, const double q) override
165 {
166 m_tet_attribute[tid].m_quality = q;
167 }
168 bool allow_surface_swap() const override { return m_tet_params.allow_surface_swap; }
169 bool check_surface_topology() const override { return m_tet_params.check_surface_topology; }
170 void split_after_vertex(const size_t vid, const bool is_open_boundary) override
171 {
172 m_vertex_extra[vid].m_is_on_open_boundary = is_open_boundary;
173 }
174 bool boundary_edges_at_vertex_inside(size_t vid) const override
175 {
176 if (!m_vertex_extra[vid].m_is_on_open_boundary || !m_order2_envelope) {
177 return true;
178 }
179 for (const size_t u : get_one_ring_vids_for_vertex(vid)) {
180 if (!m_vertex_extra[u].m_is_on_open_boundary) {
181 continue;
182 }
183 // Exact membership: an open boundary edge has exactly one incident tracked
184 // face. Flags alone would also catch interior chords between two boundary
185 // vertices (e.g. across a corner), which must not be tube-tested.
186 if (get_num_surface_faces_for_edge({{vid, u}}) != 1) {
187 continue;
188 }
189 if (m_order2_envelope->is_outside(
190 std::array<Eigen::Vector3d, 2>{
191 {m_vertex_attribute[vid].m_posf, m_vertex_attribute[u].m_posf}})) {
192 return false;
193 }
194 }
195 return true;
196 }
197 bool collapse_before_vertex(size_t v1, size_t v2, double edge_length) override
198 {
199 if (edge_length <= 0 || !m_vertex_extra[v1].m_is_on_open_boundary) return true;
200 return m_vertex_extra[v2].m_is_on_open_boundary ||
201 !m_order2_envelope->is_outside(m_vertex_attribute[v2].m_posf);
202 }
203
204 bool collapse_is_order_2_edge(const std::array<size_t, 2>& e) override
205 {
206 return is_open_boundary_edge(e);
207 }
208 bool collapse_after_connectivity(
209 size_t v1,
210 size_t v2,
211 const std::vector<std::array<size_t, 2>>&) override
212 {
213 m_vertex_extra[v2].m_is_on_open_boundary =
214 m_vertex_extra[v1].m_is_on_open_boundary || m_vertex_extra[v2].m_is_on_open_boundary;
215 m_vertex_extra[v2].m_is_on_feature_curve =
216 m_vertex_extra[v1].m_is_on_feature_curve || m_vertex_extra[v2].m_is_on_feature_curve;
217 return true;
218 }
219 void collapse_after_vertex(size_t, size_t v2) override
220 {
221 if (m_vertex_extra[v2].m_is_on_open_boundary && !is_vertex_on_boundary(v2)) {
222 m_vertex_extra[v2].m_is_on_open_boundary = false;
223 }
224 }
225 void collapse_after_features(size_t, size_t v2) override
226 {
227 // Same cleanup for the feature flag: v1's flag was OR-ed in (see
228 // collapse_after_connectivity), but if the survivor has no incident tagged edge the
229 // curve rerouted around it and the flag is stale.
230 if (m_vertex_extra[v2].m_is_on_feature_curve && !vertex_has_feature_edge(v2)) {
231 m_vertex_extra[v2].m_is_on_feature_curve = false;
232 }
233 }
234
235 void split_after_vertex_feature(size_t vid, bool on_feature) override
236 {
237 m_vertex_extra[vid].m_is_on_feature_curve = on_feature;
238 }
239
240
242 std::shared_ptr<Envelope> smoothing_energy_envelope(const size_t vid) const override;
243 TetWildMesh(Parameters& _m_params, std::shared_ptr<Envelope> _m_envelope, int _num_threads = 1)
244 : wmtk::TetOptimizerMesh(_m_params, std::move(_m_envelope))
245 , m_tet_params(_m_params)
246 {
247 m_vertex_attr_group.add(&m_vertex_extra);
248 // Registered unconditionally, as the ids always were: the driver exports and audits
249 // the anchors whether or not preserve_feature_points turns the policy on.
250 enable_feature_point_tracking(m_tet_params.preserve_feature_points);
251 NUM_THREADS = _num_threads;
252 m_tet_attr_group.add(&m_tet_attribute);
253 p_tet_attrs = &m_tet_attr_group;
254 m_collapse_check_link_condition = false;
255 m_collapse_check_manifold = false;
256
257 optimization::deactivate_opt_logger();
258 m_s_envelope = 1. / (m_params.eps * m_params.eps);
259 m_params.w_envelope = 1. - m_params.w_amips;
260 }
261
262 ~TetWildMesh() {}
263
264 // only used with unit tests
265 void create_mesh_attributes(
266 const std::vector<VertexAttributes>& _vertex_attribute,
267 const std::vector<TetAttributes>& _tet_attribute)
268 {
269 const size_t n_tet = _tet_attribute.size();
270 m_vertex_attribute.resize(_vertex_attribute.size());
271 // The extras carry no data a caller supplies -- every field defaults -- so they only
272 // have to be sized alongside the shared collection.
273 m_vertex_extra.resize(_vertex_attribute.size());
274 m_feature_point_attribute.resize(_vertex_attribute.size());
275 m_face_attribute.resize(4 * n_tet);
276 m_tet_attribute.resize(n_tet);
277
278 // new for edge
279 // m_edge_attribute.resize(6 * n_tet);
280
281 for (size_t i = 0; i < _vertex_attribute.size(); i++)
282 m_vertex_attribute[i] = _vertex_attribute[i];
283
284 // Keep whatever init() reserved. AttributeCollection::resize only ever grows, so the
285 // calls above cannot shrink a collection -- but assigning m_attributes directly does,
286 // and it used to drop the tet attributes to exactly n_tet. The attributes have to stay
287 // at least as large as the connectivity: an operation that creates a new element
288 // indexes them by its id, and a 5->6 swap creates one. That left m_tet_attribute one
289 // short of the tet the swap adds, and AttributeCollection::operator[] read past the end
290 // of it -- ASan reports a heap-buffer-overflow reached from swap_edge_56_after, and
291 // libstdc++ then aborts on the corrupted heap a few allocations later, while libc++
292 // carries on and the tests pass.
293 const size_t tcap = std::max(n_tet, m_tet_attribute.size());
294 m_tet_attribute.m_attributes = std::vector<TetAttributes>(tcap);
295 for (size_t i = 0; i < n_tet; i++) m_tet_attribute[i] = _tet_attribute[i];
296 for (size_t i = 0; i < n_tet; i++)
297 m_tet_attribute[i].m_quality = get_quality(tuple_from_tet(i));
298 }
299
301
302 void output_mesh(std::string file);
307 MeshData tet_mesh_data();
308 void init_from_delaunay_box_mesh(const std::vector<Eigen::Vector3d>& vertices);
309
310public:
311 //
316 bool is_vertex_on_boundary(const size_t vid);
317 //
321 void mesh_improvement_legacy(int max_its = 80);
322
327 Eigen::MatrixXd tet_barycenters(const std::vector<Tuple>& tets) const;
328
335 void compute_winding_number(
336 const std::vector<Tuple>& tets,
337 const Eigen::MatrixXd& barycenters,
338 const std::vector<Vector3d>& vertices = {},
339 const std::vector<std::array<size_t, 3>>& faces = {});
340
356 void compute_input_winding_numbers(
357 const std::vector<Tuple>& tets,
358 const Eigen::MatrixXd& barycenters,
359 const std::vector<Vector3d>& vertices,
360 const std::vector<std::array<size_t, 3>>& faces,
361 const std::vector<int>& face_input,
362 int n_inputs);
363
366 bool m_has_input_winding_number = false;
367 bool m_has_tracked_winding_number = false;
368 bool m_has_parts = false;
369
370 void filter_with_input_surface_winding_number();
371 void filter_with_tracked_surface_winding_number();
372 void filter_with_flood_fill();
373
374
375 // debug use
376 std::atomic<int> cnt_split = 0, cnt_collapse = 0;
377
378private:
379 // tags: correspondence map from new tet-face node indices to in-triangle ids.
380 // built up while triangles are inserted.
381 wmtk::threading::concurrent_map<std::array<size_t, 3>, std::vector<int>> tet_face_tags;
382
384 {
385 // local info: for each face insertion
386 int face_id;
387 std::vector<std::array<size_t, 3>> old_face_vids;
388 };
390 triangle_insertion_local_cache;
391
392 // for incremental tetwild
393public:
413 void insertion_by_volumeremesher(
414 const std::vector<Vector3d>& vertices,
415 const std::vector<std::array<size_t, 3>>& faces,
416 std::vector<Vector3r>& v_rational,
417 std::vector<std::array<size_t, 3>>& facets_after,
418 std::vector<bool>& is_v_on_input,
419 std::vector<std::array<size_t, 4>>& tets_after,
420 std::vector<bool>& tet_face_on_input_surface,
421 std::vector<int8_t>* tet_face_orientation = nullptr,
422 const std::vector<Vector3d>& feature_edge_vertices = {},
423 const std::vector<std::array<size_t, 2>>& feature_edges = {},
424 const std::vector<Vector3d>& feature_points = {},
425 utils::EmbedFeaturesResult* features_out = nullptr,
426 const std::vector<int>* face_input = nullptr,
427 std::vector<InputSet>* facet_input_set = nullptr,
428 std::vector<std::vector<uint32_t>>* facet_sources = nullptr);
429
438 void init_from_Volumeremesher(
439 const std::vector<Vector3r>& v_rational,
440 const std::vector<std::array<size_t, 3>>& facets,
441 const std::vector<bool>& is_v_on_input,
442 const std::vector<std::array<size_t, 4>>& tets,
443 const std::vector<bool>& tet_face_on_input_surface,
444 const std::vector<int8_t>* tet_face_orientation = nullptr,
445 const utils::EmbedFeaturesResult* features = nullptr,
446 const std::vector<Vector3d>* feature_anchors = nullptr,
447 const std::vector<InputSet>* facet_input_set = nullptr);
448
449 void init_from_file(std::string input_dir);
450
451
464 size_t refine_sizing_around_worst(double max_energy) override;
465
466 // for open boundary
467 void find_open_boundary();
470 bool is_open_boundary_edge(const Tuple& e) override;
471 bool is_open_boundary_edge(const std::array<size_t, 2>& e);
472
473public:
474 // substructure functions
475
479 void init_vertex_order();
480
481public:
482 // for boolean operations
483 int flood_fill();
484
485 void save_paraview(const std::string& path, const bool use_hdf5, MeshMap* output = nullptr);
486 void write_optimization_debug_output(const std::string& path) override
487 {
488 save_paraview(path, false);
489 }
490 void optimization_sanity_checks_extra() override;
491
492public:
494 {
495 // tet mesh
496 MatrixXd V;
497 MatrixXi T;
498 // tracked surface
499 MatrixXi F;
500 // attributes; the ones the finalization did not compute (see m_has_parts and the
501 // m_has_*_winding_number flags) hold their defaults: 0, and -1 for the part
502 VectorXd t_amips;
503 VectorXd t_winding_number_input;
504 VectorXd t_winding_number_tracked;
505 MatrixXd t_winding_number_per_input;
506 VectorXi t_part;
507 };
508 // export functionality
509 ExportStruct export_mesh_data() const;
510};
511
512
513} // namespace wmtk::components::tetwild
Several attribute collections for the same simplex type, behind one container.
Definition AttributeCollection.hpp:143
One envelope per input, and the containment and the pull of an INPUT SET (bit i = input i; see Surfac...
Definition CompositeEnvelopes.hpp:152
Definition SurfaceTagAttributes.h:24
size_t get_num_surface_faces_for_edge(const std::array< size_t, 2 > &vids) const
Get the number of surface faces incident to the edge.
Definition TetMeshSubstructure.cpp:82
std::vector< size_t > get_one_ring_vids_for_vertex(size_t vid, std::vector< size_t > &cache)
Get the one ring vids for vertex.
Definition TetMesh.cpp:910
What tetwild and simwild's 3D mesh share.
Definition TetOptimizerMesh.h:51
std::shared_ptr< Envelope > m_envelope
Surface envelope: what a surface vertex is pulled toward and checked against.
Definition TetOptimizerMesh.h:428
What the optimizer keeps per tet.
Definition TetWildMesh.h:43
Per-tet data that only the finalization stage reads or writes: winding numbers, the flood-fill part,...
Definition TetWildMesh.h:58
Definition TetWildMesh.h:67
bool boundary_edges_at_vertex_inside(size_t vid) const override
Definition TetWildMesh.h:174
Parameters & m_tet_params
Definition TetWildMesh.h:96
void collapse_after_features(size_t, size_t v2) override
Definition TetWildMesh.h:225
std::shared_ptr< Envelope > m_order2_envelope
Definition TetWildMesh.h:101
void split_after_vertex(const size_t vid, const bool is_open_boundary) override
Application metadata not represented by the shared vertex attributes.
Definition TetWildMesh.h:170
std::vector< std::string > m_input_names
Definition TetWildMesh.h:123
wmtk::InputEnvelopes m_input_envelopes
One envelope per input surface, when there are several: a tracked face is held to those of its input ...
Definition TetWildMesh.h:110
std::shared_ptr< Envelope > surface_envelope_for_face(const std::array< size_t, 3 > &vids, const FaceAttributes &attr) const override
A tracked face's containment: the envelopes of its input set (see m_input_envelopes).
Definition TetWildMesh.h:113
bool collapse_before_vertex(size_t v1, size_t v2, double edge_length) override
Definition TetWildMesh.h:197
double cell_quality(const size_t tid) const override
The quality of cell tid, and how to write it.
Definition TetWildMesh.h:163
void split_after_vertex_feature(size_t vid, bool on_feature) override
Definition TetWildMesh.h:235
Definition concurrent_map.hpp:66
Definition enumerable_thread_specific.hpp:37
Definition AttributeCollection.hpp:46
Definition TetOptimizerMesh.h:54
The fields shared with triwild and simwild live in wmtk::OptimizerParameters.
Definition Parameters.h:8
tetwild's per-vertex additions to the shared VertexAttributes.
Definition TetWildMesh.h:77
bool m_is_on_open_boundary
Definition TetWildMesh.h:82
bool m_is_on_feature_curve
Whether the vertex lies on an input feature curve (see EdgeAttributes).
Definition TetWildMesh.h:84
Where each feature ended up, in the COMPACTED output numbering (the same ids tets_after uses).
Definition EmbedTriangles.hpp:87