|
Wildmeshing Toolkit
|
The smooth offset potential Phi, and the offset defined as its level set Phi = c. More...
#include <OffsetPotential.hpp>
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. |
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.
| 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.
| 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 an edge's weight counts the triangles on it. |
| F | #F x 3 triangles. Must be empty when DIM == 2. |
| P | indices into V of the isolated complex vertices (in no segment/triangle). |
| delta | the offset distance the level set is calibrated to. |
| dhat_factor | support radius as a multiple of delta. Must be > 1. |
|
private |
Calibration constructor: builds the single-flat-primitive reference complex without recursing into calibration itself.
|
overridevirtual |
Diagnostic: Phi, |grad Phi| and the trace of the Hessian at p.
Implements wmtk::components::topological_offset::OffsetPotential< DIM >.
|
overridevirtual |
|
overridevirtual |
|
inlineoverridevirtual |
Phi decreases with distance, so the offset region is where it is still above the level.
Implements wmtk::components::topological_offset::OffsetPotential< DIM >.
|
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.
|
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 >.
|
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 >.
|
overridevirtual |
|
overridevirtual |
value() and gradient() at p from one collision build; see the definition.
Reimplemented from wmtk::components::topological_offset::OffsetPotential< DIM >.
|
inlineoverridevirtual |
Whether p is inside the support at all, i.e. Phi(p) > 0.
Implements wmtk::components::topological_offset::OffsetPotential< DIM >.