dust3d/third_party/libigl/include/igl/WindingNumberTree.h

502 lines
16 KiB
C
Raw Normal View History

// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// 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/.
#ifndef IGL_WINDINGNUMBERTREE_H
#define IGL_WINDINGNUMBERTREE_H
#include <list>
#include <map>
#include <Eigen/Dense>
#include "WindingNumberMethod.h"
namespace igl
{
// Space partitioning tree for computing winding number hierarchically.
//
// Templates:
// Point type for points in space, e.g. Eigen::Vector3d
template <
typename Point,
typename DerivedV,
typename DerivedF >
class WindingNumberTree
{
public:
// Method to use (see enum above)
//static double min_max_w;
static std::map<
std::pair<const WindingNumberTree*,const WindingNumberTree*>,
typename DerivedV::Scalar>
cached;
// This is only need to fill in references, it should never actually be touched
// and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
static DerivedV dummyV;
protected:
WindingNumberMethod method;
const WindingNumberTree * parent;
std::list<WindingNumberTree * > children;
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
//// List of boundary edges (recall edges are vertices in 2d)
//const Eigen::MatrixXi boundary;
// Base mesh vertices
DerivedV & V;
// Base mesh vertices with duplicates removed
MatrixXS SV;
// Facets in this bounding volume
MatrixXF F;
// Tessellated boundary curve
MatrixXF cap;
// Upper Bound on radius of enclosing ball
typename DerivedV::Scalar radius;
// (Approximate) center (of mass)
Point center;
public:
inline WindingNumberTree();
// For root
inline WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// For chilluns
inline WindingNumberTree(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
inline virtual ~WindingNumberTree();
inline void delete_children();
inline virtual void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// Set method
inline void set_method( const WindingNumberMethod & m);
public:
inline const DerivedV & getV() const;
inline const MatrixXF & getF() const;
inline const MatrixXF & getcap() const;
// Grow the Tree recursively
inline virtual void grow();
// Determine whether a given point is inside the bounding
//
// Inputs:
// p query point
// Returns true if the point p is inside this bounding volume
inline virtual bool inside(const Point & p) const;
// Compute the (partial) winding number of a given point p
// According to method
//
// Inputs:
// p query point
// Returns winding number
inline typename DerivedV::Scalar winding_number(const Point & p) const;
// Same as above, but always computes winding number using exact method
// (sum over every facet)
inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
// Same as above, but always computes using sum over tessllated boundary
inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
//// Same as winding_number above, but if max_simple_abs_winding_number is
//// less than some threshold min_max_w just return 0 (colloquially the "fast
//// multipole method)
////
////
//// Inputs:
//// p query point
//// min_max_w minimum max simple w to be processed
//// Returns approximate winding number
//double winding_number_approx_simple(
// const Point & p,
// const double min_max_w);
// Print contents of Tree
//
// Optional input:
// tab tab to show depth
inline void print(const char * tab="");
// Determine max absolute winding number
//
// Inputs:
// p query point
// Returns max winding number of
inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
// simple polyhedron
inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
// Compute or read cached winding number for point p with respect to mesh
// in bounding box, recursing according to approximation criteria
//
// Inputs:
// p query point
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
// Returns cached winding number
inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
};
}
// Implementation
#include "WindingNumberTree.h"
#include "winding_number.h"
#include "triangle_fan.h"
#include "exterior_edges.h"
#include <igl/PI.h>
#include <igl/remove_duplicate_vertices.h>
#include <iostream>
#include <limits>
//template <typename Point, typename DerivedV, typename DerivedF>
//WindingNumberMethod WindingNumberTree<Point,DerivedV,DerivedF>::method = EXACT_WINDING_NUMBER_METHOD;
//template <typename Point, typename DerivedV, typename DerivedF>
//double WindingNumberTree<Point,DerivedV,DerivedF>::min_max_w = 0;
template <typename Point, typename DerivedV, typename DerivedF>
std::map< std::pair<const igl::WindingNumberTree<Point,DerivedV,DerivedF>*,const igl::WindingNumberTree<Point,DerivedV,DerivedF>*>, typename DerivedV::Scalar>
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached;
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
center(0,0,0)
{
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F):
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
center(0,0,0)
{
set_mesh(_V,_F);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F)
{
using namespace std;
// Remove any exactly duplicate vertices
// Q: Can this ever increase the complexity of the boundary?
// Q: Would we gain even more by remove almost exactly duplicate vertices?
MatrixXF SF,SVI,SVJ;
igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
triangle_fan(igl::exterior_edges(F),cap);
V = SV;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & _F):
method(parent.method),
parent(&parent),
V(parent.V),
SV(),
F(_F),
cap(triangle_fan(igl::exterior_edges(_F)))
{
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::~WindingNumberTree()
{
delete_children();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
{
using namespace std;
// Delete children
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
while(cit != children.end())
{
// clear the memory of this item
delete (* cit);
// erase from list, returns next element in iterator
cit = children.erase(cit);
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const WindingNumberMethod & m)
{
this->method = m;
for(auto child : children)
{
child->set_method(m);
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const DerivedV & igl::WindingNumberTree<Point,DerivedV,DerivedF>::getV() const
{
return V;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getF() const
{
return F;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getcap() const
{
return cap;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::grow()
{
// Don't grow
return;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberTree<Point,DerivedV,DerivedF>::inside(const Point & /*p*/) const
{
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p) const
{
using namespace std;
//cout<<"+"<<boundary.rows();
// If inside then we need to be careful
if(inside(p))
{
// If not a leaf then recurse
if(children.size()>0)
{
// Recurse on each child and accumulate
typename DerivedV::Scalar sum = 0;
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
switch(method)
{
case EXACT_WINDING_NUMBER_METHOD:
sum += (*cit)->winding_number(p);
break;
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
case APPROX_CACHE_WINDING_NUMBER_METHOD:
//if((*cit)->max_simple_abs_winding_number(p) > min_max_w)
//{
sum += (*cit)->winding_number(p);
//}
break;
default:
assert(false);
break;
}
}
return sum;
}else
{
return winding_number_all(p);
}
}else{
// Otherwise we can just consider boundary
// Q: If we using the "multipole" method should we also subdivide the
// boundary case?
if((cap.rows() - 2) < F.rows())
{
switch(method)
{
case EXACT_WINDING_NUMBER_METHOD:
return winding_number_boundary(p);
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
{
typename DerivedV::Scalar dist = (p-center).norm();
// Radius is already an overestimate of inside
if(dist>1.0*radius)
{
return 0;
}else
{
return winding_number_boundary(p);
}
}
case APPROX_CACHE_WINDING_NUMBER_METHOD:
{
return parent->cached_winding_number(*this,p);
}
default: assert(false);break;
}
}else
{
// doesn't pay off to use boundary
return winding_number_all(p);
}
}
return 0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_all(const Point & p) const
{
return igl::winding_number(V,F,p);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const Point & p) const
{
using namespace Eigen;
using namespace std;
return igl::winding_number(V,cap,p);
}
//template <typename Point, typename DerivedV, typename DerivedF>
//inline double igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_approx_simple(
// const Point & p,
// const double min_max_w)
//{
// using namespace std;
// if(max_simple_abs_winding_number(p) > min_max_w)
// {
// return winding_number(p);
// }else
// {
// cout<<"Skipped! "<<max_simple_abs_winding_number(p)<<"<"<<min_max_w<<endl;
// return 0;
// }
//}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char * tab)
{
using namespace std;
// Print all facets
cout<<tab<<"["<<endl<<F<<endl<<"]";
// Print children
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
cit != children.end();
cit++)
{
cout<<","<<endl;
(*cit)->print((string(tab)+"").c_str());
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & /*p*/) const
{
return std::numeric_limits<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
const Point & /*p*/) const
{
using namespace std;
return numeric_limits<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & that,
const Point & p) const
{
using namespace std;
// Simple metric for `is_far`
//
// this that
// --------
// ----- / | \ .
// / r \ / R \ .
// | p ! | | ! |
// \_____/ \ /
// \________/
//
//
// a = angle formed by trapazoid formed by raising sides with lengths r and R
// at respective centers.
//
// a = atan2(R-r,d), where d is the distance between centers
// That should be bigger (what about parent? what about sister?)
bool is_far = this->radius<that.radius;
if(is_far)
{
typename DerivedV::Scalar a = atan2(
that.radius - this->radius,
(that.center - this->center).norm());
assert(a>0);
is_far = (a<PI/8.0);
}
if(is_far)
{
// Not implemented yet
pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
// Need to compute it for first time?
if(cached.count(this_that)==0)
{
cached[this_that] =
that.winding_number_boundary(this->center);
}
return cached[this_that];
}else if(children.size() == 0)
{
// not far and hierarchy ended too soon: can't use cache
return that.winding_number_boundary(p);
}else
{
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
if((*cit)->inside(p))
{
return (*cit)->cached_winding_number(that,p);
}
}
// Not inside any children? This can totally happen because bounding boxes
// are set to bound contained facets. So sibilings may overlap and their
// union may not contain their parent (though, their union is certainly a
// subset of their parent).
assert(false);
}
return 0;
}
// Explicit instantiation of static variable
template <
typename Point,
typename DerivedV,
typename DerivedF >
DerivedV igl::WindingNumberTree<Point,DerivedV,DerivedF>::dummyV;
#endif