Wildmeshing Toolkit
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
wmtk::components::topological_offset::SmoothOffsetPotential< DIM > Class Template Reference

The smooth offset potential Phi, and the offset defined as its level set Phi = c. More...

#include <OffsetPotential.hpp>

Inheritance diagram for wmtk::components::topological_offset::SmoothOffsetPotential< DIM >:
wmtk::components::topological_offset::OffsetPotential< DIM >

Classes

struct  Impl
 Everything that mentions ipc-toolkit. More...
 

Public Types

using VecD = typename OffsetPotential< DIM >::VecD
 
using MatD = typename OffsetPotential< DIM >::MatD
 
- Public Types inherited from wmtk::components::topological_offset::OffsetPotential< DIM >
using VecD = Eigen::Matrix< double, DIM, 1 >
 
using MatD = Eigen::Matrix< double, DIM, DIM >
 

Public Member Functions

 SmoothOffsetPotential (const MatrixXd &V, const MatrixXi &E, const MatrixXi &F, const std::vector< int > &P, double delta, double dhat_factor)
 Build the potential of a fixed complex.
 
double value (const VecD &p) const override
 
VecD gradient (const VecD &p) const override
 
MatD hessian (const VecD &p) const override
 
void value_gradient (const VecD &p, double &v, VecD &g) const override
 value() and gradient() at p from one collision build; see the definition.
 
double residual_length (const VecD &p) const override
 The distance from p to the level set Phi = c ALONG THE FIELD, in length units.
 
double relative_residual (const VecD &p) const override
 The same root, signed and over delta: t / delta, > 0 outside the offset region. NaN where residual_length() is infinite.
 
bool within_support (const VecD &p) const override
 Whether p is inside the support at all, i.e. Phi(p) > 0.
 
bool is_inside_offset (const VecD &p) const override
 Phi decreases with distance, so the offset region is where it is still above the level.
 
std::string describe_active (const VecD &p) const override
 Diagnostic: Phi, |grad Phi| and the trace of the Hessian at p.
 
- Public Member Functions inherited from wmtk::components::topological_offset::OffsetPotential< DIM >
virtual ~OffsetPotential ()
 
double target_level () const
 The level value the offset boundary is placed on.
 
double delta () const
 The offset distance the field is calibrated to.
 
double dhat () const
 
double level_set_slope () const
 |d(field)/d(distance)| at the level set on a flat stretch of input.
 
virtual bool is_euclidean () const
 The Euclidean field: value() is the distance, so a distance residual is the plain one.
 

Private Member Functions

 SmoothOffsetPotential (double delta, double dhat_factor, int)
 
void build (const MatrixXd &V, const MatrixXi &E, const MatrixXi &F, const std::vector< int > &P)
 
bool level_set_distance (const VecD &p, double &t) const
 

Private Attributes

std::unique_ptr< Impl > m_impl
 

Additional Inherited Members

- Protected Member Functions inherited from wmtk::components::topological_offset::OffsetPotential< DIM >
 OffsetPotential (const double delta, const double dhat)
 
- Protected Attributes inherited from wmtk::components::topological_offset::OffsetPotential< DIM >
double m_delta = 0.
 
double m_dhat = 0.
 
double m_c = 0.
 
double m_grad_ref = 1.
 

Detailed Description

template<int DIM>
class wmtk::components::topological_offset::SmoothOffsetPotential< DIM >

The smooth offset potential Phi, and the offset defined as its level set Phi = c.

Phi is C^2 with an analytic gradient and Hessian, so placing a vertex on the offset is an ordinary term in the smoothing objective and the front is smoothed by the same code path as every other vertex.

What Phi is: the Extremum-Sum Potential (ESP) of ipc-toolkit's esp subtree (ipc::ArbitraryPointESP), evaluated at a point q against the input complex,

Phi(q) = sum over elements s of  w_s * b( dist(q, s), dhat )
b(d, dhat) = -(d/dhat - 1)^2 * log(d/dhat)   for d < dhat, 0 otherwise

(ipc::NormalizedClampedLogBarrier), dist being to the closed element. The integer weights make every point of the complex count once (ESP supplemental, S2): a triangle weighs 1, an edge 1 - (triangles on it), a vertex 1 - (edges at it) + (triangles at it). A closed surface gets +1/-1/+1 (a closed curve +1/-1), the boundary of an open sheet and the ends of an open curve weigh 0, segments in no triangle and isolated points 1. Phi is b of the Euclidean distance wherever the complex within every radius r < dhat of q is one piece without holes: bitwise outside the cube, on any flat stretch. Where it is several pieces – two walls within dhat: a reentrant edge, a gap narrower than (1 + dhat_factor) delta – each adds its own term, Phi is larger and the level set moves outward. Measured in 3D at delta 0.1, dhat_factor 2: a 90-degree reentrant edge rounds to a fillet reaching 1.175 delta; two faces 2.5 delta apart hold their level sets at 1.041 delta; gaps up to 2.36 delta close, against 2 delta for the Euclidean offset. Near a sharp convex vertex the ball can also wrap around the vertex before reaching it (measured: Phi about 0.3% off b just outside an octahedron's apex). So Phi = c is a smoothed offset, not the Euclidean one, and that difference is deliberate; the Euclidean distance is still reported as a diagnostic.

Calibration: c is not a free parameter. It is Phi at perpendicular distance delta from one large flat primitive – one active pair, no feature interaction – computed at construction through this same class, so it cannot drift from a hand-kept analytic formula. Both dimensions therefore calibrate to the same c for the same delta and dhat_factor, which tests/test_offset_potential.cpp asserts.

dhat, the support radius beyond which Phi and every derivative are identically zero, is dhat_factor * delta. delta must sit strictly inside the support (at exactly dhat the potential and its gradient are both 0, so a vertex there gets no direction to move in) and the support must not be so wide that distant parts of the complex reach the level set. A vertex beyond dhat is a hard error – see TopoOffsetTriMesh::check_offset_within_support() and its 3D twin.

Threading: ipc builds the collision set around each query point in per-thread scratch, so value, gradient and hessian are const and safe to call concurrently from the smoothing pass.

Constructor & Destructor Documentation

◆ SmoothOffsetPotential() [1/2]

template<int DIM>
wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::SmoothOffsetPotential ( const MatrixXd &  V,
const MatrixXi &  E,
const MatrixXi &  F,
const std::vector< int > &  P,
double  delta,
double  dhat_factor 
)

Build the potential of a fixed complex.

The complex is given as ipc gives a collision mesh – vertices, edges, triangles – plus the indices of its isolated points. Phi has no area primitive in 2D and no volume primitive in 3D, so a solid input region must enter as its boundary; outside the region, the only place an offset exists, the two descriptions agree exactly.

Parameters
VV x DIM complex vertices.
E#E x 2 segments. In 3D this must contain every edge of every triangle in F as well as the complex's own isolated edges: ipc derives faces_to_edges from it and throws if an edge of a face is missing, and an edge's weight counts the triangles on it.
F#F x 3 triangles. Must be empty when DIM == 2.
Pindices into V of the isolated complex vertices (in no segment/triangle).
deltathe offset distance the level set is calibrated to.
dhat_factorsupport radius as a multiple of delta. Must be > 1.

◆ SmoothOffsetPotential() [2/2]

template<int DIM>
wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::SmoothOffsetPotential ( double  delta,
double  dhat_factor,
int   
)
private

Calibration constructor: builds the single-flat-primitive reference complex without recursing into calibration itself.

Member Function Documentation

◆ describe_active()

template<int DIM>
std::string wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::describe_active ( const VecD &  p) const
overridevirtual

Diagnostic: Phi, |grad Phi| and the trace of the Hessian at p.

Implements wmtk::components::topological_offset::OffsetPotential< DIM >.

◆ gradient()

template<int DIM>
SmoothOffsetPotential< DIM >::VecD wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::gradient ( const VecD &  p) const
overridevirtual

◆ hessian()

template<int DIM>
SmoothOffsetPotential< DIM >::MatD wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::hessian ( const VecD &  p) const
overridevirtual

◆ is_inside_offset()

template<int DIM>
bool wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::is_inside_offset ( const VecD &  p) const
inlineoverridevirtual

Phi decreases with distance, so the offset region is where it is still above the level.

Implements wmtk::components::topological_offset::OffsetPotential< DIM >.

◆ level_set_distance()

template<int DIM>
bool wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::level_set_distance ( const VecD &  p,
double &  t 
) const
private

The signed distance t from p to the level set along the field (> 0 outside the offset region), or false where there is none to measure. residual_length() is |t|, relative_residual() t / delta.

◆ relative_residual()

template<int DIM>
double wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::relative_residual ( const VecD &  p) const
overridevirtual

The same root, signed and over delta: t / delta, > 0 outside the offset region. NaN where residual_length() is infinite.

NOT the relative field error (Phi - c)/c, which the 3D loop measured before 2026-09-27 and which is a length only for a field linear in the distance. For this one it is the length error times the logarithmic slope delta |dPhi/dd| / c at the level set, which for b(d) = -(d/dhat - 1)^2 ln(d/dhat) is 2/(k - 1) + 1/ln k with k = dhat/delta: 3.4427 at the default k = 2, 6.47 at k = 1.5, 1.91 at k = 3, unbounded as k -> 1. Measured on the cube (target_distance_rel 1e-2, front_conv_rel 1e-4, 10 threads): (Phi - c)/c over the true relative distance error was 3.443 on every flat side, rounded edge and corner at convergence (the regional 3.4 / 3.3 / 3.1 of turns 1 to 4 are the same factor at vertices several bars off the level set, where b is visibly curved), and since the sag goes as h^2 that cost one extra halving: 9 turns and 80054 front faces against the Euclidean field's 7 and 25006 on the same offset surface.

Implements wmtk::components::topological_offset::OffsetPotential< DIM >.

◆ residual_length()

template<int DIM>
double wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::residual_length ( const VecD &  p) const
overridevirtual

The distance from p to the level set Phi = c ALONG THE FIELD, in length units.

|t| for the root t of Phi(p + t n) = c nearest p along n = grad Phi(p) / |grad Phi(p)|, on p's own side of the complex. No calibration constant and no reference geometry enter: it is a distance in the field's own geometry, and where Phi is a function of the Euclidean distance alone (one active pair) it is exactly |d - delta|. +infinity where it cannot be measured – outside the support (Phi = 0, no direction), on the complex (Phi infinite), where grad Phi vanishes, or where no root lies along n within dhat. The runaway guard turns the first of those into a hard error before this number decides anything. See the definition for the search and its tolerance.

Implements wmtk::components::topological_offset::OffsetPotential< DIM >.

◆ value()

template<int DIM>
double wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::value ( const VecD &  p) const
overridevirtual

◆ value_gradient()

template<int DIM>
void wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::value_gradient ( const VecD &  p,
double &  v,
VecD &  g 
) const
overridevirtual

value() and gradient() at p from one collision build; see the definition.

Reimplemented from wmtk::components::topological_offset::OffsetPotential< DIM >.

◆ within_support()

template<int DIM>
bool wmtk::components::topological_offset::SmoothOffsetPotential< DIM >::within_support ( const VecD &  p) const
inlineoverridevirtual

Whether p is inside the support at all, i.e. Phi(p) > 0.

Implements wmtk::components::topological_offset::OffsetPotential< DIM >.


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