123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #include "point_areas.h"
- #include "delaunay_triangulation.h"
- #include "../../colon.h"
- #include "../../slice.h"
- #include "../../slice_mask.h"
- #include "../../parallel_for.h"
- #include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
- #include "CGAL/Triangulation_vertex_base_with_info_2.h"
- #include "CGAL/Triangulation_data_structure_2.h"
- #include "CGAL/Delaunay_triangulation_2.h"
- typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
- typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
- typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
- typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
- typedef Kernel::Point_2 Point;
- namespace igl {
- namespace copyleft{
- namespace cgal{
-
- template <typename DerivedP, typename DerivedI, typename DerivedN,
- typename DerivedA>
- IGL_INLINE void point_areas(
- const Eigen::MatrixBase<DerivedP>& P,
- const Eigen::MatrixBase<DerivedI>& I,
- const Eigen::MatrixBase<DerivedN>& N,
- Eigen::PlainObjectBase<DerivedA> & A)
- {
- Eigen::MatrixXd T;
- point_areas(P,I,N,A,T);
- }
-
-
- template <typename DerivedP, typename DerivedI, typename DerivedN,
- typename DerivedA, typename DerivedT>
- IGL_INLINE void point_areas(
- const Eigen::MatrixBase<DerivedP>& P,
- const Eigen::MatrixBase<DerivedI>& I,
- const Eigen::MatrixBase<DerivedN>& N,
- Eigen::PlainObjectBase<DerivedA> & A,
- Eigen::PlainObjectBase<DerivedT> & T)
- {
- typedef typename DerivedP::Scalar real;
- typedef typename DerivedN::Scalar scalarN;
- typedef typename DerivedA::Scalar scalarA;
- typedef Eigen::Matrix<real,1,3> RowVec3;
- typedef Eigen::Matrix<real,1,2> RowVec2;
-
- typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
- typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
- typedef Eigen::Matrix<typename DerivedN::Scalar,
- Eigen::Dynamic, Eigen::Dynamic> VecotorO;
- typedef Eigen::Matrix<typename DerivedI::Scalar,
- Eigen::Dynamic, Eigen::Dynamic> MatrixI;
-
-
-
- const int n = P.rows();
-
- assert(P.cols() == 3 && "P must have exactly 3 columns");
- assert(P.rows() == N.rows()
- && "P and N must have the same number of rows");
- assert(P.rows() == I.rows()
- && "P and I must have the same number of rows");
-
- A.setZero(n,1);
- T.setZero(n,3);
- igl::parallel_for(P.rows(),[&](int i)
- {
- MatrixI neighbor_index = I.row(i);
- MatrixP neighbors;
- igl::slice(P,neighbor_index,1,neighbors);
- if(N.rows() && neighbors.rows() > 1){
- MatrixN neighbor_normals;
- igl::slice(N,neighbor_index,1,neighbor_normals);
- Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
- Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
- poi_normal(0)*neighbor_normals.col(0)
- + poi_normal(1)*neighbor_normals.col(1)
- + poi_normal(2)*neighbor_normals.col(2);
- Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
- igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors);
- }
- if(neighbors.rows() <= 2){
- A(i) = 0;
- } else {
- //subtract the mean from neighbors, then take svd,
- //the scores will be U*S. This is our pca plane fitting
- RowVec3 mean = neighbors.colwise().mean();
- MatrixP mean_centered = neighbors.rowwise() - mean;
- Eigen::JacobiSVD<MatrixP> svd(mean_centered,
- Eigen::ComputeThinU | Eigen::ComputeThinV);
- MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
-
- T.row(i) = svd.matrixV().col(2).transpose();
- if(T.row(i).dot(N.row(i)) < 0){
- T.row(i) *= -1;
- }
-
- MatrixP plane;
- igl::slice(scores,igl::colon<int>(0,scores.rows()-1),
- igl::colon<int>(0,1),plane);
-
- std::vector< std::pair<Point,unsigned> > points;
- //This is where we obtain a delaunay triangulation of the points
- for(unsigned iter = 0; iter < plane.rows(); iter++){
- points.push_back( std::make_pair(
- Point(plane(iter,0),plane(iter,1)), iter ) );
- }
- Delaunay triangulation;
- triangulation.insert(points.begin(),points.end());
- Eigen::MatrixXi F(triangulation.number_of_faces(),3);
- int f_row = 0;
- for(Delaunay::Finite_faces_iterator fit =
- triangulation.finite_faces_begin();
- fit != triangulation.finite_faces_end(); ++fit) {
- Delaunay::Face_handle face = fit;
- F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
- (int)face->vertex(1)->info(),
- (int)face->vertex(2)->info());
- f_row++;
- }
-
- //Here we calculate the voronoi area of the point
- scalarA area_accumulator = 0;
- for(int f = 0; f < F.rows(); f++){
- int X = -1;
- for(int face_iter = 0; face_iter < 3; face_iter++){
- if(F(f,face_iter) == 0){
- X = face_iter;
- }
- }
- if(X >= 0){
- //Triangle XYZ with X being the point we want the area of
- int Y = (X+1)%3;
- int Z = (X+2)%3;
- scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
- scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
- scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
- scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
- scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
- scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
- Eigen::Matrix<scalarA,1,3> barycentric;
- barycentric << x*cosX, y*cosY, z*cosZ;
- barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
-
- //TODO: to make numerically stable, reorder so that x≥y≥z:
- scalarA full_area = 0.25*std::sqrt(
- (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
- Eigen::Matrix<scalarA,1,3> partial_area =
- barycentric * full_area;
- if(cosX < 0){
- area_accumulator += 0.5*full_area;
- } else if (cosY < 0 || cosZ < 0){
- area_accumulator += 0.25*full_area;
- } else {
- area_accumulator += (partial_area(1) + partial_area(2))/2;
- }
- }
- }
-
- if(std::isfinite(area_accumulator)){
- A(i) = area_accumulator;
- } else {
- A(i) = 0;
- }
- }
- },1000);
- }
- }
- }
- }
|