point_areas.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "point_areas.h"
  2. #include "delaunay_triangulation.h"
  3. #include "../../find.h"
  4. #include "../../parallel_for.h"
  5. #include "../../placeholders.h"
  6. #include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
  7. #include "CGAL/Triangulation_vertex_base_with_info_2.h"
  8. #include "CGAL/Triangulation_data_structure_2.h"
  9. #include "CGAL/Delaunay_triangulation_2.h"
  10. typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
  11. typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
  12. typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
  13. typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
  14. typedef Kernel::Point_2 Point;
  15. namespace igl {
  16. namespace copyleft{
  17. namespace cgal{
  18. template <typename DerivedP, typename DerivedI, typename DerivedN,
  19. typename DerivedA>
  20. IGL_INLINE void point_areas(
  21. const Eigen::MatrixBase<DerivedP>& P,
  22. const Eigen::MatrixBase<DerivedI>& I,
  23. const Eigen::MatrixBase<DerivedN>& N,
  24. Eigen::PlainObjectBase<DerivedA> & A)
  25. {
  26. Eigen::MatrixXd T;
  27. point_areas(P,I,N,A,T);
  28. }
  29. template <typename DerivedP, typename DerivedI, typename DerivedN,
  30. typename DerivedA, typename DerivedT>
  31. IGL_INLINE void point_areas(
  32. const Eigen::MatrixBase<DerivedP>& P,
  33. const Eigen::MatrixBase<DerivedI>& I,
  34. const Eigen::MatrixBase<DerivedN>& N,
  35. Eigen::PlainObjectBase<DerivedA> & A,
  36. Eigen::PlainObjectBase<DerivedT> & T)
  37. {
  38. typedef typename DerivedP::Scalar real;
  39. typedef typename DerivedN::Scalar scalarN;
  40. typedef typename DerivedA::Scalar scalarA;
  41. typedef Eigen::Matrix<real,1,3> RowVec3;
  42. typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
  43. typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
  44. typedef Eigen::Matrix<typename DerivedI::Scalar,
  45. Eigen::Dynamic, Eigen::Dynamic> MatrixI;
  46. const int n = P.rows();
  47. assert(P.cols() == 3 && "P must have exactly 3 columns");
  48. assert(P.rows() == N.rows()
  49. && "P and N must have the same number of rows");
  50. assert(P.rows() == I.rows()
  51. && "P and I must have the same number of rows");
  52. A.setZero(n,1);
  53. T.setZero(n,3);
  54. igl::parallel_for(P.rows(),[&](int i)
  55. {
  56. MatrixP neighbors;
  57. neighbors = P(I.row(i),igl::placeholders::all);
  58. if(N.rows() && neighbors.rows() > 1){
  59. MatrixN neighbor_normals;
  60. neighbor_normals = N(I.row(i),igl::placeholders::all);
  61. Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
  62. Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
  63. poi_normal(0)*neighbor_normals.col(0)
  64. + poi_normal(1)*neighbor_normals.col(1)
  65. + poi_normal(2)*neighbor_normals.col(2);
  66. Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
  67. neighbors = neighbors(igl::find(keep),igl::placeholders::all).eval();
  68. }
  69. if(neighbors.rows() <= 2){
  70. A(i) = 0;
  71. } else {
  72. //subtract the mean from neighbors, then take svd,
  73. //the scores will be U*S. This is our pca plane fitting
  74. RowVec3 mean = neighbors.colwise().mean();
  75. MatrixP mean_centered = neighbors.rowwise() - mean;
  76. Eigen::JacobiSVD<MatrixP> svd(mean_centered,
  77. Eigen::ComputeThinU | Eigen::ComputeThinV);
  78. MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
  79. T.row(i) = svd.matrixV().col(2).transpose();
  80. if(T.row(i).dot(N.row(i)) < 0){
  81. T.row(i) *= -1;
  82. }
  83. MatrixP plane = scores(igl::placeholders::all,{0,1});
  84. std::vector< std::pair<Point,unsigned> > points;
  85. //This is where we obtain a delaunay triangulation of the points
  86. for(unsigned iter = 0; iter < plane.rows(); iter++){
  87. points.push_back( std::make_pair(
  88. Point(plane(iter,0),plane(iter,1)), iter ) );
  89. }
  90. Delaunay triangulation;
  91. triangulation.insert(points.begin(),points.end());
  92. Eigen::MatrixXi F(triangulation.number_of_faces(),3);
  93. int f_row = 0;
  94. for(Delaunay::Finite_faces_iterator fit =
  95. triangulation.finite_faces_begin();
  96. fit != triangulation.finite_faces_end(); ++fit) {
  97. Delaunay::Face_handle face = fit;
  98. F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
  99. (int)face->vertex(1)->info(),
  100. (int)face->vertex(2)->info());
  101. f_row++;
  102. }
  103. //Here we calculate the voronoi area of the point
  104. scalarA area_accumulator = 0;
  105. for(int f = 0; f < F.rows(); f++){
  106. int X = -1;
  107. for(int face_iter = 0; face_iter < 3; face_iter++){
  108. if(F(f,face_iter) == 0){
  109. X = face_iter;
  110. }
  111. }
  112. if(X >= 0){
  113. //Triangle XYZ with X being the point we want the area of
  114. int Y = (X+1)%3;
  115. int Z = (X+2)%3;
  116. scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
  117. scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
  118. scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
  119. scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
  120. scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
  121. scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
  122. Eigen::Matrix<scalarA,1,3> barycentric;
  123. barycentric << x*cosX, y*cosY, z*cosZ;
  124. barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
  125. //TODO: to make numerically stable, reorder so that x≥y≥z:
  126. scalarA full_area = 0.25*std::sqrt(
  127. (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
  128. Eigen::Matrix<scalarA,1,3> partial_area =
  129. barycentric * full_area;
  130. if(cosX < 0){
  131. area_accumulator += 0.5*full_area;
  132. } else if (cosY < 0 || cosZ < 0){
  133. area_accumulator += 0.25*full_area;
  134. } else {
  135. area_accumulator += (partial_area(1) + partial_area(2))/2;
  136. }
  137. }
  138. }
  139. if(std::isfinite(area_accumulator)){
  140. A(i) = area_accumulator;
  141. } else {
  142. A(i) = 0;
  143. }
  144. }
  145. },1000);
  146. }
  147. }
  148. }
  149. }
  150. #ifdef IGL_STATIC_LIBRARY
  151. // Explicit template instantiation
  152. // generated by autoexplicit.sh
  153. template void igl::copyleft::cgal::point_areas<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::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  154. #endif