OrcaSlicer/src/libigl/igl/WindingNumberAABB.h
tamasmeszaros 2ae2672ee9 Building igl statically and moving to the dep scripts
Fixing dep build script on Windows and removing some warnings.

Use bundled igl by default.

Not building with the dependency scripts if not explicitly stated. This way, it will stay in
Fix the libigl patch to include C source files in header only mode.
2019-06-19 14:52:55 +02:00

377 lines
11 KiB
C++

// 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/.
// # 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<Point,DerivedV,DerivedF>
{
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<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{}
inline WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
inline WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
// Initialize some things
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & 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 <limits>
#include <vector>
#include <iostream>
// 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 <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F)
{
igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(V,F);
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::init()
{
using namespace Eigen;
assert(max_corner.size() == 3);
assert(min_corner.size() == 3);
compute_min_max_corners();
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> dblA;
doublearea(this->getV(),this->getF(),dblA);
total_positive_area = dblA.sum()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(V,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(parent,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
{
using namespace std;
using namespace Eigen;
// Clear anything that already exists
this->delete_children();
//cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
//cout<<"F.rows(): "<<this->getF().rows()<<endl;
// Base cases
if(
this->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<typename DerivedV::Scalar>::infinity();
for(int d = 0;d<min_corner.size();d++)
{
if( (max_corner[d] - min_corner[d]) > max_len )
{
max_len = (max_corner[d] - min_corner[d]);
max_d = d;
}
}
// Compute facet barycenters
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> 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: "<<split_value<<endl;;
vector<int> id( this->getF().rows());
for(int i = 0;i<this->getF().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;i<this->getF().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<Point,DerivedV,DerivedF> * leftWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,leftF);
leftWindingNumberAABB->grow();
this->children.push_back(leftWindingNumberAABB);
WindingNumberAABB<Point,DerivedV,DerivedF> * rightWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,rightF);
rightWindingNumberAABB->grow();
this->children.push_back(rightWindingNumberAABB);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point & p) const
{
assert(p.size() == max_corner.size());
assert(p.size() == min_corner.size());
for(int i = 0;i<p.size();i++)
{
//// Perfect matching is **not** robust
//if( p(i) < min_corner(i) || p(i) >= max_corner(i))
// **MUST** be conservative
if( p(i) < min_corner(i) || p(i) > max_corner(i))
{
return false;
}
}
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_corners()
{
using namespace std;
// initialize corners
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] = numeric_limits<typename Point::Scalar>::infinity();
max_corner[d] = -numeric_limits<typename Point::Scalar>::infinity();
}
this->center = Point(0,0,0);
// Loop over facets
for(int i = 0;i<this->getF().rows();i++)
{
for(int j = 0;j<this->getF().cols();j++)
{
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] =
this->getV()(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: "<<this->min_corner.transpose()<<endl;
//cout<<"Center: "<<this->center.transpose()<<endl;
//cout<<"max_corner: "<<this->max_corner.transpose()<<endl;
//cout<<"Diag center: "<<((this->max_corner + this->min_corner)*0.5).transpose()<<endl;
//cout<<endl;
this->radius = (max_corner-min_corner).norm()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & p) const
{
using namespace std;
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::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<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::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<typename DerivedV::Scalar>::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<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
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<BFN.rows();i++)
{
if(p2c.dot(BFN.row(i)) > 0)
{
PBF.row(pbfi++) = BF.row(i);
}
}
PBF.conservativeResize(pbfi,PBF.cols());
return igl::winding_number(BV,PBF,p);
}
#endif