frame_field.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203
  1. #include "frame_field.h"
  2. #include <igl/tt.h>
  3. #include <igl/edgetopology.h>
  4. #include <igl/per_face_normals.h>
  5. #include <igl/comiso/nrosy.h>
  6. #include <iostream>
  7. namespace igl
  8. {
  9. class FrameInterpolator
  10. {
  11. public:
  12. // Constraint type
  13. enum ConstraintType { FREE, SOFT, HARD };
  14. // Init
  15. IGL_INLINE FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F);
  16. IGL_INLINE ~FrameInterpolator();
  17. // Generate the frame field
  18. IGL_INLINE void solve(bool hard_const);
  19. IGL_INLINE void setConstraint(const int fid, const Eigen::VectorXd& v, ConstraintType type = HARD);
  20. IGL_INLINE void setConstraintProportionalScale(const int fid, const double scale, ConstraintType type = HARD);
  21. // Set the ratio between smoothness and soft constraints (0 -> smoothness only, 1 -> soft constr only)
  22. IGL_INLINE void setSoftAlpha(double alpha);
  23. // Reset constraints (at least one constraint must be present or solve will fail)
  24. IGL_INLINE void resetConstraints();
  25. // Return the current field
  26. IGL_INLINE Eigen::MatrixXd getFieldPerFace();
  27. // Return the singularities
  28. IGL_INLINE Eigen::VectorXd getSingularityIndexPerVertex();
  29. // -------------- This is untested and unstable code
  30. IGL_INLINE void setConstraint_polar(const int fid, const Eigen::VectorXd& v, ConstraintType type);
  31. IGL_INLINE void interpolateSymmetric_polar(const bool bilaplacian);
  32. // Generate the frame field
  33. IGL_INLINE void solve_polar(const bool bilaplacian,bool hard_const);
  34. // Convert the frame field in the canonical representation
  35. IGL_INLINE void frame2canonical_polar(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S);
  36. // Convert the canonical representation in a frame field
  37. IGL_INLINE void canonical2frame_polar(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S, Eigen::RowVectorXd& v);
  38. IGL_INLINE Eigen::MatrixXd getFieldPerFace_polar();
  39. IGL_INLINE void PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P);
  40. // Symmetric
  41. Eigen::MatrixXd S_polar;
  42. std::vector<ConstraintType> S_polar_c;
  43. // -------------------------------------------------
  44. // Face Topology
  45. Eigen::MatrixXi TT, TTi;
  46. // Two faces are consistent if their representative vector are taken modulo PI
  47. std::vector<bool> edge_consistency;
  48. Eigen::MatrixXi edge_consistency_TT;
  49. private:
  50. IGL_INLINE double mod2pi(double d);
  51. IGL_INLINE double modpi2(double d);
  52. IGL_INLINE double modpi(double d);
  53. // Convert a direction on the tangent space into an angle
  54. IGL_INLINE double vector2theta(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v);
  55. // Convert an angle in a vector in the tangent space
  56. IGL_INLINE Eigen::RowVectorXd theta2vector(const Eigen::MatrixXd& TP, const double theta);
  57. // Convert the frame field in the canonical representation
  58. IGL_INLINE void frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, double& beta, Eigen::RowVectorXd& d);
  59. // Convert the canonical representation in a frame field
  60. IGL_INLINE void canonical2frame(const Eigen::MatrixXd& TP, const double theta, const double beta, const Eigen::RowVectorXd& d, Eigen::RowVectorXd& v);
  61. // Interpolate the cross field (theta)
  62. IGL_INLINE void interpolateCross(bool hard_const);
  63. // Interpolate the skewness (beta)
  64. IGL_INLINE void interpolateSkewness();
  65. // Interpolate the scale (d)
  66. IGL_INLINE void interpolateScale();
  67. // Compute difference between reference frames
  68. IGL_INLINE void computek();
  69. // Compute edge consistency
  70. IGL_INLINE void compute_edge_consistency();
  71. // Cross field direction
  72. Eigen::VectorXd thetas;
  73. std::vector<ConstraintType> thetas_c;
  74. // Skewness
  75. Eigen::VectorXd betas;
  76. std::vector<ConstraintType> betas_c;
  77. // Scale
  78. Eigen::MatrixXd ds;
  79. std::vector<ConstraintType> ds_c;
  80. // Soft constraints strenght
  81. double softAlpha;
  82. // Edge Topology
  83. Eigen::MatrixXi EV, FE, EF;
  84. std::vector<bool> isBorderEdge;
  85. // Angle between two reference frames
  86. // R(k) * t0 = t1
  87. Eigen::VectorXd k;
  88. // Mesh
  89. Eigen::MatrixXd V;
  90. Eigen::MatrixXi F;
  91. // Normals per face
  92. Eigen::MatrixXd N;
  93. // Singularity index
  94. Eigen::VectorXd singularityIndex;
  95. // Reference frame per triangle
  96. std::vector<Eigen::MatrixXd> TPs;
  97. };
  98. FrameInterpolator::FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
  99. {
  100. using namespace std;
  101. using namespace Eigen;
  102. V = _V;
  103. F = _F;
  104. assert(V.rows() > 0);
  105. assert(F.rows() > 0);
  106. // Generate topological relations
  107. igl::tt(V,F,TT,TTi);
  108. igl::edgetopology(V,F, EV, FE, EF);
  109. // Flag border edges
  110. isBorderEdge.resize(EV.rows());
  111. for(unsigned i=0; i<EV.rows(); ++i)
  112. isBorderEdge[i] = (EF(i,0) == -1) || ((EF(i,1) == -1));
  113. // Generate normals per face
  114. igl::per_face_normals(V, F, N);
  115. // Generate reference frames
  116. for(unsigned fid=0; fid<F.rows(); ++fid)
  117. {
  118. // First edge
  119. Vector3d e1 = V.row(F(fid,1)) - V.row(F(fid,0));
  120. e1.normalize();
  121. Vector3d e2 = N.row(fid);
  122. e2 = e2.cross(e1);
  123. e2.normalize();
  124. MatrixXd TP(2,3);
  125. TP << e1.transpose(), e2.transpose();
  126. TPs.push_back(TP);
  127. }
  128. // Reset the constraints
  129. resetConstraints();
  130. // Compute k, differences between reference frames
  131. computek();
  132. softAlpha = 0.5;
  133. // Alloc internal variables
  134. thetas = VectorXd::Zero(F.rows());
  135. // thetas_c.resize(F.rows());
  136. betas = VectorXd::Zero(F.rows());
  137. // betas_c.resize(F.rows());
  138. ds = MatrixXd::Constant(F.rows(),2,1);
  139. // ds_c.resize(F.rows());
  140. S_polar = MatrixXd::Zero(F.rows(),3);
  141. // S_polar_c.resize(F.rows());
  142. singularityIndex = VectorXd::Zero(V.rows());
  143. compute_edge_consistency();
  144. }
  145. FrameInterpolator::~FrameInterpolator()
  146. {
  147. }
  148. void FrameInterpolator::solve(bool hard_const)
  149. {
  150. interpolateCross(hard_const);
  151. interpolateSkewness();
  152. interpolateScale();
  153. }
  154. void FrameInterpolator::setConstraint(const int fid, const Eigen::VectorXd& v, ConstraintType type)
  155. {
  156. using namespace std;
  157. using namespace Eigen;
  158. double t_;
  159. double b_;
  160. RowVectorXd d_;
  161. frame2canonical(TPs[fid],v,t_,b_,d_);
  162. // cerr << "TP: " << endl << TPs[fid] << endl;
  163. // cerr << "v: " << endl << TPs[fid] << endl;
  164. // cerr << "t_: " << endl << TPs[fid] << endl;
  165. // cerr << "b_: " << endl << TPs[fid] << endl;
  166. // cerr << "d_: " << endl << TPs[fid] << endl;
  167. Eigen::RowVectorXd v2;
  168. canonical2frame(TPs[fid], t_, b_, d_, v2);
  169. // cerr << "Cosntraint: " << t_ << " " << b_ << " " << d_ << endl;
  170. // cerr << "Compare: " << endl << v.transpose() << endl << v2 << endl;
  171. thetas(fid) = t_;
  172. thetas_c[fid] = type;
  173. betas(fid) = b_;
  174. betas_c[fid] = type;
  175. ds.row(fid) = d_;
  176. ds_c[fid] = type;
  177. }
  178. void FrameInterpolator::setConstraintProportionalScale(const int fid, const double scale, ConstraintType type)
  179. {
  180. using namespace std;
  181. using namespace Eigen;
  182. assert(scale>0);
  183. ds.row(fid) = ds.row(fid) * scale;
  184. ds_c[fid] = type;
  185. }
  186. void FrameInterpolator::setSoftAlpha(double alpha)
  187. {
  188. assert(alpha >= 0 && alpha <= 1);
  189. softAlpha = alpha;
  190. }
  191. Eigen::MatrixXd FrameInterpolator::getFieldPerFace()
  192. {
  193. Eigen::MatrixXd R(F.rows(),6);
  194. for (unsigned i=0; i<F.rows(); ++i)
  195. {
  196. Eigen::RowVectorXd v;
  197. canonical2frame(TPs[i],thetas(i),betas(i),ds.row(i),v);
  198. R.row(i) = v;
  199. }
  200. return R;
  201. }
  202. Eigen::VectorXd FrameInterpolator::getSingularityIndexPerVertex()
  203. {
  204. assert(0);
  205. }
  206. double FrameInterpolator::mod2pi(double d)
  207. {
  208. while(d<0)
  209. d = d + (2.0*M_PI);
  210. return fmod(d, (2.0*M_PI));
  211. }
  212. double FrameInterpolator::modpi2(double d)
  213. {
  214. while(d<0)
  215. d = d + (M_PI/2.0);
  216. return fmod(d, (M_PI/2.0));
  217. }
  218. double FrameInterpolator::modpi(double d)
  219. {
  220. while(d<0)
  221. d = d + (M_PI);
  222. return fmod(d, (M_PI));
  223. }
  224. double FrameInterpolator::vector2theta(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v)
  225. {
  226. // Project onto the tangent plane
  227. Eigen::Vector2d vp = TP * v.transpose();
  228. // Convert to angle
  229. double theta = atan2(vp(1),vp(0));
  230. // cerr << v << endl << theta2vector(TP, theta) << endl;
  231. // assert((v.normalized() - theta2vector(TP, theta)).norm() < 10e-5);
  232. return theta;
  233. }
  234. Eigen::RowVectorXd FrameInterpolator::theta2vector(const Eigen::MatrixXd& TP, const double theta)
  235. {
  236. Eigen::Vector2d vp(cos(theta),sin(theta));
  237. return vp.transpose() * TP;
  238. }
  239. void FrameInterpolator::frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, double& beta, Eigen::RowVectorXd& d)
  240. {
  241. using namespace std;
  242. using namespace Eigen;
  243. bool debug = false;
  244. if (debug)
  245. {
  246. cerr << "TP:" << endl << TP << endl;
  247. cerr << "v:" << endl << v << endl;
  248. }
  249. RowVectorXd v0 = v.segment<3>(0);
  250. RowVectorXd v1 = v.segment<3>(3);
  251. if (debug)
  252. {
  253. cerr << "v0:" << endl << v0 << endl;
  254. cerr << "v1:" << endl << v1 << endl;
  255. }
  256. // Find canonical cross field
  257. double theta0 = mod2pi(vector2theta(TP,v0));
  258. double theta1 = mod2pi(vector2theta(TP,v1));
  259. //cerr << mod2pi(theta0) << " " << mod2pi(theta1) << endl;
  260. // Find the closest pair
  261. // if (mod2pi(abs(theta0 + M_PI - theta1)) < mod2pi(abs(theta0 - theta1)))
  262. // theta0 = theta0 + M_PI;
  263. // Express theta1 as a displacement wrt theta0
  264. theta1 = mod2pi(theta1 - theta0);
  265. // Find the closest representative
  266. if (theta1 > M_PI)
  267. theta1 -= M_PI;
  268. assert(theta1 < M_PI);
  269. // Extract theta and beta
  270. theta = mod2pi(theta1/2.0 + theta0);
  271. beta = theta1/2.0;
  272. //cerr << mod2pi(beta + theta) << " " << mod2pi(-beta + theta) << endl;
  273. d.resize(2);
  274. // Find the scaling factors
  275. d(0) = v0.norm();
  276. d(1) = v1.norm();
  277. if (debug)
  278. {
  279. cerr << "d:" << endl << d << endl;
  280. cerr << "thetavector:" << endl << theta2vector(TP, theta) << endl;
  281. }
  282. }
  283. void FrameInterpolator::canonical2frame(const Eigen::MatrixXd& TP, const double theta, const double beta, const Eigen::RowVectorXd& d, Eigen::RowVectorXd& v)
  284. {
  285. using namespace std;
  286. using namespace Eigen;
  287. assert(d.cols() == 2 && d.rows() == 1);
  288. double theta0 = theta + M_PI - beta;
  289. double theta1 = theta + M_PI + beta;
  290. RowVectorXd v0 = theta2vector(TP,modpi(theta0)) * d(0);
  291. RowVectorXd v1 = theta2vector(TP,modpi(theta1)) * d(1);
  292. // cerr << "v0 : " << v0 << endl;
  293. // cerr << "v1 : " << v1 << endl;
  294. v.resize(6);
  295. v << v0, v1;
  296. }
  297. void FrameInterpolator::interpolateCross(bool hard_const)
  298. {
  299. using namespace std;
  300. using namespace Eigen;
  301. NRosyField nrosy(V,F);
  302. nrosy.setSoftAlpha(softAlpha);
  303. for (unsigned i=0; i<F.rows(); ++i)
  304. {
  305. switch (thetas_c[i])
  306. {
  307. case FREE:
  308. break;
  309. case SOFT:
  310. // nrosy.setConstraintSoft(i,1,theta2vector(TPs[i],thetas(i)));
  311. // cerr << theta2vector(TPs[i],thetas(i)) << endl;
  312. // break;
  313. case HARD:
  314. // nrosy.setConstraintHard(i,theta2vector(TPs[i],thetas(i)));
  315. if (hard_const)
  316. nrosy.setConstraintHard(i,theta2vector(TPs[i],thetas(i)));
  317. else
  318. nrosy.setConstraintSoft(i,1,theta2vector(TPs[i],thetas(i)));
  319. break;
  320. default:
  321. assert(0);
  322. }
  323. }
  324. nrosy.solve(4);
  325. MatrixXd R = nrosy.getFieldPerFace();
  326. // std::cerr << "Cross: " << R << std::endl;
  327. assert(R.rows() == F.rows());
  328. for (unsigned i=0; i<F.rows(); ++i)
  329. if (thetas_c[i] != HARD)
  330. thetas(i) = vector2theta(TPs[i],R.row(i));
  331. }
  332. void FrameInterpolator::interpolateSkewness()
  333. {
  334. using namespace std;
  335. using namespace Eigen;
  336. compute_edge_consistency();
  337. // Generate enriched Laplacian matrix (see notes)
  338. typedef Eigen::Triplet<double> triplet;
  339. std::vector<triplet> triplets;
  340. triplets.reserve(4*F.rows());
  341. VectorXd b = VectorXd::Zero(F.rows());
  342. // Build L and b
  343. for (unsigned eid=0; eid<EF.rows(); ++eid)
  344. {
  345. if (!isBorderEdge[eid])
  346. {
  347. int i = EF(eid,0);
  348. int j = EF(eid,1);
  349. double v = edge_consistency[eid]? 1 : -1;
  350. // Off-diagonal, symmetric
  351. triplets.push_back(triplet(i,j,v));
  352. triplets.push_back(triplet(j,i,v));
  353. // Diagonal
  354. triplets.push_back(triplet(i,i,-1));
  355. triplets.push_back(triplet(j,j,-1));
  356. if (!edge_consistency[eid])
  357. {
  358. b(i) -= M_PI/2.0; // CHECK
  359. b(j) -= M_PI/2.0; // CHECK
  360. }
  361. }
  362. }
  363. // Add soft constraints
  364. double w = 100000;
  365. for (unsigned fid=0; fid < F.rows(); ++fid)
  366. {
  367. if (betas_c[fid] != FREE)
  368. {
  369. triplets.push_back(triplet(fid,fid,w));
  370. b(fid) += w*betas(fid);
  371. }
  372. }
  373. SparseMatrix<double> L(F.rows(),F.rows());
  374. L.setFromTriplets(triplets.begin(), triplets.end());
  375. // Solve Lx = b;
  376. SimplicialLDLT<SparseMatrix<double> > solver;
  377. solver.compute(L);
  378. if(solver.info()!=Success)
  379. {
  380. std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl;
  381. assert(0);
  382. }
  383. VectorXd x;
  384. x = solver.solve(b);
  385. // cerr << "Skewness: " << x << endl;
  386. if(solver.info()!=Success)
  387. {
  388. std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl;
  389. assert(0);
  390. }
  391. // Copy back the result
  392. betas = x;
  393. }
  394. void FrameInterpolator::interpolateScale()
  395. {
  396. using namespace std;
  397. using namespace Eigen;
  398. compute_edge_consistency();
  399. // Generate enriched Laplacian matrix (see notes)
  400. // the variables here are d1, d2
  401. typedef Eigen::Triplet<double> triplet;
  402. std::vector<triplet> triplets;
  403. triplets.reserve(4*F.rows()*2);
  404. VectorXd b = VectorXd::Zero(F.rows()*2);
  405. // Build L and b
  406. for (unsigned eid=0; eid<EF.rows(); ++eid)
  407. {
  408. if (!isBorderEdge[eid])
  409. {
  410. int d1 = EF(eid,0);
  411. int d2 = EF(eid,0)+F.rows();
  412. int d1p = EF(eid,1);
  413. int d2p = EF(eid,1)+F.rows();
  414. if (edge_consistency[eid])
  415. {
  416. triplets.push_back(triplet(d1 ,d1p,1));
  417. triplets.push_back(triplet(d2 ,d2p,1));
  418. triplets.push_back(triplet(d1p,d1 ,1));
  419. triplets.push_back(triplet(d2p,d2 ,1));
  420. }
  421. else
  422. {
  423. triplets.push_back(triplet(d1 ,d2p,1));
  424. triplets.push_back(triplet(d2 ,d1p,1));
  425. triplets.push_back(triplet(d1p,d2 ,1));
  426. triplets.push_back(triplet(d2p,d1 ,1));
  427. }
  428. // Diagonal
  429. triplets.push_back(triplet(d1,d1, -1));
  430. triplets.push_back(triplet(d2,d2, -1));
  431. triplets.push_back(triplet(d1p,d1p,-1));
  432. triplets.push_back(triplet(d2p,d2p,-1));
  433. }
  434. }
  435. // Add soft constraints
  436. double w = 100000;
  437. for (unsigned fid=0; fid < F.rows(); ++fid)
  438. {
  439. if (ds_c[fid] != FREE)
  440. {
  441. int d1 = fid;
  442. int d2 = fid + F.rows();
  443. triplets.push_back(triplet(d1,d1,w));
  444. b(d1) += w*ds(fid,0);
  445. triplets.push_back(triplet(d2,d2,w));
  446. b(d2) += w*ds(fid,1);
  447. }
  448. }
  449. SparseMatrix<double> L(F.rows()*2,F.rows()*2);
  450. L.setFromTriplets(triplets.begin(), triplets.end());
  451. // Solve Lx = b;
  452. SimplicialLDLT<SparseMatrix<double> > solver;
  453. solver.compute(L);
  454. if(solver.info()!=Success)
  455. {
  456. std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl;
  457. assert(0);
  458. }
  459. VectorXd x;
  460. x = solver.solve(b);
  461. // cerr << "Scale: " << endl << x << endl;
  462. if(solver.info()!=Success)
  463. {
  464. std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl;
  465. assert(0);
  466. }
  467. // Copy back the result
  468. ds << x.block(0, 0, ds.rows(), 1), x.block(ds.rows(), 0, ds.rows(), 1);
  469. }
  470. void FrameInterpolator::resetConstraints()
  471. {
  472. thetas_c.resize(F.rows());
  473. betas_c.resize(F.rows());
  474. ds_c.resize(F.rows());
  475. S_polar_c.resize(F.rows());
  476. for(unsigned i=0; i<F.rows(); ++i)
  477. {
  478. thetas_c[i] = FREE;
  479. betas_c[i] = FREE;
  480. ds_c[i] = FREE;
  481. S_polar_c[i] = FREE;
  482. }
  483. }
  484. void FrameInterpolator::compute_edge_consistency()
  485. {
  486. using namespace std;
  487. using namespace Eigen;
  488. // Compute per-edge consistency
  489. edge_consistency.resize(EF.rows());
  490. edge_consistency_TT = MatrixXi::Constant(TT.rows(),3,-1);
  491. // For every non-border edge
  492. for (unsigned eid=0; eid<EF.rows(); ++eid)
  493. {
  494. if (!isBorderEdge[eid])
  495. {
  496. int fid0 = EF(eid,0);
  497. int fid1 = EF(eid,1);
  498. double theta0 = thetas(fid0);
  499. double theta1 = thetas(fid1);
  500. theta0 = theta0 + k(eid);
  501. double r = modpi(theta0-theta1);
  502. edge_consistency[eid] = r < M_PI/4.0 || r > 3*(M_PI/4.0);
  503. // Copy it into edge_consistency_TT
  504. int i1 = -1;
  505. int i2 = -1;
  506. for (unsigned i=0; i<3; ++i)
  507. {
  508. if (TT(fid0,i) == fid1)
  509. i1 = i;
  510. if (TT(fid1,i) == fid0)
  511. i2 = i;
  512. }
  513. assert(i1 != -1);
  514. assert(i2 != -1);
  515. edge_consistency_TT(fid0,i1) = edge_consistency[eid];
  516. edge_consistency_TT(fid1,i2) = edge_consistency[eid];
  517. }
  518. }
  519. }
  520. void FrameInterpolator::computek()
  521. {
  522. using namespace std;
  523. using namespace Eigen;
  524. k.resize(EF.rows());
  525. // For every non-border edge
  526. for (unsigned eid=0; eid<EF.rows(); ++eid)
  527. {
  528. if (!isBorderEdge[eid])
  529. {
  530. int fid0 = EF(eid,0);
  531. int fid1 = EF(eid,1);
  532. Vector3d N0 = N.row(fid0);
  533. //Vector3d N1 = N.row(fid1);
  534. // find common edge on triangle 0 and 1
  535. int fid0_vc = -1;
  536. int fid1_vc = -1;
  537. for (unsigned i=0;i<3;++i)
  538. {
  539. if (EV(eid,0) == F(fid0,i))
  540. fid0_vc = i;
  541. if (EV(eid,1) == F(fid1,i))
  542. fid1_vc = i;
  543. }
  544. assert(fid0_vc != -1);
  545. assert(fid1_vc != -1);
  546. Vector3d common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
  547. common_edge.normalize();
  548. // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
  549. MatrixXd P(3,3);
  550. VectorXd o = V.row(F(fid0,fid0_vc));
  551. VectorXd tmp = -N0.cross(common_edge);
  552. P << common_edge, tmp, N0;
  553. P.transposeInPlace();
  554. MatrixXd V0(3,3);
  555. V0.row(0) = V.row(F(fid0,0)).transpose() -o;
  556. V0.row(1) = V.row(F(fid0,1)).transpose() -o;
  557. V0.row(2) = V.row(F(fid0,2)).transpose() -o;
  558. V0 = (P*V0.transpose()).transpose();
  559. assert(V0(0,2) < 10e-10);
  560. assert(V0(1,2) < 10e-10);
  561. assert(V0(2,2) < 10e-10);
  562. MatrixXd V1(3,3);
  563. V1.row(0) = V.row(F(fid1,0)).transpose() -o;
  564. V1.row(1) = V.row(F(fid1,1)).transpose() -o;
  565. V1.row(2) = V.row(F(fid1,2)).transpose() -o;
  566. V1 = (P*V1.transpose()).transpose();
  567. assert(V1(fid1_vc,2) < 10e-10);
  568. assert(V1((fid1_vc+1)%3,2) < 10e-10);
  569. // compute rotation R such that R * N1 = N0
  570. // i.e. map both triangles to the same plane
  571. double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
  572. MatrixXd R(3,3);
  573. R << 1, 0, 0,
  574. 0, cos(alpha), -sin(alpha) ,
  575. 0, sin(alpha), cos(alpha);
  576. V1 = (R*V1.transpose()).transpose();
  577. assert(V1(0,2) < 10e-10);
  578. assert(V1(1,2) < 10e-10);
  579. assert(V1(2,2) < 10e-10);
  580. // measure the angle between the reference frames
  581. // k_ij is the angle between the triangle on the left and the one on the right
  582. VectorXd ref0 = V0.row(1) - V0.row(0);
  583. VectorXd ref1 = V1.row(1) - V1.row(0);
  584. ref0.normalize();
  585. ref1.normalize();
  586. double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
  587. // just to be sure, rotate ref0 using angle ktemp...
  588. MatrixXd R2(2,2);
  589. R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
  590. tmp = R2*ref0.head<2>();
  591. assert(tmp(0) - ref1(0) < (0.000001));
  592. assert(tmp(1) - ref1(1) < (0.000001));
  593. k[eid] = ktemp;
  594. }
  595. }
  596. }
  597. void FrameInterpolator::frame2canonical_polar(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S_v)
  598. {
  599. using namespace std;
  600. using namespace Eigen;
  601. RowVectorXd v0 = v.segment<3>(0);
  602. RowVectorXd v1 = v.segment<3>(3);
  603. // Project onto the tangent plane
  604. Vector2d vp0 = TP * v0.transpose();
  605. Vector2d vp1 = TP * v1.transpose();
  606. // Assemble matrix
  607. MatrixXd M(2,2);
  608. M << vp0, vp1;
  609. if (M.determinant() < 0)
  610. M.col(1) = -M.col(1);
  611. assert(M.determinant() > 0);
  612. // cerr << "M: " << M << endl;
  613. MatrixXd R,S;
  614. // PolarDecomposition
  615. PolarDecomposition(M,R,S);
  616. // cerr << M << endl;
  617. // cerr << "--------" << endl;
  618. // cerr << R*S << endl;
  619. // Finally, express the cross field as an angle
  620. theta = atan2(R(1,0),R(0,0)); // atan2(R(1,0),R(0,0));
  621. MatrixXd R2(2,2);
  622. R2 << cos(theta), -sin(theta), sin(theta), cos(theta);
  623. // cerr << "R: " << R << endl;
  624. // cerr << "Should be zero2: " << R2-R << endl;
  625. assert((R2-R).norm() < 10e-8);
  626. // Convert into rotation invariant form
  627. S = R * S * R.inverse();
  628. // cerr << "R" << endl << R << endl;
  629. // cerr << "S" << endl << S << endl;
  630. // Copy in vector form
  631. S_v = VectorXd(3);
  632. S_v << S(0,0), S(0,1), S(1,1);
  633. }
  634. void FrameInterpolator::canonical2frame_polar(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S_v, Eigen::RowVectorXd& v)
  635. {
  636. using namespace std;
  637. using namespace Eigen;
  638. assert(S_v.size() == 3);
  639. MatrixXd S(2,2);
  640. S << S_v(0), S_v(1), S_v(1), S_v(2);
  641. // Convert angle in vector in the tangent plane
  642. // Vector2d vp(cos(theta),sin(theta));
  643. // First reconstruct R
  644. MatrixXd R(2,2);
  645. // R.col(0) << cos(theta), sin(theta);
  646. // R(0,1) = -R(1,0);
  647. // R(1,1) = R(0,0);
  648. R << cos(theta), -sin(theta), sin(theta), cos(theta);
  649. // cerr << "R2" << endl << R << endl;
  650. // cerr << "S2" << endl << S << endl;
  651. // Multiply to reconstruct
  652. //MatrixXd M = R * S;
  653. // Rotation invariant reconstruction
  654. MatrixXd M = S * R;
  655. // cerr << "M2: " << M << endl;
  656. Vector2d vp0(M(0,0),M(1,0));
  657. Vector2d vp1(M(0,1),M(1,1));
  658. // Unproject the vectors
  659. RowVectorXd v0 = vp0.transpose() * TP;
  660. RowVectorXd v1 = vp1.transpose() * TP;
  661. v.resize(6);
  662. v << v0, v1;
  663. }
  664. void FrameInterpolator::solve_polar(const bool bilaplacian, bool hard_const)
  665. {
  666. interpolateCross(hard_const);
  667. //interpolateSymmetric_polar(bilaplacian);
  668. interpolateSymmetric_polar(false);
  669. }
  670. void FrameInterpolator::interpolateSymmetric_polar(const bool bilaplacian)
  671. {
  672. using namespace std;
  673. using namespace Eigen;
  674. //compute_edge_consistency();
  675. // Generate uniform Laplacian matrix (see notes)
  676. typedef Eigen::Triplet<double> triplet;
  677. std::vector<triplet> triplets;
  678. // Variables are stacked as x1,y1,z1,x2,y2,z2
  679. triplets.reserve(3*4*F.rows());
  680. MatrixXd b = MatrixXd::Zero(3*F.rows(),1);
  681. // Build L and b
  682. for (unsigned eid=0; eid<EF.rows(); ++eid)
  683. {
  684. if (!isBorderEdge[eid])
  685. {
  686. for (int z=0;z<2;++z)
  687. {
  688. // W = [w_a, w_b
  689. // w_b, w_c]
  690. //
  691. // It is not symmetric
  692. int i = EF(eid,z==0?0:1);
  693. int j = EF(eid,z==0?1:0);
  694. int w_a_0 = (i*3)+0;
  695. int w_b_0 = (i*3)+1;
  696. int w_c_0 = (i*3)+2;
  697. int w_a_1 = (j*3)+0;
  698. int w_b_1 = (j*3)+1;
  699. int w_c_1 = (j*3)+2;
  700. // Rotation to change frame
  701. double r_a = cos(z==1?k(eid):-k(eid));
  702. double r_b = -sin(z==1?k(eid):-k(eid));
  703. double r_c = sin(z==1?k(eid):-k(eid));
  704. double r_d = cos(z==1?k(eid):-k(eid));
  705. if (true)
  706. {
  707. if (true)
  708. {
  709. // First term
  710. // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0
  711. triplets.push_back(triplet(w_a_0,w_a_0, -1 ));
  712. triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a ));
  713. triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b ));
  714. triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b ));
  715. // Second term
  716. // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c
  717. triplets.push_back(triplet(w_b_0,w_b_0, -1 ));
  718. triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c ));
  719. triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d ));
  720. triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d ));
  721. // Third term
  722. // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c
  723. triplets.push_back(triplet(w_c_0,w_c_0, -1 ));
  724. triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c ));
  725. triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d ));
  726. triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d ));
  727. }
  728. else
  729. {
  730. // First term
  731. // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0
  732. triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a ));
  733. triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b ));
  734. triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b ));
  735. triplets.push_back(triplet(w_a_0,w_a_0, - r_a*r_a ));
  736. triplets.push_back(triplet(w_a_0,w_a_0, - 2 * r_a*r_b ));
  737. triplets.push_back(triplet(w_a_0,w_a_0, - r_b*r_b ));
  738. // Second term
  739. // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c
  740. triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c ));
  741. triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d ));
  742. triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d ));
  743. triplets.push_back(triplet(w_b_0,w_b_0, - r_a*r_c ));
  744. triplets.push_back(triplet(w_b_0,w_b_0, -r_b*r_c + r_a*r_d ));
  745. triplets.push_back(triplet(w_b_0,w_b_0, - r_b*r_d ));
  746. // Third term
  747. // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c
  748. triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c ));
  749. triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d ));
  750. triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d ));
  751. triplets.push_back(triplet(w_c_0,w_c_0, - r_c*r_c ));
  752. triplets.push_back(triplet(w_c_0,w_c_0, - 2 * r_c*r_d ));
  753. triplets.push_back(triplet(w_c_0,w_c_0, - r_d*r_d ));
  754. }
  755. }
  756. else
  757. {
  758. // Simple Laplacian
  759. // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0
  760. triplets.push_back(triplet(w_a_0,w_a_0, -1 ));
  761. triplets.push_back(triplet(w_a_0,w_a_1, 1 ));
  762. // Second term
  763. // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c
  764. triplets.push_back(triplet(w_b_0,w_b_0, -1 ));
  765. triplets.push_back(triplet(w_b_0,w_b_1, 1 ));
  766. // Third term
  767. // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c
  768. triplets.push_back(triplet(w_c_0,w_c_0, -1 ));
  769. triplets.push_back(triplet(w_c_0,w_c_1, 1 ));
  770. }
  771. }
  772. }
  773. }
  774. SparseMatrix<double> L(3*F.rows(),3*F.rows());
  775. L.setFromTriplets(triplets.begin(), triplets.end());
  776. triplets.clear();
  777. // Add soft constraints
  778. double w = 100000;
  779. for (unsigned fid=0; fid < F.rows(); ++fid)
  780. {
  781. if (S_polar_c[fid] != FREE)
  782. {
  783. for (unsigned i=0;i<3;++i)
  784. {
  785. triplets.push_back(triplet(3*fid + i,3*fid + i,w));
  786. b(3*fid + i) += w*S_polar(fid,i);
  787. }
  788. }
  789. }
  790. SparseMatrix<double> soft(3*F.rows(),3*F.rows());
  791. soft.setFromTriplets(triplets.begin(), triplets.end());
  792. SparseMatrix<double> M;
  793. if (!bilaplacian)
  794. M = L + soft;
  795. else
  796. M = L * L + soft;
  797. // Solve Lx = b;
  798. // MatrixXd Dense(L);
  799. //
  800. // cerr << "Is sym:" << (Dense - Dense.transpose()).maxCoeff() << endl;
  801. // SimplicialLDLT<SparseMatrix<double> > solver;
  802. SparseLU<SparseMatrix<double> > solver;
  803. solver.compute(M);
  804. if(solver.info()!=Success)
  805. {
  806. std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl;
  807. assert(0);
  808. }
  809. MatrixXd x;
  810. x = solver.solve(b);
  811. // cerr << "Skewness: " << x << endl;
  812. if(solver.info()!=Success)
  813. {
  814. std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl;
  815. assert(0);
  816. }
  817. S_polar = MatrixXd::Zero(F.rows(),3);
  818. // Copy back the result
  819. for (unsigned i=0;i<F.rows();++i)
  820. S_polar.row(i) << x(i*3+0), x(i*3+1), x(i*3+2);
  821. for (unsigned i=0;i<F.rows();++i)
  822. {
  823. if (false)
  824. {
  825. MatrixXd T_POLAR(2,2);
  826. T_POLAR << x(i*3+0), x(i*3+1), x(i*3+1), x(i*3+2);
  827. Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> S_es(T_POLAR);
  828. VectorXd eivals = S_es.eigenvalues();
  829. // cerr << "eivals:" << eivals << endl;
  830. double t = eivals.minCoeff();
  831. if (t < 0)
  832. {
  833. cerr << "NOOOOOOOO!" << endl;
  834. exit(1);
  835. }
  836. // cerr << S_polar << endl;
  837. }
  838. }
  839. }
  840. void FrameInterpolator::setConstraint_polar(const int fid, const Eigen::VectorXd& v, ConstraintType type)
  841. {
  842. using namespace std;
  843. using namespace Eigen;
  844. double t_;
  845. VectorXd S_;
  846. frame2canonical_polar(TPs[fid],v,t_,S_);
  847. Eigen::RowVectorXd v2;
  848. canonical2frame_polar(TPs[fid], t_, S_, v2);
  849. // cerr << "Constraint: " << t_ << " " << S_ << endl;
  850. // cerr << "Compare: " << endl << v.transpose() << endl << v2 << endl;
  851. // cerr << "Diff: " << endl << v.transpose() - v2 << endl;
  852. // cerr << "Diff: " << endl << v.transpose() + v2 << endl;
  853. thetas(fid) = t_;
  854. thetas_c[fid] = type;
  855. S_polar.row(fid) = S_;
  856. S_polar_c[fid] = type;
  857. }
  858. Eigen::MatrixXd FrameInterpolator::getFieldPerFace_polar()
  859. {
  860. using namespace std;
  861. using namespace Eigen;
  862. MatrixXd R(F.rows(),6);
  863. for (unsigned i=0; i<F.rows(); ++i)
  864. {
  865. RowVectorXd v;
  866. canonical2frame_polar(TPs[i],thetas(i),S_polar.row(i),v);
  867. R.row(i) = v;
  868. }
  869. return R;
  870. }
  871. void FrameInterpolator::PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P)
  872. {
  873. using namespace std;
  874. using namespace Eigen;
  875. // Polar Decomposition
  876. JacobiSVD<MatrixXd> svd(V,Eigen::ComputeFullU | Eigen::ComputeFullV);
  877. U = svd.matrixU() * svd.matrixV().transpose();
  878. P = svd.matrixV() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();
  879. // If not SPD, change sign of both
  880. // Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> S_es(P);
  881. // if (S_es.eigenvalues().minCoeff() < 0)
  882. // {
  883. // U = -U;
  884. // P = -P;
  885. // }
  886. }
  887. }
  888. IGL_INLINE void igl::frame_field(
  889. const Eigen::MatrixXd& V,
  890. const Eigen::MatrixXi& F,
  891. const Eigen::VectorXi& b,
  892. const Eigen::MatrixXd& bc1,
  893. const Eigen::MatrixXd& bc2,
  894. Eigen::MatrixXd& F1,
  895. Eigen::MatrixXd& F2,
  896. Eigen::VectorXd& S
  897. )
  898. {
  899. using namespace std;
  900. using namespace Eigen;
  901. assert(b.size() > 0);
  902. // Init Solver
  903. FrameInterpolator field(V,F);
  904. for (unsigned i=0; i<b.size(); ++i)
  905. {
  906. VectorXd t(6); t << bc1.row(i).transpose(), bc2.row(i).transpose();
  907. field.setConstraint_polar(b(i), t,FrameInterpolator::SOFT);
  908. }
  909. // Solve
  910. field.solve_polar(false,true);
  911. // Copy back
  912. MatrixXd R = field.getFieldPerFace_polar();
  913. F1 = R.block(0, 0, R.rows(), 3);
  914. F2 = R.block(0, 3, R.rows(), 3);
  915. }