Wildmeshing Toolkit
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Public Attributes | Private Member Functions | Private Attributes | List of all members
wmtk::SampleEnvelope Class Reference
Inheritance diagram for wmtk::SampleEnvelope:
wmtk::Envelope

Public Types

enum class  Kind { Uninitialized , Triangles3d , Edges3d , Edges2d }
 

Public Member Functions

 SampleEnvelope (bool exact=false)
 
void init (const std::vector< Eigen::Vector3d > &m_ver, const std::vector< Eigen::Vector3i > &m_faces, const double)
 
void init (const std::vector< Eigen::Vector3d > &m_ver, const std::vector< Eigen::Vector2i > &m_edges, const double)
 
void init (const std::vector< Eigen::Vector2d > &m_ver, const std::vector< Eigen::Vector2i > &m_edges, const double)
 
void init (const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const double eps)
 Same, from Eigen matrices, dispatching on the column counts.
 
bool is_outside (const std::array< Eigen::Vector3d, 3 > &tris) const
 
bool is_outside (const std::array< Eigen::Vector3d, 2 > &edge) const
 
bool is_outside (const std::array< Eigen::Vector2d, 2 > &edge) const
 
bool is_outside (const Eigen::Vector3d &pts) const
 
bool is_outside (const Eigen::Vector2d &pts) const
 
double nearest_point (const Eigen::Vector3d &pts, Eigen::Vector3d &result) const
 
double nearest_point (const Eigen::Vector2d &pts, Eigen::Vector2d &result) const
 
double nearest_point_feature (const Eigen::Vector2d &p, Eigen::Vector2d &result, bool &on_corner, Eigen::Vector2d &seg_normal, int &feature_id) const
 
double nearest_point_feature (const Eigen::Vector3d &p, Eigen::Vector3d &result, int &feature_dim, Eigen::Vector3d &dir, long long &feature_id) const
 
bool initialized ()
 
Kind kind () const
 
double squared_distance (const Eigen::Vector3d &p) const
 
double squared_distance (const Eigen::Vector2d &p) const
 

Public Attributes

double eps2 = 1e-6
 
double eps2_edge = 1e-6
 
double sampling_dist = 1e-3
 
bool use_exact = false
 
bool disabled = false
 

Private Member Functions

void require_exact_kind (Kind expected, const char *query) const
 
void require_exact_3d (const char *query) const
 
void require_exact_built (const char *query) const
 
template<typename VertexList >
void init_exact_edges (const VertexList &V, const std::vector< Eigen::Vector2i > &F, const double _eps)
 

Private Attributes

std::vector< int > geo_vertex_ind
 
std::vector< int > geo_face_ind
 
std::vector< Eigen::Vector2d > m_v2
 Input copies backing nearest_point_feature (filled by the matching init only).
 
std::vector< Eigen::Vector2i > m_e2
 
std::vector< Eigen::Vector3d > m_v3
 
std::vector< Eigen::Vector3i > m_f3
 
std::vector< Eigen::Vector2i > m_e3
 
std::shared_ptr< SimpleBVH::BVH > m_bvh
 
fastEnvelope::FastEnvelope exact_envelope
 Serves both Triangles3d and Edges3d: FastEnvelope has an init() for each.
 
fastEnvelope::FastEnvelope2D exact_envelope_2d
 Edges2d only. A separate class upstream, not an overload.
 
Kind m_kind = Kind::Uninitialized
 
bool m_exact_built = false
 

Member Enumeration Documentation

◆ Kind

enum class wmtk::SampleEnvelope::Kind
strong

Which of the three init() overloads built this envelope.

The sampled path does not need it – every overload ends up in the same BVH, and a 2D query is answered by lifting to z = 0. The exact path does: a triangle-built and an edge-built FastEnvelope are different objects, a 2D envelope is a different class again, and only init() knows which one was filled in. Without this, is_outside(Vector2d) would lift to 3D and query a FastEnvelope that was never initialized, which answers "outside" for everything rather than failing.

Member Function Documentation

◆ init() [1/2]

void wmtk::SampleEnvelope::init ( const Eigen::MatrixXd &  V,
const Eigen::MatrixXi &  F,
const double  eps 
)

Same, from Eigen matrices, dispatching on the column counts.

V Nx3, F Mx3 -> a 3D triangle envelope V Nx3, F Mx2 -> a 3D edge envelope V Nx2, F Mx2 -> a 2D edge envelope

Marshals into the vector form above. Most callers already hold matrices and were each writing the same ten-line copy loop; this is that loop, once.

◆ init() [2/2]

void wmtk::SampleEnvelope::init ( const std::vector< Eigen::Vector3d > &  m_ver,
const std::vector< Eigen::Vector3i > &  m_faces,
const double  _eps 
)
virtual

Reimplemented from wmtk::Envelope.

◆ init_exact_edges()

template<typename VertexList >
void wmtk::SampleEnvelope::init_exact_edges ( const VertexList &  V,
const std::vector< Eigen::Vector2i > &  F,
const double  _eps 
)
private

Build the exact edge envelope, when there is one to build and anything will ask for it.

Unlike the triangle overload, this is conditional on use_exact. The triangle envelope has to carry both structures because callers flip the flag on an already-initialized envelope – tetwild does that around its simplification, simwild around its insertion – but every one of those toggles is on a triangle envelope. Building the hexahedra or rectangles for a sampled edge envelope is pure cost: it added ~12% to the integration suite when this was unconditional. A toggle that arrives afterwards anyway is caught by m_exact_built rather than silently answering "outside" against an empty structure.

A zero epsilon is a legitimate way to ask for an envelope that will only ever be used for nearest_point() – triwild's Delaunay seeding does it, to reject grid points that fall too close to the input curves. There is no such thing as a zero-width exact envelope: the 2D construction asserts on it, and a containment query against one would answer "outside" for everything not exactly on the input. So skip that too, and let the query fail rather than quietly reject everything.

◆ is_outside() [1/2]

bool wmtk::SampleEnvelope::is_outside ( const Eigen::Vector3d &  pts) const
virtual

Reimplemented from wmtk::Envelope.

◆ is_outside() [2/2]

bool wmtk::SampleEnvelope::is_outside ( const std::array< Eigen::Vector3d, 3 > &  tris) const
virtual

Reimplemented from wmtk::Envelope.

◆ nearest_point_feature() [1/2]

double wmtk::SampleEnvelope::nearest_point_feature ( const Eigen::Vector2d &  p,
Eigen::Vector2d &  result,
bool &  on_corner,
Eigen::Vector2d &  seg_normal,
int &  feature_id 
) const

Nearest point plus which feature of the input carries it, for the TRUE Hessian of the squared distance: within each closest-feature region the distance to a piecewise- linear input is exactly quadratic, and the region's kind decides the Hessian's rank.

2D polylines: on_corner reports a polyline-vertex foot; seg_normal is the segment's unit normal (valid when !on_corner, sign arbitrary); feature_id is the polyline vertex index or the segment index – canonical, so two queries compare as "did the closest feature change".

◆ nearest_point_feature() [2/2]

double wmtk::SampleEnvelope::nearest_point_feature ( const Eigen::Vector3d &  p,
Eigen::Vector3d &  result,
int &  feature_dim,
Eigen::Vector3d &  dir,
long long &  feature_id 
) const

3D counterpart, for triangle envelopes AND edge (curve) envelopes. feature_dim: 2 = face interior, 1 = edge/segment interior, 0 = vertex. dir is the face normal (dim 2) or the edge direction (dim 1), unit length, sign arbitrary. feature_id is canonical across adjacent primitives (face index / sorted vertex pair packed as min * n_vertices + max / vertex index).

◆ require_exact_3d()

void wmtk::SampleEnvelope::require_exact_3d ( const char *  query) const
private

The 3D point and segment queries work against either 3D envelope, so they check only that this is not the 2D one – and that its exact structure actually exists.

◆ require_exact_kind()

void wmtk::SampleEnvelope::require_exact_kind ( Kind  expected,
const char *  query 
) const
private

An exact query must be answered by the structure the matching init() built.

Getting this wrong is silent and dangerous rather than noisy: a default-constructed FastEnvelope has no prisms, and a query against no prisms answers "outside" for every point – so a mismatched envelope does not crash, it just vetoes every operation and looks like an optimization that cannot move.

Member Data Documentation

◆ disabled

bool wmtk::SampleEnvelope::disabled = false

Debug escape hatch: when set, every is_outside() answers "inside".

The envelope is the only thing that can reject an operation for geometric rather than combinatorial reasons, so turning it off tells you whether a stalled optimization is blocked by the envelope or by the mesh itself. It removes the containment guarantee entirely – the output is not usable, only diagnostic.

Note nearest_point() is unaffected, so EnvelopeEnergy still pulls surface vertices toward the input while smoothing. Only the veto goes away, which is the point: it separates "the optimizer cannot move because the envelope forbids it" from "the optimizer cannot move at all".

◆ eps2

double wmtk::SampleEnvelope::eps2 = 1e-6

Per-sample acceptance radius, squared, for POINT and TRIANGLE queries.

eps shrunk by the covering radius of sampleTriangle's lattice, sampling_dist/sqrt(3). A point query needs no shrink at all and is therefore merely conservative here; it is left as it is because every 3D operation goes through it and widening it would change tetwild's behaviour everywhere, which belongs in its own change.

◆ eps2_edge

double wmtk::SampleEnvelope::eps2_edge = 1e-6

The same, for EDGE queries, where the covering radius is different.

is_outside(edge) samples the segment at N+1 evenly spaced points with N = floor(L/sampling_dist) + 1 > L/sampling_dist, so the spacing is L/N < sampling_dist and every point of the segment lies within sampling_dist/2 of a sample. Distance to a set is 1-Lipschitz, so "every sample within r" implies "every point within r + sampling_dist/2"; for that to imply containment in eps,

r = eps - sampling_dist / 2      (= eps/2, since sampling_dist = eps)

The lattice constant eps - sampling_dist/sqrt(3) belongs to sampleTriangle and is simply the wrong figure here: it is 0.4226*eps against the correct 0.5*eps, so using it made the edge test 18% stricter than the geometry requires. That is safe on its own – but it also made the simplification's own guarantee (r_s + sampling_dist_s/2 = eps_s) exceed the acceptance threshold of the coarser envelope the optimizer checks against, so a correctly simplified input could be rejected by the init sanity check. It was, once in 15665 models.

◆ m_exact_built

bool wmtk::SampleEnvelope::m_exact_built = false
private

Whether the edge/2D exact structure was actually built. Always false for Triangles3d, which builds its exact envelope unconditionally and is checked by kind alone.


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