|
|
| 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 |
| |
|
|
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 |
| |
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.
| 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.
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.
| 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".
| 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).
| 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".
| 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.
| 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.