Wildmeshing Toolkit
Loading...
Searching...
No Matches
OffsetPotential.hpp
1#pragma once
2
3#include <wmtk/Types.hpp>
4#include <wmtk/envelope/Envelope.hpp>
5
6#include <wmtk/threading/enumerable_thread_specific.hpp>
7#include "SimplicialComplexBVH.hpp"
8
9#include <polysolve/nonlinear/Problem.hpp>
10
11#include <cmath>
12#include <memory>
13#include <string>
14#include <vector>
15
16namespace wmtk::components::topological_offset {
17
35template <int DIM>
37{
38 static_assert(DIM == 2 || DIM == 3, "the offset potential exists in 2D and 3D only");
39
40public:
41 using VecD = Eigen::Matrix<double, DIM, 1>;
42 using MatD = Eigen::Matrix<double, DIM, DIM>;
43
48
50 double target_level() const { return m_c; }
51
53 double delta() const { return m_delta; }
54
57 double dhat() const { return m_dhat; }
58
71 double level_set_slope() const { return m_grad_ref; }
72
73 virtual double value(const VecD& p) const = 0;
75 virtual bool is_euclidean() const { return false; }
76 virtual VecD gradient(const VecD& p) const = 0;
77 virtual MatD hessian(const VecD& p) const = 0;
78
85 virtual double residual_length(const VecD& p) const = 0;
86
88 virtual bool within_support(const VecD& p) const = 0;
89
96 virtual bool is_inside_offset(const VecD& p) const = 0;
97
99 virtual std::string describe_active(const VecD& p) const = 0;
100
101protected:
104 OffsetPotential(const double delta, const double dhat)
105 : m_delta(delta)
106 , m_dhat(dhat)
107 {}
108
109 double m_delta = 0.;
110 double m_dhat = 0.;
111 double m_c = 0.;
114 double m_grad_ref = 1.;
115};
116
119
120
158template <int DIM>
160{
161 static_assert(DIM == 2 || DIM == 3, "the offset potential exists in 2D and 3D only");
162
163public:
164 using VecD = typename OffsetPotential<DIM>::VecD;
165 using MatD = typename OffsetPotential<DIM>::MatD;
166
186 const MatrixXd& V,
187 const MatrixXi& E,
188 const MatrixXi& F,
189 const std::vector<int>& P,
190 double delta,
191 double dhat_factor);
192
193 ~SmoothOffsetPotential() override;
194
195 double value(const VecD& p) const override;
196 VecD gradient(const VecD& p) const override;
197 MatD hessian(const VecD& p) const override;
198
206 double residual_length(const VecD& p) const override;
207
209 bool within_support(const VecD& p) const override { return value(p) > 0.; }
210
212 bool is_inside_offset(const VecD& p) const override { return value(p) >= m_c; }
213
216 std::string describe_active(const VecD& p) const override;
217
218private:
219 // Dependent base members: name them unqualified in the definitions below.
220 using OffsetPotential<DIM>::m_delta;
221 using OffsetPotential<DIM>::m_dhat;
222 using OffsetPotential<DIM>::m_c;
224
227 SmoothOffsetPotential(double delta, double dhat_factor, int /*calibration tag*/);
228
229 void build(const MatrixXd& V, const MatrixXi& E, const MatrixXi& F, const std::vector<int>& P);
230
233 struct Impl;
234 std::unique_ptr<Impl> m_impl;
235};
236
237using SmoothOffsetPotential2D = SmoothOffsetPotential<2>;
238using SmoothOffsetPotential3D = SmoothOffsetPotential<3>;
239
240
269template <int DIM>
271{
272 static_assert(DIM == 2 || DIM == 3, "the offset potential exists in 2D and 3D only");
273
274public:
275 bool is_euclidean() const override { return true; }
276 using VecD = typename OffsetPotential<DIM>::VecD;
277 using MatD = typename OffsetPotential<DIM>::MatD;
278
286 EuclideanOffsetPotential(const std::shared_ptr<SampleEnvelope>& envelope, double delta);
287
297 EuclideanOffsetPotential(const std::shared_ptr<SimplicialComplexBVH>& bvh, double delta);
298
299 double value(const VecD& p) const override;
300 VecD gradient(const VecD& p) const override;
301 MatD hessian(const VecD& p) const override;
302
305 double residual_length(const VecD& p) const override
306 {
307 return std::abs(value(p) - m_c) / m_grad_ref;
308 }
309
311 bool within_support(const VecD& p) const override { return true; }
312
315 bool is_inside_offset(const VecD& p) const override { return value(p) <= m_c; }
316
317 std::string describe_active(const VecD& p) const override;
318
319private:
322 void nearest_feature(const VecD& p, VecD& foot, int& dim, VecD& dir) const;
323
324 using OffsetPotential<DIM>::m_delta;
326 using OffsetPotential<DIM>::m_dhat;
327 using OffsetPotential<DIM>::m_c;
328
331 std::shared_ptr<SampleEnvelope> m_envelope;
332 std::shared_ptr<SimplicialComplexBVH> m_bvh;
333};
334
337
338
361template <int DIM>
362class OffsetEnergy : public polysolve::nonlinear::Problem
363{
364public:
365 using typename polysolve::nonlinear::Problem::Scalar;
366 using typename polysolve::nonlinear::Problem::THessian;
367 using typename polysolve::nonlinear::Problem::TVector;
368
369 using VecD = Eigen::Matrix<double, DIM, 1>;
370 using MatD = Eigen::Matrix<double, DIM, DIM>;
371
378 const std::shared_ptr<const OffsetPotential<DIM>>& potential,
379 double weight = 1.,
380 bool gauss_newton = true,
381 bool distance_residual = false);
382
383 double value(const TVector& x) override;
384 void gradient(const TVector& x, TVector& gradv) override;
385 void hessian(const TVector& x, THessian& hessian) override
386 {
387 log_and_throw_error("Sparse functions do not exist, use dense solver");
388 }
389 void hessian(const TVector& x, MatrixXd& hessian) override;
390
391 void solution_changed(const TVector& new_x) override {}
392
393private:
394 std::shared_ptr<const OffsetPotential<DIM>> m_potential;
395 double m_weight;
396 bool m_gauss_newton;
397 bool m_distance_residual;
401 bool root_distance(const VecD& p, double& s, VecD& n) const;
404 void residual(const VecD& p, double& r, VecD& dr) const;
405 mutable double m_last_root = 0.;
406 mutable bool m_cache_valid = false;
407 mutable VecD m_cache_p;
408 mutable double m_cache_r = 0.;
409 mutable VecD m_cache_dr;
410};
411
413
432class AlignEnergy2D : public polysolve::nonlinear::Problem
433{
434public:
435 using typename polysolve::nonlinear::Problem::Scalar;
436 using typename polysolve::nonlinear::Problem::THessian;
437 using typename polysolve::nonlinear::Problem::TVector;
438 struct Edge
439 {
440 Eigen::Vector2d q;
441 double sigma;
448 double agree = 1.;
449 };
451 const std::shared_ptr<const OffsetPotential2D>& potential,
452 std::vector<Edge> edges,
453 double outward_sign,
454 double weight);
456 void residual(const Eigen::Vector2d& x, const Edge& e, double& r, Eigen::Vector2d& J) const;
457 double value(const TVector& x) override;
458 void gradient(const TVector& x, TVector& gradv) override;
459 void hessian(const TVector& x, THessian& hessian) override
460 {
461 log_and_throw_error("Sparse functions do not exist, use dense solver");
462 }
463 void hessian(const TVector& x, MatrixXd& hessian) override;
464 void solution_changed(const TVector& new_x) override {}
465
466private:
467 std::shared_ptr<const OffsetPotential2D> m_potential;
468 std::vector<Edge> m_edges;
469 double m_sign, m_weight;
470};
471using OffsetEnergy3D = OffsetEnergy<3>;
472
491class RestAMIPSEnergy2D : public polysolve::nonlinear::Problem
492{
493public:
494 using typename polysolve::nonlinear::Problem::Scalar;
495 using typename polysolve::nonlinear::Problem::THessian;
496 using typename polysolve::nonlinear::Problem::TVector;
497 struct Cell
498 {
499 Eigen::Vector2d q1, q2;
500 Eigen::Matrix2d rest_inv;
501 };
502 RestAMIPSEnergy2D(std::vector<Cell> cells, double weight);
503
504 double value(const TVector& x) override;
505 void gradient(const TVector& x, TVector& gradv) override;
506 void hessian(const TVector& x, THessian& hessian) override
507 {
508 log_and_throw_error("Sparse functions do not exist, use dense solver");
509 }
510 void hessian(const TVector& x, MatrixXd& hessian) override;
511 void solution_changed(const TVector& new_x) override {}
512 bool is_step_valid(const TVector& x0, const TVector& x1) override;
513
514private:
516 bool cell_F(const Eigen::Vector2d& x, const Cell& c, Eigen::Matrix2d& F, double& d) const;
517 std::vector<Cell> m_cells;
518 double m_weight;
519};
520
521} // namespace wmtk::components::topological_offset
First-order offset term: each front edge at the vertex against the field.
Definition OffsetPotential.hpp:433
void residual(const Eigen::Vector2d &x, const Edge &e, double &r, Eigen::Vector2d &J) const
r_e and its derivative for one edge; r = 0 with J = 0 where grad Phi vanishes.
Definition OffsetPotential.cpp:726
The Euclidean offset: Phi = d(p, input complex), level set d = delta.
Definition OffsetPotential.hpp:271
std::string describe_active(const VecD &p) const override
Diagnostic: what the field is made of at p, one contribution per line.
Definition OffsetPotential.cpp:1099
bool is_euclidean() const override
The Euclidean field: value() is the distance, so a distance residual is the plain one.
Definition OffsetPotential.hpp:275
std::shared_ptr< SampleEnvelope > m_envelope
Definition OffsetPotential.hpp:331
bool is_inside_offset(const VecD &p) const override
Definition OffsetPotential.hpp:315
void nearest_feature(const VecD &p, VecD &foot, int &dim, VecD &dir) const
Definition OffsetPotential.cpp:994
bool within_support(const VecD &p) const override
Everywhere. d has no compact support.
Definition OffsetPotential.hpp:311
double residual_length(const VecD &p) const override
Definition OffsetPotential.hpp:305
The offset term of the smoothing objective: w * (Phi(x) - c)^2.
Definition OffsetPotential.hpp:363
void residual(const VecD &p, double &r, VecD &dr) const
Definition OffsetPotential.cpp:878
bool root_distance(const VecD &p, double &s, VecD &n) const
Definition OffsetPotential.cpp:793
double m_last_root
warm start for root_distance(), see there
Definition OffsetPotential.hpp:405
The offset potential: the scalar field on space whose level set the front is placed on.
Definition OffsetPotential.hpp:37
double delta() const
The offset distance the field is calibrated to.
Definition OffsetPotential.hpp:53
virtual bool is_inside_offset(const VecD &p) const =0
Whether p lies inside the offset region – on the complex's side of the level set.
virtual std::string describe_active(const VecD &p) const =0
Diagnostic: what the field is made of at p, one contribution per line.
double m_grad_ref
Definition OffsetPotential.hpp:114
double level_set_slope() const
|d(field)/d(distance)| at the level set on a flat stretch of input.
Definition OffsetPotential.hpp:71
OffsetPotential(const double delta, const double dhat)
Definition OffsetPotential.hpp:104
virtual double residual_length(const VecD &p) const =0
Distance from p to the level set, in length units.
double dhat() const
Definition OffsetPotential.hpp:57
virtual bool is_euclidean() const
The Euclidean field: value() is the distance, so a distance residual is the plain one.
Definition OffsetPotential.hpp:75
double target_level() const
The level value the offset boundary is placed on.
Definition OffsetPotential.hpp:50
virtual bool within_support(const VecD &p) const =0
Whether p is somewhere the field can give a direction to the level set at all.
AMIPS against a rest shape, for deform_others: the smoothing term of a deformable region's faces.
Definition OffsetPotential.hpp:492
bool cell_F(const Eigen::Vector2d &x, const Cell &c, Eigen::Matrix2d &F, double &d) const
e = tr(F^T F), d = det F at x for one cell; false when d <= 0.
Definition OffsetPotential.cpp:1133
The smooth offset potential Phi, and the offset defined as its level set Phi = c.
Definition OffsetPotential.hpp:160
std::string describe_active(const VecD &p) const override
Definition OffsetPotential.cpp:652
bool within_support(const VecD &p) const override
Whether p is inside the support at all, i.e. Phi(p) > 0.
Definition OffsetPotential.hpp:209
double residual_length(const VecD &p) const override
First-order distance from p to the level set Phi = c, in length units.
Definition OffsetPotential.cpp:687
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.
Definition OffsetPotential.hpp:212
Eigen::Vector2d q
the other endpoint
Definition OffsetPotential.hpp:440
double agree
Definition OffsetPotential.hpp:448
double sigma
Definition OffsetPotential.hpp:441
Eigen::Matrix2d rest_inv
inverse rest Jacobian [r1-r0, r2-r0]^-1, same corner order
Definition OffsetPotential.hpp:500
Eigen::Vector2d q2
the fixed endpoints, current positions
Definition OffsetPotential.hpp:499