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
 
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
 
- 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
 
void value_gradient (const VecD &p, double &v, VecD &g) const
 value() and gradient() at p from one collision build per part; see the definition.
 

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 offset geometric contact potential of ipc-toolkit's high_order_contact subtree, evaluated at a point q against the input complex,

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

(ipc::NormalizedClampedLogBarrier). "Active" is the OGC feasible-region rule: a triangle is active at q when q projects into its interior, an edge when q projects into its interior and lies outside the wedges its incident triangles claim, a vertex when q lies in its Voronoi region. Away from features exactly one primitive contributes and Phi is a monotone function of the Euclidean distance alone; at a reentrant feature several contribute, their barriers add, and the level set bulges outward. 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: an evaluation writes the query point into a scratch vertex matrix and builds a collision set around it, so it holds per-thread state; 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
V#V 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 the OGC feasible-region test for a vertex reads its edge neighbours.
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: the active pairs at p, one per line, with each one's contribution – the only way to see why Phi has the value it has.

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

◆ 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: