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.
682 lines
20 KiB
682 lines
20 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 POLYGON_H |
|
#define POLYGON_H |
|
|
|
#include <vcg/space/plane3.h> |
|
#include <vcg/space/fitting3.h> |
|
#include <vcg/space/point_matching.h> |
|
#include <vcg/math/matrix33.h> |
|
#include <vcg/space/distance3.h> |
|
|
|
namespace vcg { |
|
|
|
////return true if the |
|
//template <class CoordType> |
|
//bool CheckNormalizedCoords(CoordType dir) |
|
//{ |
|
// typedef typename CoordType::ScalarType ScalarType; |
|
// if(isnan(dir.X()))return false; |
|
// if(isnan(dir.Y()))return false; |
|
// if(isnan(dir.Z()))return false; |
|
// ScalarType Norm=dir.Norm(); |
|
// if(fabs(Norm-1.f)>0.01f)return false; |
|
// return true; |
|
//} |
|
|
|
//return per vertex Normals of a polygonal face stored as a vector of coords |
|
template <class CoordType> |
|
void GetNormals(std::vector<CoordType> &Pos, |
|
std::vector<CoordType> &Norms) |
|
{ |
|
Norms.clear(); |
|
int size=Pos.size(); |
|
if (size<=2) return; |
|
for (int i=0;i<size;i++) |
|
Norms.push_back(Normal(Pos[i],Pos[(i+1)%size],Pos[(i+2)%size]).Normalize()); |
|
} |
|
|
|
//return the normal of a polygonal face stored as a vector of coords |
|
template <class CoordType> |
|
CoordType Normal(std::vector<CoordType> &Pos) |
|
{ |
|
std::vector<CoordType> Norms; |
|
GetNormals(Pos,Norms); |
|
if (Norms.size()==0) |
|
return(CoordType(1,0,0)); |
|
|
|
CoordType NSum=CoordType(0,0,0); |
|
for (size_t i=0;i<Norms.size();i++) |
|
NSum+=Norms[i]; |
|
|
|
NSum.Normalize(); |
|
return (NSum); |
|
} |
|
|
|
//return the area of a polygonal face stored as a vector of coords |
|
template <class CoordType> |
|
typename CoordType::ScalarType Area(const std::vector<CoordType> &Pos) |
|
{ |
|
typedef typename CoordType::ScalarType ScalarType; |
|
CoordType bary=CoordType(0,0,0); |
|
for (size_t i=0;i<Pos.size();i++) |
|
bary+=Pos[i]; |
|
|
|
bary/=Pos.size(); |
|
ScalarType Area=0; |
|
for (size_t i=0;i<Pos.size();i++) |
|
{ |
|
CoordType p0=Pos[i]; |
|
CoordType p1=Pos[(i+1)% Pos.size()]; |
|
CoordType p2=bary; |
|
vcg::Triangle3<ScalarType> T(p0,p1,p2); |
|
Area+=(vcg::DoubleArea(T)/2); |
|
} |
|
return Area; |
|
} |
|
|
|
//return per vertex Normals of a polygonal face |
|
template<class PolygonType> |
|
void PolyNormals(const PolygonType &F, |
|
std::vector<typename PolygonType::CoordType> &Norms) |
|
{ |
|
Norms.clear(); |
|
if (F.VN()<=2) return; |
|
for (int i=0;i<F.VN();i++) |
|
Norms.push_back(Normal(F.cP0(i),F.cP1(i),F.cP2(i)).Normalize()); |
|
} |
|
|
|
//return the barycenter of a polygonal face |
|
template<class PolygonType> |
|
typename PolygonType::CoordType PolyBarycenter(const PolygonType &F) |
|
{ |
|
typename PolygonType::CoordType bary(0,0,0); |
|
for (int i=0;i<F.VN();i++) |
|
bary+=F.cP(i); |
|
|
|
bary/=(typename PolygonType::ScalarType)F.VN(); |
|
return bary; |
|
} |
|
|
|
//return the area of a polygonal face |
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolyArea(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
if (F.VN() == 3) |
|
return vcg::DoubleArea(F) / 2; |
|
|
|
CoordType bary=PolyBarycenter(F); |
|
ScalarType Area=0; |
|
for (size_t i=0;i<(size_t)F.VN();i++) |
|
{ |
|
CoordType p0=F.cP0(i); |
|
CoordType p1=F.cP1(i); |
|
CoordType p2=bary; |
|
vcg::Triangle3<ScalarType> T(p0,p1,p2); |
|
Area+=(vcg::DoubleArea(T)/2); |
|
} |
|
return Area; |
|
} |
|
|
|
//return the normal of a polygonal face |
|
template<class PolygonType> |
|
typename PolygonType::CoordType PolygonNormal(const PolygonType &F) |
|
{ |
|
typename PolygonType::CoordType n(0,0,0); |
|
|
|
for (int i=0;i<F.VN();i++) |
|
n+=Normal(F.cP0(i),F.cP1(i),F.cP2(i)).Normalize(); |
|
|
|
return n.Normalize(); |
|
} |
|
|
|
//return the perimeter of a polygonal face |
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolyPerimeter(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
ScalarType SumL=0; |
|
for (int i=0;i<F.VN();i++) |
|
{ |
|
ScalarType L=(F.cP0(i)-F.cP1(i)).Norm(); |
|
SumL+=L; |
|
} |
|
return (SumL); |
|
} |
|
|
|
//return a Scalar value that encode the variance of the normals |
|
//wrt the average one (1 means hight variance, 0 no variance) |
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolyNormDeviation(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
std::vector<CoordType> Norms; |
|
PolyNormals(F,Norms); |
|
|
|
//calculate the Avg Normal |
|
CoordType AvgNorm(0,0,0); |
|
for (int i=0;i<Norms.size();i++) |
|
AvgNorm+=Norms[i]; |
|
|
|
AvgNorm.Normalize(); |
|
|
|
//if (!CheckNormalizedCoords(AvgNorm))return 1; |
|
|
|
ScalarType Dev=0; |
|
for (int i=0;i<Norms.size();i++) |
|
Dev+=pow((Norms[i]-AvgNorm).Norm()/2.0,2); |
|
|
|
Dev/=(ScalarType)Norms.size(); |
|
Dev=sqrt(Dev); |
|
return Dev; |
|
} |
|
|
|
//return a Scalar value that encode the distance wrt ideal angle for each |
|
//wrt the average one (1 correspond to hight variance, 0 no variance) |
|
template<class PolygonType> |
|
void PolyAngleDeviation(const PolygonType &F, |
|
typename PolygonType::ScalarType &AvgDev, |
|
typename PolygonType::ScalarType &MaxDev) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
assert(F.VN()>2); |
|
ScalarType IdealAngle=M_PI-(2*M_PI/(ScalarType)F.VN()); |
|
assert(IdealAngle>0); |
|
|
|
//then compute the angle deviation |
|
MaxDev=0; |
|
AvgDev=0; |
|
|
|
for (int i=0;i<F.VN();i++) |
|
{ |
|
CoordType dir0=F.cP0(i)-F.cP1(i); |
|
CoordType dir1=F.cP2(i)-F.cP1(i); |
|
|
|
ScalarType VAngle=vcg::Angle(dir0,dir1); |
|
assert(VAngle>=0); |
|
ScalarType VAngleDiff=fabs(VAngle-IdealAngle); |
|
|
|
if (VAngleDiff>MaxDev)MaxDev=VAngleDiff; |
|
|
|
AvgDev+=VAngleDiff; |
|
} |
|
AvgDev/=(ScalarType)F.VN(); |
|
|
|
AvgDev/=(M_PI/2.0); |
|
MaxDev/=(M_PI/2.0); |
|
|
|
if (AvgDev>1)AvgDev=1; |
|
if (MaxDev>1)MaxDev=1; |
|
} |
|
|
|
//return the fitting plane of a polygonal face |
|
template<class PolygonType> |
|
vcg::Plane3<typename PolygonType::ScalarType> PolyFittingPlane(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
vcg::Plane3<ScalarType> BestPL; |
|
assert(F.VN()>=3); |
|
std::vector<CoordType> pointVec; |
|
for (int i=0;i<F.VN();i++) |
|
pointVec.push_back(F.cP(i)); |
|
|
|
vcg::FitPlaneToPointSet(pointVec,BestPL); |
|
return BestPL; |
|
} |
|
|
|
//return the flatness of a polygonal face as avg distance to the best fitting plane divided by half perimeter |
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolyFlatness(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
if (F.VN()<=3) |
|
return 0; |
|
|
|
//average lenght |
|
ScalarType SumL=PolyPerimeter(F)/2.0; |
|
|
|
//diagonal distance |
|
vcg::Plane3<ScalarType> BestPL=PolyFittingPlane(F); |
|
|
|
//then project points on the plane |
|
ScalarType Flatness=0; |
|
for (int i=0;i<F.VN();i++) |
|
{ |
|
CoordType pos=F.cP(i); |
|
CoordType proj=BestPL.Projection(pos); |
|
Flatness+=(pos-proj).Norm(); |
|
} |
|
Flatness/=(ScalarType)F.VN(); |
|
return((Flatness)/SumL); |
|
} |
|
|
|
//evaluate the PCA directions of a polygonal face |
|
template<class PolygonType> |
|
void PolyPCA(const PolygonType &F, |
|
typename PolygonType::CoordType PCA[]) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
//compute the covariance matrix |
|
Eigen::Matrix3d EigenCovMat; |
|
//ComputeCovarianceMatrix(EigenCovMat); |
|
//compute covariance matrix |
|
///compute the barycenter |
|
CoordType Barycenter=PolyBarycenter(F); |
|
|
|
// second cycle: compute the covariance matrix |
|
EigenCovMat.setZero(); |
|
Eigen::Vector3d p; |
|
for (int i=0;i<F.VN();i++) |
|
{ |
|
(F.cP(i)-Barycenter).ToEigenVector(p); |
|
EigenCovMat+= p*p.transpose(); // outer product |
|
} |
|
|
|
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d > eig(EigenCovMat); |
|
|
|
Eigen::Vector3d eval = eig.eigenvalues(); |
|
Eigen::Matrix3d evec = eig.eigenvectors(); |
|
|
|
eval = eval.cwiseAbs(); |
|
int normInd,maxInd,minInd; |
|
|
|
///get min and max coff .. |
|
///the minumum is the Normal |
|
///the other two the anisotropy directions |
|
eval.minCoeff(&normInd); |
|
eval.maxCoeff(&maxInd); |
|
minInd=(maxInd+1)%3; |
|
|
|
if (minInd==normInd)minInd=(normInd+1)%3; |
|
assert((minInd!=normInd)&&(minInd!=maxInd)&&(minInd!=maxInd)); |
|
|
|
///maximum direction of PCA |
|
PCA[0][0] = evec(0,maxInd); |
|
PCA[0][1] = evec(1,maxInd); |
|
PCA[0][2] = evec(2,maxInd); |
|
///minimum direction of PCA |
|
PCA[1][0] = evec(0,minInd); |
|
PCA[1][1] = evec(1,minInd); |
|
PCA[1][2] = evec(2,minInd); |
|
///Normal direction |
|
PCA[2][0] = evec(0,normInd); |
|
PCA[2][1] = evec(1,normInd); |
|
PCA[2][2] = evec(2,normInd); |
|
|
|
ScalarType LX=sqrt(eval[maxInd]); |
|
ScalarType LY=sqrt(eval[minInd]); |
|
//ScalarType LZ=sqrt(eval[normInd]); |
|
|
|
///scale the directions |
|
PCA[0]*=LX; |
|
PCA[1]*=LY; |
|
//PCA[2]*=LZ;//.Normalize(); |
|
PCA[2].Normalize(); |
|
} |
|
|
|
//evaluate the PCA directions of a polygonal face |
|
//scaled by the area of the face |
|
template<class PolygonType> |
|
void PolyScaledPCA(const PolygonType &F, |
|
typename PolygonType::CoordType PCA[]) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
std::vector<CoordType> SwapPos; |
|
|
|
///compute the barycenter |
|
//CoordType Barycenter=PolyBarycenter(F); |
|
|
|
///compute the Area |
|
ScalarType Area=PolyArea(F); |
|
|
|
PolyPCA(F,PCA); |
|
|
|
ScalarType Scale=sqrt(Area/(PCA[0].Norm()*PCA[1].Norm())); |
|
PCA[0]*=Scale; |
|
PCA[1]*=Scale; |
|
|
|
} |
|
|
|
//return the base template polygon as |
|
//described by "Static Aware Grid Shells" by Pietroni et Al. |
|
template<class CoordType> |
|
void getBaseTemplatePolygon(int N, |
|
std::vector<CoordType> &TemplatePos) |
|
{ |
|
typedef typename CoordType::ScalarType ScalarType; |
|
///first find positions in the |
|
///reference frame of the passed matrix |
|
ScalarType AngleInterval=2.0*M_PI/(ScalarType)N; |
|
ScalarType CurrAngle=0; |
|
TemplatePos.resize(N); |
|
for (size_t i=0;i<TemplatePos.size();i++) |
|
{ |
|
///find with trigonometric functions |
|
TemplatePos[i].X()=cos(CurrAngle); |
|
TemplatePos[i].Y()=sin(CurrAngle); |
|
TemplatePos[i].Z()=0; |
|
// TemplatePos[i].Normalize(); |
|
// TemplatePos[i].X()*=Anisotropy; |
|
// TemplatePos[i].Y()*=(1-Anisotropy); |
|
|
|
///increment the angle |
|
CurrAngle+=AngleInterval; |
|
} |
|
} |
|
|
|
//return the rigidly aligned template polygon as |
|
//described by "Static Aware Grid Shells" by Pietroni et Al. |
|
template<class PolygonType> |
|
void GetPolyTemplatePos(const PolygonType &F, |
|
std::vector<typename PolygonType::CoordType> &TemplatePos, |
|
bool force_isotropy=false) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
std::vector<CoordType> UniformPos,UniformTempl; |
|
|
|
CoordType Barycenter=PolyBarycenter(F); |
|
|
|
getBaseTemplatePolygon(F.VN(),TemplatePos); |
|
|
|
CoordType PCA[3]; |
|
PolyPCA(F,PCA); |
|
|
|
vcg::Matrix44<ScalarType> ToPCA,ToPCAInv; |
|
ToPCA.SetIdentity(); |
|
|
|
CoordType dirX=PCA[0]; |
|
CoordType dirY=PCA[1]; |
|
CoordType dirZ=PCA[2]; |
|
|
|
if (force_isotropy) |
|
{ |
|
dirX.Normalize(); |
|
dirY.Normalize(); |
|
dirZ.Normalize(); |
|
// CoordType dirXN=dirX;dirXN.Normalize(); |
|
// CoordType dirYN=dirY;dirYN.Normalize(); |
|
// CoordType dirZN=dirZ;dirZN.Normalize(); |
|
|
|
// dirX=dirX*0.8+dirXN*0.2; |
|
// dirY=dirY*0.8+dirYN*0.2; |
|
// dirZ=dirZ*0.8+dirZN*0.2; |
|
} |
|
|
|
///set the Rotation matrix |
|
ToPCA.SetColumn(0,dirX); |
|
ToPCA.SetColumn(1,dirY); |
|
ToPCA.SetColumn(2,dirZ); |
|
ToPCAInv=ToPCA; |
|
ToPCA=vcg::Inverse(ToPCA); |
|
|
|
///then transform the polygon to PCA space |
|
for (int i=0;i<F.VN();i++) |
|
{ |
|
///translate |
|
CoordType Pos=F.cP(i)-Barycenter; |
|
///rotate |
|
Pos=ToPCA*Pos; |
|
//retranslate |
|
UniformPos.push_back(Pos); |
|
} |
|
|
|
///calculate the Area |
|
ScalarType AreaTemplate=Area(TemplatePos); |
|
ScalarType AreaUniform=Area(UniformPos); |
|
|
|
// if (TargetArea>0) |
|
// { |
|
// AreaUniform*=(AreaUniform/TargetArea); |
|
// } |
|
|
|
ScalarType Scale=sqrt(AreaTemplate/AreaUniform); |
|
|
|
for (size_t i=0;i<UniformPos.size();i++) |
|
UniformPos[i]*=Scale; |
|
|
|
///check side |
|
CoordType N0=Normal(UniformPos); |
|
CoordType N1=Normal(TemplatePos); |
|
if ((N0*N1)<0)std::reverse(TemplatePos.begin(),TemplatePos.end()); |
|
|
|
///initialize |
|
std::vector<CoordType> FixPoints(UniformPos.begin(),UniformPos.end()); |
|
std::vector<CoordType> MovPoints(TemplatePos.begin(),TemplatePos.end()); |
|
|
|
///add displacement along Z |
|
for (size_t i=0;i<FixPoints.size();i++) |
|
{ |
|
FixPoints[i]+=CoordType(0,0,0.1); |
|
MovPoints[i]+=CoordType(0,0,0.1); |
|
} |
|
///add original points |
|
FixPoints.insert(FixPoints.end(),UniformPos.begin(),UniformPos.end()); |
|
MovPoints.insert(MovPoints.end(),TemplatePos.begin(),TemplatePos.end()); |
|
|
|
///then find the alignment |
|
vcg::Matrix44<ScalarType> Rigid; |
|
///compute rigid match |
|
vcg::ComputeRigidMatchMatrix<ScalarType>(FixPoints,MovPoints,Rigid); |
|
|
|
///then apply transformation |
|
UniformTempl.resize(TemplatePos.size(),CoordType(0,0,0)); |
|
for (size_t i=0;i<TemplatePos.size();i++) |
|
UniformTempl[i]=Rigid*TemplatePos[i]; |
|
|
|
///then map back to 3D space |
|
for (size_t i=0;i<TemplatePos.size();i++) |
|
{ |
|
TemplatePos[i]=UniformTempl[i]; |
|
TemplatePos[i]*=1/Scale; |
|
TemplatePos[i]=ToPCAInv*TemplatePos[i]; |
|
} |
|
|
|
for (size_t i=0;i<TemplatePos.size();i++) |
|
TemplatePos[i]+=Barycenter; |
|
|
|
} |
|
|
|
//compute the aspect ratio using the rigidly aligned template polygon as |
|
//described by "Static Aware Grid Shells" by Pietroni et Al. |
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolyAspectRatio(const PolygonType &F, |
|
bool isotropic=false) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
std::vector<CoordType> TemplatePos; |
|
|
|
GetPolyTemplatePos(F,TemplatePos,isotropic); |
|
|
|
ScalarType diff=0; |
|
assert((int)TemplatePos.size()==F.VN()); |
|
|
|
ScalarType AreaP=PolyArea(F); |
|
for (size_t i=0;i<TemplatePos.size();i++) |
|
diff+=pow((TemplatePos[i]-F.cP(i)).Norm(),2)/AreaP; |
|
|
|
return(diff); |
|
} |
|
|
|
|
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolygonPointDistance(const PolygonType &F, |
|
const vcg::Point3<typename PolygonType::ScalarType> &pos, |
|
vcg::Point3<typename PolygonType::ScalarType> &ClosestP, |
|
typename PolygonType::ScalarType minD = std::numeric_limits<typename PolygonType::ScalarType>::max()) |
|
{ |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
typedef typename PolygonType::CoordType CoordType; |
|
|
|
CoordType bary=vcg::PolyBarycenter(F); |
|
for (size_t j=0;j<F.VN();j++) |
|
{ |
|
vcg::Triangle3<ScalarType> T(F.cP0(j),F.cP1(j),bary); |
|
ScalarType dist; |
|
CoordType closest; |
|
vcg::TrianglePointDistance(T,pos,dist,closest); |
|
if (dist>minD)continue; |
|
minD=dist; |
|
ClosestP=closest; |
|
} |
|
return minD; |
|
} |
|
|
|
template<class PolygonType> |
|
vcg::Box3<typename PolygonType::ScalarType> PolygonBox(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
vcg::Box3<ScalarType> bb; |
|
for (size_t j=0;j<F.VN();j++) |
|
bb.Add(F.V(j)->P()); |
|
return bb; |
|
} |
|
|
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolygonTorsion(const PolygonType &F,int side) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
assert(side>=0); |
|
assert(side<2); |
|
assert(F.VN()==4); |
|
|
|
//get firts two edges directions |
|
CoordType Dir0,Dir1; |
|
if (side==0) |
|
{ |
|
Dir0=F.cP(1)-F.cP(0); |
|
Dir1=F.cP(2)-F.cP(3); |
|
} |
|
else |
|
{ |
|
Dir0=F.cP(2)-F.cP(1); |
|
Dir1=F.cP(3)-F.cP(0); |
|
} |
|
|
|
Dir0.Normalize(); |
|
Dir1.Normalize(); |
|
|
|
//then make them lying on face's Normal |
|
CoordType DirPlane0=Dir0*0.5+Dir1*0.5; |
|
CoordType DirPlane1=F.cN(); |
|
CoordType NormPlane=DirPlane0^DirPlane1; |
|
NormPlane.Normalize(); |
|
CoordType subV0=NormPlane*(NormPlane*Dir0); |
|
CoordType subV1=NormPlane*(NormPlane*Dir1); |
|
Dir0-=subV0; |
|
Dir1-=subV1; |
|
Dir0.Normalize(); |
|
Dir1.Normalize(); |
|
ScalarType AngleVal=vcg::Angle(Dir0,Dir1); |
|
return AngleVal; |
|
} |
|
|
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolygonBending(const PolygonType &F,int side) |
|
{ |
|
typedef typename PolygonType::CoordType CoordType; |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
|
|
assert(side>=0); |
|
assert(side<2); |
|
assert(F.VN()==4); |
|
|
|
//get firts two edges directions |
|
CoordType Norm0,Norm1; |
|
CoordType Avg0,Avg1; |
|
if (side==0) |
|
{ |
|
Norm0=F.V(0)->N()*0.5+F.V(1)->N()*0.5; |
|
Avg0=F.cP(0)*0.5+F.cP(1)*0.5; |
|
Norm1=F.V(2)->N()*0.5+F.V(3)->N()*0.5; |
|
Avg1=F.cP(2)*0.5+F.cP(3)*0.5; |
|
} |
|
else |
|
{ |
|
Norm0=F.V(2)->N()*0.5+F.V(1)->N()*0.5; |
|
Avg0=F.cP(2)*0.5+F.cP(1)*0.5; |
|
Norm1=F.V(3)->N()*0.5+F.V(0)->N()*0.5; |
|
Avg1=F.cP(3)*0.5+F.cP(0)*0.5; |
|
} |
|
|
|
Norm0.Normalize(); |
|
Norm1.Normalize(); |
|
|
|
//then make them lying on face's Normal |
|
CoordType DirPlane0=Avg0-Avg1; |
|
DirPlane0.Normalize(); |
|
CoordType DirPlane1=F.cN(); |
|
CoordType NormPlane=DirPlane0^DirPlane1; |
|
NormPlane.Normalize(); |
|
CoordType subV0=NormPlane*(NormPlane*Norm0); |
|
CoordType subV1=NormPlane*(NormPlane*Norm1); |
|
Norm0-=subV0; |
|
Norm1-=subV1; |
|
Norm0.Normalize(); |
|
Norm1.Normalize(); |
|
ScalarType AngleVal=vcg::Angle(Norm0,Norm1); |
|
return AngleVal; |
|
} |
|
|
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolygonBending(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
ScalarType Bend0=PolygonBending(F,0); |
|
ScalarType Bend1=PolygonBending(F,1); |
|
assert(Bend0>=0); |
|
assert(Bend1>=0); |
|
return (std::max(Bend0,Bend1)); |
|
} |
|
|
|
template<class PolygonType> |
|
typename PolygonType::ScalarType PolygonTorsion(const PolygonType &F) |
|
{ |
|
typedef typename PolygonType::ScalarType ScalarType; |
|
ScalarType Torsion0=PolygonTorsion(F,0); |
|
ScalarType Torsion1=PolygonTorsion(F,1); |
|
assert(Torsion0>=0); |
|
assert(Torsion1>=0); |
|
return (std::max(Torsion0,Torsion1)); |
|
} |
|
|
|
} |
|
#endif // POLYGON_H
|
|
|