// 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/. // # MUTUAL DEPENDENCY ISSUE FOR HEADER ONLY VERSION // MUST INCLUDE winding_number.h first before guard: #include "winding_number.h" #ifndef IGL_WINDINGNUMBERAABB_H #define IGL_WINDINGNUMBERAABB_H #include "WindingNumberTree.h" namespace igl { template < typename Point, typename DerivedV, typename DerivedF > class WindingNumberAABB : public WindingNumberTree { protected: Point min_corner; Point max_corner; typename DerivedV::Scalar total_positive_area; public: enum SplitMethod { CENTER_ON_LONGEST_AXIS = 0, MEDIAN_ON_LONGEST_AXIS = 1, NUM_SPLIT_METHODS = 2 } split_method; public: inline WindingNumberAABB(): total_positive_area(std::numeric_limits::infinity()), split_method(MEDIAN_ON_LONGEST_AXIS) {} inline WindingNumberAABB( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F); inline WindingNumberAABB( const WindingNumberTree & parent, const Eigen::MatrixBase & F); // Initialize some things inline void set_mesh( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F); inline void init(); inline bool inside(const Point & p) const; inline virtual void grow(); // Compute min and max corners inline void compute_min_max_corners(); inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const; inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const; }; } // Implementation #include "winding_number.h" #include "barycenter.h" #include "median.h" #include "doublearea.h" #include "per_face_normals.h" #include #include #include // Minimum number of faces in a hierarchy element (this is probably dependent // on speed of machine and compiler optimization) #ifndef WindingNumberAABB_MIN_F # define WindingNumberAABB_MIN_F 100 #endif template inline void igl::WindingNumberAABB::set_mesh( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F) { igl::WindingNumberTree::set_mesh(V,F); init(); } template inline void igl::WindingNumberAABB::init() { using namespace Eigen; assert(max_corner.size() == 3); assert(min_corner.size() == 3); compute_min_max_corners(); Eigen::Matrix dblA; doublearea(this->getV(),this->getF(),dblA); total_positive_area = dblA.sum()/2.0; } template inline igl::WindingNumberAABB::WindingNumberAABB( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F): WindingNumberTree(V,F), min_corner(), max_corner(), total_positive_area( std::numeric_limits::infinity()), split_method(MEDIAN_ON_LONGEST_AXIS) { init(); } template inline igl::WindingNumberAABB::WindingNumberAABB( const WindingNumberTree & parent, const Eigen::MatrixBase & F): WindingNumberTree(parent,F), min_corner(), max_corner(), total_positive_area( std::numeric_limits::infinity()), split_method(MEDIAN_ON_LONGEST_AXIS) { init(); } template inline void igl::WindingNumberAABB::grow() { using namespace std; using namespace Eigen; // Clear anything that already exists this->delete_children(); //cout<<"cap.rows(): "<getcap().rows()<getF().rows()<getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) || (this->getcap().rows() - 2) >= this->getF().rows()) { // Don't grow return; } // Compute longest direction int max_d = -1; typename DerivedV::Scalar max_len = -numeric_limits::infinity(); for(int d = 0;d max_len ) { max_len = (max_corner[d] - min_corner[d]); max_d = d; } } // Compute facet barycenters Eigen::Matrix BC; barycenter(this->getV(),this->getF(),BC); // Blerg, why is selecting rows so difficult typename DerivedV::Scalar split_value; // Split in longest direction switch(split_method) { case MEDIAN_ON_LONGEST_AXIS: // Determine median median(BC.col(max_d),split_value); break; default: assert(false); case CENTER_ON_LONGEST_AXIS: split_value = 0.5*(max_corner[max_d] + min_corner[max_d]); break; } //cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<< // "m: "< id( this->getF().rows()); for(int i = 0;igetF().rows();i++) { if(BC(i,max_d) <= split_value) { id[i] = 0; //left }else { id[i] = 1; //right } } const int lefts = (int) count(id.begin(),id.end(),0); const int rights = (int) count(id.begin(),id.end(),1); if(lefts == 0 || rights == 0) { // badly balanced base case (could try to recut) return; } assert(lefts+rights == this->getF().rows()); DerivedF leftF(lefts, this->getF().cols()); DerivedF rightF(rights,this->getF().cols()); int left_i = 0; int right_i = 0; for(int i = 0;igetF().rows();i++) { if(id[i] == 0) { leftF.row(left_i++) = this->getF().row(i); }else if(id[i] == 1) { rightF.row(right_i++) = this->getF().row(i); }else { assert(false); } } assert(right_i == rightF.rows()); assert(left_i == leftF.rows()); // Finally actually grow children and Recursively grow WindingNumberAABB * leftWindingNumberAABB = new WindingNumberAABB(*this,leftF); leftWindingNumberAABB->grow(); this->children.push_back(leftWindingNumberAABB); WindingNumberAABB * rightWindingNumberAABB = new WindingNumberAABB(*this,rightF); rightWindingNumberAABB->grow(); this->children.push_back(rightWindingNumberAABB); } template inline bool igl::WindingNumberAABB::inside(const Point & p) const { assert(p.size() == max_corner.size()); assert(p.size() == min_corner.size()); for(int i = 0;i= max_corner(i)) // **MUST** be conservative if( p(i) < min_corner(i) || p(i) > max_corner(i)) { return false; } } return true; } template inline void igl::WindingNumberAABB::compute_min_max_corners() { using namespace std; // initialize corners for(int d = 0;d::infinity(); max_corner[d] = -numeric_limits::infinity(); } this->center = Point(0,0,0); // Loop over facets for(int i = 0;igetF().rows();i++) { for(int j = 0;jgetF().cols();j++) { for(int d = 0;dgetV()(this->getF()(i,j),d) < min_corner[d] ? this->getV()(this->getF()(i,j),d) : min_corner[d]; max_corner[d] = this->getV()(this->getF()(i,j),d) > max_corner[d] ? this->getV()(this->getF()(i,j),d) : max_corner[d]; } // This is biased toward vertices incident on more than one face, but // perhaps that's good this->center += this->getV().row(this->getF()(i,j)); } } // Average this->center.array() /= this->getF().size(); //cout<<"min_corner: "<min_corner.transpose()<center.transpose()<max_corner.transpose()<max_corner + this->min_corner)*0.5).transpose()<radius = (max_corner-min_corner).norm()/2.0; } template inline typename DerivedV::Scalar igl::WindingNumberAABB::max_abs_winding_number(const Point & p) const { using namespace std; // Only valid if not inside if(inside(p)) { return numeric_limits::infinity(); } // Q: we know the total positive area so what's the most this could project // to? Remember it could be layered in the same direction. return numeric_limits::infinity(); } template inline typename DerivedV::Scalar igl::WindingNumberAABB::max_simple_abs_winding_number( const Point & p) const { using namespace std; using namespace Eigen; // Only valid if not inside if(inside(p)) { return numeric_limits::infinity(); } // Max simple is the same as sum of positive winding number contributions of // bounding box // begin precomputation //MatrixXd BV((int)pow(2,3),3); typedef Eigen::Matrix MatrixXS; typedef Eigen::Matrix MatrixXF; MatrixXS BV((int)(1<<3),3); BV << min_corner[0],min_corner[1],min_corner[2], min_corner[0],min_corner[1],max_corner[2], min_corner[0],max_corner[1],min_corner[2], min_corner[0],max_corner[1],max_corner[2], max_corner[0],min_corner[1],min_corner[2], max_corner[0],min_corner[1],max_corner[2], max_corner[0],max_corner[1],min_corner[2], max_corner[0],max_corner[1],max_corner[2]; MatrixXF BF(2*2*3,3); BF << 0,6,4, 0,2,6, 0,3,2, 0,1,3, 2,7,6, 2,3,7, 4,6,7, 4,7,5, 0,4,5, 0,5,1, 1,5,7, 1,7,3; MatrixXS BFN; per_face_normals(BV,BF,BFN); // end of precomputation // Only keep those with positive dot products MatrixXF PBF(BF.rows(),BF.cols()); int pbfi = 0; Point p2c = 0.5*(min_corner+max_corner)-p; for(int i = 0;i 0) { PBF.row(pbfi++) = BF.row(i); } } PBF.conservativeResize(pbfi,PBF.cols()); return igl::winding_number(BV,PBF,p); } #endif