add vcglib
This commit is contained in:
1 parent
6f6c0c8eb7
commit
af8100f851
1537 files changed
+634197
No files matched your search
@@ -0,0 +1,556 @@
|
||||
/****************************************************************************
|
||||
* 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 VCG_PARAM_DISTORTION
|
||||
#define VCG_PARAM_DISTORTION
|
||||
#include <vcg/complex/algorithms/parametrization/uv_utils.h>
|
||||
#include <vcg/complex/algorithms/parametrization/tangent_field_operators.h>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
|
||||
template <class MeshType, bool PerWedge>
|
||||
struct UVHelper {};
|
||||
|
||||
template <class MeshType>
|
||||
struct UVHelper<MeshType, true>
|
||||
{
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename FaceType::TexCoordType::PointType TexCoordType;
|
||||
static TexCoordType Coord(const FaceType *f, int i)
|
||||
{
|
||||
return f->cWT(i).P();
|
||||
}
|
||||
};
|
||||
|
||||
template <class MeshType>
|
||||
struct UVHelper<MeshType, false>
|
||||
{
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename VertexType::TexCoordType::PointType TexCoordType;
|
||||
static TexCoordType Coord(const FaceType *f, int i)
|
||||
{
|
||||
return f->cV(i)->T().P();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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]
|
||||
* ARAPEnergy : 0 for isometric mappings
|
||||
* Described in [2]
|
||||
*
|
||||
* [1] Sander, P. V., Snyder, J., Gortler, S. J., & Hoppe, H.
|
||||
* "Texture mapping progressive meshes."
|
||||
* In Proc. ACM SIGGRAPH (pp. 409-416). 2001
|
||||
*
|
||||
* [2] Liu, L., Zhang, L., Xu, Y., Gotsman, C., & Gortler, S. J. (2008, July).
|
||||
* A local/global approach to mesh parameterization.
|
||||
* Computer Graphics Forum (Vol. 27, No. 5, pp. 1495-1504). Blackwell Publishing Ltd.
|
||||
*/
|
||||
|
||||
template <class MeshType, bool PerWedgeFlag>
|
||||
class Distortion
|
||||
{
|
||||
public:
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::FaceType::CurVecType CurVecType;
|
||||
typedef UVHelper<MeshType, PerWedgeFlag> UV;
|
||||
typedef typename UV::TexCoordType TexCoordType;
|
||||
typedef typename TexCoordType::ScalarType TexScalarType;
|
||||
|
||||
static TexCoordType UVCoord(const FaceType *f, int i)
|
||||
{
|
||||
return UV::Coord(f, i);
|
||||
}
|
||||
|
||||
static ScalarType Area3D(const FaceType *f)
|
||||
{
|
||||
return DoubleArea(*f)*(0.5);
|
||||
}
|
||||
|
||||
static ScalarType AreaUV(const FaceType *f)
|
||||
{
|
||||
TexCoordType uv0 = UVCoord(f, 0);
|
||||
TexCoordType uv1 = UVCoord(f, 1);
|
||||
TexCoordType uv2 = UVCoord(f, 2);
|
||||
ScalarType AreaUV=((uv1-uv0)^(uv2-uv0))/2.0;
|
||||
return AreaUV;
|
||||
}
|
||||
|
||||
static ScalarType EdgeLenght3D(const FaceType *f,int e)
|
||||
{
|
||||
assert((e>=0)&&(e<3));
|
||||
ScalarType length=(f->cP0(e)-f->cP1(e)).Norm();
|
||||
return (length);
|
||||
}
|
||||
|
||||
static ScalarType EdgeLenghtUV(const FaceType *f,int e)
|
||||
{
|
||||
assert((e>=0)&&(e<3));
|
||||
TexCoordType uv0 = UVCoord(f, e+0);
|
||||
TexCoordType uv1 = UVCoord(f, (e+1)%3);
|
||||
ScalarType UVlength=Distance(uv0,uv1);
|
||||
return UVlength;
|
||||
}
|
||||
|
||||
static ScalarType AngleCos3D(const FaceType *f,int e)
|
||||
{
|
||||
assert((e>=0)&&(e<3));
|
||||
CoordType p0=f->P((e+2)%3);
|
||||
CoordType p1=f->P(e);
|
||||
CoordType p2=f->P((e+1)%3);
|
||||
CoordType dir0=p2-p1;
|
||||
CoordType dir1=p0-p1;
|
||||
dir0.Normalize();
|
||||
dir1.Normalize();
|
||||
ScalarType angle=dir0*dir1;
|
||||
return angle;
|
||||
}
|
||||
|
||||
static ScalarType AngleCosUV(const FaceType *f,int e)
|
||||
{
|
||||
TexCoordType uv0 = UVCoord(f, (e+2)%3);
|
||||
TexCoordType uv1 = UVCoord(f, e);
|
||||
TexCoordType uv2 = UVCoord(f, (e+1)%3);
|
||||
vcg::Point2<ScalarType> dir0=uv2-uv1;
|
||||
vcg::Point2<ScalarType> dir1=uv0-uv1;
|
||||
dir0.Normalize();
|
||||
dir1.Normalize();
|
||||
ScalarType angle=dir0*dir1;
|
||||
return angle;
|
||||
}
|
||||
|
||||
static ScalarType AngleRad3D(const FaceType *f,int e)
|
||||
{
|
||||
assert((e>=0)&&(e<3));
|
||||
CoordType p0=f->cP((e+2)%3);
|
||||
CoordType p1=f->cP(e);
|
||||
CoordType p2=f->cP((e+1)%3);
|
||||
CoordType dir0=p2-p1;
|
||||
CoordType dir1=p0-p1;
|
||||
return Angle(dir0,dir1);
|
||||
}
|
||||
|
||||
static ScalarType AngleRadUV(const FaceType *f,int e)
|
||||
{
|
||||
TexCoordType uv0 = UVCoord(f, (e+2)%3);
|
||||
TexCoordType uv1 = UVCoord(f, e);
|
||||
TexCoordType uv2 = UVCoord(f, (e+1)%3);
|
||||
vcg::Point2<TexScalarType> dir0=uv2-uv1;
|
||||
vcg::Point2<TexScalarType> dir1=uv0-uv1;
|
||||
dir0.Normalize();
|
||||
dir1.Normalize();
|
||||
ScalarType t=dir0*dir1;
|
||||
if(t>1) t = 1;
|
||||
else if(t<-1) t = -1;
|
||||
return acos(t);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
enum DistType{AreaDist,EdgeDist,EdgeComprStretch,AngleDist,CrossDist,L2Stretch,LInfStretch,ARAPDist};
|
||||
|
||||
///return the absolute difference between angle in 3D space and texture space
|
||||
///Actually the difference in cos space
|
||||
static ScalarType AngleCosDistortion(const FaceType *f,int e)
|
||||
{
|
||||
ScalarType Angle_3D=AngleCos3D(f,e);
|
||||
ScalarType Angle_UV=AngleCosUV(f,e);
|
||||
ScalarType diff=fabs(Angle_3D-Angle_UV);///Angle_3D;
|
||||
return diff;
|
||||
}
|
||||
///return the absolute difference between angle in 3D space and texture space
|
||||
///Actually the difference in cos space
|
||||
static ScalarType AngleRadDistortion(const FaceType *f,int e)
|
||||
{
|
||||
ScalarType Angle_3D=AngleRad3D(f,e);
|
||||
ScalarType Angle_UV=AngleRadUV(f,e);
|
||||
ScalarType diff=fabs(Angle_3D-Angle_UV)/Angle_3D;///Angle_3D;
|
||||
return diff;
|
||||
}
|
||||
|
||||
///return the variance of angle, normalized
|
||||
///in absolute value
|
||||
static ScalarType AngleDistortion(const FaceType *f)
|
||||
{
|
||||
return (AngleRadDistortion(f,0) +
|
||||
AngleRadDistortion(f,1) +
|
||||
AngleRadDistortion(f,2))/3.0;
|
||||
}
|
||||
|
||||
///return the global scaling factors from 3D to UV
|
||||
static void MeshScalingFactor(const MeshType &m,
|
||||
ScalarType &AreaScale,
|
||||
ScalarType &EdgeScale)
|
||||
{
|
||||
ScalarType SumArea3D=0;
|
||||
ScalarType SumArea2D=0;
|
||||
ScalarType SumEdge3D=0;
|
||||
ScalarType SumEdge2D=0;
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
SumArea3D+=Area3D(&m.face[i]);
|
||||
SumArea2D+=AreaUV(&m.face[i]);
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
SumEdge3D+=EdgeLenght3D(&m.face[i],j);
|
||||
SumEdge2D+=EdgeLenghtUV(&m.face[i],j);
|
||||
}
|
||||
}
|
||||
AreaScale=SumArea3D/SumArea2D;
|
||||
EdgeScale=SumEdge3D/SumEdge2D;
|
||||
}
|
||||
|
||||
///return the variance of edge length, normalized in absolute value,
|
||||
///the needed scaling factor EdgeScaleVal may be calculated
|
||||
///by using the ScalingFactor function
|
||||
static ScalarType EdgeDistortion(const FaceType *f,int e,
|
||||
ScalarType EdgeScaleVal,
|
||||
bool AbsValue=true)
|
||||
{
|
||||
ScalarType edgeUV=EdgeLenghtUV(f,e)*EdgeScaleVal;
|
||||
ScalarType edge3D=EdgeLenght3D(f,e);
|
||||
assert(edge3D > 0);
|
||||
|
||||
ScalarType diff=0;
|
||||
if (AbsValue)
|
||||
diff=fabs(edge3D-edgeUV)/edge3D;
|
||||
else
|
||||
diff=(edge3D-edgeUV)/edge3D;
|
||||
|
||||
assert(!math::IsNAN(diff));
|
||||
return diff;
|
||||
}
|
||||
|
||||
///return the variance of area, normalized
|
||||
///in absolute value, the scalar AreaScaleVal may be calculated
|
||||
///by using the ScalingFactor function
|
||||
static ScalarType AreaDistortion(const FaceType *f,
|
||||
ScalarType AreaScaleVal)
|
||||
{
|
||||
ScalarType areaUV=AreaUV(f)*AreaScaleVal;
|
||||
ScalarType area3D=Area3D(f);
|
||||
assert(area3D > 0);
|
||||
ScalarType diff=fabs(areaUV-area3D)/area3D;
|
||||
assert(!math::IsNAN(diff));
|
||||
return diff;
|
||||
}
|
||||
|
||||
static ScalarType L2StretchEnergySquared(const FaceType *f,
|
||||
ScalarType AreaScaleVal)
|
||||
{
|
||||
TexCoordType p0 = UVCoord(f, 0);
|
||||
TexCoordType p1 = UVCoord(f, 1);
|
||||
TexCoordType p2 = UVCoord(f, 2);
|
||||
|
||||
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 = UVCoord(f, 0);
|
||||
TexCoordType p1 = UVCoord(f, 1);
|
||||
TexCoordType p2 = UVCoord(f, 2);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static ScalarType ARAPEnergy(const FaceType *f)
|
||||
{
|
||||
if (f == NULL)
|
||||
{
|
||||
return std::numeric_limits<ScalarType>::infinity();
|
||||
}
|
||||
|
||||
const Eigen::Matrix2d F = mappingTransform2D(*f);
|
||||
const Eigen::Vector2d singular = svd2x2(F);
|
||||
const double a = singular(0) - 1;
|
||||
const double b = singular(1) - 1;
|
||||
return ScalarType(0.5 * (a*a + b*b));
|
||||
}
|
||||
|
||||
static Eigen::Matrix2d mappingTransform2D(const FaceType & triangle)
|
||||
{
|
||||
typedef Eigen::Matrix<double, 3, 2> Matrix32;
|
||||
typedef Eigen::Matrix2d Matrix22;
|
||||
|
||||
|
||||
Matrix22 param3d, param2d;
|
||||
// 3D
|
||||
{
|
||||
Matrix32 edges3D, P3D;
|
||||
Eigen::Vector3d e0, e1;
|
||||
(triangle.cP(1) - triangle.cP(0)).ToEigenVector(e0); // 0->1
|
||||
(triangle.cP(2) - triangle.cP(0)).ToEigenVector(e1); // 0->2
|
||||
edges3D.col(0) = e0;
|
||||
edges3D.col(1) = e1;
|
||||
|
||||
// Projection/frame change matrix
|
||||
P3D.col(0) = edges3D.col(0).normalized(); // 0->1 normalized e0 basis
|
||||
P3D.col(1) = (edges3D.col(1) - edges3D.col(1).dot(P3D.col(0)) * P3D.col(0)).normalized(); // e1 basis orthogonal to e0
|
||||
|
||||
param3d = (P3D.transpose() * edges3D);
|
||||
}
|
||||
|
||||
// 2D
|
||||
{
|
||||
Matrix22 edges2D, P2D;
|
||||
TexCoordType uv0 = UVCoord(&triangle, 0);
|
||||
TexCoordType uv1 = UVCoord(&triangle, 1);
|
||||
TexCoordType uv2 = UVCoord(&triangle, 2);
|
||||
|
||||
const TexCoordType e0 = (uv1 - uv0); // 0->1
|
||||
const TexCoordType e1 = (uv2 - uv0); // 0->2
|
||||
param2d << e0.X(), e1.X(),
|
||||
e0.Y(), e1.Y();
|
||||
}
|
||||
|
||||
return param2d * param3d.inverse(); // transf mapping
|
||||
}
|
||||
|
||||
// svd 2x2 matrix (singular values only)
|
||||
static Eigen::Vector2d svd2x2(const Eigen::Matrix2d & M)
|
||||
{
|
||||
const double a=M(0,0), b=M(0,1), c=M(1,0), d=M(1,1);
|
||||
const double tmp1 = a*a + b*b;
|
||||
const double tmp2 = c*c + d*d;
|
||||
const double s1 = tmp1 + tmp2;
|
||||
const double s2 = std::sqrt(std::pow((tmp1 -tmp2), 2.0) + 4 * std::pow(a*c + b*d, 2.0));
|
||||
return Eigen::Vector2d(std::sqrt((s1+s2)/2.0), std::sqrt((s1-s2)/2.0));
|
||||
}
|
||||
|
||||
|
||||
///return the number of folded faces
|
||||
static bool IsFolded(const FaceType *f)
|
||||
{
|
||||
ScalarType areaUV=AreaUV(f);
|
||||
/*if (areaUV<0)
|
||||
printf("area %5.5f \n",areaUV);*/
|
||||
return (areaUV<0);
|
||||
}
|
||||
|
||||
static int FoldedNum(const MeshType &m)
|
||||
{
|
||||
int folded=0;
|
||||
|
||||
ForEachFace(m, std::function<void (const FaceType&)>([&folded](const FaceType &f){
|
||||
if(IsFolded(&f)) folded++;
|
||||
}));
|
||||
|
||||
return folded;
|
||||
}
|
||||
|
||||
static bool GloballyUnFolded(const MeshType &m)
|
||||
{
|
||||
int num=FoldedNum(m);
|
||||
return (num>(m.fn)/2);
|
||||
}
|
||||
|
||||
static ScalarType MeshAngleDistortion(const MeshType &m)
|
||||
{
|
||||
ScalarType UDdist=0;
|
||||
ForEachFace(m, std::function<void (const FaceType&)>([&UDdist](const FaceType &f){
|
||||
UDdist += AngleDistortion(f)*Area3D(f);
|
||||
}));
|
||||
|
||||
return UDdist;
|
||||
}
|
||||
|
||||
static ScalarType SetFQAsCrossDirDistortion(MeshType &m)
|
||||
{
|
||||
//first save the old UV dir
|
||||
std::vector<CurVecType> Dir1,Dir2;
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
Dir1.push_back(m.face[i].PD1());
|
||||
Dir2.push_back(m.face[i].PD2());
|
||||
}
|
||||
vcg::tri::CrossField<MeshType>::InitDirFromWEdgeUV(m);
|
||||
|
||||
ScalarType tot = 0, totA = 0;
|
||||
|
||||
//then compute angle deficit
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
|
||||
FaceType &f( m.face[i] );
|
||||
CoordType transfPD1=vcg::tri::CrossField<MeshType>::K_PI(CoordType::Construct( Dir1[i] ),
|
||||
CoordType::Construct( f.PD1() ),
|
||||
f.N());
|
||||
transfPD1.Normalize();
|
||||
ScalarType AngleDeficit=vcg::Angle(transfPD1,CoordType::Construct( f.PD1() ));
|
||||
AngleDeficit=math::ToDeg(AngleDeficit);
|
||||
if ((AngleDeficit>45)||(AngleDeficit<0))
|
||||
{
|
||||
std::cout<<"Warnign A Deficit "<<AngleDeficit<<std::endl;
|
||||
}
|
||||
// assert(AngleDeficit<45);
|
||||
// assert(AngleDeficit>=0);
|
||||
|
||||
ScalarType doubleArea = vcg::DoubleArea( f );
|
||||
ScalarType distortion = (AngleDeficit)/ 45 ;
|
||||
|
||||
m.face[i].Q()= distortion;
|
||||
tot += distortion * doubleArea;
|
||||
totA += doubleArea;
|
||||
}
|
||||
|
||||
//finally restore the original directions
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
m.face[i].PD1()=Dir1[i];
|
||||
m.face[i].PD2()=Dir2[i];
|
||||
}
|
||||
|
||||
return tot / totA;
|
||||
}
|
||||
|
||||
static ScalarType SetQasDistorsion(MeshType &m, DistType DType=AreaDist)
|
||||
{
|
||||
if (DType==CrossDist)
|
||||
{
|
||||
ScalarType res = SetFQAsCrossDirDistortion(m);
|
||||
|
||||
vcg::tri::UpdateQuality<MeshType>::VertexFromFace(m,true);
|
||||
return res;
|
||||
}
|
||||
|
||||
ScalarType edge_scale,area_scale;
|
||||
MeshScalingFactor(m,area_scale,edge_scale);
|
||||
|
||||
ScalarType tot = 0;
|
||||
ScalarType totA = 0;
|
||||
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
if (m.face[i].IsD())continue;
|
||||
ScalarType q;
|
||||
switch (DType) {
|
||||
case CrossDist:
|
||||
// make compiler happy
|
||||
q = 0;
|
||||
break;
|
||||
case AreaDist:
|
||||
q = AreaDistortion(&m.face[i],area_scale);
|
||||
break;
|
||||
case AngleDist:
|
||||
q = AngleDistortion(&m.face[i]);
|
||||
break;
|
||||
case EdgeDist:
|
||||
q =( EdgeDistortion(&m.face[i],0,edge_scale)+
|
||||
EdgeDistortion(&m.face[i],1,edge_scale)+
|
||||
EdgeDistortion(&m.face[i],2,edge_scale) )/3;
|
||||
break;
|
||||
case EdgeComprStretch:
|
||||
q =( EdgeDistortion(&m.face[i],0,edge_scale,false)+
|
||||
EdgeDistortion(&m.face[i],1,edge_scale,false)+
|
||||
EdgeDistortion(&m.face[i],2,edge_scale,false) )/3;
|
||||
break;
|
||||
case L2Stretch:
|
||||
q = L2StretchEnergySquared( &m.face[i],area_scale );
|
||||
break;
|
||||
case LInfStretch:
|
||||
q = LInfStretchEnergy( &m.face[i],area_scale );
|
||||
break;
|
||||
case ARAPDist:
|
||||
q = ARAPEnergy(&m.face[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
m.face[i].Q() = q; // note: for L2Stretch, we are puttning E^2 on Q
|
||||
|
||||
// aggregate:
|
||||
if (DType==LInfStretch) {
|
||||
tot = std::max( tot, q );
|
||||
} else {
|
||||
ScalarType a = Area3D(&m.face[i]);
|
||||
tot += q*a;
|
||||
totA += a;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vcg::tri::UpdateQuality<MeshType>::VertexFromFace(m,true);
|
||||
|
||||
switch (DType) {
|
||||
case L2Stretch: return sqrt(tot/totA);
|
||||
case LInfStretch: return tot;
|
||||
default: return tot/totA;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,683 @@
|
||||
/****************************************************************************
|
||||
* 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 VCG_POISSON_SOLVER
|
||||
#define VCG_POISSON_SOLVER
|
||||
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/parametrization/distortion.h>
|
||||
#include <vcg/complex/algorithms/parametrization/uv_utils.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri{
|
||||
template <class MeshType>
|
||||
class PoissonSolver
|
||||
{
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
|
||||
MeshType &mesh;
|
||||
|
||||
///solver data
|
||||
std::map<VertexType*,int> VertexToInd;
|
||||
std::map<int, VertexType*> IndToVertex;
|
||||
|
||||
///vertices to fix
|
||||
std::vector<VertexType *> to_fix;
|
||||
Eigen::SparseMatrix<double> A; // A
|
||||
Eigen::VectorXd b,x;// x and b
|
||||
|
||||
//number of variables
|
||||
unsigned int n_vert_vars;
|
||||
///total system size
|
||||
unsigned int total_size;
|
||||
///number of fixed variables
|
||||
unsigned int n_fixed_vars;
|
||||
|
||||
///if you intend to follow the cross field
|
||||
bool use_direction_field,fix_selected,correct_fixed;
|
||||
///size of the scalar field
|
||||
ScalarType fieldScale;
|
||||
|
||||
int VertexIndex(VertexType* v)
|
||||
{
|
||||
typename std::map<VertexType*,int>::iterator iteMap=VertexToInd.find(v);
|
||||
assert(iteMap!=VertexToInd.end());
|
||||
return ((*iteMap).second);
|
||||
}
|
||||
|
||||
VertexType* IndexVertex(int index)
|
||||
{
|
||||
typename std::map<int,VertexType*>::iterator iteMap=IndToVertex.find(index);
|
||||
assert(iteMap!=IndToVertex.end());
|
||||
return ((*iteMap).second);
|
||||
}
|
||||
|
||||
void AddVertexIndex(VertexType* v,int index)
|
||||
{
|
||||
VertexToInd.insert(std::pair<VertexType*,int>(v,index));
|
||||
IndToVertex.insert(std::pair<int,VertexType*>(index,v));
|
||||
}
|
||||
///set the value of A of the system Ax=b
|
||||
void SetValA(int Xindex,int Yindex,ScalarType val)
|
||||
{
|
||||
assert(0 <= Xindex && Xindex < int(total_size));
|
||||
assert(0 <= Yindex && Yindex < int(total_size));
|
||||
A.coeffRef(Xindex,Yindex) +=val;
|
||||
}
|
||||
|
||||
void FindFarthestVert(VertexType* &v0, VertexType* &v1)
|
||||
{
|
||||
v0=v1=NULL;
|
||||
const int bestAxis = mesh.bbox.MaxDim();
|
||||
for(VertexType &vv : mesh.vert) {
|
||||
if(vv.P()[bestAxis] <= mesh.bbox.min[bestAxis]) v0 = &vv;
|
||||
if(vv.P()[bestAxis] >= mesh.bbox.max[bestAxis]) v1 = &vv;
|
||||
}
|
||||
assert( (v0!=v1) && v0 && v1);
|
||||
}
|
||||
|
||||
///set the value of b of the system Ax=b
|
||||
void SetValB(int Xindex,
|
||||
ScalarType val)
|
||||
{
|
||||
/*S.b()[Xindex] += val;*/
|
||||
b[Xindex] += val;
|
||||
}
|
||||
|
||||
///add the area term, scalefactor is used to sum up
|
||||
///and normalize on the overlap zones
|
||||
void AddAreaTerm(int index[3][3][2],ScalarType ScaleFactor)
|
||||
{
|
||||
const ScalarType entry=0.5*ScaleFactor;
|
||||
ScalarType val[3][3]= { {0, entry, -entry},
|
||||
{-entry, 0, entry},
|
||||
{entry, -entry, 0} };
|
||||
|
||||
for (int i=0;i<3;i++)
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
///add for both u and v
|
||||
int Xindex=index[i][j][0]*2;
|
||||
int Yindex=index[i][j][1]*2;
|
||||
|
||||
SetValA(Xindex+1,Yindex,-val[i][j]);
|
||||
SetValA(Xindex,Yindex+1,val[i][j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///set the diagonal of the matrix (which is zero at the beginning)
|
||||
///as the sum of the other element inverted by sign
|
||||
void SetDiagonal(ScalarType val[3][3])
|
||||
{
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
ScalarType sum=0;
|
||||
for (int j=0;j<3;j++)
|
||||
sum+=val[i][j];
|
||||
val[i][i]=-sum;
|
||||
}
|
||||
}
|
||||
|
||||
///add this values to the right hand side
|
||||
void AddRHS(ScalarType b[6],
|
||||
int index[3])
|
||||
{
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
ScalarType valU=b[i*2];
|
||||
ScalarType valV=b[(i*2)+1];
|
||||
SetValB((index[i]*2),valU);
|
||||
SetValB((index[i]*2)+1,valV);
|
||||
}
|
||||
}
|
||||
|
||||
///add a 3x3 block matrix to the system matrix...
|
||||
///indexes are specified in the 3x3 matrix of x,y pairs
|
||||
///indexes must be multiplied by 2 cause u and v
|
||||
void Add33Block(ScalarType val[3][3],int index[3][3][2])
|
||||
{
|
||||
for (int i=0;i<3;i++)
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
///add for both u and v
|
||||
int Xindex=index[i][j][0]*2;
|
||||
int Yindex=index[i][j][1]*2;
|
||||
assert(Xindex<int(n_vert_vars*2));
|
||||
assert(Yindex<int(n_vert_vars*2));
|
||||
SetValA(Xindex,Yindex,val[i][j]);
|
||||
SetValA(Xindex+1,Yindex+1,val[i][j]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///add a 3x3 block matrix to the system matrix...
|
||||
///indexes are specified in the 3x3 matrix of x,y pairs
|
||||
///indexes must be multiplied by 2 cause u and v
|
||||
void Add44Block(ScalarType val[4][4],int index[4][4][2])
|
||||
{
|
||||
for (int i=0;i<4;i++)
|
||||
for (int j=0;j<4;j++)
|
||||
{
|
||||
///add for both u and v
|
||||
int Xindex=index[i][j][0]*2;
|
||||
int Yindex=index[i][j][1]*2;
|
||||
assert(Xindex<(n_vert_vars*2));
|
||||
assert(Yindex<(n_vert_vars*2));
|
||||
SetValA(Xindex,Yindex,val[i][j]);
|
||||
SetValA(Xindex+1,Yindex+1,val[i][j]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///return the LHS for a given face
|
||||
void perElementLHS(FaceType *f,
|
||||
ScalarType val[3][3],
|
||||
int index[3][3][2])
|
||||
{
|
||||
///initialize to zero
|
||||
for (int x=0;x<3;x++)
|
||||
for (int y=0;y<3;y++)
|
||||
val[x][y]=0;
|
||||
|
||||
///get the vertices
|
||||
VertexType *v[3];
|
||||
v[0]=f->V(0);
|
||||
v[1]=f->V(1);
|
||||
v[2]=f->V(2);
|
||||
|
||||
///get the indexes of vertex instance (to consider cuts)
|
||||
///for the current face
|
||||
int Vindexes[3];
|
||||
Vindexes[0]=VertexIndex(f->V(0));
|
||||
Vindexes[1]=VertexIndex(f->V(1));
|
||||
Vindexes[2]=VertexIndex(f->V(2));
|
||||
|
||||
///initialize the indexes for the block
|
||||
for (int x=0;x<3;x++)
|
||||
for (int y=0;y<3;y++)
|
||||
{
|
||||
index[x][y][0]=Vindexes[x];
|
||||
index[x][y][1]=Vindexes[y];
|
||||
}
|
||||
|
||||
///initialize edges
|
||||
CoordType e[3];
|
||||
for (int k=0;k<3;k++)
|
||||
e[k]=v[(k+2)%3]->P()-v[(k+1)%3]->P();
|
||||
|
||||
///then consider area but also considering scale factor dur to overlaps
|
||||
ScalarType areaT=((f->P(1)-f->P(0))^(f->P(2)-f->P(0))).Norm()/2.0;
|
||||
for (int x=0;x<3;x++)
|
||||
for (int y=0;y<3;y++)
|
||||
if (x!=y)
|
||||
{
|
||||
ScalarType num=(e[x]*e[y]);
|
||||
val[x][y] =num/(4.0*areaT);
|
||||
}
|
||||
|
||||
///set the matrix as diagonal
|
||||
SetDiagonal(val);
|
||||
}
|
||||
|
||||
///return the RHS for a given face
|
||||
void perElementRHS(FaceType *f,
|
||||
ScalarType b[6],
|
||||
ScalarType vector_field_scale=1)
|
||||
{
|
||||
|
||||
/// then set the rhs
|
||||
CoordType scaled_Kreal;
|
||||
CoordType scaled_Kimag;
|
||||
CoordType fNorm=f->N();
|
||||
fNorm.Normalize();
|
||||
CoordType p[3];
|
||||
p[0]=f->P0(0);
|
||||
p[1]=f->P0(1);
|
||||
p[2]=f->P0(2);
|
||||
|
||||
CoordType neg_t[3];
|
||||
neg_t[0] = fNorm ^ (p[2] - p[1]);
|
||||
neg_t[1] = fNorm ^ (p[0] - p[2]);
|
||||
neg_t[2] = fNorm ^ (p[1] - p[0]);
|
||||
|
||||
CoordType K1 = CoordType::Construct(f->PD1());
|
||||
CoordType K2 = CoordType::Construct(f->PD2());
|
||||
K1.Normalize();
|
||||
K2.Normalize();
|
||||
|
||||
scaled_Kreal = K1*(vector_field_scale);///2);
|
||||
scaled_Kimag = K2*(vector_field_scale);///2);
|
||||
|
||||
b[0] = scaled_Kreal * neg_t[0];
|
||||
b[1] = scaled_Kimag * neg_t[0];
|
||||
b[2] = scaled_Kreal * neg_t[1];
|
||||
b[3] = scaled_Kimag * neg_t[1];
|
||||
b[4] = scaled_Kreal * neg_t[2];
|
||||
b[5] = scaled_Kimag * neg_t[2];
|
||||
|
||||
}
|
||||
|
||||
///return the LHS and RHS for a given face
|
||||
void PerElementSystemReal(FaceType *f,
|
||||
ScalarType val[3][3],
|
||||
int index[3][3][2],
|
||||
ScalarType b[6],
|
||||
ScalarType vector_field_scale=1.0)
|
||||
{
|
||||
perElementLHS(f,val,index);
|
||||
|
||||
if (use_direction_field)
|
||||
perElementRHS(f,b,vector_field_scale);
|
||||
}
|
||||
|
||||
void FixPointLSquares()
|
||||
{
|
||||
ScalarType penalization=1000000;
|
||||
int offset_row=n_vert_vars;
|
||||
assert(to_fix.size()>0);
|
||||
for (size_t i=0;i<to_fix.size();i++)
|
||||
{
|
||||
///take a vertex
|
||||
VertexType *v=to_fix[i];
|
||||
assert(!v->IsD());
|
||||
int index=VertexIndex(v);
|
||||
//v->vertex_index[0];
|
||||
int indexvert=index*2;
|
||||
int indexRow=(offset_row+i)*2;
|
||||
|
||||
SetValA(indexRow,indexRow,penalization);
|
||||
SetValA(indexRow+1,indexRow+1,penalization);
|
||||
|
||||
///add values to the B vector
|
||||
ScalarType U=v->T().U()*penalization;
|
||||
ScalarType V=v->T().V()*penalization;
|
||||
SetValB(indexRow,U);
|
||||
SetValB(indexRow+1,V);
|
||||
|
||||
/*///set upper right part
|
||||
SetValA(indexvert,indexCol,penalization);
|
||||
SetValA(indexvert+1,indexCol+1,penalization);*/
|
||||
|
||||
SetValA(indexvert,indexvert,penalization);
|
||||
SetValA(indexvert+1,indexvert+1,penalization);
|
||||
SetValA(indexRow,indexRow,penalization);
|
||||
SetValA(indexRow+1,indexRow+1,penalization);
|
||||
SetValA(indexvert,indexRow,-penalization);
|
||||
SetValA(indexvert+1,indexRow+1,-penalization);
|
||||
SetValA(indexRow,indexvert,-penalization);
|
||||
SetValA(indexRow+1,indexvert+1,-penalization);
|
||||
//SetValA(indexCol+1,indexCol+1,-1);
|
||||
}
|
||||
}
|
||||
|
||||
//build the laplacian matrix cyclyng over all rangemaps
|
||||
//and over all faces
|
||||
void BuildLaplacianMatrix(double vfscale=1)
|
||||
{
|
||||
|
||||
///then for each face
|
||||
for (unsigned int j=0;j<mesh.face.size();j++)
|
||||
{
|
||||
|
||||
FaceType *f=&mesh.face[j];
|
||||
if (f->IsD())
|
||||
continue;
|
||||
|
||||
int var_idx[3];//vertex variable indices
|
||||
for(int k = 0; k < 3; ++k)
|
||||
{
|
||||
VertexType *v=f->V(k);
|
||||
var_idx[k] = VertexIndex(v);
|
||||
}
|
||||
ScalarType val[3][3];
|
||||
int index[3][3][2];
|
||||
ScalarType b[6];
|
||||
PerElementSystemReal(f, val,index, b, vfscale);
|
||||
|
||||
//Add the element to the matrix
|
||||
Add33Block(val,index);
|
||||
|
||||
/////add area term.. to test if needed
|
||||
/*if (!use_direction_field)
|
||||
AddAreaTerm(index,1.0);//f->area);*/
|
||||
/*ScalarType area=((f->P(1)-f->P(0))^(f->P(2)-f->P(0))).Norm();
|
||||
if (!use_direction_field)
|
||||
AddAreaTerm(index,area);*/
|
||||
|
||||
//ScalarType area=((f->P(1)-f->P(0))^(f->P(2)-f->P(0))).Norm();
|
||||
if (!use_direction_field)
|
||||
AddAreaTerm(index,1);
|
||||
|
||||
///add right hand side
|
||||
if (use_direction_field)
|
||||
AddRHS(b,var_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FindSizes()
|
||||
{
|
||||
// tag vertices and compute numbers of equations to determine the number of rows in the matrix
|
||||
//TagVertices_Constrained(n_vert_vars, n_transition_eqs, n_align_sharp_eqs);
|
||||
n_vert_vars=mesh.vn;
|
||||
|
||||
///initialize matrix size
|
||||
total_size = (n_fixed_vars + n_vert_vars)*2;///must be multiplied by 2 becasue of u and v
|
||||
|
||||
}
|
||||
|
||||
void AllocateSystem()
|
||||
{
|
||||
//--- Allocates the data for Ax=b
|
||||
A=Eigen::SparseMatrix<double>(total_size, total_size); // A
|
||||
A.reserve(Eigen::VectorXi::Constant(total_size,32)); // This prealloaction trick greatly speed up the acc
|
||||
b = Eigen::VectorXd::Zero(total_size); // x and b
|
||||
}
|
||||
|
||||
|
||||
|
||||
///intitialize the whole matrix
|
||||
void InitMatrix()
|
||||
{
|
||||
FindSizes();
|
||||
AllocateSystem();
|
||||
}
|
||||
|
||||
bool Solve()
|
||||
{
|
||||
//return true;
|
||||
A.finalize();
|
||||
Eigen::SparseMatrix<double> As=Eigen::SparseMatrix<double>(A);
|
||||
As.finalize();
|
||||
|
||||
Eigen::SimplicialCholesky<Eigen::SparseMatrix<double> > solver(As);
|
||||
x = solver.solve(b);
|
||||
return (solver.info()==Eigen::Success);
|
||||
}
|
||||
|
||||
|
||||
void InitIndex()
|
||||
{
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
if (!mesh.vert[i].IsD())
|
||||
AddVertexIndex(&mesh.vert[i],i);
|
||||
}
|
||||
|
||||
///map back values to vertex
|
||||
///if normalize==true then set the
|
||||
///coordinates between 0 and 1
|
||||
void MapCoords(bool normalize=true,
|
||||
ScalarType /*fieldScale*/=1.0)
|
||||
{
|
||||
///clear Visited Flag
|
||||
if (correct_fixed)
|
||||
tri::UpdateFlags<MeshType>::VertexClearV(mesh);
|
||||
//set fixed to V
|
||||
for (size_t i=0;i<to_fix.size();i++)
|
||||
to_fix[i]->SetV();
|
||||
|
||||
Box2<ScalarType> bbox;
|
||||
if (normalize)
|
||||
{
|
||||
for (size_t i=0;i<n_vert_vars;i++)
|
||||
{
|
||||
ScalarType U=x[i*2];
|
||||
ScalarType V=x[(i*2)+1];
|
||||
bbox.Add(Point2<ScalarType>(U,V));
|
||||
}
|
||||
}
|
||||
|
||||
//for each vertex
|
||||
for (size_t i=0;i<n_vert_vars;i++)
|
||||
{
|
||||
VertexType* v=IndexVertex(i);
|
||||
//take U and V
|
||||
ScalarType U=x[i*2];
|
||||
ScalarType V=x[(i*2)+1];
|
||||
Point2<ScalarType> p;
|
||||
if (!v->IsV())
|
||||
p=Point2<ScalarType>(U,V);
|
||||
else
|
||||
p=v->T().P();
|
||||
//p/=fieldScale;
|
||||
if (normalize)
|
||||
{
|
||||
p-=bbox.min;
|
||||
p*=1/bbox.Diag();
|
||||
}
|
||||
|
||||
v->T().P()=p;
|
||||
}
|
||||
|
||||
///then copy to faces
|
||||
for (size_t i=0;i<mesh.face.size();i++)
|
||||
{
|
||||
FaceType *f=&mesh.face[i];
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
VertexType* v=f->V(j);
|
||||
Point2<ScalarType> p=v->T().P();
|
||||
f->WT(j).P()=p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
///return true if is possible to
|
||||
bool IsFeasible()
|
||||
{
|
||||
tri::UpdateTopology<MeshType>::FaceFace(mesh);
|
||||
int NNmanifoldE=tri::Clean<MeshType>::CountNonManifoldEdgeFF(mesh);
|
||||
if (NNmanifoldE!=0)
|
||||
{
|
||||
printf("Non Manifold Edges \n");
|
||||
return false;
|
||||
}
|
||||
int NNmanifoldV=tri::Clean<MeshType>::CountNonManifoldVertexFF(mesh);
|
||||
if (NNmanifoldV!=0)
|
||||
{
|
||||
printf("Non Manifold Vertices \n");
|
||||
return false;
|
||||
}
|
||||
int H=tri::Clean<MeshType>::CountHoles(mesh);
|
||||
if (H==0)return false;
|
||||
|
||||
int G=tri::Clean<MeshType>::MeshGenus(mesh);
|
||||
if (G!=0)
|
||||
{
|
||||
printf("Genus %d\n",G);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
///set the border as fixed
|
||||
void SetBorderAsFixed()
|
||||
{
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
{
|
||||
VertexType* v=&mesh.vert[i];
|
||||
if (v->IsD()) continue;
|
||||
if(v->IsB()) to_fix.push_back(v);
|
||||
}
|
||||
std::sort(to_fix.begin(),to_fix.end());
|
||||
auto new_end=std::unique(to_fix.begin(),to_fix.end());
|
||||
to_fix.resize(distance(to_fix.begin(),new_end));
|
||||
}
|
||||
|
||||
///set selected vertices as fixed
|
||||
void SetSelectedAsFixed()
|
||||
{
|
||||
for (int i=0;i<mesh.vert.size();i++)
|
||||
{
|
||||
VertexType* v=&mesh.vert[i];
|
||||
if (v->IsD())continue;
|
||||
if(v->IsS())to_fix.push_back(v);
|
||||
}
|
||||
std::sort(to_fix.begin(),to_fix.end());
|
||||
typename std::vector<VertexType*>::iterator new_end=std::unique(to_fix.begin(),to_fix.end());
|
||||
int dist=distance(to_fix.begin(),new_end);
|
||||
to_fix.resize(dist);
|
||||
}
|
||||
|
||||
|
||||
///fix default vertices no need if already border on other vertices are fixed
|
||||
///you need at least 2 fixed for solving without field ,
|
||||
///while only 1 if you conforms to a given cross field
|
||||
void FixDefaultVertices()
|
||||
{
|
||||
///in this case there are already vertices fixed, so no need to fix by default
|
||||
assert(to_fix.size()==0);
|
||||
///then fix only one vertex
|
||||
if (use_direction_field)
|
||||
{
|
||||
for (size_t i=0;i<mesh.vert.size();i++)
|
||||
if (!mesh.vert[i].IsD())
|
||||
{
|
||||
mesh.vert[i].T().P()=Point2<ScalarType>(0,0);
|
||||
to_fix.push_back(&mesh.vert[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
///then fix 2 vertices
|
||||
else
|
||||
{
|
||||
VertexType *v0;
|
||||
VertexType *v1;
|
||||
FindFarthestVert(v0,v1);
|
||||
if (v0==v1)
|
||||
{
|
||||
// tri::io::ExporterPLY<MeshType>::Save(mesh,"./parametrized.ply");
|
||||
assert(0);
|
||||
}
|
||||
v0->T().P()=Point2<ScalarType>(0,0);
|
||||
v1->T().P()=Point2<ScalarType>(1,1);
|
||||
to_fix.push_back(v0);
|
||||
to_fix.push_back(v1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
///intialize parameters and setup fixed vertices vector
|
||||
void Init(bool _use_direction_field=false,
|
||||
bool _correct_fixed=true,
|
||||
ScalarType _fieldScale=1.0)
|
||||
{
|
||||
use_direction_field=_use_direction_field;
|
||||
correct_fixed=_correct_fixed;
|
||||
fieldScale=_fieldScale;
|
||||
to_fix.clear();
|
||||
}
|
||||
|
||||
///solve the system, it return false if the matrix is singular
|
||||
bool SolvePoisson(bool _write_messages=false,
|
||||
ScalarType fieldScale=1.0,
|
||||
bool solve_global_fold=true)
|
||||
{
|
||||
int t0,t1,t2,t3;
|
||||
|
||||
///Initializing Matrix
|
||||
if (_write_messages)
|
||||
{
|
||||
printf("\n INITIALIZING THE MATRIX \n");
|
||||
t0=clock();
|
||||
}
|
||||
|
||||
///set vertex indexes
|
||||
InitIndex();
|
||||
|
||||
if (use_direction_field)
|
||||
{
|
||||
assert(to_fix.size()>0);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(to_fix.size()>1);
|
||||
}
|
||||
|
||||
n_fixed_vars=to_fix.size();
|
||||
///initialize the matrix ALLOCATING SPACE
|
||||
InitMatrix();
|
||||
|
||||
///build the laplacian system
|
||||
BuildLaplacianMatrix(fieldScale);
|
||||
|
||||
////add the lagrange multiplier
|
||||
FixPointLSquares();
|
||||
|
||||
if (_write_messages)
|
||||
{
|
||||
t1=clock();
|
||||
printf("\n time:%d \n",t1-t0);
|
||||
printf("\n SOLVING \n");
|
||||
}
|
||||
|
||||
//int n_vars=(n_vert_vars)*2;
|
||||
//int integer_constr_size=(n_transition_vars+n_fixed_vars+n_bary_transition_vars)*2;
|
||||
//X=std::vector< double >(n_vars+n_fixed_vars*2);
|
||||
bool done=Solve();
|
||||
if (!done)
|
||||
return false;
|
||||
if (_write_messages)
|
||||
{
|
||||
t2=clock();
|
||||
printf("\n time:%d \n",t2-t1);
|
||||
printf("\n ASSIGNING COORDS \n");
|
||||
}
|
||||
|
||||
MapCoords(false,fieldScale);
|
||||
if (_write_messages)
|
||||
{
|
||||
t3=clock();
|
||||
printf("\n time:%d \n",t3-t2);
|
||||
}
|
||||
|
||||
///then check if majority of faces are folded
|
||||
if (!solve_global_fold) return true;
|
||||
if (tri::Distortion<MeshType,false>::GloballyUnFolded(mesh))
|
||||
{
|
||||
tri::UV_Utils<MeshType>::GloballyMirrorX(mesh);
|
||||
bool isUnfolded = tri::Distortion<MeshType,false>::GloballyUnFolded(mesh);
|
||||
assert( ! isUnfolded);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PoissonSolver(MeshType &_mesh):mesh(_mesh)
|
||||
{
|
||||
assert(mesh.vert.size()>=3);
|
||||
assert(mesh.face.size()>=1);
|
||||
}
|
||||
|
||||
|
||||
}; // end class
|
||||
} // End Namespace tri
|
||||
} // End Namespace vcg
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,248 @@
|
||||
/****************************************************************************
|
||||
* 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 VCG_COMPLEX_ALGORITHMS_PARAMETRIZATION_UV_UTILS_H
|
||||
#define VCG_COMPLEX_ALGORITHMS_PARAMETRIZATION_UV_UTILS_H
|
||||
|
||||
#include <vcg/space/point2.h>
|
||||
#include <vcg/space/box2.h>
|
||||
#include <vcg/space/triangle2.h>
|
||||
#include <vcg/space/triangle3.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
template <class MeshType>
|
||||
class UV_Utils
|
||||
{
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
typedef typename MeshType::ScalarType ScalarType;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::VertexIterator VertexIterator;
|
||||
typedef typename MeshType::FaceIterator FaceIterator;
|
||||
typedef typename vcg::Point2<ScalarType> UVCoordType;
|
||||
|
||||
public:
|
||||
|
||||
/// calculate the area in UV space
|
||||
static ScalarType PerVertUVArea(MeshType &m)
|
||||
{
|
||||
FaceIterator fi;
|
||||
ScalarType Area=0;
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
if ((*fi).IsD()) continue;
|
||||
UVCoordType E0= (*fi).V(1)->T().P()-(*fi).V(0)->T().P();
|
||||
UVCoordType E1= (*fi).V(2)->T().P()-(*fi).V(0)->T().P();
|
||||
ScalarType doubleA=fabs(E0^E1);
|
||||
Area+=doubleA/2;
|
||||
}
|
||||
return Area;
|
||||
}
|
||||
|
||||
///scale vert UV to match 3D area
|
||||
static void ScaleVertUVToMatchArea(MeshType &m)
|
||||
{
|
||||
FaceIterator fi;
|
||||
ScalarType Area3D=0;
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
if ((*fi).IsD()) continue;
|
||||
Area3D+=vcg::DoubleArea((*fi))/2;
|
||||
}
|
||||
ScalarType Area2D=PerVertUVArea(m);
|
||||
ScalarType ScaleFact=sqrt( Area3D / Area2D );
|
||||
|
||||
VertexIterator vi;
|
||||
for (vi=m.vert.begin();vi!=m.vert.end();vi++)
|
||||
{
|
||||
if ((*vi).IsD()) continue;
|
||||
(*vi).T().P()*=ScaleFact;
|
||||
}
|
||||
}
|
||||
|
||||
///calculate the BBox in UV space
|
||||
static vcg::Box2<ScalarType> PerWedgeUVBox(MeshType &m)
|
||||
{
|
||||
vcg::Box2<ScalarType> UVBox;
|
||||
FaceIterator fi;
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
if ((*fi).IsD()) continue;
|
||||
for (int i=0;i<3;i++)
|
||||
UVBox.Add((*fi).WT(i).P());
|
||||
}
|
||||
return UVBox;
|
||||
}
|
||||
|
||||
///calculate the BBox in UV space
|
||||
static vcg::Box2<ScalarType> PerVertUVBox(const MeshType &m)
|
||||
{
|
||||
vcg::Box2<ScalarType> UVBox;
|
||||
for (auto vi=m.vert.begin();vi!=m.vert.end();vi++)
|
||||
{
|
||||
if ((*vi).IsD()) continue;
|
||||
UVBox.Add((*vi).T().P());
|
||||
}
|
||||
return UVBox;
|
||||
}
|
||||
|
||||
void PerWedgeMakeUnitaryUV(MeshType &m)
|
||||
{
|
||||
vcg::Box2<typename MeshType::ScalarType> UVBox = PerWedgeUVBox(m);
|
||||
|
||||
typename MeshType::FaceIterator fi;
|
||||
Point2f boxSize(UVBox.max-UVBox.min);
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
if ((*fi).IsD()) continue;
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
(*fi).WT(i).U() = ((*fi).WT(i).U()-UVBox.min[0])/boxSize[0] ;
|
||||
(*fi).WT(i).V() = ((*fi).WT(i).V()-UVBox.min[1])/boxSize[1] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
///transform curvature to UV space
|
||||
static UVCoordType Coord3DtoUV(FaceType &f,const CoordType &dir)
|
||||
{
|
||||
///then transform to UV
|
||||
CoordType bary3d=(f.P(0)+f.P(1)+f.P(2))/3.0;
|
||||
UVCoordType baryUV=(f.WT(0).P()+f.WT(1).P()+f.WT(2).P())/3.0;
|
||||
CoordType dir3d=bary3d+dir;
|
||||
CoordType baryCoordsUV;
|
||||
vcg::InterpolationParameters<FaceType,ScalarType>(f,dir3d,baryCoordsUV);
|
||||
UVCoordType dirUV=baryCoordsUV.X()*f.WT(0).P()+
|
||||
baryCoordsUV.Y()*f.WT(1).P()+
|
||||
baryCoordsUV.Z()*f.WT(2).P()-baryUV;
|
||||
dirUV.Normalize();
|
||||
return dirUV;
|
||||
}
|
||||
|
||||
static void GloballyMirrorX(MeshType &m)
|
||||
{
|
||||
vcg::Box2<ScalarType> BBuv=PerVertUVBox(m);
|
||||
ScalarType Xmin=BBuv.min.X();
|
||||
ScalarType Xmax=BBuv.max.X();
|
||||
ScalarType XAv=(Xmax+Xmin)/2;
|
||||
VertexIterator vi;
|
||||
for (vi=m.vert.begin();vi!=m.vert.end();vi++)
|
||||
{
|
||||
ScalarType distAV=(*vi).T().P().X()-XAv;
|
||||
(*vi).T().P().X()=XAv-distAV;
|
||||
}
|
||||
}
|
||||
|
||||
static void GloballyRotate(MeshType &m,ScalarType Angle)
|
||||
{
|
||||
vcg::Box2<ScalarType> BB=PerWedgeUVBox(m);
|
||||
UVCoordType Origin=BB.Center();
|
||||
typename MeshType::FaceIterator fi;
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
if ((*fi).IsD()) continue;
|
||||
for (int i=0;i<3;i++)
|
||||
{
|
||||
(*fi).WT(i).P()-=Origin;
|
||||
ScalarType X1=(*fi).WT(i).P().X()*cos(Angle)-(*fi).WT(i).P().Y()*sin(Angle);
|
||||
ScalarType Y1=(*fi).WT(i).P().X()*cos(Angle)+(*fi).WT(i).P().Y()*sin(Angle);
|
||||
(*fi).WT(i).P().X()=X1;
|
||||
(*fi).WT(i).P().Y()=Y1;
|
||||
(*fi).WT(i).P()+=Origin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GloballyRotatePerVert(MeshType &m,ScalarType Angle)
|
||||
{
|
||||
vcg::Box2<ScalarType> BB=PerVertUVBox(m);
|
||||
UVCoordType Origin=BB.Center();
|
||||
typename MeshType::VertexIterator vi;
|
||||
for (vi=m.vert.begin();vi!=m.vert.end();vi++)
|
||||
{
|
||||
if ((*vi).IsD()) continue;
|
||||
(*vi).T().P()-=Origin;
|
||||
ScalarType X1=(*vi).T().P().X()*cos(Angle)-(*vi).T().P().Y()*sin(Angle);
|
||||
ScalarType Y1=(*vi).T().P().X()*cos(Angle)+(*vi).T().P().Y()*sin(Angle);
|
||||
(*vi).T().P().X()=X1;
|
||||
(*vi).T().P().Y()=Y1;
|
||||
(*vi).T().P()+=Origin;
|
||||
}
|
||||
}
|
||||
|
||||
static void LaplacianUVVert(MeshType &m,bool fix_borders=false,int steps=3)
|
||||
{
|
||||
FaceIterator fi;
|
||||
for (int s=0;s<steps;s++)
|
||||
{
|
||||
std::vector<int> num(m.vert.size(),0);
|
||||
std::vector<UVCoordType> UVpos(m.vert.size(),UVCoordType(0,0));
|
||||
for (fi=m.face.begin();fi!=m.face.end();fi++)
|
||||
{
|
||||
for (int j=0;j<3;j++)
|
||||
{
|
||||
VertexType *v0=(*fi).V(0);
|
||||
VertexType *v1=(*fi).V1(0);
|
||||
VertexType *v2=(*fi).V2(0);
|
||||
assert(v0!=v1);
|
||||
assert(v1!=v2);
|
||||
assert(v0!=v2);
|
||||
UVCoordType uv1=v1->T().P();
|
||||
UVCoordType uv2=v2->T().P();
|
||||
int index=v0-&(m.vert[0]);
|
||||
num[index]+=2;
|
||||
UVpos[index]+=uv1;
|
||||
UVpos[index]+=uv2;
|
||||
}
|
||||
}
|
||||
VertexIterator vi;
|
||||
for (int i=0;i<m.vert.size();i++)
|
||||
{
|
||||
if ((fix_borders)&&(m.vert[i].IsB()))continue;
|
||||
if (num[i]==0)continue;
|
||||
m.vert[i].T().P()=UVpos[i]/(ScalarType)num[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CopyVertUVWedge(MeshType &m)
|
||||
{
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
for (size_t j=0;j<3;j++)
|
||||
m.face[i].WT(j).P()=m.face[i].V(j)->T().P();
|
||||
}
|
||||
|
||||
static void CopyWedgeVertUV(MeshType &m,bool onlyS=false)
|
||||
{
|
||||
for (size_t i=0;i<m.face.size();i++)
|
||||
{
|
||||
if ((onlyS)&&(!m.face[i].IsS()))continue;
|
||||
for (int j=0;j<3;j++)
|
||||
m.face[i].V(j)->T().P()=m.face[i].WT(j).P();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end Namespace tri
|
||||
} // end Namespace vcg
|
||||
#endif // VCG_COMPLEX_ALGORITHMS_PARAMETRIZATION_UV_UTILS_H
|
||||
@@ -0,0 +1,275 @@
|
||||
/****************************************************************************
|
||||
* 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 VORONOI_ATLAS_H
|
||||
#define VORONOI_ATLAS_H
|
||||
|
||||
#include<vcg/complex/algorithms/parametrization/poisson_solver.h>
|
||||
#include<vcg/complex/algorithms/parametrization/uv_utils.h>
|
||||
#include<vcg/complex/algorithms/parametrization/distortion.h>
|
||||
#include<vcg/space/outline2_packer.h>
|
||||
#include<vcg/space/rasterized_outline2_packer.h>
|
||||
#include<vcg/complex/algorithms/update/texture.h>
|
||||
#include<vcg/complex/algorithms/point_sampling.h>
|
||||
#include<vcg/complex/algorithms/voronoi_processing.h>
|
||||
|
||||
//#include<wrap/qt/outline2_rasterizer.h>
|
||||
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
template <class MeshType>
|
||||
class VoronoiAtlas
|
||||
{
|
||||
//private:
|
||||
public:
|
||||
class VoroEdge;
|
||||
class VoroFace;
|
||||
class VoroVertex;
|
||||
struct VoroUsedTypes : public UsedTypes< Use<VoroVertex> ::template AsVertexType,
|
||||
Use<VoroEdge> ::template AsEdgeType,
|
||||
Use<VoroFace> ::template AsFaceType>{};
|
||||
|
||||
class VoroVertex : public Vertex< VoroUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::TexCoord2f, vertex::VFAdj , vertex::Qualityf, vertex::Color4b, vertex::BitFlags >{};
|
||||
class VoroFace : public Face< VoroUsedTypes, face::VertexRef, face::BitFlags, face::FFAdj ,face::VFAdj , face::CurvatureDirf,face::WedgeTexCoord2f> {};
|
||||
class VoroEdge : public Edge< VoroUsedTypes>{};
|
||||
class VoroMesh : public tri::TriMesh< std::vector<VoroVertex>, std::vector<VoroFace> , std::vector<VoroEdge> > {};
|
||||
|
||||
typedef typename VoroMesh::FaceIterator FaceIterator;
|
||||
typedef typename VoroMesh::VertexType VertexType;
|
||||
typedef typename VoroMesh::FaceType FaceType;
|
||||
|
||||
static void CollectUVBorder(VoroMesh *rm, std::vector<Point2f> &uvBorder)
|
||||
{
|
||||
tri::UpdateTopology<VoroMesh>::FaceFace(*rm);
|
||||
tri::UpdateFlags<VoroMesh>::FaceClearV(*rm);
|
||||
for(FaceIterator fi=rm->face.begin();fi!=rm->face.end();++fi)
|
||||
{
|
||||
for(int j=0;j<3;++j)
|
||||
if(face::IsBorder(*fi,j) && !(fi->IsV()))
|
||||
{
|
||||
face::Pos<FaceType> pp(&*fi,j,fi->V(j));
|
||||
assert(pp.IsBorder());
|
||||
face::Pos<FaceType> startPos = pp;
|
||||
do
|
||||
{
|
||||
uvBorder.push_back( pp.F()->WT(pp.VInd()).P() );
|
||||
pp.F()->SetV();
|
||||
pp.NextB();
|
||||
} while(pp != startPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// take a mesh and rescale its uv so that they are in the 0..1 range
|
||||
static void RegularizeTexArea(VoroMesh &m)
|
||||
{
|
||||
float areaTex=0;
|
||||
float areaGeo=0;
|
||||
|
||||
vcg::Box2f UVBox = tri::UV_Utils<VoroMesh>::PerWedgeUVBox(m);
|
||||
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
|
||||
{
|
||||
areaTex+= fabs((fi->WT(1).P() - fi->WT(0).P()) ^ (fi->WT(2).P() - fi->WT(0).P())) ;
|
||||
areaGeo+= DoubleArea(*fi);
|
||||
}
|
||||
|
||||
float ratio = sqrt(areaGeo/areaTex);
|
||||
|
||||
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
|
||||
{
|
||||
for(int j=0;j<3;++j)
|
||||
fi->WT(j).P() = (fi->WT(j).P()-UVBox.min) *ratio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
struct VoronoiAtlasParam
|
||||
{
|
||||
VoronoiAtlasParam()
|
||||
{
|
||||
maxIterNum = 5;
|
||||
sampleNum=10;
|
||||
overlap=false;
|
||||
}
|
||||
|
||||
struct Stat
|
||||
{
|
||||
void clear() { iterNum=totalTime=unwrapTime=voronoiTime=samplingTime=0;}
|
||||
int totalTime;
|
||||
int unwrapTime;
|
||||
int voronoiTime;
|
||||
int samplingTime;
|
||||
|
||||
int regionNum;
|
||||
int iterNum;
|
||||
};
|
||||
|
||||
int sampleNum;
|
||||
bool overlap;
|
||||
Stat vas;
|
||||
int maxIterNum;
|
||||
CallBackPos *cb=vcg::CErrCallBackPos;
|
||||
};
|
||||
|
||||
// Main parametrization function:
|
||||
// it takes a startMesh, copy it and
|
||||
|
||||
static void Build( MeshType &startMesh, MeshType ¶Mesh, VoronoiAtlasParam &pp)
|
||||
{
|
||||
pp.vas.clear();
|
||||
int t0=clock();
|
||||
VoroMesh m; // the mesh used for the processing is a copy of the passed one.
|
||||
tri::Append<VoroMesh, MeshType>::Mesh(m, startMesh);
|
||||
tri::Clean<VoroMesh>::RemoveUnreferencedVertex(m);
|
||||
tri::Allocator<VoroMesh>::CompactVertexVector(m);
|
||||
tri::Allocator<VoroMesh>::CompactFaceVector(m);
|
||||
|
||||
tri::UpdateBounding<VoroMesh>::Box(m);
|
||||
std::vector<VoroMesh *> meshRegionVec;
|
||||
std::vector< std::vector<Point2f> > uvBorders;
|
||||
|
||||
// Main processing loop
|
||||
do
|
||||
{
|
||||
// qDebug("************ ITERATION %i sampling mesh of %i with %i ************",pp.vas.iterNum,m.fn,pp.sampleNum);
|
||||
int st0=clock();
|
||||
std::vector<Point3f> PoissonSamples;
|
||||
float diskRadius=0;
|
||||
tri::PoissonSampling(m,PoissonSamples,pp.sampleNum,diskRadius);
|
||||
int st1=clock();
|
||||
pp.vas.samplingTime+= st1-st0;
|
||||
pp.cb(50,StrFormat("Sampling created a new mesh of %lu points\n",PoissonSamples.size()));
|
||||
EuclideanDistance<VoroMesh> edFunc;
|
||||
std::vector<VertexType *> seedVec;
|
||||
tri::VoronoiProcessing<VoroMesh>::SeedToVertexConversion(m,PoissonSamples,seedVec);
|
||||
tri::UpdateTopology<VoroMesh>::VertexFace(m);
|
||||
tri::VoronoiProcessing<VoroMesh>::ComputePerVertexSources(m,seedVec,edFunc);
|
||||
tri::VoronoiProcessing<VoroMesh>::FaceAssociateRegion(m);
|
||||
tri::VoronoiProcessing<VoroMesh>::VoronoiColoring(m,true);
|
||||
std::vector<VoroMesh *> badRegionVec;
|
||||
int st2=clock();
|
||||
pp.vas.voronoiTime+=st2-st1;
|
||||
for(size_t i=0; i<seedVec.size();++i)
|
||||
{
|
||||
VoroMesh *rm = new VoroMesh();
|
||||
int selCnt = tri::VoronoiProcessing<VoroMesh>::FaceSelectAssociateRegion(m,seedVec[i]);
|
||||
pp.cb(50,StrFormat("Region %i of %i faces",i,selCnt));
|
||||
if(selCnt==0) continue;
|
||||
assert(selCnt>0);
|
||||
if(pp.overlap){
|
||||
tri::UpdateSelection<VoroMesh>::VertexFromFaceLoose(m);
|
||||
tri::UpdateSelection<VoroMesh>::FaceFromVertexLoose(m);
|
||||
}
|
||||
tri::Append<VoroMesh,VoroMesh>::Mesh(*rm, m, true);
|
||||
int tp0=clock();
|
||||
tri::PoissonSolver<VoroMesh> PS(*rm);
|
||||
tri::UpdateBounding<VoroMesh>::Box(*rm);
|
||||
if(PS.IsFeasible())
|
||||
{
|
||||
PS.Init();
|
||||
PS.FixDefaultVertices();
|
||||
PS.SolvePoisson(false);
|
||||
tri::UpdateTexture<VoroMesh>::WedgeTexFromVertexTex(*rm);
|
||||
RegularizeTexArea(*rm);
|
||||
|
||||
std::vector<Point2f> uvBorder;
|
||||
CollectUVBorder(rm,uvBorder);
|
||||
meshRegionVec.push_back(rm);
|
||||
uvBorders.push_back(uvBorder);
|
||||
int foldedCnt = tri::Distortion<VoroMesh,false>::FoldedNum(*rm);
|
||||
if( foldedCnt > rm->fn/10)
|
||||
{
|
||||
badRegionVec.push_back(rm);
|
||||
// qDebug("-- region %i Parametrized but with %i fold on %i!",i,foldedCnt,rm->fn);
|
||||
}
|
||||
// else qDebug("-- region %i Parametrized!",i);
|
||||
|
||||
} else
|
||||
{
|
||||
// qDebug("-- region %i is NOT homeomorphic to a disk\n",i);
|
||||
badRegionVec.push_back(rm);
|
||||
}
|
||||
int tp1=clock();
|
||||
pp.vas.unwrapTime +=tp1-tp0;
|
||||
++pp.vas.iterNum;
|
||||
}
|
||||
// qDebug("\n -- Completed (%i bad regions) -- \n", badRegionVec.size());
|
||||
VoroMesh *rm = new VoroMesh();
|
||||
tri::VoronoiProcessing<VoroMesh>::FaceSelectAssociateRegion(m,0);
|
||||
tri::Append<VoroMesh,VoroMesh>::Mesh(*rm, m, true);
|
||||
|
||||
if(rm->fn>0)
|
||||
{
|
||||
// qDebug("ACH - unreached faces %i fn\n",rm->fn);
|
||||
badRegionVec.push_back(rm);
|
||||
}
|
||||
m.Clear();
|
||||
pp.sampleNum = 10;
|
||||
if(!badRegionVec.empty())
|
||||
{
|
||||
for(size_t i=0;i<badRegionVec.size();++i)
|
||||
if(badRegionVec[i]->fn>50)
|
||||
tri::Append<VoroMesh,VoroMesh>::Mesh(m, *badRegionVec[i], false);
|
||||
|
||||
tri::Clean<VoroMesh>::RemoveDuplicateFace(m);
|
||||
tri::Clean<VoroMesh>::RemoveUnreferencedVertex(m);
|
||||
tri::Allocator<VoroMesh>::CompactVertexVector(m);
|
||||
tri::Allocator<VoroMesh>::CompactFaceVector(m);
|
||||
}
|
||||
} while (m.fn>0);
|
||||
|
||||
std::vector<Similarity2f> trVec;
|
||||
Point2f finalSize;
|
||||
//PolyPacker<float>::WritePolyVec(uvBorders,"borders.poly");
|
||||
PolyPacker<float>::PackAsObjectOrientedRect(uvBorders,Point2i(1024,1024),trVec,finalSize);
|
||||
// RasterizedOutline2Packer<float,QtOutline2Rasterizer>::Parameters prp;
|
||||
// RasterizedOutline2Packer<float,QtOutline2Rasterizer>::Pack(uvBorders,Point2i(1024,1024),trVec,prp);
|
||||
// loop again over all the patches
|
||||
pp.vas.regionNum=meshRegionVec.size();
|
||||
for(size_t i=0; i<meshRegionVec.size();++i)
|
||||
{
|
||||
VoroMesh *rm = meshRegionVec[i];
|
||||
for(FaceIterator fi=rm->face.begin();fi!=rm->face.end();++fi)
|
||||
{
|
||||
for(int j=0;j<3;++j)
|
||||
{
|
||||
Point2f pp(fi->WT(j).U(),fi->WT(j).V());
|
||||
Point2f newpp=trVec[i]*pp;
|
||||
fi->WT(j).U()=newpp[0]/1024.0f;
|
||||
fi->WT(j).V()=newpp[1]/1024.0f;
|
||||
}
|
||||
}
|
||||
tri::Append<MeshType,VoroMesh>::Mesh(paraMesh, *rm, false);
|
||||
}
|
||||
int t2=clock();
|
||||
pp.vas.totalTime=t2-t0;
|
||||
}
|
||||
}; //end
|
||||
|
||||
|
||||
} // end namespace vcg
|
||||
} // end namespace tri
|
||||
|
||||
|
||||
#endif // VORONOI_ATLAS_H
|
||||
Reference in new issue
Block a user