// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2014 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 "signed_distance.h" #include "../per_vertex_normals.h" #include "../per_edge_normals.h" #include "../per_face_normals.h" #include "../get_seconds.h" #include "point_mesh_squared_distance.h" template IGL_INLINE void igl::signed_distance( const Eigen::MatrixXd & P, const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const SignedDistanceType sign_type, Eigen::VectorXd & S, Eigen::VectorXi & I, Eigen::MatrixXd & C, Eigen::MatrixXd & N) { using namespace Eigen; using namespace std; assert(V.cols() == 3 && "V should have 3d positions"); assert(P.cols() == 3 && "P should have 3d positions"); assert(F.cols() == 3 && "F should have triangles"); typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename CGAL::Triangle_3 Triangle_3; typedef typename std::vector::iterator Iterator; typedef typename CGAL::AABB_triangle_primitive Primitive; typedef typename CGAL::AABB_traits AABB_triangle_traits; typedef typename CGAL::AABB_tree Tree; typedef typename Tree::Point_and_primitive_id Point_and_primitive_id; // Prepare distance computation Tree tree; vector T; point_mesh_squared_distance_precompute(V,F,tree,T); Eigen::MatrixXd FN,VN,EN; Eigen::MatrixXi E; Eigen::VectorXi EMAP; WindingNumberAABB hier; switch(sign_type) { default: assert(false && "Unknown SignedDistanceType"); case SIGNED_DISTANCE_TYPE_DEFAULT: case SIGNED_DISTANCE_TYPE_WINDING_NUMBER: hier.set_mesh(V,F); hier.grow(); break; case SIGNED_DISTANCE_TYPE_PSEUDONORMAL: // "Signed Distance Computation Using the Angle Weighted Pseudonormal" // [Bærentzen & Aanæs 2005] per_face_normals(V,F,FN); per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN); per_edge_normals( V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP); N.resize(P.rows(),3); break; } S.resize(P.rows(),1); I.resize(P.rows(),1); C.resize(P.rows(),3); for(int p = 0;p IGL_INLINE typename Kernel::FT igl::signed_distance_pseudonormal( const CGAL::AABB_tree< CGAL::AABB_traits >::iterator > > > & tree, const std::vector > & T, const Eigen::MatrixXi & F, const Eigen::MatrixXd & FN, const Eigen::MatrixXd & VN, const Eigen::MatrixXd & EN, const Eigen::VectorXi & EMAP, const typename Kernel::Point_3 & q) { typename CGAL::AABB_tree< CGAL::AABB_traits >::iterator> > >::Point_and_primitive_id pp; typename Kernel::FT s,sqrd; Eigen::Vector3d n(0,0,0); signed_distance_pseudonormal(tree,T,F,FN,VN,EN,EMAP,q,s,sqrd,pp,n); return s*sqrt(sqrd); } template IGL_INLINE void igl::signed_distance_pseudonormal( const CGAL::AABB_tree< CGAL::AABB_traits >::iterator > > > & tree, const std::vector > & T, const Eigen::MatrixXi & F, const Eigen::MatrixXd & FN, const Eigen::MatrixXd & VN, const Eigen::MatrixXd & EN, const Eigen::VectorXi & EMAP, const typename Kernel::Point_3 & q, typename Kernel::FT & s, typename Kernel::FT & sqrd, typename CGAL::AABB_tree< CGAL::AABB_traits >::iterator> > >::Point_and_primitive_id & pp, Eigen::Vector3d & n) { using namespace Eigen; using namespace std; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename CGAL::Triangle_3 Triangle_3; typedef typename std::vector::iterator Iterator; typedef typename CGAL::AABB_triangle_primitive Primitive; typedef typename CGAL::AABB_traits AABB_triangle_traits; typedef typename CGAL::AABB_tree Tree; typedef typename Tree::Point_and_primitive_id Point_and_primitive_id; pp = tree.closest_point_and_primitive(q); Point_3 & p = pp.first; const auto & qp = q-p; sqrd = qp.squared_length(); Vector3d v(qp.x(),qp.y(),qp.z()); const int f = pp.second - T.begin(); const Triangle_3 & t = *pp.second; // barycentric coordinates const auto & area = [&p,&t](const int i, const int j)->FT { return sqrt(Triangle_3(p,t.vertex(i),t.vertex(j)).squared_area()); }; Vector3d b(area(1,2),area(2,0),area(0,1)); b /= b.sum(); // Determine which normal to use const double epsilon = 1e-12; const int type = (b.array()<=epsilon).cast().sum(); switch(type) { case 2: // Find vertex for(int c = 0;c<3;c++) { if(b(c)>epsilon) { n = VN.row(F(f,c)); break; } } break; case 1: // Find edge for(int c = 0;c<3;c++) { if(b(c)<=epsilon) { n = EN.row(EMAP(F.rows()*c+f)); break; } } break; default: assert(false && "all barycentric coords zero."); case 0: n = FN.row(f); break; } s = (v.dot(n) >= 0 ? 1. : -1.); } template IGL_INLINE typename Kernel::FT igl::signed_distance_winding_number( const CGAL::AABB_tree< CGAL::AABB_traits >::iterator > > > & tree, const igl::WindingNumberAABB & hier, const typename Kernel::Point_3 & q) { typename CGAL::AABB_tree< CGAL::AABB_traits >::iterator> > >::Point_and_primitive_id pp; typename Kernel::FT s,sqrd; signed_distance_winding_number(tree,hier,q,s,sqrd,pp); return s*sqrt(sqrd); } template IGL_INLINE void igl::signed_distance_winding_number( const CGAL::AABB_tree< CGAL::AABB_traits >::iterator > > > & tree, const igl::WindingNumberAABB & hier, const typename Kernel::Point_3 & q, typename Kernel::FT & s, typename Kernel::FT & sqrd, typename CGAL::AABB_tree< CGAL::AABB_traits >::iterator> > >::Point_and_primitive_id & pp) { typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename CGAL::Triangle_3 Triangle_3; typedef typename std::vector::iterator Iterator; typedef typename CGAL::AABB_triangle_primitive Primitive; typedef typename CGAL::AABB_traits AABB_triangle_traits; typedef typename CGAL::AABB_tree Tree; typedef typename Tree::Point_and_primitive_id Point_and_primitive_id; using namespace Eigen; using namespace std; using namespace igl; pp = tree.closest_point_and_primitive(q); Point_3 & p = pp.first; const auto & qp = q-p; const Vector3d eq(q.x(),q.y(),q.z()); sqrd = qp.squared_length(); const double w = hier.winding_number(eq); s = 1.-2.*w; } #ifdef IGL_STATIC_LIBRARY // This template is necessary for the others to compile with clang // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable template void igl::signed_distance( const Eigen::MatrixXd & , const Eigen::MatrixXd & , const Eigen::MatrixXi & , const SignedDistanceType , Eigen::VectorXd & , Eigen::VectorXi &, Eigen::MatrixXd & , Eigen::MatrixXd & ); template CGAL::Epick::FT igl::signed_distance_winding_number(CGAL::AABB_tree, std::allocator > >::iterator, CGAL::Boolean_tag > > > const&, igl::WindingNumberAABB > const&, CGAL::Epick::Point_3 const&); template CGAL::Epick::FT igl::signed_distance_pseudonormal(CGAL::AABB_tree, std::allocator > >::iterator, CGAL::Boolean_tag > > > const&, std::vector, std::allocator > > const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, CGAL::Epick::Point_3 const&); template void igl::signed_distance_pseudonormal >(CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag > > > const&, std::vector >, std::allocator > > > const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, Eigen::Matrix const&, CGAL::Simple_cartesian::Point_3 const&, CGAL::Simple_cartesian::FT&, CGAL::Simple_cartesian::FT&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag > > >::Point_and_primitive_id&, Eigen::Matrix&); template void igl::signed_distance_winding_number >(CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag > > > const&, igl::WindingNumberAABB > const&, CGAL::Simple_cartesian::Point_3 const&, CGAL::Simple_cartesian::FT&, CGAL::Simple_cartesian::FT&, CGAL::AABB_tree, CGAL::AABB_triangle_primitive, std::vector >, std::allocator > > >::iterator, CGAL::Boolean_tag > > >::Point_and_primitive_id&); #endif