Wildmeshing Toolkit
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | Private Attributes | List of all members
wmtk::components::topological_offset::TopoOffsetTetMesh Class Reference

The offset's tet mesh, on the shared 3D optimizer. More...

#include <TopoOffsetTetMesh.h>

Inheritance diagram for wmtk::components::topological_offset::TopoOffsetTetMesh:
wmtk::TetOptimizerMesh wmtk::TetMesh wmtk::RationalPositions wmtk::components::manifold_extraction::ManExtractTetMesh

Classes

struct  EdgeSplitCache
 
struct  FaceSnapshot
 A face's shared surface tags together with the offset's own label. More...
 
struct  FaceSplitCache
 
struct  OptSplitCache
 
struct  TetSplitCache
 

Public Types

enum class  EdgeSplitMode {
  Midpoint = 0 , Initial = 1 , BinarySearch = 2 , LogRootFind = 3 ,
  SphereTracing = 4 , Optimization = 5
}
 
using VertexExtraCol = wmtk::AttributeCollection< VertexExtra >
 
using EdgeAttCol = wmtk::AttributeCollection< EdgeAttributes >
 
using FaceExtraCol = wmtk::AttributeCollection< FaceExtra >
 
using TetAttCol = wmtk::AttributeCollection< TetAttributes >
 
- Public Types inherited from wmtk::TetOptimizerMesh
using FaceAttributes = wmtk::SurfaceTagAttributes
 
using VertAttCol = AttributeCollection< VertexAttributes >
 
using FaceAttCol = AttributeCollection< FaceAttributes >
 
using SurfaceTopoSignature = wmtk::utils::SurfaceTopoSignature
 
- Public Types inherited from wmtk::TetMesh
template<typename T >
using vector = std::vector< T >
 
using VertexMutex = wmtk::threading::VertexMutex
 

Public Member Functions

FaceSnapshot face_snapshot (const size_t fid) const
 
void restore_face (const size_t fid, const FaceSnapshot &s)
 
void set_vertex_position (const size_t vid, const Vector3d &p)
 Place a vertex, keeping its exact and rounded coordinates in step.
 
bool cell_in_region (const size_t tid) const
 Whether tet tid belongs to the closed offset region, read from its TAGS.
 
bool face_is_offset (const size_t fid) const
 Whether face fid is on the offset boundary (as opposed to the input complex).
 
bool face_is_input (const size_t fid) const
 Whether face fid carries input-complex geometry.
 
 TopoOffsetTetMesh (Parameters &_m_offset_params, int _num_threads=0)
 
double cell_quality (const size_t tid) const override
 The quality of cell tid, and how to write it.
 
void set_cell_quality (const size_t tid, const double q) override
 
std::shared_ptr< SampleEnvelopesurface_envelope_for_face (const std::array< size_t, 3 > &vids) const override
 Only the input complex is envelope-constrained.
 
bool allow_surface_swap () const override
 
bool check_surface_topology () const override
 
std::shared_ptr< SampleEnvelopesmoothing_energy_envelope (const size_t) const override
 
void write_optimization_debug_output (const std::string &path) override
 
size_t refine_sizing_around_worst (double) override
 The offset's sizing refinement, as the base's stall escape hatch.
 
bool swap_before_interior (const std::vector< size_t > &tids) override
 Which tag the tets a swap creates should carry.
 
bool swap_before_surface (const std::vector< size_t > &tids, size_t a, size_t b, size_t c, size_t d) override
 
bool swap_after_cells (const std::vector< size_t > &tids, bool is_surface_flip) override
 Propagate application data to the cells made by a successful topological swap.
 
bool collapse_edge_before (const Tuple &t) override
 Collapse policy that is the offset's own.
 
bool collapse_before_vertex (size_t v1, size_t v2, double edge_length) override
 
bool collapse_after_connectivity (size_t v1, size_t v2, const std::vector< std::array< size_t, 2 > > &boundary_edges) override
 
bool collapse_is_order_2_edge (const std::array< size_t, 2 > &e) override
 
void collapse_after_vertex (size_t v1, size_t v2) override
 
bool split_before_cells (const Tuple &edge, const std::vector< Tuple > &parents) override
 Split policy that is the offset's own.
 
bool split_after_cells (size_t v1, size_t v2, size_t v_new, const std::vector< Tuple > &children) override
 Restore application cell data on the children made by a split.
 
void split_after_vertex (size_t v_new, bool is_edge_open_boundary) override
 Application metadata not represented by the shared vertex attributes.
 
bool is_open_boundary_edge (const Tuple &e) override
 
void init_from_image (const MatrixXd &V, const MatrixXi &T, const MatrixSi &T_tags, const MatrixXd &V_env, const MatrixXi F_env, const std::vector< std::string > &tag_names)
 initialize TetMesh from vertex, tet, and tag data
 
void init_surfaces_and_boundaries ()
 
bool is_edge_on_input (const Tuple &loc)
 
bool is_edge_on_offset (const Tuple &loc)
 
bool ambient_assert ()
 check that the ambient tag does not overlap with any other tags
 
void label_input_complex ()
 label input simplicial complex simplices, as defined in m_offset_params.offset_selection
 
bool empty_input_complex ()
 check if the input complex is empty. Only valid after calling init_from_image(...). Checks if any vertices (therefore any simplices) are labelled 1, if not returns true
 
void init_input_complex_bvh ()
 initialize BVH for input complex. Must be called after init_from_image(...)
 
void edge_split_binary_search (const size_t v1, const size_t v2, Vector3d &p_new) const
 split edge at point by minimizing m_offset_params.target_distance - d() (where d() is distance to input complex via BVH) along the edge. Uses binary search, so implicitly assumes distance field is monotonic along edge. May give weird results if not monotonic
 
void edge_split_binary_search (const Vector3d &v1_pos, const Vector3d &v2_pos, Vector3d &p_new) const
 
void edge_split_log_root_find (const size_t v1, const size_t v2, Vector3d &p_new) const
 uses custom root finding routine, attempting to find first root (nearest to v1) to split edge at
 
void edge_split_sphere_tracing (const size_t v1, const size_t v2, Vector3d &p_new) const
 split edge at first root of d(l) - d*, where d(l) is distance to input complex, using sphere tracing method. This is the best method and should be used instead of binary or log root finding methods
 
size_t flood_fill ()
 label connected simplicial complex components (simplices labelled 1 or 2)
 
std::vector< std::array< size_t, 3 > > get_faces_by_condition (std::function< bool(const FaceAttributes &)> cond) const
 
bool split_edge_before (const Tuple &t) override
 
bool split_edge_after (const Tuple &t) override
 This function computes the attributes for the added simplices. User specified modifications and desideratas for after an edge split.
 
bool marching_split_edge_before (const Tuple &t)
 
bool marching_split_edge_after (const Tuple &t)
 
bool split_face_before (const Tuple &t) override
 User specified preparations and desideratas for a face split before changing the connectivity.
 
bool split_face_after (const Tuple &t) override
 Compute the attributes for the added simplices.
 
bool split_tet_before (const Tuple &t) override
 User specified preparations and desideratas for a tet split before changing the connectivity.
 
bool split_tet_after (const Tuple &t) override
 Compute the attributes for the added simplices.
 
bool invariants (const std::vector< Tuple > &tets) override
 
bool smooth_before (const Tuple &t) override
 
bool smooth_after (const Tuple &t) override
 User specified modifications and desideratas for after smoothing a vertex.
 
void execute_offset (const std::filesystem::path &output_file)
 main function from which all others are called
 
void optimize_offset (const std::filesystem::path &output_file)
 optimize the offset
 
bool is_offset_face (const Tuple &f) const
 true if face f has exactly one incident tet labelled 2 (offset), i.e. it lies on the boundary between the offset region and the rest of the mesh
 
bool is_offset_face (const size_t fid) const
 
std::vector< Tupleget_offset_surface_faces_for_vertex (const Tuple &t) const
 offset-surface faces (see is_offset_face()) incident to vertex t
 
std::array< OffsetSurfaceSample, 4 > offset_surface_samples (const Tuple &f) const
 the 4 offset-field samples for face f (centroid + one near each corner), following Quadrics.cpp's get_triangle_samples_and_area(). Shared by the Quadrics construction below and by the feature-preserving checks in Collapse.cpp – a single centroid sample cannot tell a locally-flat patch from one straddling a sharp feature of the input complex, since a single BVH nearest-point query just picks whichever side of the feature is closer.
 
bool smooth_after_offset_surface (const Tuple &t)
 quadrics-based smoothing step for offset surface vertices: blends a Laplacian step with a projection onto quadrics built from target_distance-offset samples of the input complex, following https://github.com/wildmeshing/topological-offsets/blob/main/components/topological_offsets/wmtk/components/topological_offsets/internal/OffsetOptimization.cpp#L2226
 
double face_normal_deviation (const Tuple &f) const
 max angle (degrees, 0-90, orientation independent) between offset-surface face f's own normal and any of its offset_surface_samples() normals. Taking the max over all 4 samples (rather than a single centroid sample) is what makes this sensitive to features: a face straddling a sharp fold of the input complex will have samples on either side of the fold, so at least one of them disagrees strongly with the face's own (necessarily flat) normal, even though the face may look locally fine from any single sample alone.
 
double max_offset_surface_normal_deviation_at_vertex (size_t vid) const
 max face_normal_deviation() over the offset-surface faces incident to vertex vid
 
double collapse_normal_deviation (size_t v_from, size_t v_to, size_t remove_vid) const
 OffsetCollapseBeforeInvariant analogue: pools offset_surface_samples() normals from every offset-surface face incident to remove_vid and returns the spread (max - min, degrees, orientation dependent via normal_angle_180-style acos) of their angles to the collapsing edge's direction. A small spread means the samples around the survivor agree with each other relative to the edge, i.e. the edge runs along a locally flat/consistent part of the offset surface; a large spread means the true target-normal field disagrees with itself nearby – a sign of a feature edge – and collapsing there should be rejected. See https://github.com/wildmeshing/topological-offsets/blob/main/components/topological_offsets/wmtk/components/topological_offsets/internal/invariants/OffsetCollapseBeforeInvariant.cpp.
 
size_t update_sizing_field ()
 refine or coarsen the sizing field (VertexAttributes::m_sizing_scalar) based on the mean ratio metric of the offset triangulation (offset-class surface faces), following the reference's compute_target_edge_length(): for every vertex incident to at least one offset-surface face, take the worst (minimum) mean_ratio_metric() among those faces, and halve the sizing scalar if it is below m_offset_params.sizing_mrm_threshold, or multiply it by 1.5 (coarsen) if above – clamped to [m_offset_params.min_sizing_scalar, m_offset_params.max_sizing_scalar]. Vertices not incident to any offset-surface face are left untouched. The vertices actually refined this pass then seed wmtk::utils::gradation_smooth_sizing() (m_offset_params.sizing_gradation), matching SimWildMesh::gradation_smooth_sizing(), so a newly refined patch doesn't sit right next to an unrelated coarse one. Called once per optimize_offset() iteration, after smoothing.
 
bool offset_swap_normal_deviation_ok (const Tuple &face_abc, const Tuple &face_abd, size_t a, size_t b, size_t c, size_t d) const
 OffsetSwapInvariant analogue: for the offset-surface diagonal flip (a,b) -> (c,d) across the two current offset faces (a,b,c)/(a,b,d), reject only a regression – if the old diagonal (a,b) was already poorly aligned (spread >= m_offset_params.max_normal_deviation_deg) with the offset target-normal field sampled on both faces, the flip is not blocked on these grounds; if it was well aligned and the new diagonal (c,d) would not be, it is rejected. See https://github.com/wildmeshing/topological-offsets/blob/main/components/topological_offsets/wmtk/components/topological_offsets/internal/invariants/OffsetSwapInvariant.cpp.
 
void marching_tets ()
 execute simplistic marching tets. All edges with one vertex labelled 0 and the other 1/2 are split. If m_edge_split_mode=BinarySearch, edges are split according to BVH distance field and the offset target distance (m_offset_params.target_distance). If m_edge_split_mode=Midpoint, edges are split at the midpoint
 
bool is_simplicially_embedded () const
 check if the input complex (simplices labelled 1) are simplicially embedded w.r.t. the entire mesh
 
bool tet_is_simp_emb (const Tuple &t) const
 check if a tet satisfies simpicial embedding criteria w.r.t. input complex (simplices labelled 1)
 
void simplicial_embedding ()
 make mesh a simplicial embedding of the input complex (simplices labelled 1)
 
bool tag_tet_consistent_topology (size_t t_id, int64_t tag) const
 check if removing the tet would change the topology of any label
 
bool offset_tet_consistent_topology (const size_t t_id) const
 check if adding a tet to the offset region does not change the topology of the offset. Returns true if topology would not be changed
 
bool tet_is_in_offset_conservative (const size_t t_id, const double threshold_r) const
 check if a tet is inside the offset (implicitly defined via BVH distance field to input complex) via conservative sphere subdivision estimation
 
bool tet_is_in_offset_aggressive (const size_t t_id) const
 check if a tet is inside the offset (implicitly defined via BVH distance field to input complex) by check if all its vertices are inside the offset region.
 
void grow_offset_conservative ()
 grow offset region conservatively using conservative checks while ensuring consistent topology
 
void grow_offset_aggressive ()
 Grow offset region aggressively. A tet is considered in the offset if all its vertices are in the offset.
 
void set_offset_tet_tags ()
 update 'tags' data for tets in the offset region (tets labelled 2) based on the given offset tag values in m_offset_params.offset_tag_value
 
bool offset_is_manifold ()
 verify that the closed offset region (simplices labelled 1 or 2) form a manifold region. This should be true for any offset. This function is for verification.
 
void write_input_complex (const std::string &path)
 
void write_vtu (const std::string &path)
 
void write_msh_groups (const std::string &file)
 
bool is_order_2_edge (const Tuple &e) const
 
bool is_order_2_edge (const std::array< size_t, 2 > &e) const
 
bool vertex_is_on_surface (const size_t vid) const override
 Is a vertex part of the substructure.
 
bool face_is_on_surface (const size_t fid) const override
 Is a face part of the substructure.
 
size_t get_order_of_vertex (const size_t vid) const override
 Get the order of a vertex.
 
void init_vertex_order ()
 Compute the vertex order for every vertex.
 
void compute_vertex_partition ()
 assign each vertex a partition id (by spatial Morton order) for the parallel ExecutePass policies (kPartition/kColor) used by smooth_all_vertices()/ collapse_all_edges(). A no-op if NUM_THREADS == 0.
 
size_t get_partition_id (const Tuple &loc) const
 
std::vector< Tupleget_face_adjacent_tets (const Tuple &t) const
 get tets (as Tuples) that are face-adjacent to the given tet (as Tuple)
 
std::vector< size_t > connected_components_helper (const size_t &v_id)
 get all one-ring vertices through input simplices (labelled 1)
 
void reset_connected_components ()
 reset connected component assignments.
 
- Public Member Functions inherited from wmtk::TetOptimizerMesh
bool is_force_split_edge (const size_t v1, const size_t v2) const
 
 TetOptimizerMesh (OptimizerParameters &params, std::shared_ptr< SampleEnvelope > env)
 
virtual double quality_rel (const size_t tid) const
 A cell's quality relative to the quality it is required to reach; <= 1 means it meets it.
 
void compute_vertex_partition ()
 
void compute_vertex_partition_morton ()
 
size_t get_partition_id (const Tuple &loc) const
 
double get_length2 (const Tuple &l) const
 
bool is_inverted (const std::array< size_t, 4 > &vs) const
 
bool is_inverted (const Tuple &loc) const
 
bool is_inverted_f (const Tuple &loc) const
 Inversion check using only the double positions.
 
double get_quality (const std::array< size_t, 4 > &vs) const
 
double get_quality (const Tuple &loc) const
 
std::tuple< double, double > get_max_avg_energy ()
 
void mesh_improvement (int max_its=80)
 
std::tuple< double, double > local_operations (const std::array< int, 4 > &ops, bool collapse_limit_length=true)
 
bool round (const Tuple &v)
 Round a vertex position to floating point, if that inverts no incident tet.
 
bool is_edge_on_surface (const Tuple &loc)
 
bool is_edge_on_bbox (const Tuple &loc)
 
int edge_incident_surface_face_count (const Tuple &e)
 How many of the faces incident to edge e are on the tracked surface.
 
bool surface_triangle_is_outside (const size_t a, const size_t b, const size_t c) const
 
std::vector< std::array< size_t, 3 > > get_faces_by_condition (std::function< bool(const FaceAttributes &)> cond) const
 
void output_faces (std::string file, std::function< bool(const FaceAttributes &)> cond)
 
void gradation_smooth_sizing (double grade, const std::vector< size_t > &seeds)
 Grade the refined sizing region into its surroundings (monotone, only lowers).
 
double active_quality_threshold () const
 Cell-quality threshold above which a tet is "active" (worth operating on) for the skip-good-regions filter.
 
virtual std::vector< size_t > active_vertices () const
 
void split_all_edges ()
 
void collapse_all_edges (bool is_limit_length=true)
 
bool collapse_edge_after (const Tuple &t) override
 User specified modifications and desideratas for after an edge collapse.
 
size_t coarsen_mesh ()
 Coarsen the mesh without letting the max energy rise.
 
bool coarsen_collapse_edge (const Tuple &e, std::vector< Tuple > &new_tets)
 One collapse under the coarsening rules, outside a coarsening pass.
 
size_t swap_all_edges_32 ()
 
bool swap_edge_before (const Tuple &t) override
 User specified preparations and desideratas for an 3-2 edge swap before changing the conenctivity.
 
bool swap_edge_after (const Tuple &t) override
 User specified modifications and desideratas for after a 3-2 edge swap.
 
size_t swap_all_edges_44 ()
 
bool swap_edge_44_before (const Tuple &t) override
 User specified preparations and desideratas for an 4-4 edge swap before changing the connectivity.
 
bool swap_edge_44_accept_case (const std::array< size_t, 2 > &new_edge) override
 Filter which of the 4-4 orientations may be chosen.
 
bool swap_edge_44_after (const Tuple &t) override
 User specified modifications and desideratas for after a 4-4 edge swap.
 
size_t swap_all_edges_56 ()
 
bool swap_edge_56_before (const Tuple &t) override
 User specified preparations and desideratas for a 5-6 edge swap before changing the connectivity.
 
bool swap_edge_56_accept_case (const std::array< size_t, 3 > &new_face) override
 Filter which of the 5-6 orientations may be chosen.
 
bool swap_edge_56_after (const Tuple &t) override
 User specified modifications and desideratas for after a 5-6 edge swap.
 
size_t swap_all_faces ()
 
bool swap_face_before (const Tuple &t) override
 User specified preparations and desideratas for an 2-3 face swap befroe changing the geometry.
 
bool swap_face_after (const Tuple &t) override
 User specified modifications and desideratas for after a 2-3 face swap.
 
size_t swap_all_edges_all ()
 
bool prepare_surface_flip (const Tuple &t, const std::vector< size_t > &incident_tets)
 
SurfaceTopoSignature surface_topology_signature () const
 
void warn_if_surface_topology_changed (const SurfaceTopoSignature &before, const char *where) const
 
double swap_edge_44_energy (const std::vector< std::array< size_t, 4 > > &tets, const int op_case) override
 User specified energy to decide which of the 4 possible orientations should be chosen.
 
double swap_edge_56_energy (const std::vector< std::array< size_t, 4 > > &tets, const int op_case) override
 User specified energy to decide which of the 5 possible orientations should be chosen.
 
virtual std::shared_ptr< SampleEnvelopesmoothing_containment_envelope (const size_t vid) const
 Envelope the resulting surface triangles are checked against.
 
void smooth_all_vertices (const size_t n_iters=1)
 
- Public Member Functions inherited from wmtk::TetMesh
size_t vert_capacity () const
 get the current largest global vid
 
size_t tet_capacity () const
 get the current largest global tid
 
size_t vertex_size () const
 get the number of unremoved verticies
 
size_t tet_size () const
 get the number of unremoved tets
 
void init (size_t n_vertices, const std::vector< std::array< size_t, 4 > > &tets)
 
void init_with_isolated_vertices (size_t n_vertices, const std::vector< std::array< size_t, 4 > > &tets)
 
void init (const MatrixXi &T)
 Generate the connectivity of the mesh from an IGL-style T matrix.
 
bool split_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 
virtual bool collapse_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool link_condition (const Tuple &t)
 
bool collapse_edge_conn (const Tuple &loc0, size_t &v1_id, Tuple &new_loc, std::map< size_t, wmtk::TetMesh::VertexConnectivity > &rollback_vert_conn, std::vector< size_t > &n1_t_ids_copy, std::vector< size_t > &new_tet_id, std::vector< TetrahedronConnectivity > &old_tets)
 
bool collapse_edge_check_topology (const std::vector< size_t > &new_tet_id)
 Check topology after collapse connectivity change. This is a sanity check and should not be necessary.
 
void collapse_edge_rollback (size_t &v1_id, std::map< size_t, wmtk::TetMesh::VertexConnectivity > &rollback_vert_conn, std::vector< size_t > &n1_t_ids, std::vector< size_t > &new_tet_id, std::vector< TetrahedronConnectivity > &old_tets)
 
bool swap_edge_56 (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool swap_edge_44 (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool swap_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 3-2 edge swap
 
bool swap_face (const Tuple &t, std::vector< Tuple > &new_tets)
 2-3 face swap
 
bool smooth_vertex (const Tuple &t)
 
bool split_tet (const Tuple &t, std::vector< Tuple > &new_tets)
 Split a tet in 4 tets.
 
bool split_face (const Tuple &t, std::vector< Tuple > &new_tets)
 Split a face in 3 faces.
 
void triangle_insertion (const std::vector< Tuple > &intersected_tets, const std::vector< Tuple > &intersected_edges, std::vector< size_t > &new_edge_vids, std::vector< size_t > &new_center_vids, std::vector< std::array< size_t, 4 > > &center_split_tets)
 Insert a triangle into a tetmesh, with known intersection information.
 
bool insert_point (const Tuple &t, std::vector< Tuple > &new_tets)
 Insert a point into a tetmesh inside a tet. In general position, this split a tet into 4. In face position, split two tets. In edge position, In point position, do nothing.
 
virtual bool insert_point_before (const Tuple &t)
 
virtual bool insert_point_after (std::vector< Tuple > &new_tets)
 
void consolidate_mesh ()
 cleans up the deleted vertices or tetrahedra, fixes the corresponding indices, and reset the version number. WARNING: it invalidates all tuples!
 
std::vector< Tupleget_edges () const
 
std::vector< Tupleget_faces () const
 
std::vector< Tupleget_vertices () const
 
std::vector< Tupleget_tets () const
 
virtual void for_each_face (const std::function< void(const TetMesh::Tuple &)> &)
 looping through all the unique edges and perform the given function
 
void set_preallocation_factor (double factor)
 Preallocation factor: init/consolidate reserve capacity = max(floor, ceil(factor * live_count)) so operations can grab fresh slots without resizing the storage. When a pass exhausts the reserved capacity the affected operations fail (and are retried later after a consolidate). Tune per application (e.g. from JSON); values < 1 are clamped to 1.
 
double preallocation_factor () const
 
long request_tet_slots (size_t n)
 
long request_vert_slots (size_t n)
 
void ensure_free_tet_capacity (size_t extra)
 
void ensure_free_vert_capacity (size_t extra)
 
Tuple tuple_from_edge (size_t tid, int local_eid) const
 get a Tuple from global tetra index and local edge index (from 0-5).
 
Tuple tuple_from_edge (const std::array< size_t, 2 > &vids) const
 get a Tuple from global vids of the 2 end of an edge
 
Tuple tuple_from_face (size_t tid, int local_fid) const
 get a Tuple from global tetra index and local face index (from 0-3).
 
std::tuple< Tuple, size_t > tuple_from_face (const std::array< size_t, 3 > &vids) const
 get a Tuple and the global face index from global vertex index of the face.
 
std::optional< std::tuple< Tuple, size_t > > try_tuple_from_face (const std::array< size_t, 3 > &vids) const
 tuple_from_face for callers where a missing face is an answer, not a bug.
 
size_t lowest_common_tet (size_t v0_id, size_t v1_id, size_t v2_id) const
 Lowest tet id incident to all three vertices, or size_t(-1) if there is none.
 
size_t vertex_valence (const size_t vid) const
 Number of tets incident to a vertex, in O(1).
 
std::tuple< Tuple, size_t > tuple_from_face (const simplex::Face &f) const
 
Tuple tuple_from_vertex (size_t vid) const
 get a Tuple from global vertex index
 
Tuple tuple_from_tet (size_t tid) const
 get a Tuple from global tetra index
 
Tuple tuple_from_vids (size_t vid0, size_t vid1, size_t vid2, size_t vid3) const
 Get a Tuple from global vertex IDs.
 
simplex::Tet simplex_from_tet (const Tuple &t) const
 
simplex::Tet simplex_from_tet (const size_t tid) const
 
simplex::Face simplex_from_face (const Tuple &t) const
 
simplex::Edge simplex_from_edge (const Tuple &t) const
 
Tuple switch_vertex (const Tuple &t) const
 wrapper function from Tuple::switch_vertex
 
Tuple switch_edge (const Tuple &t) const
 wrapper function from Tuple::switch_edge
 
Tuple switch_face (const Tuple &t) const
 wrapper function from Tuple::switch_face
 
std::optional< Tupleswitch_tetrahedron (const Tuple &t) const
 wrapper function from Tuple::switch_tetrahedron
 
std::vector< Tupleget_one_ring_tets_for_vertex (const Tuple &t) const
 Get the one ring tets for a vertex.
 
const std::vector< size_t > & get_one_ring_tids_for_vertex (const Tuple &t) const
 Get the one ring tids for vertex.
 
const std::vector< size_t > & get_one_ring_tids_for_vertex (const size_t vid) const
 
std::vector< Tupleget_one_ring_vertices_for_vertex (const Tuple &t) const
 Get the one ring vertices for a vertex.
 
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.
 
std::vector< size_t > get_one_ring_vids_for_vertex (size_t vid) const
 Get the one ring vids for vertex.
 
std::vector< size_t > get_one_ring_vids_for_vertex_adj (size_t vid) const
 Duplicate of the function TetMesh::get_one_ring_vids_for_vertex.
 
std::vector< size_t > get_one_ring_vids_for_vertex_adj (size_t vid, std::vector< size_t > &cache)
 Duplicate of the function TetMesh::get_one_ring_vids_for_vertex.
 
std::vector< Tupleget_incident_tets_for_edge (const Tuple &t) const
 Get the incident tets for edge.
 
std::vector< Tupleget_incident_tets_for_edge (const size_t vid0, const size_t vid1) const
 
std::vector< size_t > get_incident_tids_for_edge (const Tuple &t) const
 
std::vector< size_t > get_incident_tids_for_edge (const size_t vid0, const size_t vid1) const
 
std::vector< Tupleget_one_ring_tets_for_edge (const Tuple &t) const
 Get the one ring tets for edge.
 
std::vector< std::array< size_t, 3 > > vertex_adjacent_boundary_faces (const Tuple &t) const
 
std::array< Tuple, 4 > oriented_tet_vertices (const Tuple &t) const
 
std::array< size_t, 4 > oriented_tet_vids (const Tuple &t) const
 
std::array< size_t, 4 > oriented_tet_vids (const size_t tid) const
 
std::array< Tuple, 3 > get_face_vertices (const Tuple &t) const
 Get the 3 vertices of a face represented by Tuple.
 
std::array< size_t, 3 > get_face_vids (const Tuple &t) const
 
std::array< Tuple, 6 > tet_edges (const Tuple &t) const
 get the 6 edges of a tet represented by Tuples
 
void check_tuple_validity (const Tuple &t) const
 
bool check_mesh_connectivity_validity () const
 checks the validity of the connectivity of the mesh. Including the validity of each Tuple
 
void remove_tets_by_ids (const std::vector< size_t > &tids)
 remove the tetrahedrons in the mesh that have given tet ids
 
void start_protect_attributes ()
 
void release_protect_attributes ()
 
void rollback_protected_attributes ()
 
int release_vertex_mutex_in_stack ()
 
int release_vertex_mutex_to (size_t mark)
 Release the mutexes taken since the release stack held mark entries.
 
bool try_set_vertex_mutex_n_ring (const Tuple &v, int threadid, int n)
 Lock every vertex within graph distance n of v, the seed included.
 
bool try_set_vertex_mutex_n_ring (size_t vid, int threadid, int n)
 
bool try_set_edge_mutex_n_ring (const Tuple &e, int threadid, int n)
 try_set_vertex_mutex_n_ring seeded from both ends of an edge.
 
bool try_set_face_mutex_n_ring (size_t v1, size_t v2, size_t v3, int threadid, int n)
 try_set_vertex_mutex_n_ring seeded from the three vertices of a face.
 
void for_each_edge (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each edge
 
void for_each_vertex (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each vertex
 
void for_each_tetra (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each tet
 
simplex::SimplexCollection get_surface_faces_for_vertex (const size_t vid) const
 Get all faces on the surface that are incident to vid.
 
simplex::SimplexCollection get_surface_faces_for_edge (const std::array< size_t, 2 > &vids) const
 Get all faces on the surface that are incident to the edge.
 
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.
 
size_t compute_vertex_order (const size_t vid) const
 Compute the vertex order for a single vertex.
 
size_t get_order_of_edge (const std::array< size_t, 2 > &vids) const
 Compute the order of an edge.
 
bool substructure_link_condition (const Tuple &e_tuple) const
 Link condition that also considers substructures.
 
bool try_set_vertex_mutex_two_ring (const Tuple &v, int threadid)
 Lock v's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_vertex_mutex_two_ring_vid (const Tuple &v, int threadid)
 try_set_vertex_mutex_two_ring reached through vids rather than Tuples.
 
bool try_set_vertex_mutex_two_ring_vid (size_t v, int threadid)
 try_set_vertex_mutex_two_ring reached through vids rather than Tuples.
 
bool try_set_edge_mutex_two_ring (const Tuple &e, int threadid=0)
 Lock the edge's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (const Tuple &f, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (const Tuple &v1, const Tuple &v2, const Tuple &v3, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (size_t v1, size_t v2, size_t v3, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_vertex_mutex_one_ring (const Tuple &v, int threadid=0)
 Lock v and its one-ring. Complete, unlike the two-ring family.
 
size_t cell_capacity () const
 
Tuple tuple_from_cell (size_t cid) const
 
- Public Member Functions inherited from wmtk::RationalPositions
size_t round_all_vertices ()
 Try to round every un-rounded vertex; returns the number reclaimed.
 
bool round_and_check_all_rounded ()
 Run the sweep, then report whether the mesh is now fully rounded.
 

Static Public Member Functions

static double mean_ratio_metric (const Vector3d &p0, const Vector3d &p1, const Vector3d &p2)
 unsigned mean ratio metric of a triangle: 2*sqrt(3)*area / (sum of squared edge lengths). 1 for equilateral, -> 0 as the triangle degenerates. See https://github.com/wildmeshing/topological-offsets/blob/main/components/topological_offsets/wmtk/components/topological_offsets/internal/utils/mean_ratio_metric.hpp
 

Public Attributes

int m_vtu_counter = 0
 
std::array< size_t, 4 > m_init_counts = {{0, 0, 0, 0}}
 
size_t m_tags_count
 
SimplicialComplexBVH m_input_complex_bvh
 
EdgeSplitMode m_edge_split_mode = EdgeSplitMode::Midpoint
 
std::map< std::string, int64_t > m_tag_name_to_id
 
std::map< int64_t, std::string > m_tag_id_to_name
 
CellTag m_offset_output_tag_ids
 
bool m_singlebody = false
 
int64_t m_single_tag
 
bool m_has_envelope
 
std::vector< Vector3d > m_V_envelope
 
std::vector< Vector3i > m_F_envelope
 
double m_envelope_eps = -1
 
Parametersm_offset_params
 
VertexExtraCol m_vertex_extra
 
FaceExtraCol m_face_extra
 
EdgeAttCol m_edge_attribute
 
TetAttCol m_tet_attribute
 
std::atomic< int > cnt_split = 0
 
std::atomic< int > cnt_collapse = 0
 
double m_max_normal_deviation_swap_max_deg = 75.0
 
- Public Attributes inherited from wmtk::TetOptimizerMesh
VertAttCol m_vertex_attribute
 
FaceAttCol m_face_attribute
 
AttributeContainerGroup m_vertex_attr_group
 What p_vertex_attrs points at, so a derived class can register more.
 
AttributeContainerGroup m_face_attr_group
 What p_face_attrs points at, so a derived class can register more.
 
OptimizerParametersm_params
 
std::shared_ptr< SampleEnvelopem_envelope
 Surface envelope: what a surface vertex is pulled toward and checked against.
 
double m_s_amips = 1.
 
double m_s_envelope = -1.
 
double time_env = 0.0
 
igl::Timer isout_timer
 
wmtk::threading::enumerable_thread_specific< std::unique_ptr< polysolve::nonlinear::Solver > > m_solver
 Per-thread Newton solver for smoothing; created on first use.
 
optimization::SmoothRejectCounters m_smooth_rejects
 Why smoothing attempts were refused, reported once per pass.
 
bool m_collapse_limit_length = true
 
std::set< simplex::Edgem_force_split_edges
 
size_t m_force_split_count = 0
 Force-splits taken in the current split pass. Diagnostic only.
 
std::unique_ptr< std::atomic< int >[]> m_high_valence_claim
 Per-pass claims for the shared high-valence split gate.
 
size_t m_high_valence_claim_size = 0
 
std::atomic< size_t > m_high_valence_rejects = 0
 
int m_iterations_used = 0
 Shared TetWild/SimWild outer optimization schedule.
 
int m_debug_print_counter = 0
 
CoarsenStats m_coarsen_stats
 
std::atomic< int > cnt_swap = 0
 
std::atomic< int > cnt_surface_swap = 0
 
std::atomic< int > cnt_surface_swap_32 = 0
 
std::atomic< int > cnt_surface_swap_44 = 0
 
std::atomic< int > cnt_surface_swap_56 = 0
 
- Public Attributes inherited from wmtk::TetMesh
AbstractAttributeContainerp_vertex_attrs = nullptr
 
AbstractAttributeContainerp_edge_attrs = nullptr
 
AbstractAttributeContainerp_face_attrs = nullptr
 
AbstractAttributeContainerp_tet_attrs = nullptr
 
bool m_collapse_check_link_condition = true
 
bool m_collapse_check_topology = false
 
bool m_collapse_check_manifold = true
 
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > mutex_release_stack
 
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > get_one_ring_cache
 
int NUM_THREADS = 0
 

Static Public Attributes

static constexpr int OFFSET_SURFACE_CLASS = 1
 SurfaceTagAttributes::m_surface_class for the offset boundary.
 
- Static Public Attributes inherited from wmtk::TetOptimizerMesh
static constexpr double MAX_ENERGY = 1e50
 The sentinel get_quality returns for an element AMIPS cannot score.
 
- Static Public Attributes inherited from wmtk::TetMesh
static constexpr int EDGES_PER_CELL = 6
 
static constexpr int FACES_PER_CELL = 4
 

Private Member Functions

bool swap_capture_tag (const std::vector< size_t > &tids)
 
bool any_tag_present (const CellTag &tag1, const CellTag &tag2)
 determine if any tag from tag1 is also present in tag2.
 
void sort_edges_by_length (std::vector< simplex::Edge > &edges)
 sort edge simplices in place by decreasing edge length
 

Private Attributes

wmtk::threading::enumerable_thread_specific< OptSplitCachem_opt_split_cache
 
wmtk::threading::enumerable_thread_specific< double > m_collapse_nd_before
 The worse of the two endpoints' offset-surface deviation before the collapse.
 
wmtk::threading::enumerable_thread_specific< CellTag > m_swap_tag
 The tag swap_after_cells writes onto the tets the swap created, chosen in before.
 
wmtk::threading::enumerable_thread_specific< EdgeSplitCacheedge_split_cache
 
wmtk::threading::enumerable_thread_specific< FaceSplitCacheface_split_cache
 
wmtk::threading::enumerable_thread_specific< TetSplitCachetet_split_cache
 

Additional Inherited Members

- Protected Member Functions inherited from wmtk::TetOptimizerMesh
std::vector< size_t > all_vertex_ids () const override
 Every live vertex, in the mesh's own iteration order.
 
bool vertex_is_rounded (const size_t vid) const override
 Whether this vertex's double position is currently trusted.
 
bool round_vertex (const size_t vid) override
 
virtual std::tuple< double, double > optimization_quality_stats ()
 
virtual double optimization_stop_metric () const
 
virtual void optimization_sanity_checks_extra ()
 
virtual bool optimization_stop_at_float () const
 
virtual bool collapse_quality_allowed (size_t v1, double quality, double ring_max) const
 
virtual bool split_adjust_position (size_t, const std::vector< Tuple > &)
 
- Protected Member Functions inherited from wmtk::TetMesh
virtual bool triangle_insertion_before (const std::vector< Tuple > &faces)
 
virtual bool triangle_insertion_after (const std::vector< std::vector< Tuple > > &)
 
void resize_vertex_mutex (size_t v)
 
- Protected Attributes inherited from wmtk::TetOptimizerMesh
wmtk::threading::enumerable_thread_specific< SwapInfoCacheswap_cache
 
wmtk::threading::enumerable_thread_specific< SplitInfoCachesplit_cache
 
wmtk::threading::enumerable_thread_specific< CollapseInfoCachecollapse_cache
 
bool m_coarsen_mode = false
 Set for the duration of coarsen_mesh(); read-only while a pass is running.
 
- Protected Attributes inherited from wmtk::RationalPositions
std::atomic< bool > m_all_rounded = false
 True when every vertex is known to be rounded.
 

Detailed Description

The offset's tet mesh, on the shared 3D optimizer.

The construction phase – marching tets, simplicial embedding, growing the offset region – is entirely its own and uses TetMesh's face and tet splits directly. The optimization phase that follows is wmtk::TetOptimizerMesh's, with the offset supplying only its own policy through the hooks: which cell quality, which tags to propagate, which surface is envelope-constrained, and how an offset-surface vertex is smoothed.

Two surfaces are tracked, not one. The input complex is class 0 and must stay inside m_envelope; the offset boundary is OFFSET_SURFACE_CLASS and is free to move, being defined by the tet labels rather than by input geometry. The base's m_is_surface_fs / m_is_on_surface are the UNION of the two – that is what must not be torn by an operation – and VertexExtra::m_is_on_input / m_is_on_offset say which.

Member Function Documentation

◆ allow_surface_swap()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::allow_surface_swap ( ) const
inlineoverridevirtual

Surface edges may be flipped, as a topology-preserving diagonal flip. Both tracked surfaces need it: the offset boundary is re-triangulated constantly, and refusing to flip its diagonals is what leaves the badly-shaped triangles the sizing field then chases.

Implements wmtk::TetOptimizerMesh.

◆ any_tag_present()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::any_tag_present ( const CellTag &  tag1,
const CellTag &  tag2 
)
inlineprivate

determine if any tag from tag1 is also present in tag2.

Note
if tag2 is empty (ambient), return true if tag1 is empty, otherwise false (tag2 is ambient, so only 'element' is ambient)

◆ cell_in_region()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::cell_in_region ( const size_t  tid) const
inline

Whether tet tid belongs to the closed offset region, read from its TAGS.

The 3D counterpart of TopoOffsetTriMesh::face_in_region, and it fixes the same defect. The region is the offset band plus the input complex it wraps, both named by tags – and tags are what the shared operations propagate. The construction label says the same thing but is derived state maintained alongside them, so it goes stale the moment a split or swap creates a cell the label was never written for, putting holes in the region that offset_is_manifold() then reports as non-manifold.

◆ cell_quality()

double wmtk::components::topological_offset::TopoOffsetTetMesh::cell_quality ( const size_t  tid) const
inlineoverridevirtual

The quality of cell tid, and how to write it.

The cell attribute types differ between the applications, so the base reaches the one field it shares through these. Both are AMIPS^3; see MAX_ENERGY. Topological operations and smoothing use the accessors so the shared algorithms remain independent of each application's cell-attribute type.

Implements wmtk::TetOptimizerMesh.

◆ check_surface_topology()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::check_surface_topology ( ) const
inlineoverridevirtual

◆ collapse_after_connectivity()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_after_connectivity ( size_t  v1,
size_t  v2,
const std::vector< std::array< size_t, 2 > > &  boundary_edges 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_after_vertex()

void wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_after_vertex ( size_t  v1,
size_t  v2 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_before_vertex()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_before_vertex ( size_t  ,
size_t  ,
double   
)
overridevirtual

Non-const: an override may cache what it measured before the collapse so its after counterpart can tell a regression from a defect that was already there.

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_edge_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_edge_before ( const Tuple t)
overridevirtual

Collapse policy that is the offset's own.

collapse_before_vertex refuses to move a vertex off the surface it belongs to (the base only knows the union of the two), to lower the order of a boundary vertex, or to collapse across what looks like a feature of the input complex; it also records how badly aligned the offset surface already was, so its after counterpart can tell a regression from a defect that was there before.

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_is_order_2_edge()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_is_order_2_edge ( const std::array< size_t, 2 > &  e)
inlineoverridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ edge_split_binary_search()

void wmtk::components::topological_offset::TopoOffsetTetMesh::edge_split_binary_search ( const size_t  v1,
const size_t  v2,
Vector3d &  p_new 
) const

split edge at point by minimizing m_offset_params.target_distance - d() (where d() is distance to input complex via BVH) along the edge. Uses binary search, so implicitly assumes distance field is monotonic along edge. May give weird results if not monotonic

Deprecated:

◆ edge_split_log_root_find()

void wmtk::components::topological_offset::TopoOffsetTetMesh::edge_split_log_root_find ( const size_t  v1,
const size_t  v2,
Vector3d &  p_new 
) const

uses custom root finding routine, attempting to find first root (nearest to v1) to split edge at

Deprecated:

◆ face_is_on_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_is_on_surface ( const size_t  fid) const
overridevirtual

Is a face part of the substructure.

Parameters
fidFace ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ get_order_of_vertex()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::get_order_of_vertex ( const size_t  vid) const
overridevirtual

Get the order of a vertex.

The order of a vertex in a TetMesh is as follows: 0: vertex is not on the surface 1: vertex is on the surface 2: vertex is on the surface boundary or a non-manifold edge 3: vertex is at the boundary of a non-manifold edge or a non-manifold vertex

Computing the vertex order is expensive. It is recommended to store the vertex order as a vertex attribute and override this method.

Parameters
vidVertex ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ init_from_image()

void wmtk::components::topological_offset::TopoOffsetTetMesh::init_from_image ( const MatrixXd &  V,
const MatrixXi &  T,
const MatrixSi &  T_tags,
const MatrixXd &  V_env,
const MatrixXi  F_env,
const std::vector< std::string > &  tag_names 
)

initialize TetMesh from vertex, tet, and tag data

Parameters
V#V by 3 vertex matrix
T#T by 4 tet matrix
T_tags#T by #tags tag matrix
V_envV_env by 3 EnvelopeSurface vertices
F_envF_env by 3 EnvelopeSurface faces

◆ invariants()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::invariants ( const std::vector< Tuple > &  tets)
overridevirtual

TODO: Check this individually in each operation

Reimplemented from wmtk::TetOptimizerMesh.

◆ is_edge_on_input()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::is_edge_on_input ( const Tuple loc)

Whether edge loc lies on the INPUT complex. The base's is_edge_on_input() asks about the union of the two tracked surfaces, and is_edge_on_bbox() is the base's.

◆ is_open_boundary_edge()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::is_open_boundary_edge ( const Tuple e)
inlineoverridevirtual

The offset's surface can end on a non-manifold or boundary edge of the input complex, which the base must not flip or split across.

Reimplemented from wmtk::TetOptimizerMesh.

◆ marching_split_edge_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::marching_split_edge_after ( const Tuple t)

check inversion & rounding

◆ offset_is_manifold()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::offset_is_manifold ( )

verify that the closed offset region (simplices labelled 1 or 2) form a manifold region. This should be true for any offset. This function is for verification.

Note
We first collect the tets labelled 1 or 2, then extract the boundary of this region and check if it is manifold.

◆ offset_surface_samples()

std::array< OffsetSurfaceSample, 4 > wmtk::components::topological_offset::TopoOffsetTetMesh::offset_surface_samples ( const Tuple f) const

the 4 offset-field samples for face f (centroid + one near each corner), following Quadrics.cpp's get_triangle_samples_and_area(). Shared by the Quadrics construction below and by the feature-preserving checks in Collapse.cpp – a single centroid sample cannot tell a locally-flat patch from one straddling a sharp feature of the input complex, since a single BVH nearest-point query just picks whichever side of the feature is closer.

Note
a sample is only accepted (non-zero OffsetSurfaceSample::normal) if it lies in the direction of offset_face_outward_normal(f); otherwise it is degenerate for our purposes, same as landing exactly on the input complex.

◆ optimize_offset()

void wmtk::components::topological_offset::TopoOffsetTetMesh::optimize_offset ( const std::filesystem::path &  output_file)

optimize the offset

All label attributes are ignored from here on out. All relevant information is stored in tags and in the "on_surface" and "on_offset" attributes.

◆ refine_sizing_around_worst()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::refine_sizing_around_worst ( double  )
inlineoverridevirtual

The offset's sizing refinement, as the base's stall escape hatch.

The base fires this when the max energy stops improving; the offset also runs update_sizing_field() unconditionally once per iteration, since its sizing field is driven by the shape of the offset triangulation rather than by the optimizer stalling.

Implements wmtk::TetOptimizerMesh.

◆ set_cell_quality()

void wmtk::components::topological_offset::TopoOffsetTetMesh::set_cell_quality ( const size_t  tid,
const double  q 
)
inlineoverridevirtual

◆ set_vertex_position()

void wmtk::components::topological_offset::TopoOffsetTetMesh::set_vertex_position ( const size_t  vid,
const Vector3d &  p 
)
inline

Place a vertex, keeping its exact and rounded coordinates in step.

The offset works in doubles throughout – its construction is driven by a BVH distance field to the input complex, which has no exact form – so every vertex it places is rounded, and its rational position is just the exact value of the double it carries.

Filling m_pos anyway is not bookkeeping for its own sake. The shared split falls back to the EXACT midpoint when the double one would invert an incident tet, which is what lets a degenerate region keep being refined instead of the split being refused; that fallback reads the endpoints' m_pos, and every quality and orientation test around an un-rounded vertex reads its neighbours'. A vertex placed here with a stale m_pos would silently feed those the wrong point.

◆ smooth_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_after ( const Tuple t)
overridevirtual

User specified modifications and desideratas for after smoothing a vertex.

Parameters
tTuple refering to a vertex
Returns
true if the preparation succeed

Reimplemented from wmtk::TetOptimizerMesh.

◆ smooth_after_offset_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_after_offset_surface ( const Tuple t)

quadrics-based smoothing step for offset surface vertices: blends a Laplacian step with a projection onto quadrics built from target_distance-offset samples of the input complex, following https://github.com/wildmeshing/topological-offsets/blob/main/components/topological_offsets/wmtk/components/topological_offsets/internal/OffsetOptimization.cpp#L2226

Note
skeleton: no bisection fallback toward p0 on rejection.

◆ smooth_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_before ( const Tuple t)
overridevirtual

The base rounds and refuses bbox vertices; this additionally freezes the input complex, and routes offset-surface vertices to the quadrics step below.

Reimplemented from wmtk::TetOptimizerMesh.

◆ smoothing_energy_envelope()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::smoothing_energy_envelope ( const size_t  ) const
inlineoverridevirtual

Input-complex vertices never move (smooth_before refuses them), and an offset-surface vertex is pulled by the quadrics rather than by an envelope, so there is nothing to pull anything toward.

Implements wmtk::TetOptimizerMesh.

◆ split_after_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_after_cells ( size_t  ,
size_t  ,
size_t  ,
const std::vector< Tuple > &   
)
overridevirtual

Restore application cell data on the children made by a split.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_after_vertex()

void wmtk::components::topological_offset::TopoOffsetTetMesh::split_after_vertex ( size_t  ,
bool   
)
overridevirtual

Application metadata not represented by the shared vertex attributes.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_before_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_before_cells ( const Tuple edge,
const std::vector< Tuple > &  parents 
)
overridevirtual

Split policy that is the offset's own.

The shared split places the vertex, keeps the quality and the shared attributes and checks containment; what it cannot know is which region tag the two child tets inherit, and which of the two tracked surfaces the new vertex joined.

The shared split places the new vertex, keeps the quality and the shared attributes and checks envelope containment. These three hooks add what only the offset knows: which region tag each child tet inherits, and which of the two tracked surfaces the new vertex joined.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_edge_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_edge_after ( const Tuple t)
overridevirtual

This function computes the attributes for the added simplices. User specified modifications and desideratas for after an edge split.

Parameters
theedge Tuple to be split
Returns
true if the modification succeed

check inversion & rounding

update quality

containment: the new surface triangles must stay inside the envelope

update vertex attribute

update face attribute

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_edge_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_edge_before ( const Tuple t)
overridevirtual

overriden splits/invariants Dispatch: the optimization phase runs the shared split, everything else the marching-tets one below.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_face_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_face_after ( const Tuple t)
overridevirtual

Compute the attributes for the added simplices.

User specified modifications and desideratas for after a face split

Parameters
tThe face tuple to be split.
Returns
true if the modification succeed

Reimplemented from wmtk::TetMesh.

◆ split_face_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_face_before ( const Tuple t)
overridevirtual

User specified preparations and desideratas for a face split before changing the connectivity.

Parameters
tThe face tuple to be split.
Returns
true if the preparation succeed.

Reimplemented from wmtk::TetMesh.

◆ split_tet_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_tet_after ( const Tuple t)
overridevirtual

Compute the attributes for the added simplices.

User specified modifications and desideratas for after a tet split

Parameters
tThe tet tuple to be split.
Returns
true if the modification succeed

Reimplemented from wmtk::TetMesh.

◆ split_tet_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_tet_before ( const Tuple t)
overridevirtual

User specified preparations and desideratas for a tet split before changing the connectivity.

Parameters
tThe tet tuple to be split.
Returns
true if the preparation succeed.

Reimplemented from wmtk::TetMesh.

◆ surface_envelope_for_face()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::surface_envelope_for_face ( const std::array< size_t, 3 > &  vids) const
inlineoverridevirtual

Only the input complex is envelope-constrained.

The offset boundary is defined by which tets carry the offset label, not by input geometry, so there is nothing for it to stay inside; the checks that keep it faithful to the implicit offset field are the normal-deviation ones in collapse and swap. Decided from the vertices rather than the face's own class because the shared operations ask about triangles they are creating, whose attributes are not written yet.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_after_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_after_cells ( const std::vector< size_t > &  ,
bool   
)
overridevirtual

Propagate application data to the cells made by a successful topological swap.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_before_interior()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_before_interior ( const std::vector< size_t > &  tids)
overridevirtual

Which tag the tets a swap creates should carry.

A swap must not move the boundary between differently tagged regions, since that boundary IS the offset. Around an interior edge every incident tet already shares a tag (a face between differently tagged tets is a tracked surface face, and the base only takes this path when the edge has none), so this is a cheap safety net there. On a surface flip the ring genuinely spans two tags and the majority one wins.

Returns false, refusing the swap, when three or more tags meet: there is then no single answer and any choice would relabel a tet.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_before_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_before_surface ( const std::vector< size_t > &  tids,
size_t  a,
size_t  b,
size_t  c,
size_t  d 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_capture_tag()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_capture_tag ( const std::vector< size_t > &  tids)
private

The swap operations themselves – the 3-2, 4-4 and 5-6 edge swaps, the 2-3 face swap, their drivers, the face-attribute tracker and the surface diagonal flip – are wmtk::TetOptimizerMesh's. What is left here is only what is the offset's own: keeping the region tags consistent, and keeping the offset surface faithful to the implicit offset field of the input complex.

◆ update_sizing_field()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::update_sizing_field ( )

refine or coarsen the sizing field (VertexAttributes::m_sizing_scalar) based on the mean ratio metric of the offset triangulation (offset-class surface faces), following the reference's compute_target_edge_length(): for every vertex incident to at least one offset-surface face, take the worst (minimum) mean_ratio_metric() among those faces, and halve the sizing scalar if it is below m_offset_params.sizing_mrm_threshold, or multiply it by 1.5 (coarsen) if above – clamped to [m_offset_params.min_sizing_scalar, m_offset_params.max_sizing_scalar]. Vertices not incident to any offset-surface face are left untouched. The vertices actually refined this pass then seed wmtk::utils::gradation_smooth_sizing() (m_offset_params.sizing_gradation), matching SimWildMesh::gradation_smooth_sizing(), so a newly refined patch doesn't sit right next to an unrelated coarse one. Called once per optimize_offset() iteration, after smoothing.

Note
skeleton: unlike the reference, this doesn't also factor in normal deviation.

◆ vertex_is_on_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_is_on_surface ( const size_t  vid) const
overridevirtual

Is a vertex part of the substructure.

Parameters
vidVertex ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ write_optimization_debug_output()

void wmtk::components::topological_offset::TopoOffsetTetMesh::write_optimization_debug_output ( const std::string &  path)
inlineoverridevirtual

Member Data Documentation

◆ m_offset_params

Parameters& wmtk::components::topological_offset::TopoOffsetTetMesh::m_offset_params

The base holds only wmtk::OptimizerParameters; this is the same object, typed, for the offset-only fields.

◆ OFFSET_SURFACE_CLASS

constexpr int wmtk::components::topological_offset::TopoOffsetTetMesh::OFFSET_SURFACE_CLASS = 1
staticconstexpr

SurfaceTagAttributes::m_surface_class for the offset boundary.

The input complex keeps the primary class 0, so a face carrying input geometry is envelope-checked by the shared operations exactly as in tetwild and simwild.


The documentation for this class was generated from the following files: