19#include <Eigen/Geometry>
20#include <Eigen/IterativeLinearSolvers>
22#include <Eigen/SparseCholesky>
46template<
typename DerivedV,
typename DerivedF>
47static inline void grad(
const Eigen::PlainObjectBase<DerivedV> &
V,
48 const Eigen::PlainObjectBase<DerivedF> &
F,
49 Eigen::SparseMatrix<typename DerivedV::Scalar> &
G,
52 Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> eperp21(
F.rows(), 3),
55 for (
int i = 0;
i <
F.rows(); ++
i) {
62 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v32 =
V.row(i3) -
V.row(i2);
63 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v13 =
V.row(i1) -
V.row(i3);
64 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v21 =
V.row(i2) -
V.row(i1);
65 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> n = v32.cross(v13);
70 double dblA = std::sqrt(n.dot(n));
71 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> u;
80 double h =
sqrt((dblA) /
83 Eigen::VectorXd v1,
v2, v3;
86 v3 << h / 2., (
sqrt(3) / 2.) * h, 0;
96 double norm21 = std::sqrt(v21.dot(v21));
97 double norm13 = std::sqrt(v13.dot(v13));
98 eperp21.row(
i) = u.cross(v21);
99 eperp21.row(
i) = eperp21.row(
i) / std::sqrt(eperp21.row(
i).dot(eperp21.row(
i)));
100 eperp21.row(
i) *= norm21 / dblA;
101 eperp13.row(
i) = u.cross(v13);
102 eperp13.row(
i) = eperp13.row(
i) / std::sqrt(eperp13.row(
i).dot(eperp13.row(
i)));
103 eperp13.row(
i) *= norm13 / dblA;
107 rs.reserve(
F.rows() * 4 * 3);
109 cs.reserve(
F.rows() * 4 * 3);
110 std::vector<double> vs;
111 vs.reserve(
F.rows() * 4 * 3);
114 for (
int r = 0; r < 3; r++) {
115 for (
int j = 0; j < 4; j++) {
116 for (
int i = r *
F.rows();
i < (r + 1) *
F.rows();
i++) {
123 for (
int r = 0; r < 3; r++) {
124 for (
int i = 0;
i <
F.rows();
i++) {
125 cs.push_back(
F(
i, 1));
127 for (
int i = 0;
i <
F.rows();
i++) {
128 cs.push_back(
F(
i, 0));
130 for (
int i = 0;
i <
F.rows();
i++) {
131 cs.push_back(
F(
i, 2));
133 for (
int i = 0;
i <
F.rows();
i++) {
134 cs.push_back(
F(
i, 0));
139 for (
int i = 0;
i <
F.rows();
i++) {
140 vs.push_back(eperp13(
i, 0));
142 for (
int i = 0;
i <
F.rows();
i++) {
143 vs.push_back(-eperp13(
i, 0));
145 for (
int i = 0;
i <
F.rows();
i++) {
146 vs.push_back(eperp21(
i, 0));
148 for (
int i = 0;
i <
F.rows();
i++) {
149 vs.push_back(-eperp21(
i, 0));
151 for (
int i = 0;
i <
F.rows();
i++) {
152 vs.push_back(eperp13(
i, 1));
154 for (
int i = 0;
i <
F.rows();
i++) {
155 vs.push_back(-eperp13(
i, 1));
157 for (
int i = 0;
i <
F.rows();
i++) {
158 vs.push_back(eperp21(
i, 1));
160 for (
int i = 0;
i <
F.rows();
i++) {
161 vs.push_back(-eperp21(
i, 1));
163 for (
int i = 0;
i <
F.rows();
i++) {
164 vs.push_back(eperp13(
i, 2));
166 for (
int i = 0;
i <
F.rows();
i++) {
167 vs.push_back(-eperp13(
i, 2));
169 for (
int i = 0;
i <
F.rows();
i++) {
170 vs.push_back(eperp21(
i, 2));
172 for (
int i = 0;
i <
F.rows();
i++) {
173 vs.push_back(-eperp21(
i, 2));
177 G.resize(3 *
F.rows(),
V.rows());
178 std::vector<Eigen::Triplet<typename DerivedV::Scalar>> triplets;
179 for (
int i = 0;
i < (int)vs.size(); ++
i) {
180 triplets.push_back(Eigen::Triplet<typename DerivedV::Scalar>(rs[
i], cs[
i], vs[
i]));
182 G.setFromTriplets(triplets.begin(), triplets.end());
197template<
typename DerivedA,
203static inline void polar_svd(
const Eigen::PlainObjectBase<DerivedA> &
A,
204 Eigen::PlainObjectBase<DerivedR> &
R,
205 Eigen::PlainObjectBase<DerivedT> &
T,
206 Eigen::PlainObjectBase<DerivedU> &
U,
207 Eigen::PlainObjectBase<DerivedS> &S,
208 Eigen::PlainObjectBase<DerivedV> &
V)
211 Eigen::JacobiSVD<DerivedA> svd;
212 svd.compute(
A, Eigen::ComputeFullU | Eigen::ComputeFullV);
215 S = svd.singularValues();
216 R =
U *
V.transpose();
217 const auto &SVT = S.asDiagonal() *
V.adjoint();
219 if (
R.determinant() < 0) {
222 W.col(
V.cols() - 1) *= -1.;
223 R =
U *
W.transpose();
232 const Eigen::MatrixXi &
F,
233 const Eigen::MatrixXd &F1,
234 const Eigen::MatrixXd &F2,
235 Eigen::SparseMatrix<double> &D1,
236 Eigen::SparseMatrix<double> &D2)
238 Eigen::SparseMatrix<double>
G;
240 Eigen::SparseMatrix<double> Dx =
G.block(0, 0,
F.rows(),
V.rows());
241 Eigen::SparseMatrix<double> Dy =
G.block(
F.rows(), 0,
F.rows(),
V.rows());
242 Eigen::SparseMatrix<double> Dz =
G.block(2 *
F.rows(), 0,
F.rows(),
V.rows());
244 D1 = F1.col(0).asDiagonal() * Dx + F1.col(1).asDiagonal() * Dy + F1.col(2).asDiagonal() * Dz;
245 D2 = F2.col(0).asDiagonal() * Dx + F2.col(1).asDiagonal() * Dy + F2.col(2).asDiagonal() * Dz;
253 s.
Ji.col(0) = s.
Dx * uv.col(0);
254 s.
Ji.col(1) = s.
Dy * uv.col(0);
255 s.
Ji.col(2) = s.
Dx * uv.col(1);
256 s.
Ji.col(3) = s.
Dy * uv.col(1);
260 s.
Ji.col(0) = weights.cwiseProduct(s.
Ji.col(0));
261 s.
Ji.col(1) = weights.cwiseProduct(s.
Ji.col(1));
262 s.
Ji.col(2) = weights.cwiseProduct(s.
Ji.col(2));
263 s.
Ji.col(3) = weights.cwiseProduct(s.
Ji.col(3));
271 s.
Ji.col(0) = s.
Dx * uv.col(0);
272 s.
Ji.col(1) = s.
Dy * uv.col(0);
273 s.
Ji.col(2) = s.
Dx * uv.col(1);
274 s.
Ji.col(3) = s.
Dy * uv.col(1);
294 const double eps = 1
e-8;
297 for (
int i = 0;
i < s.
Ji.rows(); ++
i) {
298 using Mat2 = Eigen::Matrix<double, 2, 2>;
299 using Vec2 = Eigen::Matrix<double, 2, 1>;
300 Mat2 ji, ri, ti, ui, vi;
302 Vec2 closest_sing_vec;
307 ji(0, 0) = s.
Ji(
i, 0);
308 ji(0, 1) = s.
Ji(
i, 1);
309 ji(1, 0) = s.
Ji(
i, 2);
310 ji(1, 1) = s.
Ji(
i, 3);
324 double s1_g = 2 * (s1 -
pow(s1, -3));
325 double s2_g = 2 * (s2 -
pow(s2, -3));
326 m_sing_new <<
sqrt(s1_g / (2 * (s1 - 1))),
sqrt(s2_g / (2 * (s2 - 1)));
330 double s1_g = 2 * (
log(s1) / s1);
331 double s2_g = 2 * (
log(s2) / s2);
332 m_sing_new <<
sqrt(s1_g / (2 * (s1 - 1))),
sqrt(s2_g / (2 * (s2 - 1)));
336 double s1_g = 1 / (2 * s2) - s2 / (2 *
pow(s1, 2));
337 double s2_g = 1 / (2 * s1) - s1 / (2 *
pow(s2, 2));
339 double geo_avg =
sqrt(s1 * s2);
340 double s1_min = geo_avg;
341 double s2_min = geo_avg;
343 m_sing_new <<
sqrt(s1_g / (2 * (s1 - s1_min))),
sqrt(s2_g / (2 * (s2 - s2_min)));
346 closest_sing_vec << s1_min, s2_min;
347 ri = ui * closest_sing_vec.asDiagonal() * vi.transpose();
351 double s1_g = 2 * (s1 -
pow(s1, -3));
352 double s2_g = 2 * (s2 -
pow(s2, -3));
354 double in_exp = exp_f * ((
pow(s1, 2) +
pow(s2, 2)) / (2 * s1 * s2));
355 double exp_thing =
exp(in_exp);
357 s1_g *= exp_thing * exp_f;
358 s2_g *= exp_thing * exp_f;
360 m_sing_new <<
sqrt(s1_g / (2 * (s1 - 1))),
sqrt(s2_g / (2 * (s2 - 1)));
364 double s1_g = 2 * (s1 -
pow(s1, -3));
365 double s2_g = 2 * (s2 -
pow(s2, -3));
367 double in_exp = exp_f * (
pow(s1, 2) +
pow(s1, -2) +
pow(s2, 2) +
pow(s2, -2));
368 double exp_thing =
exp(in_exp);
370 s1_g *= exp_thing * exp_f;
371 s2_g *= exp_thing * exp_f;
373 m_sing_new <<
sqrt(s1_g / (2 * (s1 - 1))),
sqrt(s2_g / (2 * (s2 - 1)));
378 if (std::abs(s1 - 1) <
eps) {
381 if (std::abs(s2 - 1) <
eps) {
384 mat_W = ui * m_sing_new.asDiagonal() * ui.transpose();
386 s.
W_11(
i) = mat_W(0, 0);
387 s.
W_12(
i) = mat_W(0, 1);
388 s.
W_21(
i) = mat_W(1, 0);
389 s.
W_22(
i) = mat_W(1, 1);
393 s.
Ri(
i, 0) = ri(0, 0);
394 s.
Ri(
i, 1) = ri(1, 0);
395 s.
Ri(
i, 2) = ri(0, 1);
396 s.
Ri(
i, 3) = ri(1, 1);
400template<
typename DerivedV,
typename DerivedF>
401static inline void local_basis(
const Eigen::PlainObjectBase<DerivedV> &
V,
402 const Eigen::PlainObjectBase<DerivedF> &
F,
403 Eigen::PlainObjectBase<DerivedV> &B1,
404 Eigen::PlainObjectBase<DerivedV> &B2,
405 Eigen::PlainObjectBase<DerivedV> &B3)
407 using namespace Eigen;
409 B1.resize(
F.rows(), 3);
410 B2.resize(
F.rows(), 3);
411 B3.resize(
F.rows(), 3);
413 for (
unsigned i = 0;
i <
F.rows(); ++
i) {
414 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v1 =
415 (
V.row(
F(
i, 1)) -
V.row(
F(
i, 0))).normalized();
416 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> t =
V.row(
F(
i, 2)) -
V.row(
F(
i, 0));
417 Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v3 = v1.cross(t).normalized();
418 Eigen::Matrix<typename DerivedV::Scalar, 1, 3>
v2 = v1.cross(v3).normalized();
434 Eigen::MatrixXd F1, F2, F3;
443 s.
Dx.makeCompressed();
444 s.
Dy.makeCompressed();
445 s.
Dz.makeCompressed();
452 for (
int i = 0;
i < s.
dim * s.
dim;
i++) {
453 for (
int j = 0; j < s.
f_n; j++) {
467 std::vector<Eigen::Triplet<double>> IJV;
469 IJV.reserve(4 * (s.
Dx.outerSize() + s.
Dy.outerSize()));
475 for (
int k = 0; k < s.
Dx.outerSize(); ++k) {
476 for (Eigen::SparseMatrix<double>::InnerIterator it(s.
Dx, k); it; ++it) {
479 double val = it.value();
482 IJV.emplace_back(dx_r, dx_c, weight * val * s.
W_11(dx_r));
483 IJV.emplace_back(dx_r, s.
v_n + dx_c, weight * val * s.
W_12(dx_r));
485 IJV.emplace_back(2 * s.
f_n + dx_r, dx_c, weight * val * s.
W_21(dx_r));
486 IJV.emplace_back(2 * s.
f_n + dx_r, s.
v_n + dx_c, weight * val * s.
W_22(dx_r));
490 for (
int k = 0; k < s.
Dy.outerSize(); ++k) {
491 for (Eigen::SparseMatrix<double>::InnerIterator it(s.
Dy, k); it; ++it) {
494 double val = it.value();
497 IJV.emplace_back(s.
f_n + dy_r, dy_c, weight * val * s.
W_11(dy_r));
498 IJV.emplace_back(s.
f_n + dy_r, s.
v_n + dy_c, weight * val * s.
W_12(dy_r));
500 IJV.emplace_back(3 * s.
f_n + dy_r, dy_c, weight * val * s.
W_21(dy_r));
501 IJV.emplace_back(3 * s.
f_n + dy_r, s.
v_n + dy_c, weight * val * s.
W_22(dy_r));
505 A.setFromTriplets(IJV.begin(), IJV.end());
512 Eigen::VectorXd f_rhs(s.
dim * s.
dim * s.
f_n);
519 for (
int i = 0;
i < s.
f_n;
i++) {
526 Eigen::VectorXd uv_flat(s.
dim * s.
v_n);
527 for (
int i = 0;
i < s.
dim;
i++) {
528 for (
int j = 0; j < s.
v_n; j++) {
529 uv_flat(s.
v_n *
i + j) = s.
V_o(j,
i);
540 for (
int d = 0; d < s.
dim; d++) {
541 for (
int i = 0;
i < s.
b.rows();
i++) {
544 L.coeffRef(d * v_n + v_idx, d * v_n + v_idx) += s.
soft_const_p;
556 Eigen::SparseMatrix<double> At =
A.transpose();
559 Eigen::SparseMatrix<double> id_m(At.rows(), At.rows());
567 Eigen::SparseMatrix<double> OldL =
L;
573 const Eigen::MatrixXd &Ji,
574 Eigen::VectorXd &areas,
575 Eigen::VectorXd &singularValues,
576 bool gatherSingularValues)
581 Eigen::Matrix<double, 2, 2> ji;
582 for (
int i = 0;
i < s.
f_n;
i++) {
588 using Mat2 = Eigen::Matrix<double, 2, 2>;
589 using Vec2 = Eigen::Matrix<double, 2, 1>;
598 energy += areas(
i) * (
pow(s1 - 1, 2) +
pow(s2 - 1, 2));
602 energy += areas(
i) * (
pow(s1, 2) +
pow(s1, -2) +
pow(s2, 2) +
pow(s2, -2));
604 if (gatherSingularValues) {
605 singularValues(
i) = s1;
606 singularValues(
i + s.
F.rows()) = s2;
620 energy += areas(
i) * ((
pow(s1, 2) +
pow(s2, 2)) / (2 * s1 * s2));
637 for (
int i = 0;
i < s.
b.rows();
i++) {
644 Eigen::MatrixXd &V_new,
645 Eigen::VectorXd &singularValues,
646 bool gatherSingularValues)
657 Eigen::VectorXd temp;
662 Eigen::MatrixXd &V_new,
663 Eigen::VectorXd &singularValues)
671 Eigen::MatrixXd &V_init,
683 data.v_num =
V.rows();
684 data.f_num =
F.rows();
686 data.slim_energy = slim_energy;
690 data.soft_const_p = soft_p;
692 data.proximal_p = 0.0001;
698 data.mesh_improvement_3d =
false;
711 Eigen::VectorXd &areas)
713 int nFaces = singularValues.rows() / 2;
715 Eigen::VectorXd areasChained(2 * nFaces);
716 areasChained << areas, areas;
741 Eigen::VectorXd squaredSingularValues = singularValues.cwiseProduct(singularValues);
742 Eigen::VectorXd inverseSquaredSingularValues =
743 singularValues.cwiseProduct(singularValues).cwiseInverse();
745 Eigen::VectorXd weightedSquaredSingularValues = squaredSingularValues.cwiseProduct(areasChained);
746 Eigen::VectorXd weightedInverseSquaredSingularValues = inverseSquaredSingularValues.cwiseProduct(
749 double s1 = weightedSquaredSingularValues.head(nFaces).sum();
750 double s2 = weightedSquaredSingularValues.tail(nFaces).sum();
752 double t1 = weightedInverseSquaredSingularValues.head(nFaces).sum();
753 double t2 = weightedInverseSquaredSingularValues.tail(nFaces).sum();
766 using namespace Eigen;
768 Eigen::SparseMatrix<double>
L;
773 SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
774 Uc = solver.compute(
L).solve(s.
rhs);
776 for (
int i = 0;
i < Uc.size();
i++) {
777 if (!std::isfinite(Uc(
i))) {
782 for (
int i = 0;
i < s.
dim;
i++) {
783 uv.col(
i) = Uc.block(
i * s.
v_n, 0, s.
v_n, 1);
790 Eigen::VectorXd singularValues;
791 bool are_pins_present =
data.b.rows() > 0;
793 if (are_pins_present) {
794 singularValues.resize(
data.F.rows() * 2);
798 for (
int i = 0;
i < iter_num;
i++) {
799 Eigen::MatrixXd dest_res;
806 std::function<double(Eigen::MatrixXd &)> compute_energy_func = [&](Eigen::MatrixXd &aaa) {
818 if (are_pins_present) {
821 data.Dx /=
data.globalScaleInvarianceFactor;
822 data.Dy /=
data.globalScaleInvarianceFactor;
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define assert(assertion)
static double compute_soft_const_energy(SLIMData &s, Eigen::MatrixXd &V_o)
void slim_precompute(Eigen::MatrixXd &V, Eigen::MatrixXi &F, Eigen::MatrixXd &V_init, SLIMData &data, SLIMData::SLIM_ENERGY slim_energy, Eigen::VectorXi &b, Eigen::MatrixXd &bc, double soft_p)
static void compute_jacobians(SLIMData &s, const Eigen::MatrixXd &uv)
static void update_weights_and_closest_rotations(SLIMData &s, Eigen::MatrixXd &uv)
static void polar_svd(const Eigen::PlainObjectBase< DerivedA > &A, Eigen::PlainObjectBase< DerivedR > &R, Eigen::PlainObjectBase< DerivedT > &T, Eigen::PlainObjectBase< DerivedU > &U, Eigen::PlainObjectBase< DerivedS > &S, Eigen::PlainObjectBase< DerivedV > &V)
void doublearea(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DeriveddblA > &dblA)
static void buildRhs(SLIMData &s, const Eigen::SparseMatrix< double > &At)
static void compute_surface_gradient_matrix(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::MatrixXd &F1, const Eigen::MatrixXd &F2, Eigen::SparseMatrix< double > &D1, Eigen::SparseMatrix< double > &D2)
static double compute_energy_with_jacobians(SLIMData &s, const Eigen::MatrixXd &Ji, Eigen::VectorXd &areas, Eigen::VectorXd &singularValues, bool gatherSingularValues)
static void build_linear_system(SLIMData &s, Eigen::SparseMatrix< double > &L)
static void buildA(SLIMData &s, Eigen::SparseMatrix< double > &A)
static void pre_calc(SLIMData &s)
double computeGlobalScaleInvarianceFactor(Eigen::VectorXd &singularValues, Eigen::VectorXd &areas)
static void solve_weighted_arap(SLIMData &s, Eigen::MatrixXd &uv)
static void local_basis(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedV > &B1, Eigen::PlainObjectBase< DerivedV > &B2, Eigen::PlainObjectBase< DerivedV > &B3)
static void compute_weighted_jacobians(SLIMData &s, const Eigen::MatrixXd &uv)
static void add_soft_constraints(SLIMData &s, Eigen::SparseMatrix< double > &L)
Eigen::MatrixXd slim_solve(SLIMData &data, int iter_num)
double flip_avoiding_line_search(const Eigen::MatrixXi F, Eigen::MatrixXd &cur_v, Eigen::MatrixXd &dst_v, std::function< double(Eigen::MatrixXd &)> energy, double cur_energy)
static double compute_energy(SLIMData &s, Eigen::MatrixXd &V_new, Eigen::VectorXd &singularValues, bool gatherSingularValues)
static void compute_unweighted_jacobians(SLIMData &s, const Eigen::MatrixXd &uv)
static void grad(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::SparseMatrix< typename DerivedV::Scalar > &G, bool uniform=false)
bool withWeightedParameterization
Eigen::VectorXf weightPerFaceMap
Eigen::SparseMatrix< double > Dy
@ EXP_SYMMETRIC_DIRICHLET
Eigen::SparseMatrix< double > Dx
Eigen::SparseMatrix< double > Dz
CCL_NAMESPACE_BEGIN struct Window V