diff --git a/vcg/complex/algorithms/parametrization/distortion.h b/vcg/complex/algorithms/parametrization/distortion.h index f5ec2393..a2278892 100644 --- a/vcg/complex/algorithms/parametrization/distortion.h +++ b/vcg/complex/algorithms/parametrization/distortion.h @@ -29,6 +29,27 @@ namespace vcg { namespace tri{ template + + +/* + * Energy types: + * + * AreaDist : 0 for equiareal (equipotent) mappings + * EdgeDist (hack): 0 for isometric mappings (computed on edges only) + * AngleDist (hack): 0 for conformal mappings + * CrossDist : as above, but computed on tangent directions (not UVs) + * L2Stretch : 1 for isometric mappings (averaged case on the mesh), + * +inf on degenerate / folded cases + * Described in [1] + * LInfStretch : as above, but WORST case + * (returns the worst stretch on any position and direction) + * Described in [1] + * + * [1] Sander, P. V., Snyder, J., Gortler, S. J., & Hoppe, H. + * "Texture mapping progressive meshes." + * In Proc. ACM SIGGRAPH (pp. 409-416). 2001 + */ + class Distortion { public: @@ -36,7 +57,9 @@ public: typedef typename MeshType::VertexType VertexType; typedef typename MeshType::CoordType CoordType; typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::FaceType::CurVecType CurVecType; typedef typename MeshType::FaceType::TexCoordType::ScalarType TexScalarType; + typedef Point2 TexCoordType; static ScalarType Area3D(const FaceType *f) { @@ -45,7 +68,7 @@ public: static ScalarType AreaUV(const FaceType *f) { - Point2 uv0,uv1,uv2; + TexCoordType uv0,uv1,uv2; if(PerWedgeFlag) { uv0=f->cWT(0).P(); uv1=f->cWT(1).P(); @@ -152,7 +175,7 @@ public: public: - enum DistType{AreaDist,EdgeDist,AngleDist,CrossDist}; + enum DistType{AreaDist,EdgeDist,AngleDist,CrossDist,L2Stretch,LInfStretch}; ///return the absolute difference between angle in 3D space and texture space ///Actually the difference in cos space @@ -206,7 +229,7 @@ public: } ///return the variance of edge length, normalized in absolute value, - // the needed scaling factor EdgeScaleVal may be calculated + ///the needed scaling factor EdgeScaleVal may be calculated ///by using the ScalingFactor function static ScalarType EdgeDistortion(const FaceType *f,int e, ScalarType EdgeScaleVal) @@ -233,6 +256,60 @@ public: return diff; } + static ScalarType L2StretchEnergySquared(const FaceType *f, + ScalarType AreaScaleVal) + { + TexCoordType p0 = (PerWedgeFlag)? f->cWT(0).P() : f->cV(0)->T().P() ; + TexCoordType p1 = (PerWedgeFlag)? f->cWT(1).P() : f->cV(1)->T().P() ; + TexCoordType p2 = (PerWedgeFlag)? f->cWT(2).P() : f->cV(2)->T().P() ; + + CoordType q0 = f->cP(0); + CoordType q1 = f->cP(1); + CoordType q2 = f->cP(2); + + TexScalarType A2 = ((p1-p0)^(p2-p0)); + + if (A2<0) A2 = 0; // will be NAN, +infinity + + CoordType Ss = ( q0 * ( p1[1]-p2[1] ) + q1 * (p2[1]-p0[1]) + q2 * (p0[1]-p1[1]) ) / A2; + CoordType St = ( q0 * ( p2[0]-p1[0] ) + q1 * (p0[0]-p2[0]) + q2 * (p1[0]-p0[0]) ) / A2; + + ScalarType a = Ss.SquaredNorm() / AreaScaleVal; + ScalarType c = St.SquaredNorm() / AreaScaleVal; + + return ((a+c)/2); + } + + + + static ScalarType LInfStretchEnergy(const FaceType *f, ScalarType AreaScaleVal) + { + TexCoordType p0 = (PerWedgeFlag)? f->cWT(0).P() : f->cV(0)->T().P() ; + TexCoordType p1 = (PerWedgeFlag)? f->cWT(1).P() : f->cV(1)->T().P() ; + TexCoordType p2 = (PerWedgeFlag)? f->cWT(2).P() : f->cV(2)->T().P() ; + + CoordType q0 = f->cP(0); + CoordType q1 = f->cP(1); + CoordType q2 = f->cP(2); + + TexScalarType A2 = ((p1-p0)^(p2-p0)); + + if (A2<0) A2 = 0; // will be NAN, +infinity + + CoordType Ss = ( q0 * ( p1[1]-p2[1] ) + q1 * (p2[1]-p0[1]) + q2 * (p0[1]-p1[1]) ) / A2; + CoordType St = ( q0 * ( p2[0]-p1[0] ) + q1 * (p0[0]-p2[0]) + q2 * (p1[0]-p0[0]) ) / A2; + + ScalarType a = Ss.SquaredNorm() / AreaScaleVal; + ScalarType b = Ss*St / AreaScaleVal; + ScalarType c = St.SquaredNorm() / AreaScaleVal; + + ScalarType delta = sqrt((a-c)*(a-c)+4*b*b); + ScalarType G = sqrt( (a+c+delta)/2 ); + //ScalarType g = sqrt( (a+c-delta)/2 ); // not needed + return G; + } + + ///return the number of folded faces static bool Folded(const FaceType *f) { @@ -271,10 +348,10 @@ public: return UDdist; } - static void SetQasCrossDirDistortion(MeshType &m) + static ScalarType SetFQAsCrossDirDistortion(MeshType &m) { //first save the old UV dir - std::vector Dir1,Dir2; + std::vector Dir1,Dir2; for (size_t i=0;i::InitDirFromWEdgeUV(m); + ScalarType tot = 0, totA = 0; + //then compute angle deficit for (size_t i=0;i::K_PI(Dir1[i], - m.face[i].PD1(), - m.face[i].N()); + + FaceType &f( m.face[i] ); + CoordType transfPD1=vcg::tri::CrossField::K_PI(CoordType::Construct( Dir1[i] ), + CoordType::Construct( f.PD1() ), + f.N()); transfPD1.Normalize(); - ScalarType AngleDeficit=vcg::Angle(transfPD1,m.face[i].PD1()); + ScalarType AngleDeficit=vcg::Angle(transfPD1,CoordType::Construct( f.PD1() )); AngleDeficit=math::ToDeg(AngleDeficit); if ((AngleDeficit>45)||(AngleDeficit<0)) { @@ -297,7 +378,13 @@ public: } // assert(AngleDeficit<45); // assert(AngleDeficit>=0); - m.face[i].Q()=(AngleDeficit)/(ScalarType)45; + + ScalarType doubleArea = vcg::DoubleArea( f ); + ScalarType distortion = (AngleDeficit)/ 45 ; + + m.face[i].Q()= distortion; + tot += distortion * doubleArea; + totA += doubleArea; } //finally restore the original directions @@ -306,36 +393,77 @@ public: m.face[i].PD1()=Dir1[i]; m.face[i].PD2()=Dir2[i]; } + + return tot / totA; } - static void SetQasDistorsion(MeshType &m, - DistType DType=AreaDist) + static ScalarType SetQasDistorsion(MeshType &m, DistType DType=AreaDist) { if (DType==CrossDist) { - SetQasCrossDirDistortion(m); + ScalarType res = SetFQAsCrossDirDistortion(m); + vcg::tri::UpdateQuality::VertexFromFace(m,true); - return; + return res; } ScalarType edge_scale,area_scale; MeshScalingFactor(m,area_scale,edge_scale); + + float tot = 0; + float totA = 0; + for (int i=0;i::VertexFromFace(m,true); + + switch (DType) { + case L2Stretch: return sqrt(tot/totA); + case LInfStretch: return tot; + default: return tot/totA; + } } }; -} -} + +}} // namespace end + #endif