principal_curvature.cpp 21 KB

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