You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
22 KiB
470 lines
22 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* Visual Computing Lab /\/| * |
|
* ISTI - Italian National Research Council | * |
|
* \ * |
|
* All rights reserved. * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
* * |
|
* This program is distributed in the hope that it will be useful, * |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * |
|
* for more details. * |
|
* * |
|
****************************************************************************/ |
|
|
|
#ifndef __VCGLIB_FACE_DISTANCE |
|
#define __VCGLIB_FACE_DISTANCE |
|
|
|
#include <vcg/math/base.h> |
|
#include <vcg/space/point3.h> |
|
#include <vcg/space/segment3.h> |
|
#include <vcg/space/distance3.h> |
|
|
|
namespace vcg { |
|
namespace face{ |
|
/* |
|
Basic Wrapper for getting point-triangular face distance |
|
distance is unsigned; |
|
|
|
return true if the closest point <q> on <f> is nearer than the passed <dist>; |
|
return false otherwiswe (and q is not valid) |
|
|
|
This wrapper requires that your face has |
|
- Per Face Flags well initialized |
|
- Per Face EdgePlane component initialized. |
|
Initialization must be done with: |
|
|
|
tri::UpdateEdges<MeshType>::Set(yourMesh); |
|
*/ |
|
template <class FaceType> |
|
bool PointDistanceEP( const FaceType &f, |
|
const vcg::Point3<typename FaceType::ScalarType> & q, |
|
typename FaceType::ScalarType & dist, |
|
vcg::Point3<typename FaceType::ScalarType> & p ) |
|
{ |
|
typedef typename FaceType::ScalarType ScalarType; |
|
const ScalarType EPS = ScalarType( 0.000001); |
|
|
|
ScalarType b,b0,b1,b2; |
|
|
|
ScalarType d = SignedDistancePlanePoint( f.cPlane(), q ); |
|
if( d>dist || d<-dist ) return false; |
|
|
|
Point3<ScalarType> t = f.cPlane().Direction(); |
|
p = q - t*d; // p is the projection of q on the face plane |
|
// Now Choose the best plane and test to see if p is inside the triangle |
|
|
|
switch( f.cFlags() & (FaceType::NORMX|FaceType::NORMY|FaceType::NORMZ) ) |
|
{ |
|
case FaceType::NORMX: |
|
b0 = f.cEdge(1)[1]*(p[2] - f.cP(1)[2]) - f.cEdge(1)[2]*(p[1] - f.cP(1)[1]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = f.cEdge(2)[1]*(p[2] - f.cP(2)[2]) - f.cEdge(2)[2]*(p[1] - f.cP(2)[1]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = f.cEdge(0)[1]*(p[2] - f.cP(0)[2]) - f.cEdge(0)[2]*(p[1] - f.cP(0)[1]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
// if all these tests failed the projection p should be inside. |
|
// Some further tests for more robustness... |
|
if( (b=std::min(b0,std::min(b1,b2)) ) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else { assert(b==b2); |
|
bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
} |
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
|
|
case FaceType::NORMY: |
|
b0 = f.cEdge(1)[2]*(p[0] - f.cP(1)[0]) - f.cEdge(1)[0]*(p[2] - f.cP(1)[2]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = f.cEdge(2)[2]*(p[0] - f.cP(2)[0]) - f.cEdge(2)[0]*(p[2] - f.cP(2)[2]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = f.cEdge(0)[2]*(p[0] - f.cP(0)[0]) - f.cEdge(0)[0]*(p[2] - f.cP(0)[2]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
if( (b=math::Min<ScalarType>(b0,b1,b2)) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else { assert(b==b2); |
|
bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
} |
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
|
|
case FaceType::NORMZ: |
|
b0 = f.cEdge(1)[0]*(p[1] - f.cP(1)[1]) - f.cEdge(1)[1]*(p[0] - f.cP(1)[0]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = f.cEdge(2)[0]*(p[1] - f.cP(2)[1]) - f.cEdge(2)[1]*(p[0] - f.cP(2)[0]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = f.cEdge(0)[0]*(p[1] - f.cP(0)[1]) - f.cEdge(0)[1]*(p[0] - f.cP(0)[0]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
if( (b=math::Min<ScalarType>(b0,b1,b2)) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else { assert(b==b2); |
|
bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
} |
|
|
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
|
|
} // end switch |
|
|
|
dist = ScalarType(fabs(d)); |
|
return true; |
|
} |
|
|
|
template <class S> |
|
class PointDistanceEPFunctor { |
|
public: |
|
typedef S ScalarType; |
|
typedef Point3<ScalarType> QueryType; |
|
static inline const Point3<ScalarType> & Pos(const QueryType & qt) {return qt;} |
|
|
|
template <class FACETYPE, class SCALARTYPE> |
|
inline bool operator () (const FACETYPE & f, const Point3<SCALARTYPE> & p, SCALARTYPE & minDist, Point3<SCALARTYPE> & q) { |
|
const Point3<typename FACETYPE::ScalarType> fp = Point3<typename FACETYPE::ScalarType>::Construct(p); |
|
Point3<typename FACETYPE::ScalarType> fq; |
|
typename FACETYPE::ScalarType md = (typename FACETYPE::ScalarType)(minDist); |
|
const bool ret = PointDistanceEP(f, fp, md, fq); |
|
minDist = (SCALARTYPE)(md); |
|
q = Point3<SCALARTYPE>::Construct(fq); |
|
return (ret); |
|
} |
|
}; |
|
|
|
|
|
|
|
template <class S> |
|
class PointNormalDistanceFunctor { |
|
public: |
|
typedef typename S::ScalarType ScalarType; |
|
typedef S QueryType; |
|
static inline const Point3<ScalarType> & Pos(const QueryType & qt) {return qt.P();} |
|
|
|
|
|
static ScalarType & Alpha(){static ScalarType alpha = 1.0; return alpha;} |
|
static ScalarType & Beta (){static ScalarType beta = 1.0; return beta;} |
|
static ScalarType & Gamma(){static ScalarType gamma = 1.0; return gamma;} |
|
static ScalarType & InterPoint(){static ScalarType interpoint= 1.0; return interpoint;} |
|
|
|
|
|
template <class FACETYPE, class SCALARTYPE> |
|
inline bool operator () (const FACETYPE &f, const typename FACETYPE::VertexType &p, |
|
SCALARTYPE & minDist,Point3<SCALARTYPE> & q) |
|
{ |
|
const Point3<typename FACETYPE::ScalarType> fp = Point3<typename FACETYPE::ScalarType>::Construct(p.cP()); |
|
const Point3<typename FACETYPE::ScalarType> fn = Point3<typename FACETYPE::ScalarType>::Construct(p.cN()); |
|
Point3<typename FACETYPE::ScalarType> fq; |
|
typename FACETYPE::ScalarType md = (typename FACETYPE::ScalarType)(minDist); |
|
const bool ret=PointDistance(f,fp,md,fq); |
|
|
|
SCALARTYPE dev=InterPoint()*(pow((ScalarType)(1-f.cN().dot(fn)),(ScalarType)Beta())/(Gamma()*md+0.1)); |
|
|
|
if (md+dev < minDist){ |
|
minDist = (SCALARTYPE)(md+dev); |
|
q = Point3<SCALARTYPE>::Construct(fq); |
|
//q.N() = f.N(); |
|
return (ret); |
|
} |
|
return false; |
|
} |
|
}; |
|
|
|
/// BASIC VERSION of the Point-face distance that does not require the EdgePlane Additional data. |
|
/// Given a face and a point, returns the closest point of the face to p. |
|
|
|
template <class FaceType> |
|
bool PointDistanceBase( |
|
const FaceType &f, /// the face to be tested |
|
const vcg::Point3<typename FaceType::ScalarType> & q, /// the point tested |
|
typename FaceType::ScalarType & dist, /// bailout distance. It must be initialized with the max admittable value. |
|
vcg::Point3<typename FaceType::ScalarType> & p ) |
|
{ |
|
typedef typename FaceType::ScalarType ScalarType; |
|
|
|
if(f.cN()==Point3<ScalarType>(0,0,0)) // to correctly manage the case of degenerate triangles we consider them as segments. |
|
{ |
|
Box3<ScalarType> bb; |
|
f.GetBBox(bb); |
|
Segment3<ScalarType> degenTri(bb.min,bb.max); |
|
Point3<ScalarType> closest; |
|
ScalarType d; |
|
if(bb.Diag()>0) |
|
vcg::SegmentPointDistance<ScalarType>(degenTri,q,closest,d); |
|
else // very degenerate triangle (just a point) |
|
{ |
|
closest = bb.min; |
|
d=Distance(q,closest); |
|
} |
|
if( d>dist) return false; |
|
dist=d; |
|
p=closest; |
|
assert(!math::IsNAN(dist)); |
|
return true; |
|
} |
|
|
|
Plane3<ScalarType,true> fPlane; |
|
fPlane.Init(f.cP(0),f.cN()); |
|
const ScalarType EPS = ScalarType( 0.000001); |
|
ScalarType b,b0,b1,b2; |
|
// Calcolo distanza punto piano |
|
ScalarType d = SignedDistancePlanePoint( fPlane, q ); |
|
if( d>dist || d<-dist ) // Risultato peggiore: niente di fatto |
|
return false; |
|
|
|
// Projection of query point onto the triangle plane |
|
p = q - fPlane.Direction()*d; |
|
|
|
Point3<ScalarType> fEdge[3]; |
|
fEdge[0] = f.cP(1); fEdge[0] -= f.cP(0); |
|
fEdge[1] = f.cP(2); fEdge[1] -= f.cP(1); |
|
fEdge[2] = f.cP(0); fEdge[2] -= f.cP(2); |
|
|
|
/* |
|
This piece of code is part of the EdgePlane initialization structure: note that the edges are scaled!. |
|
|
|
if(nx>ny && nx>nz) { f.Flags() |= FaceType::NORMX; d = 1/f.Plane().Direction()[0]; } |
|
else if(ny>nz) { f.Flags() |= FaceType::NORMY; d = 1/f.Plane().Direction()[1]; } |
|
else { f.Flags() |= FaceType::NORMZ; d = 1/f.Plane().Direction()[2]; } |
|
f.Edge(0)*=d; f.Edge(1)*=d;f.Edge(2)*=d; |
|
|
|
So we must apply the same scaling according to the plane orientation, eg in the case of NORMX |
|
scaleFactor= 1/fPlane.Direction()[0]; |
|
fEdge[0]*=d; fEdge[1]*=d;fEdge[2]*=d; |
|
*/ |
|
|
|
int bestAxis; |
|
if(fabs(f.cN()[0])>fabs(f.cN()[1])) |
|
{ |
|
if(fabs(f.cN()[0])>fabs(f.cN()[2])) bestAxis = 0; |
|
else bestAxis = 2; |
|
} else { |
|
if(fabs(f.cN()[1])>fabs(f.cN()[2])) bestAxis=1; /* 1 > 0 ? 2 */ |
|
else bestAxis=2; /* 2 > 1 ? 2 */ |
|
} |
|
|
|
ScalarType scaleFactor; |
|
|
|
switch( bestAxis ) |
|
{ |
|
case 0: /************* X AXIS **************/ |
|
scaleFactor= 1/fPlane.Direction()[0]; |
|
fEdge[0]*=scaleFactor; fEdge[1]*=scaleFactor; fEdge[2]*=scaleFactor; |
|
|
|
b0 = fEdge[1][1]*(p[2] - f.cP(1)[2]) - fEdge[1][2]*(p[1] - f.cP(1)[1]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = fEdge[2][1]*(p[2] - f.cP(2)[2]) - fEdge[2][2]*(p[1] - f.cP(2)[1]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = fEdge[0][1]*(p[2] - f.cP(0)[2]) - fEdge[0][2]*(p[1] - f.cP(0)[1]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
// sono tutti e tre > 0 quindi dovrebbe essere dentro; |
|
// per sicurezza se il piu' piccolo dei tre e' < epsilon (scalato rispetto all'area della faccia |
|
// per renderlo dimension independent.) allora si usa ancora la distanza punto |
|
// segmento che e' piu robusta della punto piano, e si fa dalla parte a cui siamo piu' |
|
// vicini (come prodotto vettore) |
|
// Nota: si potrebbe rendere un pochino piu' veloce sostituendo Area() |
|
// con il prodotto vettore dei due edge in 2d lungo il piano migliore. |
|
if( (b=vcg::math::Min<ScalarType>(b0,b1,b2)) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else {assert(b==b2); bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p);} |
|
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt); |
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
|
|
case 1: /************* Y AXIS **************/ |
|
scaleFactor= 1/fPlane.Direction()[1]; |
|
fEdge[0]*=scaleFactor; fEdge[1]*=scaleFactor; fEdge[2]*=scaleFactor; |
|
|
|
b0 = fEdge[1][2]*(p[0] - f.cP(1)[0]) - fEdge[1][0]*(p[2] - f.cP(1)[2]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = fEdge[2][2]*(p[0] - f.cP(2)[0]) - fEdge[2][0]*(p[2] - f.cP(2)[2]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = fEdge[0][2]*(p[0] - f.cP(0)[0]) - fEdge[0][0]*(p[2] - f.cP(0)[2]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
if( (b=vcg::math::Min<ScalarType>(b0,b1,b2)) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else{ assert(b==b2); bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p);} |
|
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt); |
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
|
|
case 2: /************* Z AXIS **************/ |
|
scaleFactor= 1/fPlane.Direction()[2]; |
|
fEdge[0]*=scaleFactor; fEdge[1]*=scaleFactor; fEdge[2]*=scaleFactor; |
|
|
|
b0 = fEdge[1][0]*(p[1] - f.cP(1)[1]) - fEdge[1][1]*(p[0] - f.cP(1)[0]); |
|
if(b0<=0) |
|
{ |
|
b0 = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
if(dist>b0) { dist = b0; return true; } |
|
else return false; |
|
} |
|
b1 = fEdge[2][0]*(p[1] - f.cP(2)[1]) - fEdge[2][1]*(p[0] - f.cP(2)[0]); |
|
if(b1<=0) |
|
{ |
|
b1 = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
if(dist>b1) { dist = b1; return true; } |
|
else return false; |
|
} |
|
b2 = fEdge[0][0]*(p[1] - f.cP(0)[1]) - fEdge[0][1]*(p[0] - f.cP(0)[0]); |
|
if(b2<=0) |
|
{ |
|
b2 = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); |
|
if(dist>b2) { dist = b2; return true; } |
|
else return false; |
|
} |
|
if( (b=vcg::math::Min<ScalarType>(b0,b1,b2)) < EPS*DoubleArea(f)) |
|
{ |
|
ScalarType bt; |
|
if(b==b0) bt = PSDist(q,f.cV(1)->cP(),f.cV(2)->cP(),p); |
|
else if(b==b1) bt = PSDist(q,f.cV(2)->cP(),f.cV(0)->cP(),p); |
|
else { assert(b==b2); bt = PSDist(q,f.cV(0)->cP(),f.cV(1)->cP(),p); } |
|
//printf("Warning area:%g %g %g %g thr:%g bt:%g\n",Area(), b0,b1,b2,EPSILON*Area(),bt); |
|
|
|
if(dist>bt) { dist = bt; return true; } |
|
else return false; |
|
} |
|
break; |
|
default: assert(0); // if you get this assert it means that you forgot to set the required UpdateFlags<MeshType>::FaceProjection(m); |
|
|
|
} |
|
|
|
dist = ScalarType(fabs(d)); |
|
//dist = Distance(p,q); |
|
return true; |
|
} |
|
|
|
template <class S> |
|
class PointDistanceBaseFunctor { |
|
public: |
|
typedef S ScalarType; |
|
typedef Point3<ScalarType> QueryType; |
|
|
|
static inline const Point3<ScalarType> & Pos(const Point3<ScalarType> & qt) {return qt;} |
|
template <class FACETYPE, class SCALARTYPE> |
|
inline bool operator () (const FACETYPE & f, const Point3<SCALARTYPE> & p, SCALARTYPE & minDist, Point3<SCALARTYPE> & q) { |
|
const Point3<typename FACETYPE::ScalarType> fp = Point3<typename FACETYPE::ScalarType>::Construct(p); |
|
Point3<typename FACETYPE::ScalarType> fq; |
|
typename FACETYPE::ScalarType md = (typename FACETYPE::ScalarType)(minDist); |
|
const bool ret = PointDistanceBase(f, fp, md, fq); |
|
minDist = (SCALARTYPE)(md); |
|
q = Point3<SCALARTYPE>::Construct(fq); |
|
return (ret); |
|
} |
|
}; |
|
|
|
|
|
|
|
} // end namespace face |
|
|
|
} // end namespace vcg |
|
|
|
|
|
#endif |
|
|
|
|