mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 09:11:23 -06:00
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.
377 lines
11 KiB
C++
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
|