2#include <wmtk/TriMesh.h>
3#include <wmtk/TriOptimizerMesh.h>
8#include <wmtk/threading/enumerable_thread_specific.hpp>
10#include "SimplicialComplexBVH.hpp"
12using CellTag = std::set<int64_t>;
15namespace wmtk::components::topological_offset {
18const int64_t TEMP_OFFSET_TRI_TAG = -1;
19const CellTag TEMP_OFFSET_TRI_TAG_SET{TEMP_OFFSET_TRI_TAG};
30constexpr double TOPOLOGY_BLOCK_AVG_FRAC = 0.05;
44 bool m_is_on_input =
false;
45 bool m_is_on_offset =
false;
46 bool m_is_on_region =
false;
86 enum class EdgeSplitMode {
93 int m_vtu_counter = 0;
94 std::array<size_t, 3> m_init_counts = {{0, 0, 0}};
97 EdgeSplitMode m_edge_split_mode = EdgeSplitMode::Midpoint;
100 std::map<std::string, int64_t> m_tag_name_to_id;
101 std::map<int64_t, std::string> m_tag_id_to_name;
102 CellTag m_offset_output_tag_ids;
105 bool m_singlebody =
false;
106 int64_t m_single_tag;
109 bool m_has_envelope =
false;
110 MatrixXd m_V_envelope;
111 MatrixXi m_F_envelope;
127 static constexpr int OFFSET_SURFACE_CLASS = 1;
128 static constexpr int REGION_SURFACE_CLASS = 2;
146 NUM_THREADS = _num_threads;
163 m_vertex_attribute[vid].m_posf = p;
164 m_vertex_attribute[vid].m_pos = to_rational(p);
165 m_vertex_attribute[vid].m_is_rounded =
true;
172 return m_edge_attribute[eid].m_is_surface_fs &&
173 m_edge_attribute[eid].m_surface_class == OFFSET_SURFACE_CLASS;
175 bool edge_is_region_boundary(
const size_t eid)
const
177 return m_edge_attribute[eid].m_is_surface_fs &&
178 m_edge_attribute[eid].m_surface_class == REGION_SURFACE_CLASS;
200 void restore_edge(
const size_t eid,
const EdgeSnapshot2d& s)
202 m_edge_attribute[eid] = s.tags;
203 m_edge_extra[eid] = s.extra;
205 FaceSnapshot2d face_snapshot(
const size_t fid)
const
207 return FaceSnapshot2d{m_face_attribute[fid], m_face_extra[fid]};
209 void restore_face(
const size_t fid,
const FaceSnapshot2d& s)
211 m_face_attribute[fid] = s.attrs;
212 m_face_extra[fid] = s.extra;
310 const Vector2d& tang,
312 const std::function<
bool()>& rejected);
341 const std::optional<Tuple> opp = t.switch_face(*
this);
342 if (!opp)
return false;
343 const size_t fa = t.fid(*
this), fb = opp->fid(*
this);
350 return m_face_attribute[fa].tags != m_face_attribute[fb].tags;
367 void log_worst_dist_vertex()
const;
422 std::atomic<int> iter_cnt_split = 0, iter_cnt_collapse = 0, iter_cnt_swap = 0;
427 std::atomic<int> iter_cnt_swap_nd_reject = 0;
449 std::map<size_t, int> face_label;
455 bool marching_split_edge_before(
const Tuple& t);
456 bool marching_split_edge_after(
const Tuple& t);
482 bool collapse_before_vertex(
size_t v1,
size_t v2)
override;
483 void collapse_after_vertex(
size_t v1,
size_t v2)
override;
487 void split_after_vertex(
size_t v_new)
override;
517 return m_edge_attribute[eid].m_is_surface_fs &&
532 return m_vertex_extra[vid].m_is_on_input || !m_vertex_attribute[vid].on_bbox_faces.empty();
534 bool edge_is_frozen(
const size_t eid)
const
536 return edge_is_input(eid) || m_edge_attribute[eid].m_is_bbox_fs >= 0;
622 std::atomic<int> offset_accepted{0};
637 std::atomic<long long> offset_err_after_nano{0};
638 std::atomic<int> offset_err_max_before_nano{0};
639 std::atomic<int> offset_err_max_after_nano{0};
646 offset_err_after_nano.store(0);
647 for (std::atomic<int>* c :
662 &offset_err_max_before_nano,
663 &offset_err_max_after_nano,
670 SmoothTrace m_smooth_trace;
671 void log_smooth_trace()
const;
687 const std::array<size_t, 2>& vids)
const override
690 if (eid ==
static_cast<size_t>(-1) || !t.is_valid(*
this)) {
708 return !m_vertex_extra[vid].m_is_on_input;
721 size_t update_sizing_field();
722 void write_smoothing_debug_output(
const std::string& path)
const override
739 const MatrixSi& F_tags,
740 const MatrixXd& V_env,
741 const MatrixXi& F_env,
742 const std::vector<std::string>& tag_names);
770 bool invariants(
const std::vector<Tuple>& tris)
override;
849 void write_input_complex(
const std::string& path);
850 void write_vtu(
const std::string& path);
852 void write_msh_groups(
const std::string& file);
870 std::map<simplex::Edge, EdgeSnapshot2d> existing_eattr;
873 std::map<size_t, FaceSnapshot2d> opp_v_fattr;
885 std::map<simplex::Edge, EdgeSnapshot2d> existing_eattr;
896 for (
const int64_t& i : tag1) {
897 if (tag2.find(i) != tag2.end()) {
927 double len1 = (m_vertex_attribute[e1.vertices()[0]].m_posf -
928 m_vertex_attribute[e1.vertices()[1]].m_posf)
930 double len2 = (m_vertex_attribute[e2.vertices()[0]].m_posf -
931 m_vertex_attribute[e2.vertices()[1]].m_posf)
943 const auto& verts = e.vertices();
944 const auto incident = simplex_incident_triangles(e);
945 const auto& faces = incident.faces();
947 assert(!faces.empty());
949 const size_t f_id = tuple_from_simplex(faces.front()).
fid(*
this);
951 return t_edge.eid(*
this);
959 const auto& v = e.vertices();
960 const auto faces = simplex_incident_triangles(e).faces();
961 assert(!faces.empty());
962 const size_t fid = tuple_from_simplex(faces.front()).
fid(*
this);
971 std::vector<Tuple> adj_tris;
974 adj_tris.push_back(tri_1.value());
978 adj_tris.push_back(tri_2.value());
982 adj_tris.push_back(tri_3.value());
Whether a codimension-1 simplex is tracked surface, and which bbox side it lies on.
Definition SurfaceTagAttributes.h:15
size_t fid(const TriMesh &) const
Definition TriMesh.h:79
Tuple switch_vertex(const TriMesh &m) const
Definition TriMesh.cpp:158
Tuple switch_edge(const TriMesh &m) const
Definition TriMesh.cpp:187
std::optional< Tuple > switch_face(const TriMesh &m) const
Definition TriMesh.cpp:214
Tuple tuple_from_edge(size_t vid1, size_t vid2, size_t fid) const
Definition TriMesh.cpp:2204
What triwild and simwild's 2D mesh share.
Definition TriOptimizerMesh.h:38
AttributeContainerGroup m_edge_attr_group
What p_edge_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:110
AttributeContainerGroup m_vertex_attr_group
What p_vertex_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:95
AttributeContainerGroup m_face_attr_group
What p_face_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:121
Definition SimplicialComplexBVH.hpp:12
The offset's 2D mesh, on the shared 2D optimizer.
Definition TopoOffsetTriMesh.h:84
std::pair< double, double > compute_distance_deviation() const
How far the offset boundary is from where it should be: {max, avg} over vertices.
Definition Optimize2d.cpp:1024
void label_input_complex()
label input complex simplices as per boolean expression (or single body mode)
Definition TopoOffsetTriMesh.cpp:117
void set_vertex_position(const size_t vid, const Vector2d &p)
Place a vertex, keeping its exact and rounded coordinates in step.
Definition TopoOffsetTriMesh.h:161
Parameters & m_offset_params
The base holds only wmtk::OptimizerParameters; this is the same object, typed.
Definition TopoOffsetTriMesh.h:131
void init_from_image(const MatrixXd &V, const MatrixXi &F, const MatrixSi &F_tags, const MatrixXd &V_env, const MatrixXi &F_env, const std::vector< std::string > &tag_names)
initialize TriMesh from vertex, face, tag data
Definition TopoOffsetTriMesh.cpp:13
void init_region_boundary_envelope_from_input()
Build the same envelope from the INPUT mesh, before the offset exists.
Definition Optimize2d.cpp:255
bool split_face_before(const Tuple &t) override
User specified preparations and desideratas for a face split.
Definition EdgeSplittingTri.cpp:194
void set_offset_tri_tags()
update 'tags' data for triangles in the offset region (tris labelled 2) based on the given offset tag...
Definition TopoOffsetTriMesh.cpp:685
bool vertex_is_on_surface(const size_t vid) const override
The substructure the link condition is evaluated against, DERIVED not cached.
Definition Optimize2d.cpp:46
bool offset_is_manifold()
verify that the closed offset region (simplices labelled 1 or 2) form a manifold region....
Definition TopoOffsetTriMesh.cpp:720
void optimize_offset(const std::filesystem::path &output_file)
The 2D optimization phase: split / collapse / swap / smooth on the shared driver.
Definition Optimize2d.cpp:1298
double max_offset_normal_deviation_at_vertex(const size_t vid) const
Definition Optimize2d.cpp:1268
size_t m_worst_dist_vid
Definition TopoOffsetTriMesh.h:366
double minimize_distance_along_tangent(const size_t vid, const Vector2d &p0, const Vector2d &tang, const double cap, const std::function< bool()> &rejected)
Put a vertex at the distance-error minimum along its region tangent.
Definition Optimize2d.cpp:818
bool tag_tri_consistent_topology(size_t f_id, int64_t tag) const
check if removing the given face from the given tag set would retain its topology
Definition Spatial.cpp:335
bool edge_is_region_boundary_live(const Tuple &t) const
Live region-boundary test for an edge that currently exists in the mesh.
Definition TopoOffsetTriMesh.h:339
void grow_offset_conservative()
grow offset region conservatively using conservative checks while ensuring consistent topology
Definition TopoOffsetTriMesh.cpp:627
bool empty_input_complex()
check if the input complex is empty. Only valid after calling init_from_image(...)....
Definition TopoOffsetTriMesh.cpp:273
void init_input_complex_bvh()
initialize BVH for input complex. Must be called after init_from_image(...)
Definition TopoOffsetTriMesh.cpp:286
size_t edge_id_from_simplex(const simplex::Edge &e) const
get global id of edge from simplex::Edge object
Definition TopoOffsetTriMesh.h:941
bool face_is_offset_band(const size_t fid) const
Definition Optimize2d.cpp:1018
Tuple get_tuple_from_edge(const simplex::Edge &e) const
get Tuple simplex::Edge object
Definition TopoOffsetTriMesh.h:957
void marching_tris()
execute simplistic marching tris. All edges with one vertex labelled 0 and the other 1/2 are split,...
Definition TopoOffsetTriMesh.cpp:562
bool offset_field_normal(const Vector2d &p, Vector2d &n) const
Definition Optimize2d.cpp:1201
bool face_in_region(const size_t fid) const
Whether face fid belongs to the closed offset region, read from its LABEL.
Definition Optimize2d.cpp:56
void sort_edges_by_length(std::vector< simplex::Edge > &edges)
sort vector of edge simplices in place by decreasing length
Definition TopoOffsetTriMesh.h:921
bool swap_edge_after(const Tuple &t) override
Definition Optimize2d.cpp:350
double edge_normal_deviation(const Tuple &e) const
Paper Definition 5 for a 1-simplex: max angle between the offset normal at the edge's center and the ...
Definition Optimize2d.cpp:1215
void init_offset_sizing_field()
Definition Optimize2d.cpp:895
void warn_if_offset_reaches_domain_boundary() const
Warn if the offset band has grown into the domain boundary.
Definition Optimize2d.cpp:222
bool edge_is_offset_surface_live(const Tuple &e) const
Definition Optimize2d.cpp:1254
bool split_edge_after(const Tuple &t) override
User specified modifications and desideratas after an edge split.
Definition EdgeSplittingTri.cpp:123
bool invariants(const std::vector< Tuple > &tris) override
User specified invariants that can't be violated.
Definition TopoOffsetTriMesh.cpp:770
wmtk::threading::enumerable_thread_specific< double > m_collapse_nd_before
Definition TopoOffsetTriMesh.h:432
void execute_offset(const std::filesystem::path &output_file)
entry point for offset procedure
Definition TopoOffsetTriMesh.cpp:394
bool edge_is_input(const size_t eid) const
Definition TopoOffsetTriMesh.h:515
bool project_offset_vertex(const Tuple &t)
Definition Optimize2d.cpp:605
static constexpr int INPUT_SURFACE_CLASS
SurfaceTagAttributes::m_surface_class: which of the three tracked surfaces an edge belongs to.
Definition TopoOffsetTriMesh.h:126
bool smooth_before(const Tuple &t) override
User specified preparations and desideratas for an edge smooth.
Definition Optimize2d.cpp:524
std::shared_ptr< SampleEnvelope > surface_envelope_for_edge(const std::array< size_t, 2 > &vids) const override
Only REGION_SURFACE_CLASS segments carry a containment requirement.
Definition TopoOffsetTriMesh.h:686
wmtk::threading::enumerable_thread_specific< double > m_swap_nd_before
Definition TopoOffsetTriMesh.h:436
bool split_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge split.
Definition EdgeSplittingTri.cpp:9
bool split_face_after(const Tuple &t) override
User specified modifications and desideratas after a face split.
Definition EdgeSplittingTri.cpp:226
std::pair< double, double > compute_normal_deviation() const
How far the offset boundary faces from where it should be: {max, avg} in DEGREES.
Definition Optimize2d.cpp:1279
bool smoothing_position_is_allowed(size_t vid, const Vector2d &) const override
Definition TopoOffsetTriMesh.h:706
bool edge_is_on_surface(const std::array< size_t, 2 > &vids) const override
Is an edge part of the substructure.
Definition Optimize2d.cpp:28
bool any_tag_present(const CellTag &tag1, const CellTag &tag2) const
determine if any tag from tag1 is also present in tag2.
Definition TopoOffsetTriMesh.h:894
std::atomic< int > iter_cnt_collapse_nd_reject
Definition TopoOffsetTriMesh.h:426
bool offset_tri_consistent_topology(const size_t f_id) const
check if adding a triangle to the offset region does not change the topology of the offset....
Definition Spatial.cpp:283
bool tri_is_in_offset_conservative(const size_t f_id, const double threshold_r) const
check if a triangle is inside the offset (implicitly defined via BVH distance field to input complex)...
Definition Spatial.cpp:242
void label_offset_boundary()
Tag the two tracked surfaces for the optimization phase.
Definition Optimize2d.cpp:66
void simplicial_embedding()
make mesh a simplicial embedding of the input complex (simplices labelled 1)
Definition TopoOffsetTriMesh.cpp:499
bool edge_is_offset(const size_t eid) const
Definition TopoOffsetTriMesh.h:170
bool swap_edge_before(const Tuple &t) override
Reject a flip whose new edge already exists.
Definition Optimize2d.cpp:178
bool face_is_input_complex(const size_t fid) const
Definition Optimize2d.cpp:61
void init_region_boundary_envelope()
Build the containment envelope over every tag-region boundary, once, before the optimization starts.
Definition Optimize2d.cpp:285
bool smooth_after(const Tuple &t) override
User specified modifications and desideras after an edge smooth.
Definition Optimize2d.cpp:548
bool collapse_edge_after(const Tuple &t) override
Definition Optimize2d.cpp:400
bool split_adjust_position(size_t v_new, const std::vector< Tuple > &children) override
Carry each parent's region label onto the two children it became.
Definition Optimize2d.cpp:486
std::vector< Tuple > get_edge_adjacent_faces(const Tuple &f) const
get faces (as Tuples) that are edge-adjacent to the given face (as Tuple)
Definition TopoOffsetTriMesh.h:969
std::vector< std::array< int, 3 > > op_counts
Definition TopoOffsetTriMesh.h:421
bool ambient_assert()
ensure ambient tag does not overlap any other tags in mesh.
Definition TopoOffsetTriMesh.cpp:103
bool vertex_is_frozen(const size_t vid) const
The two simplex sets the optimization may not touch at all.
Definition TopoOffsetTriMesh.h:530
bool is_simplicially_embedded() const
check if the input complex (simplices labelled 1) are simplicially embedded w.r.t....
Definition TopoOffsetTriMesh.cpp:454
bool collapse_edge_before(const Tuple &t) override
Reject any collapse that violates the substructure link condition.
Definition Optimize2d.cpp:373
bool region_boundary_tangent(const Tuple &t, Vector2d &tang) const
The direction the REGION curve runs through this vertex, if it has one.
Definition Optimize2d.cpp:784
bool tri_is_simp_emb(const Tuple &t) const
check if a triangle satisfies simpicial embedding criteria w.r.t. input complex (simplices labelled 1...
Definition TopoOffsetTriMesh.cpp:473
bool region_boundary_is_outside_envelope(const size_t vid) const
Definition Optimize2d.cpp:328
std::vector< std::array< double, 4 > > optimization_metrics
Definition TopoOffsetTriMesh.h:415
size_t refine_sizing_around_worst(double) override
Sizing refinement over the offset polyline.
Definition TopoOffsetTriMesh.h:720
Definition Simplex.hpp:46
Definition enumerable_thread_specific.hpp:26
Definition TriOptimizerMesh.h:73
What the offset needs on top of the parameters every wmtk optimizer shares.
Definition Parameters.h:25
An edge's / face's shared attributes together with the offset's own label.
Definition TopoOffsetTriMesh.h:187
Definition TopoOffsetTriMesh.h:862
Definition TopoOffsetTriMesh.h:192
Definition TopoOffsetTriMesh.h:878
Definition TopoOffsetTriMesh.h:448
Why smoothing refused a vertex, one counter per site where it can say no.
Definition TopoOffsetTriMesh.h:612
std::atomic< long long > offset_err_before_nano
Definition TopoOffsetTriMesh.h:636
std::atomic< int > offset_no_neighbours
no offset-boundary neighbour to average
Definition TopoOffsetTriMesh.h:618
std::atomic< int > offset_clamp_env
... and the envelope is what stopped it
Definition TopoOffsetTriMesh.h:627
std::atomic< int > offset_attempted
dispatched to project_offset_vertex()
Definition TopoOffsetTriMesh.h:617
std::atomic< int > interior_attempted
dispatched to the shared AMIPS smoother
Definition TopoOffsetTriMesh.h:640
std::atomic< int > offset_envelope
search exhausted, still outside the envelope
Definition TopoOffsetTriMesh.h:621
std::atomic< int > offset_clamped
accepted with the search fraction < 0.99
Definition TopoOffsetTriMesh.h:626
std::atomic< int > attempted
smooth_before() entered
Definition TopoOffsetTriMesh.h:613
std::atomic< int > region_attempted
... of which sat on another region's boundary
Definition TopoOffsetTriMesh.h:641
std::atomic< int > offset_clamp_inv
Definition TopoOffsetTriMesh.h:628
std::atomic< int > offset_on_complex
sits on the complex, no offset direction
Definition TopoOffsetTriMesh.h:619
std::atomic< int > before_on_input
input complex, frozen
Definition TopoOffsetTriMesh.h:616
std::atomic< int > offset_slid
Definition TopoOffsetTriMesh.h:633
std::atomic< int > before_unrounded
base smooth_before said no: could not round
Definition TopoOffsetTriMesh.h:615
std::atomic< int > before_bbox
base smooth_before said no: on the bounding box
Definition TopoOffsetTriMesh.h:614
std::atomic< int > offset_inverted
search exhausted, a face still inverts
Definition TopoOffsetTriMesh.h:620