// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2013 Alec Jacobson // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "doublearea.h" #include "edge_lengths.h" #include "sort.h" #include #include template IGL_INLINE void igl::doublearea( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, Eigen::PlainObjectBase & dblA) { if (F.cols() == 4) // quads are handled by a specialized function return doublearea_quad(V,F,dblA); const int dim = V.cols(); // Only support triangles assert(F.cols() == 3); const size_t m = F.rows(); // Compute edge lengths Eigen::Matrix l; // "Lecture Notes on Geometric Robustness" Shewchuck 09, Section 3.1 // http://www.cs.berkeley.edu/~jrs/meshpapers/robnotes.pdf // Projected area helper const auto & proj_doublearea = [&V,&F](const int x, const int y, const int f)->double { auto rx = V(F(f,0),x)-V(F(f,2),x); auto sx = V(F(f,1),x)-V(F(f,2),x); auto ry = V(F(f,0),y)-V(F(f,2),y); auto sy = V(F(f,1),y)-V(F(f,2),y); return rx*sy - ry*sx; }; switch(dim) { case 3: { dblA = Eigen::PlainObjectBase::Zero(m,1); for(size_t f = 0;f IGL_INLINE void igl::doublearea( const Eigen::PlainObjectBase & A, const Eigen::PlainObjectBase & B, const Eigen::PlainObjectBase & C, Eigen::PlainObjectBase & D) { assert((B.cols() == A.cols()) && "dimensions of A and B should match"); assert((C.cols() == A.cols()) && "dimensions of A and C should match"); assert(A.rows() == B.rows() && "corners should have same length"); assert(A.rows() == C.rows() && "corners should have same length"); switch(A.cols()) { case 2: { // For 2d compute signed area const auto & R = A-C; const auto & S = B-C; D = R.col(0).array()*S.col(1).array() - R.col(1).array()*S.col(0).array(); break; } default: { Eigen::Matrix uL(A.rows(),3); uL.col(0) = (B-C).rowwise().norm(); uL.col(1) = (C-A).rowwise().norm(); uL.col(2) = (A-B).rowwise().norm(); doublearea(uL,D); } } } template < typename DerivedA, typename DerivedB, typename DerivedC> IGL_INLINE typename DerivedA::Scalar igl::doublearea_single( const Eigen::PlainObjectBase & A, const Eigen::PlainObjectBase & B, const Eigen::PlainObjectBase & C) { assert(A.size() == 2 && "Vertices should be 2D"); assert(B.size() == 2 && "Vertices should be 2D"); assert(C.size() == 2 && "Vertices should be 2D"); auto r = A-C; auto s = B-C; return r(0)*s(1) - r(1)*s(0); } template IGL_INLINE void igl::doublearea( const Eigen::PlainObjectBase & ul, Eigen::PlainObjectBase & dblA) { using namespace Eigen; using namespace std; typedef typename Derivedl::Index Index; // Only support triangles assert(ul.cols() == 3); // Number of triangles const Index m = ul.rows(); Eigen::Matrix l; MatrixXi _; sort(ul,2,false,l,_); // semiperimeters Matrix s = l.rowwise().sum()*0.5; assert((Index)s.rows() == m); // resize output dblA.resize(l.rows(),1); // Minimum number of iterms per openmp thread #ifndef IGL_OMP_MIN_VALUE # define IGL_OMP_MIN_VALUE 1000 #endif #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE) for(Index i = 0;i=0); //dblA(i) = 2.0*sqrt(arg); // Kahan's Heron's formula const typename Derivedl::Scalar arg = (l(i,0)+(l(i,1)+l(i,2)))* (l(i,2)-(l(i,0)-l(i,1)))* (l(i,2)+(l(i,0)-l(i,1)))* (l(i,0)+(l(i,1)-l(i,2))); dblA(i) = 2.0*0.25*sqrt(arg); assert( l(i,2) - (l(i,0)-l(i,1)) && "FAILED KAHAN'S ASSERTION"); assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN"); } } template IGL_INLINE void igl::doublearea_quad( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, Eigen::PlainObjectBase & dblA) { assert(V.cols() == 3); // Only supports points in 3D assert(F.cols() == 4); // Only support quads const size_t m = F.rows(); // Split the quads into triangles Eigen::MatrixXi Ft(F.rows()*2,3); for(size_t i=0; i, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); // generated by autoexplicit.sh template void igl::doublearea, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); // generated by autoexplicit.sh template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template Eigen::Matrix::Scalar igl::doublearea_single, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #endif