principal_curvature.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
  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 "principal_curvature.h"
  9. #include <iostream>
  10. #include <fstream>
  11. #include <iomanip>
  12. #include <iostream>
  13. #include <queue>
  14. #include <list>
  15. #include <cmath>
  16. #include <limits>
  17. #include <Eigen/SparseCholesky>
  18. // Lib IGL includes
  19. #include <igl/adjacency_list.h>
  20. #include <igl/per_face_normals.h>
  21. #include <igl/per_vertex_normals.h>
  22. #include <igl/avg_edge_length.h>
  23. #include <igl/vertex_triangle_adjacency.h>
  24. typedef enum
  25. {
  26. SPHERE_SEARCH,
  27. K_RING_SEARCH
  28. } searchType;
  29. typedef enum
  30. {
  31. AVERAGE,
  32. PROJ_PLANE
  33. } normalType;
  34. class CurvatureCalculator
  35. {
  36. public:
  37. /* Row number i represents the i-th vertex, whose columns are:
  38. curv[i][0] : K2
  39. curv[i][1] : K1
  40. curvDir[i][0] : PD1
  41. curvDir[i][1] : PD2
  42. */
  43. std::vector< std::vector<double> > curv;
  44. std::vector< std::vector<Eigen::Vector3d> > curvDir;
  45. bool curvatureComputed;
  46. class Quadric
  47. {
  48. public:
  49. IGL_INLINE Quadric ()
  50. {
  51. a() = b() = c() = d() = e() = 1.0;
  52. }
  53. IGL_INLINE Quadric(double av, double bv, double cv, double dv, double ev)
  54. {
  55. a() = av;
  56. b() = bv;
  57. c() = cv;
  58. d() = dv;
  59. e() = ev;
  60. }
  61. IGL_INLINE double& a() { return data[0];}
  62. IGL_INLINE double& b() { return data[1];}
  63. IGL_INLINE double& c() { return data[2];}
  64. IGL_INLINE double& d() { return data[3];}
  65. IGL_INLINE double& e() { return data[4];}
  66. double data[5];
  67. IGL_INLINE double evaluate(double u, double v)
  68. {
  69. return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
  70. }
  71. IGL_INLINE double du(double u, double v)
  72. {
  73. return 2.0*a()*u + b()*v + d();
  74. }
  75. IGL_INLINE double dv(double u, double v)
  76. {
  77. return 2.0*c()*v + b()*u + e();
  78. }
  79. IGL_INLINE double duv(double u, double v)
  80. {
  81. return b();
  82. }
  83. IGL_INLINE double duu(double u, double v)
  84. {
  85. return 2.0*a();
  86. }
  87. IGL_INLINE double dvv(double u, double v)
  88. {
  89. return 2.0*c();
  90. }
  91. IGL_INLINE static Quadric fit(const std::vector<Eigen::Vector3d> &VV)
  92. {
  93. assert(VV.size() >= 5);
  94. if (VV.size() < 5)
  95. {
  96. std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << VV.size() << " were given." << std::endl;
  97. exit(0);
  98. }
  99. Eigen::MatrixXd A(VV.size(),5);
  100. Eigen::MatrixXd b(VV.size(),1);
  101. Eigen::MatrixXd sol(5,1);
  102. for(unsigned int c=0; c < VV.size(); ++c)
  103. {
  104. double u = VV[c][0];
  105. double v = VV[c][1];
  106. double n = VV[c][2];
  107. A(c,0) = u*u;
  108. A(c,1) = u*v;
  109. A(c,2) = v*v;
  110. A(c,3) = u;
  111. A(c,4) = v;
  112. b(c) = n;
  113. }
  114. sol=A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
  115. return Quadric(sol(0),sol(1),sol(2),sol(3),sol(4));
  116. }
  117. };
  118. public:
  119. Eigen::MatrixXd vertices;
  120. // Face list of current mesh (#F x 3) or (#F x 4)
  121. // The i-th row contains the indices of the vertices that forms the i-th face in ccw order
  122. Eigen::MatrixXi faces;
  123. std::vector<std::vector<int> > vertex_to_vertices;
  124. std::vector<std::vector<int> > vertex_to_faces;
  125. std::vector<std::vector<int> > vertex_to_faces_index;
  126. Eigen::MatrixXd face_normals;
  127. Eigen::MatrixXd vertex_normals;
  128. /* Size of the neighborhood */
  129. double sphereRadius;
  130. int kRing;
  131. bool localMode; /* Use local mode */
  132. bool projectionPlaneCheck; /* Check collected vertices on tangent plane */
  133. bool montecarlo;
  134. unsigned int montecarloN;
  135. searchType st; /* Use either a sphere search or a k-ring search */
  136. normalType nt;
  137. double lastRadius;
  138. double scaledRadius;
  139. std::string lastMeshName;
  140. /* Benchmark related variables */
  141. bool expStep; /* True if we want the radius to increase exponentially */
  142. int step; /* If expStep==false, by how much rhe radius increases on every step */
  143. int maxSize; /* The maximum limit of the radius in the benchmark */
  144. IGL_INLINE CurvatureCalculator();
  145. IGL_INLINE void init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
  146. IGL_INLINE void finalEigenStuff(int, const std::vector<Eigen::Vector3d>&, Quadric&);
  147. IGL_INLINE void fitQuadric(const Eigen::Vector3d&, const std::vector<Eigen::Vector3d>& ref, const std::vector<int>& , Quadric *);
  148. IGL_INLINE void applyProjOnPlane(const Eigen::Vector3d&, const std::vector<int>&, std::vector<int>&);
  149. IGL_INLINE void getSphere(const int, const double, std::vector<int>&, int min);
  150. IGL_INLINE void getKRing(const int, const double,std::vector<int>&);
  151. IGL_INLINE Eigen::Vector3d project(const Eigen::Vector3d&, const Eigen::Vector3d&, const Eigen::Vector3d&);
  152. IGL_INLINE void computeReferenceFrame(int, const Eigen::Vector3d&, std::vector<Eigen::Vector3d>&);
  153. IGL_INLINE void getAverageNormal(int, const std::vector<int>&, Eigen::Vector3d&);
  154. IGL_INLINE void getProjPlane(int, const std::vector<int>&, Eigen::Vector3d&);
  155. IGL_INLINE void applyMontecarlo(const std::vector<int>&,std::vector<int>*);
  156. IGL_INLINE void computeCurvature();
  157. IGL_INLINE void printCurvature(const std::string& outpath);
  158. IGL_INLINE double getAverageEdge();
  159. IGL_INLINE static int rotateForward (double *v0, double *v1, double *v2)
  160. {
  161. double t;
  162. if (std::abs(*v2) >= std::abs(*v1) && std::abs(*v2) >= std::abs(*v0))
  163. return 0;
  164. t = *v0;
  165. *v0 = *v2;
  166. *v2 = *v1;
  167. *v1 = t;
  168. return 1 + rotateForward (v0, v1, v2);
  169. }
  170. IGL_INLINE static void rotateBackward (int nr, double *v0, double *v1, double *v2)
  171. {
  172. double t;
  173. if (nr == 0)
  174. return;
  175. t = *v2;
  176. *v2 = *v0;
  177. *v0 = *v1;
  178. *v1 = t;
  179. rotateBackward (nr - 1, v0, v1, v2);
  180. }
  181. IGL_INLINE static Eigen::Vector3d chooseMax (Eigen::Vector3d n, Eigen::Vector3d abc, double ab)
  182. {
  183. int max_i;
  184. double max_sp;
  185. Eigen::Vector3d nt[8];
  186. n.normalize ();
  187. abc.normalize ();
  188. max_sp = - std::numeric_limits<double>::max();
  189. for (int i = 0; i < 4; ++i)
  190. {
  191. nt[i] = n;
  192. if (ab > 0)
  193. {
  194. switch (i)
  195. {
  196. case 0:
  197. break;
  198. case 1:
  199. nt[i][2] = -n[2];
  200. break;
  201. case 2:
  202. nt[i][0] = -n[0];
  203. nt[i][1] = -n[1];
  204. break;
  205. case 3:
  206. nt[i][0] = -n[0];
  207. nt[i][1] = -n[1];
  208. nt[i][2] = -n[2];
  209. break;
  210. }
  211. }
  212. else
  213. {
  214. switch (i)
  215. {
  216. case 0:
  217. nt[i][0] = -n[0];
  218. break;
  219. case 1:
  220. nt[i][1] = -n[1];
  221. break;
  222. case 2:
  223. nt[i][0] = -n[0];
  224. nt[i][2] = -n[2];
  225. break;
  226. case 3:
  227. nt[i][1] = -n[1];
  228. nt[i][2] = -n[2];
  229. break;
  230. }
  231. }
  232. if (nt[i].dot(abc) > max_sp)
  233. {
  234. max_sp = nt[i].dot(abc);
  235. max_i = i;
  236. }
  237. }
  238. return nt[max_i];
  239. }
  240. };
  241. class comparer
  242. {
  243. public:
  244. IGL_INLINE bool operator() (const std::pair<int, double>& lhs, const std::pair<int, double>&rhs) const
  245. {
  246. return lhs.second>rhs.second;
  247. }
  248. };
  249. IGL_INLINE CurvatureCalculator::CurvatureCalculator()
  250. {
  251. this->localMode=true;
  252. this->projectionPlaneCheck=true;
  253. this->sphereRadius=5;
  254. this->st=SPHERE_SEARCH;
  255. this->nt=AVERAGE;
  256. this->montecarlo=false;
  257. this->montecarloN=0;
  258. this->kRing=3;
  259. this->curvatureComputed=false;
  260. this->expStep=true;
  261. }
  262. IGL_INLINE void CurvatureCalculator::init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
  263. {
  264. // Normalize vertices
  265. vertices = V;
  266. // vertices = vertices.array() - vertices.minCoeff();
  267. // vertices = vertices.array() / vertices.maxCoeff();
  268. // vertices = vertices.array() * (1.0/igl::avg_edge_length(V,F));
  269. faces = F;
  270. igl::adjacency_list(F, vertex_to_vertices);
  271. igl::vertex_triangle_adjacency(V, F, vertex_to_faces, vertex_to_faces_index);
  272. igl::per_face_normals(V, F, face_normals);
  273. igl::per_vertex_normals(V, F, face_normals, vertex_normals);
  274. }
  275. IGL_INLINE void CurvatureCalculator::fitQuadric(const Eigen::Vector3d& v, const std::vector<Eigen::Vector3d>& ref, const std::vector<int>& vv, Quadric *q)
  276. {
  277. std::vector<Eigen::Vector3d> points;
  278. points.reserve (vv.size());
  279. for (unsigned int i = 0; i < vv.size(); ++i) {
  280. Eigen::Vector3d cp = vertices.row(vv[i]);
  281. // vtang non e` il v tangente!!!
  282. Eigen::Vector3d vTang = cp - v;
  283. double x = vTang.dot(ref[0]);
  284. double y = vTang.dot(ref[1]);
  285. double z = vTang.dot(ref[2]);
  286. points.push_back(Eigen::Vector3d (x,y,z));
  287. }
  288. if (points.size() < 5)
  289. {
  290. std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << points.size() << " were given." << std::endl;
  291. *q = Quadric(0,0,0,0,0);
  292. }
  293. else
  294. {
  295. *q = Quadric::fit (points);
  296. }
  297. }
  298. IGL_INLINE void CurvatureCalculator::finalEigenStuff(int i, const std::vector<Eigen::Vector3d>& ref, Quadric& q)
  299. {
  300. const double a = q.a();
  301. const double b = q.b();
  302. const double c = q.c();
  303. const double d = q.d();
  304. const double e = q.e();
  305. // if (fabs(a) < 10e-8 || fabs(b) < 10e-8)
  306. // {
  307. // std::cout << "Degenerate quadric: " << i << std::endl;
  308. // }
  309. double E = 1.0 + d*d;
  310. double F = d*e;
  311. double G = 1.0 + e*e;
  312. Eigen::Vector3d n = Eigen::Vector3d(-d,-e,1.0).normalized();
  313. double L = 2.0 * a * n[2];
  314. double M = b * n[2];
  315. double N = 2 * c * n[2];
  316. // ----------------- Eigen stuff
  317. Eigen::Matrix2d m;
  318. m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
  319. m = m / (E*G-F*F);
  320. Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
  321. Eigen::Vector2d c_val = eig.eigenvalues();
  322. Eigen::Matrix2d c_vec = eig.eigenvectors();
  323. // std::cerr << "c_val:" << c_val << std::endl;
  324. // std::cerr << "c_vec:" << c_vec << std::endl;
  325. // std::cerr << "c_vec:" << c_vec(0) << " " << c_vec(1) << std::endl;
  326. c_val = -c_val;
  327. Eigen::Vector3d v1, v2;
  328. v1[0] = c_vec(0);
  329. v1[1] = c_vec(1);
  330. v1[2] = 0; //d * v1[0] + e * v1[1];
  331. v2[0] = c_vec(2);
  332. v2[1] = c_vec(3);
  333. v2[2] = 0; //d * v2[0] + e * v2[1];
  334. // v1 = v1.normalized();
  335. // v2 = v2.normalized();
  336. Eigen::Vector3d v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2];
  337. Eigen::Vector3d v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2];
  338. v1global.normalize();
  339. v2global.normalize();
  340. v1global *= c_val(0);
  341. v2global *= c_val(1);
  342. if (c_val[0] > c_val[1])
  343. {
  344. curv[i]=std::vector<double>(2);
  345. curv[i][0]=c_val(1);
  346. curv[i][1]=c_val(0);
  347. curvDir[i]=std::vector<Eigen::Vector3d>(2);
  348. curvDir[i][0]=v2global;
  349. curvDir[i][1]=v1global;
  350. }
  351. else
  352. {
  353. curv[i]=std::vector<double>(2);
  354. curv[i][0]=c_val(0);
  355. curv[i][1]=c_val(1);
  356. curvDir[i]=std::vector<Eigen::Vector3d>(2);
  357. curvDir[i][0]=v1global;
  358. curvDir[i][1]=v2global;
  359. }
  360. // ---- end Eigen stuff
  361. }
  362. IGL_INLINE void CurvatureCalculator::getKRing(const int start, const double r, std::vector<int>&vv)
  363. {
  364. int bufsize=vertices.rows();
  365. vv.reserve(bufsize);
  366. std::list<std::pair<int,int> > queue;
  367. bool* visited = (bool*)calloc(bufsize,sizeof(bool));
  368. queue.push_back(std::pair<int,int>(start,0));
  369. visited[start]=true;
  370. while (!queue.empty())
  371. {
  372. int toVisit=queue.front().first;
  373. int distance=queue.front().second;
  374. queue.pop_front();
  375. vv.push_back(toVisit);
  376. if (distance<(int)r)
  377. {
  378. for (unsigned int i=0; i<vertex_to_vertices[toVisit].size(); ++i)
  379. {
  380. int neighbor=vertex_to_vertices[toVisit][i];
  381. if (!visited[neighbor])
  382. {
  383. queue.push_back(std::pair<int,int> (neighbor,distance+1));
  384. visited[neighbor]=true;
  385. }
  386. }
  387. }
  388. }
  389. free(visited);
  390. return;
  391. }
  392. IGL_INLINE void CurvatureCalculator::getSphere(const int start, const double r, std::vector<int> &vv, int min)
  393. {
  394. int bufsize=vertices.rows();
  395. vv.reserve(bufsize);
  396. std::list<int>* queue= new std::list<int>();
  397. bool* visited = (bool*)calloc(bufsize,sizeof(bool));
  398. queue->push_back(start);
  399. visited[start]=true;
  400. Eigen::Vector3d me=vertices.row(start);
  401. std::priority_queue<std::pair<int, double>, std::vector<std::pair<int, double> >, comparer >* extra_candidates= new std::priority_queue<std::pair<int, double>, std::vector<std::pair<int, double> >, comparer >();
  402. while (!queue->empty())
  403. {
  404. int toVisit=queue->front();
  405. queue->pop_front();
  406. vv.push_back(toVisit);
  407. for (unsigned int i=0; i<vertex_to_vertices[toVisit].size(); ++i)
  408. {
  409. int neighbor=vertex_to_vertices[toVisit][i];
  410. if (!visited[neighbor])
  411. {
  412. Eigen::Vector3d neigh=vertices.row(neighbor);
  413. double distance=(me-neigh).norm();
  414. if (distance<r)
  415. queue->push_back(neighbor);
  416. else if ((int)vv.size()<min)
  417. extra_candidates->push(std::pair<int,double>(neighbor,distance));
  418. visited[neighbor]=true;
  419. }
  420. }
  421. }
  422. while (!extra_candidates->empty() && (int)vv.size()<min)
  423. {
  424. std::pair<int, double> cand=extra_candidates->top();
  425. extra_candidates->pop();
  426. vv.push_back(cand.first);
  427. for (unsigned int i=0; i<vertex_to_vertices[cand.first].size(); ++i)
  428. {
  429. int neighbor=vertex_to_vertices[cand.first][i];
  430. if (!visited[neighbor])
  431. {
  432. Eigen::Vector3d neigh=vertices.row(neighbor);
  433. double distance=(me-neigh).norm();
  434. extra_candidates->push(std::pair<int,double>(neighbor,distance));
  435. visited[neighbor]=true;
  436. }
  437. }
  438. }
  439. free(extra_candidates);
  440. free(queue);
  441. free(visited);
  442. }
  443. IGL_INLINE Eigen::Vector3d CurvatureCalculator::project(const Eigen::Vector3d& v, const Eigen::Vector3d& vp, const Eigen::Vector3d& ppn)
  444. {
  445. return (vp - (ppn * ((vp - v).dot(ppn))));
  446. }
  447. IGL_INLINE void CurvatureCalculator::computeReferenceFrame(int i, const Eigen::Vector3d& normal, std::vector<Eigen::Vector3d>& ref )
  448. {
  449. Eigen::Vector3d longest_v=Eigen::Vector3d(vertices.row(vertex_to_vertices[i][0]));
  450. longest_v=(project(vertices.row(i),longest_v,normal)-Eigen::Vector3d(vertices.row(i))).normalized();
  451. /* L'ultimo asse si ottiene come prodotto vettoriale tra i due
  452. * calcolati */
  453. Eigen::Vector3d y_axis=(normal.cross(longest_v)).normalized();
  454. ref[0]=longest_v;
  455. ref[1]=y_axis;
  456. ref[2]=normal;
  457. }
  458. IGL_INLINE void CurvatureCalculator::getAverageNormal(int j, const std::vector<int>& vv, Eigen::Vector3d& normal)
  459. {
  460. normal=(vertex_normals.row(j)).normalized();
  461. if (localMode)
  462. return;
  463. for (unsigned int i=0; i<vv.size(); ++i)
  464. {
  465. normal+=vertex_normals.row(vv[i]).normalized();
  466. }
  467. normal.normalize();
  468. }
  469. IGL_INLINE void CurvatureCalculator::getProjPlane(int j, const std::vector<int>& vv, Eigen::Vector3d& ppn)
  470. {
  471. int nr;
  472. double a, b, c;
  473. double nx, ny, nz;
  474. double abcq;
  475. a = b = c = 0;
  476. if (localMode)
  477. {
  478. for (unsigned int i=0; i<vertex_to_faces.at(j).size(); ++i)
  479. {
  480. Eigen::Vector3d faceNormal=face_normals.row(vertex_to_faces.at(j).at(i));
  481. a += faceNormal[0];
  482. b += faceNormal[1];
  483. c += faceNormal[2];
  484. }
  485. }
  486. else
  487. {
  488. for (unsigned int i=0; i<vv.size(); ++i)
  489. {
  490. a+= vertex_normals.row(vv[i])[0];
  491. b+= vertex_normals.row(vv[i])[1];
  492. c+= vertex_normals.row(vv[i])[2];
  493. }
  494. }
  495. nr = rotateForward (&a, &b, &c);
  496. abcq = a*a + b*b + c*c;
  497. nx = sqrt (a*a / abcq);
  498. ny = sqrt (b*b / abcq);
  499. nz = sqrt (1 - nx*nx - ny*ny);
  500. rotateBackward (nr, &a, &b, &c);
  501. rotateBackward (nr, &nx, &ny, &nz);
  502. ppn = chooseMax (Eigen::Vector3d(nx, ny, nz), Eigen::Vector3d (a, b, c), a * b);
  503. ppn.normalize();
  504. }
  505. IGL_INLINE double CurvatureCalculator::getAverageEdge()
  506. {
  507. double sum = 0;
  508. int count = 0;
  509. for (int i = 0; i<faces.rows(); ++i)
  510. {
  511. for (short unsigned j=0; j<3; ++j)
  512. {
  513. Eigen::Vector3d p1=vertices.row(faces.row(i)[j]);
  514. Eigen::Vector3d p2=vertices.row(faces.row(i)[(j+1)%3]);
  515. double l = (p1-p2).norm();
  516. sum+=l;
  517. ++count;
  518. }
  519. }
  520. return (sum/(double)count);
  521. }
  522. IGL_INLINE void CurvatureCalculator::applyProjOnPlane(const Eigen::Vector3d& ppn, const std::vector<int>& vin, std::vector<int> &vout)
  523. {
  524. for (std::vector<int>::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
  525. if (vertex_normals.row(*vpi) * ppn > 0.0)
  526. vout.push_back(*vpi);
  527. }
  528. IGL_INLINE void CurvatureCalculator::applyMontecarlo(const std::vector<int>& vin, std::vector<int> *vout)
  529. {
  530. if (montecarloN >= vin.size ())
  531. {
  532. *vout = vin;
  533. return;
  534. }
  535. float p = ((float) montecarloN) / (float) vin.size();
  536. for (std::vector<int>::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
  537. {
  538. float r;
  539. if ((r = ((float)rand () / RAND_MAX)) < p)
  540. {
  541. vout->push_back(*vpi);
  542. }
  543. }
  544. }
  545. IGL_INLINE void CurvatureCalculator::computeCurvature()
  546. {
  547. //CHECK che esista la mesh
  548. const size_t vertices_count=vertices.rows();
  549. if (vertices_count ==0)
  550. return;
  551. curvDir=std::vector< std::vector<Eigen::Vector3d> >(vertices_count);
  552. curv=std::vector<std::vector<double> >(vertices_count);
  553. scaledRadius=getAverageEdge()*sphereRadius;
  554. std::vector<int> vv;
  555. std::vector<int> vvtmp;
  556. Eigen::Vector3d normal;
  557. //double time_spent;
  558. //double searchtime=0, ref_time=0, fit_time=0, final_time=0;
  559. for (size_t i=0; i<vertices_count; ++i)
  560. {
  561. vv.clear();
  562. vvtmp.clear();
  563. Eigen::Vector3d me=vertices.row(i);
  564. switch (st)
  565. {
  566. case SPHERE_SEARCH:
  567. getSphere(i,scaledRadius,vv,6);
  568. break;
  569. case K_RING_SEARCH:
  570. getKRing(i,kRing,vv);
  571. break;
  572. default:
  573. fprintf(stderr,"Error: search type not recognized");
  574. return;
  575. }
  576. if (vv.size()<6)
  577. {
  578. //std::cerr << "Could not compute curvature of radius " << scaledRadius << std::endl;
  579. continue;
  580. }
  581. if (projectionPlaneCheck)
  582. {
  583. vvtmp.reserve (vv.size ());
  584. applyProjOnPlane (vertex_normals.row(i), vv, vvtmp);
  585. if (vvtmp.size() >= 6 && vvtmp.size()<vv.size())
  586. vv = vvtmp;
  587. }
  588. switch (nt)
  589. {
  590. case AVERAGE:
  591. getAverageNormal(i,vv,normal);
  592. break;
  593. case PROJ_PLANE:
  594. getProjPlane(i,vv,normal);
  595. break;
  596. default:
  597. fprintf(stderr,"Error: normal type not recognized");
  598. return;
  599. }
  600. if (vv.size()<6)
  601. {
  602. //std::cerr << "Could not compute curvature of radius " << scaledRadius << std::endl;
  603. continue;
  604. }
  605. if (montecarlo)
  606. {
  607. if(montecarloN<6)
  608. break;
  609. vvtmp.reserve(vv.size());
  610. applyMontecarlo(vv,&vvtmp);
  611. vv=vvtmp;
  612. }
  613. if (vv.size()<6)
  614. return;
  615. std::vector<Eigen::Vector3d> ref(3);
  616. computeReferenceFrame(i,normal,ref);
  617. Quadric q;
  618. fitQuadric (me, ref, vv, &q);
  619. finalEigenStuff(i,ref,q);
  620. }
  621. lastRadius=sphereRadius;
  622. curvatureComputed=true;
  623. }
  624. IGL_INLINE void CurvatureCalculator::printCurvature(const std::string& outpath)
  625. {
  626. using namespace std;
  627. if (!curvatureComputed)
  628. return;
  629. std::ofstream of;
  630. of.open(outpath.c_str());
  631. if (!of)
  632. {
  633. fprintf(stderr, "Error: could not open output file %s\n", outpath.c_str());
  634. return;
  635. }
  636. int vertices_count=vertices.rows();
  637. of << vertices_count << endl;
  638. for (int i=0; i<vertices_count; ++i)
  639. {
  640. of << curv[i][0] << " " << curv[i][1] << " " << curvDir[i][0][0] << " " << curvDir[i][0][1] << " " << curvDir[i][0][2] << " " <<
  641. curvDir[i][1][0] << " " << curvDir[i][1][1] << " " << curvDir[i][1][2] << endl;
  642. }
  643. of.close();
  644. }
  645. template <
  646. typename DerivedV,
  647. typename DerivedF,
  648. typename DerivedPD1,
  649. typename DerivedPD2,
  650. typename DerivedPV1,
  651. typename DerivedPV2,
  652. typename Index>
  653. IGL_INLINE void igl::principal_curvature(
  654. const Eigen::PlainObjectBase<DerivedV>& V,
  655. const Eigen::PlainObjectBase<DerivedF>& F,
  656. Eigen::PlainObjectBase<DerivedPD1>& PD1,
  657. Eigen::PlainObjectBase<DerivedPD2>& PD2,
  658. Eigen::PlainObjectBase<DerivedPV1>& PV1,
  659. Eigen::PlainObjectBase<DerivedPV2>& PV2,
  660. std::vector<Index>& bad_vertices,
  661. unsigned radius,
  662. bool useKring)
  663. {
  664. if (radius < 2)
  665. {
  666. radius = 2;
  667. std::cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << std::endl;
  668. }
  669. // Preallocate memory
  670. PD1.resize(V.rows(),3);
  671. PD2.resize(V.rows(),3);
  672. // Preallocate memory
  673. PV1.resize(V.rows(),1);
  674. PV2.resize(V.rows(),1);
  675. // Precomputation
  676. CurvatureCalculator cc;
  677. cc.init(V.template cast<double>(),F.template cast<int>());
  678. cc.sphereRadius = radius;
  679. if (useKring)
  680. {
  681. cc.kRing = radius;
  682. cc.st = K_RING_SEARCH;
  683. }
  684. // Compute
  685. cc.computeCurvature();
  686. // Copy it back
  687. for (unsigned i=0; i<V.rows(); ++i)
  688. {
  689. if (!cc.curv[i].empty())
  690. {
  691. PD1.row(i) << cc.curvDir[i][0][0], cc.curvDir[i][0][1], cc.curvDir[i][0][2];
  692. PD2.row(i) << cc.curvDir[i][1][0], cc.curvDir[i][1][1], cc.curvDir[i][1][2];
  693. PD1.row(i).normalize();
  694. PD2.row(i).normalize();
  695. if (std::isnan(PD1(i,0)) || std::isnan(PD1(i,1)) || std::isnan(PD1(i,2)) || std::isnan(PD2(i,0)) || std::isnan(PD2(i,1)) || std::isnan(PD2(i,2)))
  696. {
  697. PD1.row(i) << 0,0,0;
  698. PD2.row(i) << 0,0,0;
  699. }
  700. PV1(i) = cc.curv[i][0];
  701. PV2(i) = cc.curv[i][1];
  702. if (PD1.row(i) * PD2.row(i).transpose() > 10e-6)
  703. {
  704. bad_vertices.push_back((Index)i);
  705. PD1.row(i) *= 0;
  706. PD2.row(i) *= 0;
  707. }
  708. } else {
  709. bad_vertices.push_back((Index)i);
  710. PV1(i) = 0;
  711. PV2(i) = 0;
  712. PD1.row(i) << 0,0,0;
  713. PD2.row(i) << 0,0,0;
  714. }
  715. }
  716. }
  717. template <
  718. typename DerivedV,
  719. typename DerivedF,
  720. typename DerivedPD1,
  721. typename DerivedPD2,
  722. typename DerivedPV1,
  723. typename DerivedPV2>
  724. IGL_INLINE void igl::principal_curvature(
  725. const Eigen::PlainObjectBase<DerivedV>& V,
  726. const Eigen::PlainObjectBase<DerivedF>& F,
  727. Eigen::PlainObjectBase<DerivedPD1>& PD1,
  728. Eigen::PlainObjectBase<DerivedPD2>& PD2,
  729. Eigen::PlainObjectBase<DerivedPV1>& PV1,
  730. Eigen::PlainObjectBase<DerivedPV2>& PV2,
  731. unsigned radius,
  732. bool useKring)
  733. {
  734. if (radius < 2)
  735. {
  736. radius = 2;
  737. std::cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << std::endl;
  738. }
  739. // Preallocate memory
  740. PD1.resize(V.rows(),3);
  741. PD2.resize(V.rows(),3);
  742. // Preallocate memory
  743. PV1.resize(V.rows(),1);
  744. PV2.resize(V.rows(),1);
  745. // Precomputation
  746. CurvatureCalculator cc;
  747. cc.init(V.template cast<double>(),F.template cast<int>());
  748. cc.sphereRadius = radius;
  749. if (useKring)
  750. {
  751. cc.kRing = radius;
  752. cc.st = K_RING_SEARCH;
  753. }
  754. // Compute
  755. cc.computeCurvature();
  756. // Copy it back
  757. for (unsigned i=0; i<V.rows(); ++i)
  758. {
  759. PD1.row(i) << cc.curvDir[i][0][0], cc.curvDir[i][0][1], cc.curvDir[i][0][2];
  760. PD2.row(i) << cc.curvDir[i][1][0], cc.curvDir[i][1][1], cc.curvDir[i][1][2];
  761. PD1.row(i).normalize();
  762. PD2.row(i).normalize();
  763. if (std::isnan(PD1(i,0)) || std::isnan(PD1(i,1)) || std::isnan(PD1(i,2)) || std::isnan(PD2(i,0)) || std::isnan(PD2(i,1)) || std::isnan(PD2(i,2)))
  764. {
  765. PD1.row(i) << 0,0,0;
  766. PD2.row(i) << 0,0,0;
  767. }
  768. PV1(i) = cc.curv[i][0];
  769. PV2(i) = cc.curv[i][1];
  770. if (PD1.row(i) * PD2.row(i).transpose() > 10e-6)
  771. {
  772. std::cerr << "PRINCIPAL_CURVATURE: Something is wrong with vertex: " << i << std::endl;
  773. PD1.row(i) *= 0;
  774. PD2.row(i) *= 0;
  775. }
  776. }
  777. }
  778. #ifdef IGL_STATIC_LIBRARY
  779. // Explicit template instantiation
  780. // generated by autoexplicit.sh
  781. template void igl::principal_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, unsigned int, bool);
  782. template void igl::principal_curvature<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, unsigned int, bool);
  783. template void igl::principal_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, unsigned int, bool);
  784. template void igl::principal_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, std::vector<int, std::allocator<int> >&, unsigned int, bool);
  785. #endif