scaf.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2018 Zhongshi Jiang <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "scaf.h"
  9. #include "triangulate.h"
  10. #include <Eigen/Dense>
  11. #include <Eigen/IterativeLinearSolvers>
  12. #include <Eigen/Sparse>
  13. #include <Eigen/SparseCholesky>
  14. #include <Eigen/SparseQR>
  15. #include "../PI.h"
  16. #include "../Timer.h"
  17. #include "../boundary_loop.h"
  18. #include "../cat.h"
  19. #include "../IGL_ASSERT.h"
  20. #include "../doublearea.h"
  21. #include "../flip_avoiding_line_search.h"
  22. #include "../flipped_triangles.h"
  23. #include "../grad.h"
  24. #include "../harmonic.h"
  25. #include "../local_basis.h"
  26. #include "../map_vertices_to_circle.h"
  27. #include "../polar_svd.h"
  28. #include "../slice.h"
  29. #include "../slice_into.h"
  30. #include "../slim.h"
  31. #include "../placeholders.h"
  32. #include "../mapping_energy_with_jacobians.h"
  33. #include <map>
  34. #include <algorithm>
  35. #include <set>
  36. #include <vector>
  37. namespace igl
  38. {
  39. namespace triangle
  40. {
  41. namespace scaf
  42. {
  43. IGL_INLINE void update_scaffold(igl::triangle::SCAFData &s)
  44. {
  45. s.mv_num = s.m_V.rows();
  46. s.mf_num = s.m_T.rows();
  47. s.v_num = s.w_uv.rows();
  48. s.sf_num = s.s_T.rows();
  49. s.sv_num = s.v_num - s.mv_num;
  50. s.f_num = s.sf_num + s.mf_num;
  51. s.s_M = Eigen::VectorXd::Constant(s.sf_num, s.scaffold_factor);
  52. }
  53. IGL_INLINE void adjusted_grad(Eigen::MatrixXd &V,
  54. Eigen::MatrixXi &F,
  55. double area_threshold,
  56. Eigen::SparseMatrix<double> &Dx,
  57. Eigen::SparseMatrix<double> &Dy,
  58. Eigen::SparseMatrix<double> &Dz)
  59. {
  60. Eigen::VectorXd M;
  61. igl::doublearea(V, F, M);
  62. std::vector<int> degen;
  63. for (int i = 0; i < M.size(); i++)
  64. if (M(i) < area_threshold)
  65. degen.push_back(i);
  66. Eigen::SparseMatrix<double> G;
  67. igl::grad(V, F, G);
  68. Dx = G.topRows(F.rows());
  69. Dy = G.block(F.rows(), 0, F.rows(), V.rows());
  70. Dz = G.bottomRows(F.rows());
  71. // handcraft uniform gradient for faces area falling below threshold.
  72. double sin60 = std::sin(igl::PI / 3);
  73. double cos60 = std::cos(igl::PI / 3);
  74. double deno = std::sqrt(sin60 * area_threshold);
  75. Eigen::MatrixXd standard_grad(3, 3);
  76. standard_grad << -sin60 / deno, sin60 / deno, 0,
  77. -cos60 / deno, -cos60 / deno, 1 / deno,
  78. 0, 0, 0;
  79. for (auto k : degen)
  80. for (int j = 0; j < 3; j++)
  81. {
  82. Dx.coeffRef(k, F(k, j)) = standard_grad(0, j);
  83. Dy.coeffRef(k, F(k, j)) = standard_grad(1, j);
  84. Dz.coeffRef(k, F(k, j)) = standard_grad(2, j);
  85. }
  86. }
  87. IGL_INLINE void compute_scaffold_gradient_matrix(SCAFData &s,
  88. Eigen::SparseMatrix<double> &D1,
  89. Eigen::SparseMatrix<double> &D2)
  90. {
  91. Eigen::SparseMatrix<double> G;
  92. Eigen::MatrixXi F_s = s.s_T;
  93. int vn = s.v_num;
  94. Eigen::MatrixXd V = Eigen::MatrixXd::Zero(vn, 3);
  95. V.leftCols(2) = s.w_uv;
  96. double min_bnd_edge_len = INFINITY;
  97. int acc_bnd = 0;
  98. for (int i = 0; i < s.bnd_sizes.size(); i++)
  99. {
  100. int current_size = s.bnd_sizes[i];
  101. for (int e = acc_bnd; e < acc_bnd + current_size - 1; e++)
  102. {
  103. min_bnd_edge_len = (std::min)(min_bnd_edge_len,
  104. (s.w_uv.row(s.internal_bnd(e)) -
  105. s.w_uv.row(s.internal_bnd(e + 1)))
  106. .squaredNorm());
  107. }
  108. min_bnd_edge_len = (std::min)(min_bnd_edge_len,
  109. (s.w_uv.row(s.internal_bnd(acc_bnd)) -
  110. s.w_uv.row(s.internal_bnd(acc_bnd + current_size - 1)))
  111. .squaredNorm());
  112. acc_bnd += current_size;
  113. }
  114. double area_threshold = min_bnd_edge_len / 4.0;
  115. Eigen::SparseMatrix<double> Dx, Dy, Dz;
  116. adjusted_grad(V, F_s, area_threshold, Dx, Dy, Dz);
  117. Eigen::MatrixXd F1, F2, F3;
  118. igl::local_basis(V, F_s, F1, F2, F3);
  119. D1 = F1.col(0).asDiagonal() * Dx + F1.col(1).asDiagonal() * Dy +
  120. F1.col(2).asDiagonal() * Dz;
  121. D2 = F2.col(0).asDiagonal() * Dx + F2.col(1).asDiagonal() * Dy +
  122. F2.col(2).asDiagonal() * Dz;
  123. }
  124. IGL_INLINE void mesh_improve(igl::triangle::SCAFData &s)
  125. {
  126. Eigen::MatrixXd m_uv = s.w_uv.topRows(s.mv_num);
  127. Eigen::MatrixXd V_bnd;
  128. V_bnd.resize(s.internal_bnd.size(), 2);
  129. for (int i = 0; i < s.internal_bnd.size(); i++) // redoing step 1.
  130. {
  131. V_bnd.row(i) = m_uv.row(s.internal_bnd(i));
  132. }
  133. if (s.rect_frame_V.size() == 0)
  134. {
  135. Eigen::Matrix2d ob; // = rect_corners;
  136. {
  137. Eigen::VectorXd uv_max = m_uv.colwise().maxCoeff();
  138. Eigen::VectorXd uv_min = m_uv.colwise().minCoeff();
  139. Eigen::VectorXd uv_mid = (uv_max + uv_min) / 2.;
  140. Eigen::Array2d scaf_range(3, 3);
  141. ob.row(0) = uv_mid.array() + scaf_range * ((uv_min - uv_mid).array());
  142. ob.row(1) = uv_mid.array() + scaf_range * ((uv_max - uv_mid).array());
  143. }
  144. Eigen::Vector2d rect_len;
  145. rect_len << ob(1, 0) - ob(0, 0), ob(1, 1) - ob(0, 1);
  146. int frame_points = 5;
  147. s.rect_frame_V.resize(4 * frame_points, 2);
  148. for (int i = 0; i < frame_points; i++)
  149. {
  150. // 0,0;0,1
  151. s.rect_frame_V.row(i) << ob(0, 0), ob(0, 1) + i * rect_len(1) / frame_points;
  152. // 0,0;1,1
  153. s.rect_frame_V.row(i + frame_points)
  154. << ob(0, 0) + i * rect_len(0) / frame_points,
  155. ob(1, 1);
  156. // 1,0;1,1
  157. s.rect_frame_V.row(i + 2 * frame_points) << ob(1, 0), ob(1, 1) - i * rect_len(1) / frame_points;
  158. // 1,0;0,1
  159. s.rect_frame_V.row(i + 3 * frame_points)
  160. << ob(1, 0) - i * rect_len(0) / frame_points,
  161. ob(0, 1);
  162. // 0,0;0,1
  163. }
  164. s.frame_ids = Eigen::VectorXi::LinSpaced(s.rect_frame_V.rows(), s.mv_num, s.mv_num + s.rect_frame_V.rows());
  165. }
  166. // Concatenate Vert and Edge
  167. Eigen::MatrixXd V;
  168. Eigen::MatrixXi E;
  169. igl::cat(1, V_bnd, s.rect_frame_V, V);
  170. E.resize(V.rows(), 2);
  171. for (int i = 0; i < E.rows(); i++)
  172. E.row(i) << i, i + 1;
  173. int acc_bs = 0;
  174. for (auto bs : s.bnd_sizes)
  175. {
  176. E(acc_bs + bs - 1, 1) = acc_bs;
  177. acc_bs += bs;
  178. }
  179. E(V.rows() - 1, 1) = acc_bs;
  180. assert(acc_bs == s.internal_bnd.size());
  181. Eigen::MatrixXd H = Eigen::MatrixXd::Zero(s.component_sizes.size(), 2);
  182. {
  183. int hole_f = 0;
  184. int hole_i = 0;
  185. for (auto cs : s.component_sizes)
  186. {
  187. for (int i = 0; i < 3; i++)
  188. H.row(hole_i) += m_uv.row(s.m_T(hole_f, i)); // redoing step 2
  189. hole_f += cs;
  190. hole_i++;
  191. }
  192. }
  193. H /= 3.;
  194. Eigen::MatrixXd uv2;
  195. igl::triangle::triangulate(V, E, H, std::basic_string<char>("qYYQ"), uv2, s.s_T);
  196. auto bnd_n = s.internal_bnd.size();
  197. for (auto i = 0; i < s.s_T.rows(); i++)
  198. for (auto j = 0; j < s.s_T.cols(); j++)
  199. {
  200. auto &x = s.s_T(i, j);
  201. if (x < bnd_n)
  202. x = s.internal_bnd(x);
  203. else
  204. x += m_uv.rows() - bnd_n;
  205. }
  206. igl::cat(1, s.m_T, s.s_T, s.w_T);
  207. s.w_uv.conservativeResize(m_uv.rows() - bnd_n + uv2.rows(), 2);
  208. s.w_uv.bottomRows(uv2.rows() - bnd_n) = uv2.bottomRows(-bnd_n + uv2.rows());
  209. update_scaffold(s);
  210. // after_mesh_improve
  211. compute_scaffold_gradient_matrix(s, s.Dx_s, s.Dy_s);
  212. s.Dx_s.makeCompressed();
  213. s.Dy_s.makeCompressed();
  214. s.Dz_s.makeCompressed();
  215. s.Ri_s = Eigen::MatrixXd::Zero(s.Dx_s.rows(), s.dim * s.dim);
  216. s.Ji_s.resize(s.Dx_s.rows(), s.dim * s.dim);
  217. s.W_s.resize(s.Dx_s.rows(), s.dim * s.dim);
  218. }
  219. IGL_INLINE void add_new_patch(igl::triangle::SCAFData &s, const Eigen::MatrixXd &V_ref,
  220. const Eigen::MatrixXi &F_ref,
  221. const Eigen::RowVectorXd &/*center*/,
  222. const Eigen::MatrixXd &uv_init)
  223. {
  224. assert(uv_init.rows() != 0);
  225. Eigen::VectorXd M;
  226. igl::doublearea(V_ref, F_ref, M);
  227. s.mesh_measure += M.sum() / 2;
  228. Eigen::VectorXi bnd;
  229. Eigen::MatrixXd bnd_uv;
  230. std::vector<std::vector<int>> all_bnds;
  231. igl::boundary_loop(F_ref, all_bnds);
  232. s.component_sizes.push_back(F_ref.rows());
  233. Eigen::MatrixXd m_uv = s.w_uv.topRows(s.mv_num);
  234. igl::cat(1, m_uv, uv_init, s.w_uv);
  235. s.m_M.conservativeResize(s.mf_num + M.size());
  236. s.m_M.bottomRows(M.size()) = M / 2;
  237. for (auto cur_bnd : all_bnds)
  238. {
  239. s.internal_bnd.conservativeResize(s.internal_bnd.size() + cur_bnd.size());
  240. s.internal_bnd.bottomRows(cur_bnd.size()) = Eigen::Map<Eigen::ArrayXi>(cur_bnd.data(), cur_bnd.size()) + s.mv_num;
  241. s.bnd_sizes.push_back(cur_bnd.size());
  242. }
  243. s.m_T.conservativeResize(s.mf_num + F_ref.rows(), 3);
  244. s.m_T.bottomRows(F_ref.rows()) = F_ref.array() + s.mv_num;
  245. s.mf_num += F_ref.rows();
  246. s.m_V.conservativeResize(s.mv_num + V_ref.rows(), 3);
  247. s.m_V.bottomRows(V_ref.rows()) = V_ref;
  248. s.mv_num += V_ref.rows();
  249. s.rect_frame_V = Eigen::MatrixXd();
  250. mesh_improve(s);
  251. }
  252. IGL_INLINE void compute_jacobians(SCAFData &s, const Eigen::MatrixXd &V_new, bool whole)
  253. {
  254. auto comp_J2 = [](const Eigen::MatrixXd &uv,
  255. const Eigen::SparseMatrix<double> &Dx,
  256. const Eigen::SparseMatrix<double> &Dy,
  257. Eigen::MatrixXd &Ji) {
  258. // Ji=[D1*u,D2*u,D1*v,D2*v];
  259. Ji.resize(Dx.rows(), 4);
  260. Ji.col(0) = Dx * uv.col(0);
  261. Ji.col(1) = Dy * uv.col(0);
  262. Ji.col(2) = Dx * uv.col(1);
  263. Ji.col(3) = Dy * uv.col(1);
  264. };
  265. Eigen::MatrixXd m_V_new = V_new.topRows(s.mv_num);
  266. comp_J2(m_V_new, s.Dx_m, s.Dy_m, s.Ji_m);
  267. if (whole)
  268. comp_J2(V_new, s.Dx_s, s.Dy_s, s.Ji_s);
  269. }
  270. IGL_INLINE double compute_energy_from_jacobians(const Eigen::MatrixXd &Ji,
  271. const Eigen::VectorXd &areas,
  272. igl::MappingEnergyType energy_type)
  273. {
  274. double energy = 0;
  275. if (energy_type == igl::MappingEnergyType::SYMMETRIC_DIRICHLET)
  276. energy = -4; // comply with paper description
  277. return energy + igl::mapping_energy_with_jacobians(Ji, areas, energy_type, 0);
  278. }
  279. IGL_INLINE double compute_soft_constraint_energy(const SCAFData &s)
  280. {
  281. double e = 0;
  282. for (auto const &x : s.soft_cons)
  283. e += s.soft_const_p * (x.second - s.w_uv.row(x.first)).squaredNorm();
  284. return e;
  285. }
  286. IGL_INLINE double compute_energy(SCAFData &s, const Eigen::MatrixXd &w_uv, bool whole)
  287. {
  288. if (w_uv.rows() != s.v_num)
  289. assert(!whole);
  290. compute_jacobians(s, w_uv, whole);
  291. double energy = compute_energy_from_jacobians(s.Ji_m, s.m_M, s.slim_energy);
  292. if (whole)
  293. energy += compute_energy_from_jacobians(s.Ji_s, s.s_M, s.scaf_energy);
  294. energy += compute_soft_constraint_energy(s);
  295. return energy;
  296. }
  297. IGL_INLINE void buildAm(const Eigen::VectorXd &sqrt_M,
  298. const Eigen::SparseMatrix<double> &Dx,
  299. const Eigen::SparseMatrix<double> &Dy,
  300. const Eigen::MatrixXd &W,
  301. Eigen::SparseMatrix<double> &Am)
  302. {
  303. std::vector<Eigen::Triplet<double>> IJV;
  304. Eigen::SparseMatrix<double> Dz;
  305. Eigen::SparseMatrix<double> MDx = sqrt_M.asDiagonal() * Dx;
  306. Eigen::SparseMatrix<double> MDy = sqrt_M.asDiagonal() * Dy;
  307. igl::slim_buildA(MDx, MDy, Dz, W, IJV);
  308. Am.setFromTriplets(IJV.begin(), IJV.end());
  309. Am.makeCompressed();
  310. }
  311. IGL_INLINE void buildRhs(const Eigen::VectorXd &sqrt_M,
  312. const Eigen::MatrixXd &W,
  313. const Eigen::MatrixXd &Ri,
  314. Eigen::VectorXd &f_rhs)
  315. {
  316. const int dim = (W.cols() == 4) ? 2 : 3;
  317. const int f_n = W.rows();
  318. f_rhs.resize(dim * dim * f_n);
  319. for (int i = 0; i < f_n; i++)
  320. {
  321. auto sqrt_area = sqrt_M(i);
  322. f_rhs(i + 0 * f_n) = sqrt_area * (W(i, 0) * Ri(i, 0) + W(i, 1) * Ri(i, 1));
  323. f_rhs(i + 1 * f_n) = sqrt_area * (W(i, 0) * Ri(i, 2) + W(i, 1) * Ri(i, 3));
  324. f_rhs(i + 2 * f_n) = sqrt_area * (W(i, 2) * Ri(i, 0) + W(i, 3) * Ri(i, 1));
  325. f_rhs(i + 3 * f_n) = sqrt_area * (W(i, 2) * Ri(i, 2) + W(i, 3) * Ri(i, 3));
  326. }
  327. }
  328. IGL_INLINE void get_complement(const Eigen::VectorXi &bnd_ids, int v_n, Eigen::ArrayXi &unknown_ids)
  329. { // get the complement of bnd_ids.
  330. int assign = 0, i = 0;
  331. for (int get = 0; i < v_n && get < bnd_ids.size(); i++)
  332. {
  333. if (bnd_ids(get) == i)
  334. get++;
  335. else
  336. unknown_ids(assign++) = i;
  337. }
  338. while (i < v_n)
  339. unknown_ids(assign++) = i++;
  340. assert(assign + bnd_ids.size() == v_n);
  341. }
  342. IGL_INLINE void build_surface_linear_system(const SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
  343. {
  344. const int v_n = s.v_num - (s.frame_ids.size());
  345. const int dim = s.dim;
  346. const int f_n = s.mf_num;
  347. // to get the complete A
  348. Eigen::VectorXd sqrtM = s.m_M.array().sqrt();
  349. Eigen::SparseMatrix<double> A(dim * dim * f_n, dim * v_n);
  350. auto decoy_Dx_m = s.Dx_m;
  351. decoy_Dx_m.conservativeResize(s.W_m.rows(), v_n);
  352. auto decoy_Dy_m = s.Dy_m;
  353. decoy_Dy_m.conservativeResize(s.W_m.rows(), v_n);
  354. buildAm(sqrtM, decoy_Dx_m, decoy_Dy_m, s.W_m, A);
  355. const Eigen::VectorXi &bnd_ids = s.fixed_ids;
  356. auto bnd_n = bnd_ids.size();
  357. if (bnd_n == 0)
  358. {
  359. Eigen::SparseMatrix<double> At = A.transpose();
  360. At.makeCompressed();
  361. Eigen::SparseMatrix<double> id_m(At.rows(), At.rows());
  362. id_m.setIdentity();
  363. L = At * A;
  364. Eigen::VectorXd frhs;
  365. buildRhs(sqrtM, s.W_m, s.Ri_m, frhs);
  366. rhs = At * frhs;
  367. }
  368. else
  369. {
  370. Eigen::MatrixXd bnd_pos = s.w_uv(bnd_ids, igl::placeholders::all);
  371. Eigen::ArrayXi known_ids(bnd_ids.size() * dim);
  372. Eigen::ArrayXi unknown_ids((v_n - bnd_ids.rows()) * dim);
  373. get_complement(bnd_ids, v_n, unknown_ids);
  374. Eigen::VectorXd known_pos(bnd_ids.size() * dim);
  375. for (int d = 0; d < dim; d++)
  376. {
  377. auto n_b = bnd_ids.rows();
  378. known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n;
  379. known_pos.segment(d * n_b, n_b) = bnd_pos.col(d);
  380. unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) =
  381. unknown_ids.topRows(v_n - n_b) + d * v_n;
  382. }
  383. Eigen::SparseMatrix<double> Au, Ae;
  384. igl::slice(A, unknown_ids, 2, Au);
  385. igl::slice(A, known_ids, 2, Ae);
  386. Eigen::SparseMatrix<double> Aut = Au.transpose();
  387. Aut.makeCompressed();
  388. L = Aut * Au;
  389. Eigen::VectorXd frhs;
  390. buildRhs(sqrtM, s.W_m, s.Ri_m, frhs);
  391. rhs = Aut * (frhs - Ae * known_pos);
  392. }
  393. // add soft constraints.
  394. for (auto const &x : s.soft_cons)
  395. {
  396. int v_idx = x.first;
  397. for (int d = 0; d < dim; d++)
  398. {
  399. rhs(d * (v_n) + v_idx) += s.soft_const_p * x.second(d); // rhs
  400. L.coeffRef(d * v_n + v_idx,
  401. d * v_n + v_idx) += s.soft_const_p; // diagonal
  402. }
  403. }
  404. }
  405. IGL_INLINE void build_scaffold_linear_system(const SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
  406. {
  407. const int f_n = s.W_s.rows();
  408. const int v_n = s.Dx_s.cols();
  409. const int dim = s.dim;
  410. Eigen::VectorXd sqrtM = s.s_M.array().sqrt();
  411. Eigen::SparseMatrix<double> A(dim * dim * f_n, dim * v_n);
  412. buildAm(sqrtM, s.Dx_s, s.Dy_s, s.W_s, A);
  413. Eigen::VectorXi bnd_ids;
  414. igl::cat(1, s.fixed_ids, s.frame_ids, bnd_ids);
  415. auto bnd_n = bnd_ids.size();
  416. IGL_ASSERT(bnd_n > 0);
  417. Eigen::MatrixXd bnd_pos = s.w_uv(bnd_ids, igl::placeholders::all);
  418. Eigen::ArrayXi known_ids(bnd_ids.size() * dim);
  419. Eigen::ArrayXi unknown_ids((v_n - bnd_ids.rows()) * dim);
  420. get_complement(bnd_ids, v_n, unknown_ids);
  421. Eigen::VectorXd known_pos(bnd_ids.size() * dim);
  422. for (int d = 0; d < dim; d++)
  423. {
  424. auto n_b = bnd_ids.rows();
  425. known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n;
  426. known_pos.segment(d * n_b, n_b) = bnd_pos.col(d);
  427. unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) =
  428. unknown_ids.topRows(v_n - n_b) + d * v_n;
  429. }
  430. Eigen::VectorXd sqrt_M = s.s_M.array().sqrt();
  431. // manual slicing for A(:, unknown/known)'
  432. Eigen::SparseMatrix<double> Au, Ae;
  433. igl::slice(A, unknown_ids, 2, Au);
  434. igl::slice(A, known_ids, 2, Ae);
  435. Eigen::SparseMatrix<double> Aut = Au.transpose();
  436. Aut.makeCompressed();
  437. L = Aut * Au;
  438. Eigen::VectorXd frhs;
  439. buildRhs(sqrtM, s.W_s, s.Ri_s, frhs);
  440. rhs = Aut * (frhs - Ae * known_pos);
  441. }
  442. IGL_INLINE void build_weighted_arap_system(SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
  443. {
  444. // fixed frame solving:
  445. // x_e as the fixed frame, x_u for unknowns (mesh + unknown scaffold)
  446. // min ||(A_u*x_u + A_e*x_e) - b||^2
  447. // => A_u'*A_u*x_u = Au'* (b - A_e*x_e) := Au'* b_u
  448. //
  449. // separate matrix build:
  450. // min ||A_m x_m - b_m||^2 + ||A_s x_all - b_s||^2 + soft + proximal
  451. // First change dimension of A_m to fit for x_all
  452. // (Not just at the end, since x_all is flattened along dimensions)
  453. // L = A_m'*A_m + A_s'*A_s + soft + proximal
  454. // rhs = A_m'* b_m + A_s' * b_s + soft + proximal
  455. //
  456. Eigen::SparseMatrix<double> L_m, L_s;
  457. Eigen::VectorXd rhs_m, rhs_s;
  458. build_surface_linear_system(s, L_m, rhs_m); // complete Am, with soft
  459. build_scaffold_linear_system(s, L_s, rhs_s); // complete As, without proximal
  460. L = L_m + L_s;
  461. rhs = rhs_m + rhs_s;
  462. L.makeCompressed();
  463. }
  464. IGL_INLINE void solve_weighted_arap(SCAFData &s, Eigen::MatrixXd &uv)
  465. {
  466. int dim = s.dim;
  467. igl::Timer timer;
  468. timer.start();
  469. Eigen::VectorXi bnd_ids;
  470. igl::cat(1, s.fixed_ids, s.frame_ids, bnd_ids);
  471. const auto v_n = s.v_num;
  472. const auto bnd_n = bnd_ids.size();
  473. assert(bnd_n > 0);
  474. Eigen::MatrixXd bnd_pos = s.w_uv(bnd_ids, igl::placeholders::all);
  475. Eigen::ArrayXi known_ids(bnd_n * dim);
  476. Eigen::ArrayXi unknown_ids((v_n - bnd_n) * dim);
  477. get_complement(bnd_ids, v_n, unknown_ids);
  478. Eigen::VectorXd known_pos(bnd_ids.size() * dim);
  479. for (int d = 0; d < dim; d++)
  480. {
  481. auto n_b = bnd_ids.rows();
  482. known_ids.segment(d * n_b, n_b) = bnd_ids.array() + d * v_n;
  483. known_pos.segment(d * n_b, n_b) = bnd_pos.col(d);
  484. unknown_ids.block(d * (v_n - n_b), 0, v_n - n_b, unknown_ids.cols()) =
  485. unknown_ids.topRows(v_n - n_b) + d * v_n;
  486. }
  487. Eigen::SparseMatrix<double> L;
  488. Eigen::VectorXd rhs;
  489. build_weighted_arap_system(s, L, rhs);
  490. Eigen::VectorXd unknown_Uc((v_n - s.frame_ids.size() - s.fixed_ids.size()) * dim), Uc(dim * v_n);
  491. Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
  492. unknown_Uc = solver.compute(L).solve(rhs);
  493. Uc(unknown_ids) = unknown_Uc;
  494. Uc(known_ids) = known_pos;
  495. uv = Eigen::Map<Eigen::Matrix<double, -1, -1, Eigen::ColMajor>>(Uc.data(), v_n, dim);
  496. }
  497. IGL_INLINE double perform_iteration(SCAFData &s)
  498. {
  499. Eigen::MatrixXd V_out = s.w_uv;
  500. compute_jacobians(s, V_out, true);
  501. igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_m, s.slim_energy, 0, s.W_m, s.Ri_m);
  502. igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_s, s.scaf_energy, 0, s.W_s, s.Ri_s);
  503. solve_weighted_arap(s, V_out);
  504. std::function<double(Eigen::MatrixXd&)> whole_E = [&s](Eigen::MatrixXd &uv) { return compute_energy(s, uv, true); };
  505. Eigen::MatrixXi w_T;
  506. if (s.m_T.cols() == s.s_T.cols())
  507. igl::cat(1, s.m_T, s.s_T, w_T);
  508. else
  509. w_T = s.s_T;
  510. return igl::flip_avoiding_line_search( w_T, s.w_uv, V_out, whole_E, -1) /
  511. s.mesh_measure;
  512. }
  513. }
  514. }
  515. }
  516. IGL_INLINE void igl::triangle::scaf_precompute(
  517. const Eigen::MatrixXd &V,
  518. const Eigen::MatrixXi &F,
  519. const Eigen::MatrixXd &V_init,
  520. const igl::MappingEnergyType slim_energy,
  521. const Eigen::VectorXi &b,
  522. const Eigen::MatrixXd &bc,
  523. const double soft_p,
  524. igl::triangle::SCAFData &data)
  525. {
  526. Eigen::MatrixXd CN;
  527. Eigen::MatrixXi FN;
  528. igl::triangle::scaf::add_new_patch(data, V, F, Eigen::RowVector2d(0, 0), V_init);
  529. data.soft_const_p = soft_p;
  530. for (int i = 0; i < b.rows(); i++)
  531. data.soft_cons[b(i)] = bc.row(i);
  532. data.slim_energy = slim_energy;
  533. auto &s = data;
  534. if (!data.has_pre_calc)
  535. {
  536. int dim = s.dim;
  537. Eigen::MatrixXd F1, F2, F3;
  538. igl::local_basis(s.m_V, s.m_T, F1, F2, F3);
  539. auto face_proj = [](Eigen::MatrixXd& F){
  540. std::vector<Eigen::Triplet<double> >IJV;
  541. int f_num = F.rows();
  542. for(int i=0; i<F.rows(); i++) {
  543. IJV.push_back(Eigen::Triplet<double>(i, i, F(i,0)));
  544. IJV.push_back(Eigen::Triplet<double>(i, i+f_num, F(i,1)));
  545. IJV.push_back(Eigen::Triplet<double>(i, i+2*f_num, F(i,2)));
  546. }
  547. Eigen::SparseMatrix<double> P(f_num, 3*f_num);
  548. P.setFromTriplets(IJV.begin(), IJV.end());
  549. return P;
  550. };
  551. Eigen::SparseMatrix<double> G;
  552. igl::grad(s.m_V, s.m_T, G);
  553. s.Dx_m = face_proj(F1) * G;
  554. s.Dy_m = face_proj(F2) * G;
  555. igl::triangle::scaf::compute_scaffold_gradient_matrix(s, s.Dx_s, s.Dy_s);
  556. s.Dx_m.makeCompressed();
  557. s.Dy_m.makeCompressed();
  558. s.Ri_m = Eigen::MatrixXd::Zero(s.Dx_m.rows(), dim * dim);
  559. s.Ji_m.resize(s.Dx_m.rows(), dim * dim);
  560. s.W_m.resize(s.Dx_m.rows(), dim * dim);
  561. s.Dx_s.makeCompressed();
  562. s.Dy_s.makeCompressed();
  563. s.Ri_s = Eigen::MatrixXd::Zero(s.Dx_s.rows(), dim * dim);
  564. s.Ji_s.resize(s.Dx_s.rows(), dim * dim);
  565. s.W_s.resize(s.Dx_s.rows(), dim * dim);
  566. data.has_pre_calc = true;
  567. }
  568. }
  569. IGL_INLINE Eigen::MatrixXd igl::triangle::scaf_solve(const int iter_num, igl::triangle::SCAFData &s)
  570. {
  571. s.energy = igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure;
  572. for (int it = 0; it < iter_num; it++)
  573. {
  574. s.total_energy = igl::triangle::scaf::compute_energy(s, s.w_uv, true) / s.mesh_measure;
  575. s.rect_frame_V = Eigen::MatrixXd();
  576. igl::triangle::scaf::mesh_improve(s);
  577. double new_weight = s.mesh_measure * s.energy / (s.sf_num * 100);
  578. s.scaffold_factor = new_weight;
  579. igl::triangle::scaf::update_scaffold(s);
  580. s.total_energy = igl::triangle::scaf::perform_iteration(s);
  581. s.energy =
  582. igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure;
  583. }
  584. return s.w_uv.topRows(s.mv_num);
  585. }
  586. IGL_INLINE void igl::triangle::scaf_system(igl::triangle::SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
  587. {
  588. s.energy = igl::triangle::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure;
  589. s.total_energy = igl::triangle::scaf::compute_energy(s, s.w_uv, true) / s.mesh_measure;
  590. s.rect_frame_V = Eigen::MatrixXd();
  591. igl::triangle::scaf::mesh_improve(s);
  592. double new_weight = s.mesh_measure * s.energy / (s.sf_num * 100);
  593. s.scaffold_factor = new_weight;
  594. igl::triangle::scaf::update_scaffold(s);
  595. igl::triangle::scaf::compute_jacobians(s, s.w_uv, true);
  596. igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_m, s.slim_energy, 0, s.W_m, s.Ri_m);
  597. igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_s, s.scaf_energy, 0, s.W_s, s.Ri_s);
  598. igl::triangle::scaf::build_weighted_arap_system(s, L, rhs);
  599. }
  600. #ifdef IGL_STATIC_LIBRARY
  601. #endif