// 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 "AABB.h" #include "EPS.h" #include "barycenter.h" #include "colon.h" #include "doublearea.h" #include "point_simplex_squared_distance.h" #include "project_to_line_segment.h" #include "sort.h" #include "volume.h" #include "ray_box_intersect.h" #include "parallel_for.h" #include "ray_mesh_intersect.h" #include #include #include #include #include #include template template IGL_INLINE void igl::AABB::init( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const Eigen::MatrixBase & bb_mins, const Eigen::MatrixBase & bb_maxs, const Eigen::MatrixBase & elements, const int i) { using namespace std; using namespace Eigen; deinit(); if(bb_mins.size() > 0) { assert(bb_mins.rows() == bb_maxs.rows() && "Serial tree arrays must match"); assert(bb_mins.cols() == V.cols() && "Serial tree array dim must match V"); assert(bb_mins.cols() == bb_maxs.cols() && "Serial tree arrays must match"); assert(bb_mins.rows() == elements.rows() && "Serial tree arrays must match"); // construct from serialization m_box.extend(bb_mins.row(i).transpose()); m_box.extend(bb_maxs.row(i).transpose()); m_primitive = elements(i); // Not leaf then recurse if(m_primitive == -1) { m_left = new AABB(); m_left->init( V,Ele,bb_mins,bb_maxs,elements,2*i+1); m_right = new AABB(); m_right->init( V,Ele,bb_mins,bb_maxs,elements,2*i+2); //m_depth = std::max( m_left->m_depth, m_right->m_depth)+1; } }else { VectorXi allI = colon(0,Ele.rows()-1); MatrixXDIMS BC; if(Ele.cols() == 1) { // points BC = V; }else { // Simplices barycenter(V,Ele,BC); } MatrixXi SI(BC.rows(),BC.cols()); { MatrixXDIMS _; MatrixXi IS; igl::sort(BC,1,true,_,IS); // Need SI(i) to tell which place i would be sorted into const int dim = IS.cols(); for(int i = 0;i template void igl::AABB::init( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele) { using namespace Eigen; // deinit will be immediately called... return init(V,Ele,MatrixXDIMS(),MatrixXDIMS(),VectorXi(),0); } template template < typename DerivedEle, typename DerivedSI, typename DerivedI> IGL_INLINE void igl::AABB::init( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const Eigen::MatrixBase & SI, const Eigen::MatrixBase & I) { using namespace Eigen; using namespace std; deinit(); if(V.size() == 0 || Ele.size() == 0 || I.size() == 0) { return; } assert(DIM == V.cols() && "V.cols() should matched declared dimension"); //const Scalar inf = numeric_limits::infinity(); m_box = AlignedBox(); // Compute bounding box for(int i = 0;iint { size_t n = (A.size()-1)/2; nth_element(A.data(),A.data()+n,A.data()+A.size()); return A(n); }; const int med = median(SIdI); VectorXi LI((I.rows()+1)/2),RI(I.rows()/2); assert(LI.rows()+RI.rows() == I.rows()); // Distribute left and right { int li = 0; int ri = 0; for(int i = 0;i0) { m_left = new AABB(); m_left->init(V,Ele,SI,LI); //m_depth = std::max(m_depth, m_left->m_depth+1); } if(RI.rows()>0) { m_right = new AABB(); m_right->init(V,Ele,SI,RI); //m_depth = std::max(m_depth, m_right->m_depth+1); } } } } template IGL_INLINE bool igl::AABB::is_leaf() const { return m_primitive != -1; } template template IGL_INLINE std::vector igl::AABB::find( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const Eigen::MatrixBase & q, const bool first) const { using namespace std; using namespace Eigen; assert(q.size() == DIM && "Query dimension should match aabb dimension"); assert(Ele.cols() == V.cols()+1 && "AABB::find only makes sense for (d+1)-simplices"); const Scalar epsilon = igl::EPS(); // Check if outside bounding box bool inside = m_box.contains(q.transpose()); if(!inside) { return std::vector(); } assert(m_primitive==-1 || (m_left == NULL && m_right == NULL)); if(is_leaf()) { // Initialize to some value > -epsilon Scalar a1=0,a2=0,a3=0,a4=0; switch(DIM) { case 3: { // Barycentric coordinates typedef Eigen::Matrix RowVector3S; const RowVector3S V1 = V.row(Ele(m_primitive,0)); const RowVector3S V2 = V.row(Ele(m_primitive,1)); const RowVector3S V3 = V.row(Ele(m_primitive,2)); const RowVector3S V4 = V.row(Ele(m_primitive,3)); a1 = volume_single(V2,V4,V3,(RowVector3S)q); a2 = volume_single(V1,V3,V4,(RowVector3S)q); a3 = volume_single(V1,V4,V2,(RowVector3S)q); a4 = volume_single(V1,V2,V3,(RowVector3S)q); break; } case 2: { // Barycentric coordinates typedef Eigen::Matrix Vector2S; const Vector2S V1 = V.row(Ele(m_primitive,0)); const Vector2S V2 = V.row(Ele(m_primitive,1)); const Vector2S V3 = V.row(Ele(m_primitive,2)); // Hack for now to keep templates simple. If becomes bottleneck // consider using std::enable_if_t const Vector2S q2 = q.head(2); a1 = doublearea_single(V1,V2,q2); a2 = doublearea_single(V2,V3,q2); a3 = doublearea_single(V3,V1,q2); break; } default:assert(false); } // Normalization is important for correcting sign Scalar sum = a1+a2+a3+a4; a1 /= sum; a2 /= sum; a3 /= sum; a4 /= sum; if( a1>=-epsilon && a2>=-epsilon && a3>=-epsilon && a4>=-epsilon) { return std::vector(1,m_primitive); }else { return std::vector(); } } std::vector left = m_left->find(V,Ele,q,first); if(first && !left.empty()) { return left; } std::vector right = m_right->find(V,Ele,q,first); if(first) { return right; } left.insert(left.end(),right.begin(),right.end()); return left; } template IGL_INLINE int igl::AABB::subtree_size() const { // 1 for self int n = 1; int n_left = 0,n_right = 0; if(m_left != NULL) { n_left = m_left->subtree_size(); } if(m_right != NULL) { n_right = m_right->subtree_size(); } n += 2*std::max(n_left,n_right); return n; } template template IGL_INLINE void igl::AABB::serialize( Eigen::PlainObjectBase & bb_mins, Eigen::PlainObjectBase & bb_maxs, Eigen::PlainObjectBase & elements, const int i) const { using namespace std; using namespace Eigen; // Calling for root then resize output if(i==0) { const int m = subtree_size(); //cout<<"m: "<serialize(bb_mins,bb_maxs,elements,2*i+1); } if(m_right != NULL) { m_right->serialize(bb_mins,bb_maxs,elements,2*i+2); } } template template IGL_INLINE typename igl::AABB::Scalar igl::AABB::squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & p, int & i, Eigen::PlainObjectBase & c) const { return squared_distance(V,Ele,p,std::numeric_limits::infinity(),i,c); } template template IGL_INLINE typename igl::AABB::Scalar igl::AABB::squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & p, Scalar low_sqr_d, Scalar up_sqr_d, int & i, Eigen::PlainObjectBase & c) const { using namespace Eigen; using namespace std; //assert(low_sqr_d <= up_sqr_d); if(low_sqr_d > up_sqr_d) { return low_sqr_d; } Scalar sqr_d = up_sqr_d; //assert(DIM == 3 && "Code has only been tested for DIM == 3"); assert((Ele.cols() == 3 || Ele.cols() == 2 || Ele.cols() == 1) && "Code has only been tested for simplex sizes 3,2,1"); assert(m_primitive==-1 || (m_left == NULL && m_right == NULL)); if(is_leaf()) { leaf_squared_distance(V,Ele,p,low_sqr_d,sqr_d,i,c); }else { bool looked_left = false; bool looked_right = false; const auto & look_left = [&]() { int i_left; RowVectorDIMS c_left = c; Scalar sqr_d_left = m_left->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_left,c_left); this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c); looked_left = true; }; const auto & look_right = [&]() { int i_right; RowVectorDIMS c_right = c; Scalar sqr_d_right = m_right->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_right,c_right); this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c); looked_right = true; }; // must look left or right if in box if(m_left->m_box.contains(p.transpose())) { look_left(); } if(m_right->m_box.contains(p.transpose())) { look_right(); } // if haven't looked left and could be less than current min, then look Scalar left_up_sqr_d = m_left->m_box.squaredExteriorDistance(p.transpose()); Scalar right_up_sqr_d = m_right->m_box.squaredExteriorDistance(p.transpose()); if(left_up_sqr_d < right_up_sqr_d) { if(!looked_left && left_up_sqr_d template IGL_INLINE typename igl::AABB::Scalar igl::AABB::squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & p, Scalar up_sqr_d, int & i, Eigen::PlainObjectBase & c) const { return squared_distance(V,Ele,p,0.0,up_sqr_d,i,c); } template template < typename DerivedEle, typename DerivedP, typename DerivedsqrD, typename DerivedI, typename DerivedC> IGL_INLINE void igl::AABB::squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const Eigen::MatrixBase & P, Eigen::PlainObjectBase & sqrD, Eigen::PlainObjectBase & I, Eigen::PlainObjectBase & C) const { assert(P.cols() == V.cols() && "cols in P should match dim of cols in V"); sqrD.resize(P.rows(),1); I.resize(P.rows(),1); C.resizeLike(P); // O( #P * log #Ele ), where log #Ele is really the depth of this AABB // hierarchy //for(int p = 0;p template < typename DerivedEle, typename Derivedother_V, typename Derivedother_Ele, typename DerivedsqrD, typename DerivedI, typename DerivedC> IGL_INLINE void igl::AABB::squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const AABB & other, const Eigen::MatrixBase & other_V, const Eigen::MatrixBase & other_Ele, Eigen::PlainObjectBase & sqrD, Eigen::PlainObjectBase & I, Eigen::PlainObjectBase & C) const { assert(other_Ele.cols() == 1 && "Only implemented for other as list of points"); assert(other_V.cols() == V.cols() && "other must match this dimension"); sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits::infinity()); I.resize(other_Ele.rows(),1); C.resize(other_Ele.rows(),other_V.cols()); // All points in other_V currently think they need to check against root of // this. The point of using another AABB is to quickly prune chunks of // other_V so that most points just check some subtree of this. // This holds a conservative estimate of max(sqr_D) where sqr_D is the // current best minimum squared distance for all points in this subtree double up_sqr_d = std::numeric_limits::infinity(); squared_distance_helper( V,Ele,&other,other_V,other_Ele,0,up_sqr_d,sqrD,I,C); } template template < typename DerivedEle, typename Derivedother_V, typename Derivedother_Ele, typename DerivedsqrD, typename DerivedI, typename DerivedC> IGL_INLINE typename igl::AABB::Scalar igl::AABB::squared_distance_helper( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const AABB * other, const Eigen::MatrixBase & other_V, const Eigen::MatrixBase & other_Ele, const Scalar /*up_sqr_d*/, Eigen::PlainObjectBase & sqrD, Eigen::PlainObjectBase & I, Eigen::PlainObjectBase & C) const { using namespace std; using namespace Eigen; // This implementation is a bit disappointing. There's no major speed up. Any // performance gains seem to come from accidental cache coherency and // diminish for larger "other" (the opposite of what was intended). // Base case if(other->is_leaf() && this->is_leaf()) { Scalar sqr_d = sqrD(other->m_primitive); int i = I(other->m_primitive); RowVectorDIMS c = C.row( other->m_primitive); RowVectorDIMS p = other_V.row(other->m_primitive); leaf_squared_distance(V,Ele,p,sqr_d,i,c); sqrD( other->m_primitive) = sqr_d; I( other->m_primitive) = i; C.row(other->m_primitive) = c; //cout<<"leaf: "<m_low_sqr_d = sqr_d; return sqr_d; } if(other->is_leaf()) { Scalar sqr_d = sqrD(other->m_primitive); int i = I(other->m_primitive); RowVectorDIMS c = C.row( other->m_primitive); RowVectorDIMS p = other_V.row(other->m_primitive); sqr_d = squared_distance(V,Ele,p,sqr_d,i,c); sqrD( other->m_primitive) = sqr_d; I( other->m_primitive) = i; C.row(other->m_primitive) = c; //other->m_low_sqr_d = sqr_d; return sqr_d; } //// Exact minimum squared distance between arbitrary primitives inside this and //// othre's bounding boxes //const auto & min_squared_distance = [&]( // const AABB * A, // const AABB * B)->Scalar //{ // return A->m_box.squaredExteriorDistance(B->m_box); //}; if(this->is_leaf()) { //if(min_squared_distance(this,other) < other->m_low_sqr_d) if(true) { this->squared_distance_helper( V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C); this->squared_distance_helper( V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C); }else { // This is never reached... } //// we know other is not a leaf //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); return 0; } // FORCE DOWN TO OTHER LEAF EVAL //if(min_squared_distance(this,other) < other->m_low_sqr_d) if(true) { if(true) { this->squared_distance_helper( V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C); this->squared_distance_helper( V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C); }else // this direction never seems to be faster { this->m_left->squared_distance_helper( V,Ele,other,other_V,other_Ele,0,sqrD,I,C); this->m_right->squared_distance_helper( V,Ele,other,other_V,other_Ele,0,sqrD,I,C); } }else { // this is never reached ... :-( } //// we know other is not a leaf //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); return 0; #if 0 // False // _Very_ conservative approximation of maximum squared distance between // primitives inside this and other's bounding boxes const auto & max_squared_distance = []( const AABB * A, const AABB * B)->Scalar { AlignedBox combo = A->m_box; combo.extend(B->m_box); return combo.diagonal().squaredNorm(); }; //// other base-case //if(other->is_leaf()) //{ // double sqr_d = sqrD(other->m_primitive); // int i = I(other->m_primitive); // RowVectorDIMS c = C.row(m_primitive); // RowVectorDIMS p = other_V.row(m_primitive); // leaf_squared_distance(V,Ele,p,sqr_d,i,c); // sqrD(other->m_primitive) = sqr_d; // I(other->m_primitive) = i; // C.row(m_primitive) = c; // return; //} std::vector * > this_list; if(this->is_leaf()) { this_list.push_back(this); }else { assert(this->m_left); this_list.push_back(this->m_left); assert(this->m_right); this_list.push_back(this->m_right); } std::vector *> other_list; if(other->is_leaf()) { other_list.push_back(other); }else { assert(other->m_left); other_list.push_back(other->m_left); assert(other->m_right); other_list.push_back(other->m_right); } //const std::function * other) // > low_sqr_d = [&sqrD,&low_sqr_d](const AABB * other)->Scalar // { // if(other->is_leaf()) // { // return sqrD(other->m_primitive); // }else // { // return std::max(low_sqr_d(other->m_left),low_sqr_d(other->m_right)); // } // }; //// Potentially recurse on all pairs, if minimum distance is less than running //// bound //Eigen::Matrix other_low_sqr_d = // Eigen::Matrix::Constant(other_list.size(),1,up_sqr_d); for(size_t child = 0;child this_low_sqr_d(this_list.size(),1); for(size_t t = 0;t this_low_sqr_d(1)) ) { std::swap(this_list[0],this_list[1]); //std::swap(this_low_sqr_d(0),this_low_sqr_d(1)); } const Scalar sqr_d = this_low_sqr_d.minCoeff(); for(size_t t = 0;tm_low_sqr_d) { //cout<<"before: "<squared_distance_helper( // V,Ele,other_tree,other_V,other_Ele,other_low_sqr_d(child),sqrD,I,C)); //cout<<"after: "<squared_distance_helper( V,Ele,other_tree,other_V,other_Ele,0,sqrD,I,C); } } } //const Scalar ret = other_low_sqr_d.maxCoeff(); //const auto mm = low_sqr_d(other); //assert(mm == ret); //cout<<"non-leaf: "<is_leaf()) { other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d); } return 0; #endif } template template IGL_INLINE void igl::AABB::leaf_squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & p, const Scalar low_sqr_d, Scalar & sqr_d, int & i, Eigen::PlainObjectBase & c) const { using namespace Eigen; using namespace std; if(low_sqr_d > sqr_d) { sqr_d = low_sqr_d; return; } RowVectorDIMS c_candidate; Scalar sqr_d_candidate; igl::point_simplex_squared_distance( p,V,Ele,m_primitive,sqr_d_candidate,c_candidate); set_min(p,sqr_d_candidate,m_primitive,c_candidate,sqr_d,i,c); } template template IGL_INLINE void igl::AABB::leaf_squared_distance( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & p, Scalar & sqr_d, int & i, Eigen::PlainObjectBase & c) const { return leaf_squared_distance(V,Ele,p,0,sqr_d,i,c); } template IGL_INLINE void igl::AABB::set_min( const RowVectorDIMS & #ifndef NDEBUG p #endif , const Scalar sqr_d_candidate, const int i_candidate, const RowVectorDIMS & c_candidate, Scalar & sqr_d, int & i, Eigen::PlainObjectBase & c) const { #ifndef NDEBUG //std::cout< template IGL_INLINE bool igl::AABB::intersect_ray( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & origin, const RowVectorDIMS & dir, std::vector & hits) const { hits.clear(); const Scalar t0 = 0; const Scalar t1 = std::numeric_limits::infinity(); { Scalar _1,_2; if(!ray_box_intersect(origin,dir,m_box,t0,t1,_1,_2)) { return false; } } if(this->is_leaf()) { // Actually process elements assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); // Cheesecake way of hitting element bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hits); // Since we only gave ray_mesh_intersect a single face, it will have set // any hits to id=0. Set these to this primitive's id for(auto & hit : hits) { hit.id = m_primitive; } return ret; } std::vector left_hits; std::vector right_hits; const bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,left_hits); const bool right_ret = m_right->intersect_ray(V,Ele,origin,dir,right_hits); hits.insert(hits.end(),left_hits.begin(),left_hits.end()); hits.insert(hits.end(),right_hits.begin(),right_hits.end()); return left_ret || right_ret; } template template IGL_INLINE bool igl::AABB::intersect_ray( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & origin, const RowVectorDIMS & dir, igl::Hit & hit) const { // FIXME: Needs a proper path #if /*false*/ 0 // BFS std::queue Q; // Or DFS //std::stack Q; Q.push(this); bool any_hit = false; hit.t = std::numeric_limits::infinity(); while(!Q.empty()) { const AABB * tree = Q.front(); //const AABB * tree = Q.top(); Q.pop(); { Scalar _1,_2; if(!ray_box_intersect( origin,dir,tree->m_box,Scalar(0),Scalar(hit.t),_1,_2)) { continue; } } if(tree->is_leaf()) { // Actually process elements assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); igl::Hit leaf_hit; if( ray_mesh_intersect(origin,dir,V,Ele.row(tree->m_primitive),leaf_hit)&& leaf_hit.t < hit.t) { // correct the id leaf_hit.id = tree->m_primitive; hit = leaf_hit; } continue; } // Add children to queue Q.push(tree->m_left); Q.push(tree->m_right); } return any_hit; #else // DFS return intersect_ray( V,Ele,origin,dir,std::numeric_limits::infinity(),hit); #endif } template template IGL_INLINE bool igl::AABB::intersect_ray( const Eigen::MatrixBase & V, const Eigen::MatrixBase & Ele, const RowVectorDIMS & origin, const RowVectorDIMS & dir, const Scalar _min_t, igl::Hit & hit) const { //// Naive, slow //std::vector hits; //intersect_ray(V,Ele,origin,dir,hits); //if(hits.size() > 0) //{ // hit = hits.front(); // return true; //}else //{ // return false; //} Scalar min_t = _min_t; const Scalar t0 = 0; { Scalar _1,_2; if(!ray_box_intersect(origin,dir,m_box,t0,min_t,_1,_2)) { return false; } } if(this->is_leaf()) { // Actually process elements assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles"); // Cheesecake way of hitting element bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hit); hit.id = m_primitive; return ret; } // Doesn't seem like smartly choosing left before/after right makes a // differnce igl::Hit left_hit; igl::Hit right_hit; bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,min_t,left_hit); if(left_ret && left_hit.tintersect_ray(V,Ele,origin,dir,min_t,right_hit); if(right_ret && right_hit.t template<> IGL_INLINE float AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; template<> template<> IGL_INLINE float igl::AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; template<> template<> IGL_INLINE void igl::AABB, 2>::init (Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) { assert(false);}; template<> template<> IGL_INLINE double AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; template<> template<> IGL_INLINE double igl::AABB, 2>::squared_distance( Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, double, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; template<> template<> IGL_INLINE void igl::AABB, 2>::init (Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) { assert(false);}; template<> template<> IGL_INLINE void igl::AABB, 2>::init(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&) {assert(false);}; template<> template<> IGL_INLINE float igl::AABB, 2>::squared_distance(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const { assert(false);return -1;}; } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, double, int&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); // generated by autoexplicit.sh // generated by autoexplicit.sh template float igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, float, float, int&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh // generated by autoexplicit.sh template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); // generated by autoexplicit.sh template void igl::AABB, 3>::serialize, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int) const; // generated by autoexplicit.sh template std::vector > igl::AABB, 3>::find, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool) const; // generated by autoexplicit.sh template void igl::AABB, 2>::serialize, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, int) const; // generated by autoexplicit.sh template std::vector > igl::AABB, 2>::find, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, bool) const; // generated by autoexplicit.sh template void igl::AABB, 3>::init, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int); // generated by autoexplicit.sh template void igl::AABB, 2>::init, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int); // generated by autoexplicit.sh template float igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 3>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 2>::squared_distance, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template double igl::AABB, 2>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, int&, Eigen::PlainObjectBase >&) const; // generated by autoexplicit.sh template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); // generated by autoexplicit.sh template void igl::AABB, 3>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); // generated by autoexplicit.sh template void igl::AABB, 2>::init >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&); template double igl::AABB, 3>::squared_distance >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, double, int&, Eigen::PlainObjectBase >&) const; template bool igl::AABB, 3>::intersect_ray >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, Eigen::Matrix const&, Eigen::Matrix const&, igl::Hit&) const; #endif