// 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 "parallel_for.h" #include "sort.h" #include #include #include template IGL_INLINE void igl::doublearea( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, Eigen::PlainObjectBase & dblA) { // quads are handled by a specialized function if (F.cols() == 4) 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; // Projected area helper const auto & proj_doublearea = [&V,&F](const int x, const int y, const int f) ->typename DerivedV::Scalar { 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 = DeriveddblA::Zero(m,1); for(size_t f = 0;f IGL_INLINE void igl::doublearea( const Eigen::MatrixBase & A, const Eigen::MatrixBase & B, const Eigen::MatrixBase & 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()).template cast< typename DerivedD::Scalar>(); break; } default: { Eigen::Matrix uL(A.rows(),3); uL.col(0) = ((B-C).rowwise().norm()).template cast(); uL.col(1) = ((C-A).rowwise().norm()).template cast(); uL.col(2) = ((A-B).rowwise().norm()).template cast(); doublearea(uL,D); } } } template < typename DerivedA, typename DerivedB, typename DerivedC> IGL_INLINE typename DerivedA::Scalar igl::doublearea_single( const Eigen::MatrixBase & A, const Eigen::MatrixBase & B, const Eigen::MatrixBase & 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::MatrixBase & ul, Eigen::PlainObjectBase & dblA) { // Default is to leave NaNs and fire asserts in debug mode return doublearea( ul,std::numeric_limits::quiet_NaN(),dblA); } template IGL_INLINE void igl::doublearea( const Eigen::MatrixBase & ul, const typename Derivedl::Scalar nan_replacement, 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 _; // // "Miscalculating Area and Angles of a Needle-like Triangle" // https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf igl::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); parallel_for( m, [&l,&dblA,&nan_replacement](const int i) { // Kahan's Heron's formula typedef typename Derivedl::Scalar Scalar; const 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); // Alec: If the input edge lengths were computed from floating point // vertex positions then there's no guarantee that they fulfill the // triangle inequality (in their floating point approximations). For // nearly degenerate triangles the round-off error during side-length // computation may be larger than (or rather smaller) than the height of // the triangle. In "Lecture Notes on Geometric Robustness" Shewchuck 09, // Section 3.1 http://www.cs.berkeley.edu/~jrs/meshpapers/robnotes.pdf, // he recommends computing the triangle areas for 2D and 3D using 2D // signed areas computed with determinants. assert( (nan_replacement == nan_replacement || (l(i,2) - (l(i,0)-l(i,1)))>=0) && "Side lengths do not obey the triangle inequality."); if(dblA(i) != dblA(i)) { dblA(i) = nan_replacement; } assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN"); }, 1000l); } template IGL_INLINE void igl::doublearea_quad( const Eigen::MatrixBase & V, const Eigen::MatrixBase & 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::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::Matrix::Scalar, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template void igl::doublearea, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&); template Eigen::Matrix::Scalar igl::doublearea_single, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); template Eigen::Matrix::Scalar igl::doublearea_single, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); #endif