diff --git a/src/meshlabplugins/filter_isoparametrization/diam_parametrization.h b/src/meshlabplugins/filter_isoparametrization/diam_parametrization.h index 2920e0f23..cef13c267 100644 --- a/src/meshlabplugins/filter_isoparametrization/diam_parametrization.h +++ b/src/meshlabplugins/filter_isoparametrization/diam_parametrization.h @@ -1,562 +1,562 @@ -#include -#include -#include -#include -#include -#include - -#ifndef _DIAMONDPARA -#define _DIAMONDPARA - -class DiamondParametrizator -{ - typedef IsoParametrization::CoordType CoordType; - typedef IsoParametrization::ScalarType ScalarType; - - IsoParametrization *isoParam; - - ///data used for splitting - typedef std::pair EdgeKey; - - ///interpolation data - struct InterpData - { - float alpha; - int I; - vcg::Point2 UV; - }; - - std::map alphaMap; - - ///data used to store an retrieve edges - //typedef std::pair TriEdge; - //std::vector DDAdiacency; - //std::map edgeMap; - //int sampleSize; - - template - int AssignDiamond(FaceType *face) - { - ScalarType val=(ScalarType)1.0/(ScalarType)3.0; - CoordType bary3d(val,val,val); - int I_interp; - vcg::Point2 UV_interp; - isoParam->Phi(face,bary3d,I_interp,UV_interp); - int D_interp=isoParam->getHDiamIndex(I_interp,UV_interp); - face->WT(0).N()=D_interp; - face->WT(1).N()=D_interp; - face->WT(2).N()=D_interp; - return D_interp; - } - - ///associate the diamond in which a face belongs to - void AssociateDiamond() - { - ParamMesh *to_param=isoParam->ParaMesh(); - typedef ParamMesh::FaceType FaceType; - - ///first step first associating initial faces to diamond - for (unsigned int i=0;iface.size();i++) - { - #ifndef _MESHLAB - if ((i%1000)==0) - printf("associating diamond %d - %d \n",i,i+1000); - #endif - FaceType *curr=&to_param->face[i]; - AssignDiamond(curr); - curr->C()=colorDiam[curr->WT(0).N()]; - } - } - - void InterpEdge(const ParamFace *f,const int &index_edge, - const float &alpha,int &I,vcg::Point2 &UV) - { - #ifndef NDEBUG - float eps=0.00001f; - #endif - int index0=index_edge; - int index1=(index_edge+1)%3; - CoordType bary=CoordType(0,0,0); - assert((alpha>=0)&&(alpha<=1)); - bary.V(index0)=alpha; - bary.V(index1)=((ScalarType)1.0-alpha); - isoParam->Phi(f,bary,I,UV); - assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); - } - -template -void QuadCoord(FaceType * curr,const int &vert_num,vcg::Point2f &UVQuad,int &indexQuad) -{ - typedef typename FaceType::VertexType VertexType; - typedef typename FaceType::ScalarType ScalarType; - - VertexType* v=curr->V(vert_num); - - int DiamIndex=curr->WT(0).N(); ///get index of diamond associated to the face - assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N())); - - ///transform to quad coordinates - int I=v->T().N(); - vcg::Point2f UV=v->T().P(); - - ///transform in diamond coordinates - vcg::Point2f UVDiam/*,UVQuad*/; - isoParam->GE1(I,UV,DiamIndex,UVDiam); - - ///transform in quad coordinates - isoParam->GE1Quad(DiamIndex,UVDiam,UVQuad); - - indexQuad=DiamIndex; - /*return (UVQuad);*/ -} - -template - bool To_Split(FaceType * curr,const float &border, - bool to_split[3],InterpData Idata[3]) - { - to_split[0]=false; - to_split[1]=false; - to_split[2]=false; - - typedef typename FaceType::VertexType VertexType; - typedef typename FaceType::ScalarType ScalarType; - - /*ParamMesh *to_param=isoParam->ParaMesh();*/ - - /*int DiamIndex=curr->WT(0).N(); *////get index of diamond associated to the face - assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N())); - - vcg::Point2f UVQuad[3]; - int index[3]; - - QuadCoord(curr,0,UVQuad[0],index[0]); - QuadCoord(curr,1,UVQuad[1],index[1]); - QuadCoord(curr,2,UVQuad[2],index[2]); - - ///outern border - vcg::Box2 bbox,bbox0; - bbox.Add(vcg::Point2f(-border,-border)); - bbox.Add(vcg::Point2f(1+border,1+border)); - bbox0.Add(vcg::Point2f(0,0)); - bbox0.Add(vcg::Point2f(1,1)); - - if (bbox.IsIn(UVQuad[0])&&bbox.IsIn(UVQuad[1])&&bbox.IsIn(UVQuad[2])) - return false; ///no intersection is possible - - ///else test which edges must be splitted - //vcg::Segment2 border_seg[4]; - vcg::Line2 border_seg[4]; - border_seg[0].Set(vcg::Point2f(0,0),vcg::Point2f(1,0)); - border_seg[1].Set(vcg::Point2f(1,0),vcg::Point2f(0,1)); - border_seg[2].Set(vcg::Point2f(0,1),vcg::Point2f(1,0)); - border_seg[3].Set(vcg::Point2f(0,0),vcg::Point2f(0,1)); - bool intersected=false; - for (int edge=0;edge<3;edge++) - { - vcg::Segment2 curr_edge=vcg::Segment2(UVQuad[edge],UVQuad[(edge+1)%3]); - float dist_medium=1.0; - for (int j=0;j<4;j++) - { - vcg::Point2f p_inters; - vcg::Line2 curr_border=border_seg[j]; - bool intersect=LineSegmentIntersection(curr_border,curr_edge,p_inters); - - float l_test0=(curr_edge.P0()-p_inters).Norm(); - float l_test1=(curr_edge.P1()-p_inters).Norm(); - float l_test=std::min(l_test0,l_test1); - - const ScalarType _EPS=(ScalarType)0.0001; - if ((intersect)&&(l_test>=_EPS)) - { - float lenght=curr_edge.Length(); - float dist=((curr_edge.P0()-p_inters).Norm()); - float Ndist=dist/lenght; - float alpha=1.0-Ndist; - float dist_medium1=fabs(alpha-0.5); - - if (dist_medium1 - struct SplitMidPoint : public std::unary_function , typename MESH_TYPE::CoordType > - { - typedef typename MESH_TYPE::VertexType VertexType; - typedef typename MESH_TYPE::FaceType FaceType; - typedef typename MESH_TYPE::CoordType CoordType; - - std::map *alphaMap; - IsoParametrization *isoParam; - - - - void operator()(typename MESH_TYPE::VertexType &nv, vcg::face::Pos ep) - { - //printf("DONE\n"); - - ParamMesh *to_param=isoParam->ParaMesh(); - - ///get eth value on which the edge must be splitted - VertexType* v0=ep.f->V(ep.z); - VertexType* v1=ep.f->V1(ep.z); - - int i0=IndexFromPointer(v0,to_param); - int i1=IndexFromPointer(v1,to_param); - - assert(v0!=v1); - EdgeKey k; - int index0=ep.z; - int index1=(ep.z+1)%3; - - if (i0>i1) - { - std::swap(v0,v1); - std::swap(i0,i1); - std::swap(index0,index1); - } - - k=EdgeKey(i0,i1); - std::map::iterator ItE=alphaMap->find(k); - assert(ItE!=alphaMap->end()); - InterpData interp=(*ItE).second; - float alpha=interp.alpha; - assert((alpha>=0)&&(alpha<=1)); - nv.P()= v0->P()*alpha+v1->P()*(1.0-alpha); - nv.RPos= v0->RPos*alpha+v1->RPos*(1.0-alpha); - - if( MESH_TYPE::HasPerVertexNormal()) - nv.N()=v0->N()*alpha+v1->N()*((ScalarType)1.0-alpha); - if( MESH_TYPE::HasPerVertexColor()) - { - CoordType color=CoordType(v0->C().X(),v0->C().Y(),v0->C().Z()); - color=color*alpha+color*((ScalarType)1.0-alpha); - nv.C()=vcg::Color4b((unsigned char)color.X(),(unsigned char)color.Y(),(unsigned char)color.Z(),(unsigned char)255); - } - - nv.T().N()=interp.I; - nv.T().P()=interp.UV; - } - - vcg::TexCoord2 WedgeInterp(vcg::TexCoord2 &t0, vcg::TexCoord2 &t1) - { - vcg::TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } - }; - - - - template //, class FLT> - class EdgePredicate - { - typedef typename MESH_TYPE::VertexType VertexType; - typedef typename MESH_TYPE::FaceType FaceType; - public: - std::map *alphaMap; - IsoParametrization *isoParam; - - bool operator()(vcg::face::Pos ep) const - { - ParamMesh *to_param=isoParam->ParaMesh(); - - VertexType* v0=ep.f->V(ep.z); - VertexType* v1=ep.f->V1(ep.z); - - int i0=IndexFromPointer(v0,to_param); - int i1=IndexFromPointer(v1,to_param); - - assert(v0!=v1); - EdgeKey k; - - if (i0>i1) - { - std::swap(v0,v1); - std::swap(i0,i1); - } - - k=EdgeKey(i0,i1); - std::map::iterator ItE=alphaMap->find(k); - bool to_split=(ItE!=alphaMap->end()); - return (to_split); - } - }; - - static int IndexFromPointer(ParamVertex * v,ParamMesh *mesh) - { - int index=v-&(*mesh->vert.begin()); - return (index); - } - - void InsertInterpData(ParamFace *curr,const int &edge, - ParamMesh *to_param,InterpData &Idata) - { - ParamVertex *v0=curr->V(edge); - ParamVertex *v1=curr->V1(edge); - int i0=IndexFromPointer(v0,to_param); - int i1=IndexFromPointer(v1,to_param); - if (i0>i1) - { - std::swap(v0,v1); - std::swap(i0,i1); - Idata.alpha=(ScalarType)1.0-Idata.alpha; - assert((Idata.alpha>=0)&&(Idata.alpha<=1)); - } - EdgeKey k=EdgeKey(i0,i1); - std::map::iterator ItE=alphaMap.find(k); - if(ItE!=alphaMap.end()) - { - if (fabs((*ItE).second.alpha-0.5)>fabs(Idata.alpha-0.5)) - { - (*ItE).second.alpha=Idata.alpha; - (*ItE).second.I=Idata.I; - (*ItE).second.UV=Idata.UV; - } - } - else - alphaMap.insert(std::pair(k,Idata)); - } - - bool Split(const ScalarType &border) - { - alphaMap.clear(); - - ParamMesh *to_param=isoParam->ParaMesh(); - - ///copy paramesh - - typedef ParamMesh::VertexType VertexType; - typedef ParamMesh::FaceType FaceType; - SplitMidPoint splMd; - EdgePredicate eP; - - ///second step.. test the split if needed - for (unsigned int i=0;iface.size();i++) - { - ///get the current face and test the edges - FaceType * curr=&to_param->face[i]; - InterpData Idata[3]; - bool to_split[3]; -#ifndef _MESHLAB - if ((i%1000)==0) - printf("testing face %d - %d \n",i,i+1000); -#endif - bool is_out=To_Split(curr,border,to_split,Idata); - if (is_out){ - for (int edge=0;edge<3;edge++) - if (to_split[edge]) - InsertInterpData(curr,edge,to_param,Idata[edge]); - } - - } - splMd.isoParam=isoParam; - splMd.alphaMap=&alphaMap; - eP.isoParam=isoParam; - eP.alphaMap=&alphaMap; - - #ifndef _MESHLAB - int f0=to_param->fn; - #endif - bool done=vcg::RefineE,EdgePredicate >(*to_param,splMd,eP); - #ifndef _MESHLAB - printf("FACE ADDED %d \n",to_param->fn-f0); - #endif - return done; - - } - - void SetWedgeCoords(const ScalarType &border) - { - typedef ParamMesh::VertexType VertexType; - typedef ParamMesh::FaceType FaceType; - - ParamMesh *to_param=isoParam->ParaMesh(); - int edge_size=(int)ceil(sqrt((ScalarType)num_diamonds)); - ScalarType edgedim=1.0/(ScalarType)edge_size; - for (unsigned int i=0;iface.size();i++) - { - #ifndef _MESHLAB - if ((i%1000)==0) - printf("setting Wedge coords %d - %d \n",i,i+1000); - #endif - ///get the current face and test the edges - FaceType * curr=&to_param->face[i]; - for (int j=0;j<3;j++) - { - vcg::Point2f QCoord; - vcg::Point2i IntCoord; - int index; - QuadCoord(curr,j,QCoord,index); - IntCoord.X()=index/edge_size; - IntCoord.Y()=index%edge_size; - ///transform from [ -border,1 + border] to [0,1] - QCoord+=vcg::Point2f(border,border); - QCoord/=(ScalarType)1.0+(ScalarType)2.0*border; - assert((QCoord.X()>=0)&&(QCoord.X()<=1)&&(QCoord.Y()>=0)&&(QCoord.Y()<=1)); - - QCoord*=edgedim; - QCoord.X()+=edgedim*(ScalarType)IntCoord.X(); - QCoord.Y()+=edgedim*(ScalarType)IntCoord.Y(); - assert(QCoord.X()<=1); - assert(QCoord.Y()<=1); - curr->WT(j).P()=QCoord; - ///and finally set for global texture coords - } - } - } - - int num_diamonds; - -public: - - std::vector colorDiam; - - ///initialize the parameterization - void Init(IsoParametrization *_isoParam) - { - - isoParam=_isoParam; - - ///COUNT THE NUMBER OF EDGES - num_diamonds=0; - for (unsigned int i=0;iAbsMesh()->face.size();i++) - { - AbstractFace *f=&isoParam->AbsMesh()->face[i]; - for (int j=0;j<3;j++) - if (f->FFp(j)ParaMesh(); - // //vcg::tri::UpdateNormals::PerFaceNormalized(*to_param); - // glDepthRange(0.01,1.0); - // glEnable(GL_LIGHTING); - // glEnable(GL_LIGHT0); - // glEnable(GL_NORMALIZE); - // glBegin(GL_TRIANGLES); - // for (int i=0;iface.size();i++) - // { - - // /*vcg::glColor(to_param->face[i].C());*/ - - // CoordType p0=to_param->face[i].V(0)->P(); - // CoordType p1=to_param->face[i].V(1)->P(); - // CoordType p2=to_param->face[i].V(2)->P(); - // CoordType norm=(p1-p0)^(p2-p0); - // norm.Normalize(); - // vcg::glNormal(norm); - // vcg::Point2f t0=to_param->face[i].WT(0).P(); - // vcg::Point2f t1=to_param->face[i].WT(1).P(); - // vcg::Point2f t2=to_param->face[i].WT(2).P(); - // vcg::Color4b c0,c1,c2; - // if ((t0.X()< 0)||(t0.Y()< 0)||(t0.X()>1.0)||(t0.Y()>1.0)) - // c0=vcg::Color4b(0,0,255,255); - // else - // c0=vcg::Color4b(t0.X()*255.0,t0.Y()*255.0,0,255); - // if ((t1.X()< 0)||(t1.Y()< 0)||(t1.X()>1.0)||(t1.Y()>1.0)) - // c1=vcg::Color4b(0,0,255,255); - // else - // c1=vcg::Color4b(t1.X()*255.0,t1.Y()*255.0,0,255); - // if ((t2.X()< 0)||(t2.Y()< 0)||(t2.X()>1.0)||(t2.Y()>1.0)) - // c2=vcg::Color4b(0,0,255,255); - // else - // c2=vcg::Color4b(t2.X()*255.0,t2.Y()*255.0,0,255); - // vcg::glColor(c0); - // vcg::glVertex(to_param->face[i].V(0)->P()); - // vcg::glColor(c1); - // vcg::glVertex(to_param->face[i].V(1)->P()); - // vcg::glColor(c2); - // vcg::glVertex(to_param->face[i].V(2)->P()); - // } - // glEnd(); - - // /*glDepthRange(0,0.99999); - // glDisable(GL_LIGHTING); - // glDisable(GL_LIGHT0); - // glDisable(GL_NORMALIZE); - // glLineWidth(1); - // glColor3d(0,0,0); - // for (int i=0;iface.size();i++) - // { - // glBegin(GL_LINE_LOOP); - // CoordType p0=to_param->face[i].V(0)->P(); - // CoordType p1=to_param->face[i].V(1)->P(); - // CoordType p2=to_param->face[i].V(2)->P(); - // vcg::glVertex(to_param->face[i].V(0)->P()); - // vcg::glVertex(to_param->face[i].V(1)->P()); - // vcg::glVertex(to_param->face[i].V(2)->P()); - // glEnd(); - // }*/ - // - // glDepthRange(0.0,1.0); - //} - - - - ///set the vertex coordinates - template - void SetCoordinates(MeshType &mesh,const ScalarType &border=0.01) - { - std::vector colorDiam; - - //ParamMesh *to_param=isoParam->ParaMesh(); - - typedef ParamMesh::FaceType FaceType; - typedef ParamMesh::VertexType VertexType; - - bool done=true; - /*int n0=to_param->fn;*/ - int step=0; - while (done) - { - #ifndef _MESHLAB - printf("step %d \n",step); - #endif - AssociateDiamond(); - done=Split(border); - isoParam->Update(); - step++; - } - - AssociateDiamond(); - SetWedgeCoords(border); - - ///copy parametrization to the new mesh - mesh.Clear(); - vcg::tri::Append::Mesh(mesh,*isoParam->ParaMesh()); - - } - -}; -#endif +#include +#include +#include +#include +#include +#include + +#ifndef _DIAMONDPARA +#define _DIAMONDPARA + +class DiamondParametrizator +{ + typedef IsoParametrization::CoordType CoordType; + typedef IsoParametrization::ScalarType ScalarType; + + IsoParametrization *isoParam; + + ///data used for splitting + typedef std::pair EdgeKey; + + ///interpolation data + struct InterpData + { + float alpha; + int I; + vcg::Point2 UV; + }; + + std::map alphaMap; + + ///data used to store an retrieve edges + //typedef std::pair TriEdge; + //std::vector DDAdiacency; + //std::map edgeMap; + //int sampleSize; + + template + int AssignDiamond(FaceType *face) + { + ScalarType val=(ScalarType)1.0/(ScalarType)3.0; + CoordType bary3d(val,val,val); + int I_interp; + vcg::Point2 UV_interp; + isoParam->Phi(face,bary3d,I_interp,UV_interp); + int D_interp=isoParam->getHDiamIndex(I_interp,UV_interp); + face->WT(0).N()=D_interp; + face->WT(1).N()=D_interp; + face->WT(2).N()=D_interp; + return D_interp; + } + + ///associate the diamond in which a face belongs to + void AssociateDiamond() + { + ParamMesh *to_param=isoParam->ParaMesh(); + typedef ParamMesh::FaceType FaceType; + + ///first step first associating initial faces to diamond + for (unsigned int i=0;iface.size();i++) + { + #ifndef _MESHLAB + if ((i%1000)==0) + printf("associating diamond %d - %d \n",i,i+1000); + #endif + FaceType *curr=&to_param->face[i]; + AssignDiamond(curr); + curr->C()=colorDiam[curr->WT(0).N()]; + } + } + + void InterpEdge(const ParamFace *f,const int &index_edge, + const float &alpha,int &I,vcg::Point2 &UV) + { + #ifndef NDEBUG + float eps=0.00001f; + #endif + int index0=index_edge; + int index1=(index_edge+1)%3; + CoordType bary=CoordType(0,0,0); + assert((alpha>=0)&&(alpha<=1)); + bary.V(index0)=alpha; + bary.V(index1)=((ScalarType)1.0-alpha); + isoParam->Phi(f,bary,I,UV); + assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); + } + +template +void QuadCoord(FaceType * curr,const int &vert_num,vcg::Point2f &UVQuad,int &indexQuad) +{ + typedef typename FaceType::VertexType VertexType; + typedef typename FaceType::ScalarType ScalarType; + + VertexType* v=curr->V(vert_num); + + int DiamIndex=curr->WT(0).N(); ///get index of diamond associated to the face + assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N())); + + ///transform to quad coordinates + int I=v->T().N(); + vcg::Point2f UV=v->T().P(); + + ///transform in diamond coordinates + vcg::Point2f UVDiam/*,UVQuad*/; + isoParam->GE1(I,UV,DiamIndex,UVDiam); + + ///transform in quad coordinates + isoParam->GE1Quad(DiamIndex,UVDiam,UVQuad); + + indexQuad=DiamIndex; + /*return (UVQuad);*/ +} + +template + bool To_Split(FaceType * curr,const float &border, + bool to_split[3],InterpData Idata[3]) + { + to_split[0]=false; + to_split[1]=false; + to_split[2]=false; + + typedef typename FaceType::VertexType VertexType; + typedef typename FaceType::ScalarType ScalarType; + + /*ParamMesh *to_param=isoParam->ParaMesh();*/ + + /*int DiamIndex=curr->WT(0).N(); *////get index of diamond associated to the face + assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N())); + + vcg::Point2f UVQuad[3]; + int index[3]; + + QuadCoord(curr,0,UVQuad[0],index[0]); + QuadCoord(curr,1,UVQuad[1],index[1]); + QuadCoord(curr,2,UVQuad[2],index[2]); + + ///outern border + vcg::Box2 bbox,bbox0; + bbox.Add(vcg::Point2f(-border,-border)); + bbox.Add(vcg::Point2f(1+border,1+border)); + bbox0.Add(vcg::Point2f(0,0)); + bbox0.Add(vcg::Point2f(1,1)); + + if (bbox.IsIn(UVQuad[0])&&bbox.IsIn(UVQuad[1])&&bbox.IsIn(UVQuad[2])) + return false; ///no intersection is possible + + ///else test which edges must be splitted + //vcg::Segment2 border_seg[4]; + vcg::Line2 border_seg[4]; + border_seg[0].Set(vcg::Point2f(0,0),vcg::Point2f(1,0)); + border_seg[1].Set(vcg::Point2f(1,0),vcg::Point2f(0,1)); + border_seg[2].Set(vcg::Point2f(0,1),vcg::Point2f(1,0)); + border_seg[3].Set(vcg::Point2f(0,0),vcg::Point2f(0,1)); + bool intersected=false; + for (int edge=0;edge<3;edge++) + { + vcg::Segment2 curr_edge=vcg::Segment2(UVQuad[edge],UVQuad[(edge+1)%3]); + float dist_medium=1.0; + for (int j=0;j<4;j++) + { + vcg::Point2f p_inters; + vcg::Line2 curr_border=border_seg[j]; + bool intersect=LineSegmentIntersection(curr_border,curr_edge,p_inters); + + float l_test0=(curr_edge.P0()-p_inters).Norm(); + float l_test1=(curr_edge.P1()-p_inters).Norm(); + float l_test=std::min(l_test0,l_test1); + + const ScalarType _EPS=(ScalarType)0.0001; + if ((intersect)&&(l_test>=_EPS)) + { + float lenght=curr_edge.Length(); + float dist=((curr_edge.P0()-p_inters).Norm()); + float Ndist=dist/lenght; + float alpha=1.0-Ndist; + float dist_medium1=fabs(alpha-0.5); + + if (dist_medium1 + struct SplitMidPoint : public std::unary_function , typename MESH_TYPE::CoordType > + { + typedef typename MESH_TYPE::VertexType VertexType; + typedef typename MESH_TYPE::FaceType FaceType; + typedef typename MESH_TYPE::CoordType CoordType; + + std::map *alphaMap; + IsoParametrization *isoParam; + + + + void operator()(typename MESH_TYPE::VertexType &nv, vcg::face::Pos ep) + { + //printf("DONE\n"); + + ParamMesh *to_param=isoParam->ParaMesh(); + + ///get eth value on which the edge must be splitted + VertexType* v0=ep.f->V(ep.z); + VertexType* v1=ep.f->V1(ep.z); + + int i0=IndexFromPointer(v0,to_param); + int i1=IndexFromPointer(v1,to_param); + + assert(v0!=v1); + EdgeKey k; + int index0=ep.z; + int index1=(ep.z+1)%3; + + if (i0>i1) + { + std::swap(v0,v1); + std::swap(i0,i1); + std::swap(index0,index1); + } + + k=EdgeKey(i0,i1); + std::map::iterator ItE=alphaMap->find(k); + assert(ItE!=alphaMap->end()); + InterpData interp=(*ItE).second; + float alpha=interp.alpha; + assert((alpha>=0)&&(alpha<=1)); + nv.P()= v0->P()*alpha+v1->P()*(1.0-alpha); + nv.RPos= v0->RPos*alpha+v1->RPos*(1.0-alpha); + + if( MESH_TYPE::HasPerVertexNormal()) + nv.N()=v0->N()*alpha+v1->N()*((ScalarType)1.0-alpha); + if( MESH_TYPE::HasPerVertexColor()) + { + CoordType color=CoordType(v0->C().X(),v0->C().Y(),v0->C().Z()); + color=color*alpha+color*((ScalarType)1.0-alpha); + nv.C()=vcg::Color4b((unsigned char)color.X(),(unsigned char)color.Y(),(unsigned char)color.Z(),(unsigned char)255); + } + + nv.T().N()=interp.I; + nv.T().P()=interp.UV; + } + + vcg::TexCoord2 WedgeInterp(vcg::TexCoord2 &t0, vcg::TexCoord2 &t1) + { + vcg::TexCoord2 tmp; + assert(t0.n()== t1.n()); + tmp.n()=t0.n(); + tmp.t()=(t0.t()+t1.t())/2.0; + return tmp; + } + }; + + + + template //, class FLT> + class EdgePredicate + { + typedef typename MESH_TYPE::VertexType VertexType; + typedef typename MESH_TYPE::FaceType FaceType; + public: + std::map *alphaMap; + IsoParametrization *isoParam; + + bool operator()(vcg::face::Pos ep) const + { + ParamMesh *to_param=isoParam->ParaMesh(); + + VertexType* v0=ep.f->V(ep.z); + VertexType* v1=ep.f->V1(ep.z); + + int i0=IndexFromPointer(v0,to_param); + int i1=IndexFromPointer(v1,to_param); + + assert(v0!=v1); + EdgeKey k; + + if (i0>i1) + { + std::swap(v0,v1); + std::swap(i0,i1); + } + + k=EdgeKey(i0,i1); + std::map::iterator ItE=alphaMap->find(k); + bool to_split=(ItE!=alphaMap->end()); + return (to_split); + } + }; + + static int IndexFromPointer(ParamVertex * v,ParamMesh *mesh) + { + int index=v-&(*mesh->vert.begin()); + return (index); + } + + void InsertInterpData(ParamFace *curr,const int &edge, + ParamMesh *to_param,InterpData &Idata) + { + ParamVertex *v0=curr->V(edge); + ParamVertex *v1=curr->V1(edge); + int i0=IndexFromPointer(v0,to_param); + int i1=IndexFromPointer(v1,to_param); + if (i0>i1) + { + std::swap(v0,v1); + std::swap(i0,i1); + Idata.alpha=(ScalarType)1.0-Idata.alpha; + assert((Idata.alpha>=0)&&(Idata.alpha<=1)); + } + EdgeKey k=EdgeKey(i0,i1); + std::map::iterator ItE=alphaMap.find(k); + if(ItE!=alphaMap.end()) + { + if (fabs((*ItE).second.alpha-0.5)>fabs(Idata.alpha-0.5)) + { + (*ItE).second.alpha=Idata.alpha; + (*ItE).second.I=Idata.I; + (*ItE).second.UV=Idata.UV; + } + } + else + alphaMap.insert(std::pair(k,Idata)); + } + + bool Split(const ScalarType &border) + { + alphaMap.clear(); + + ParamMesh *to_param=isoParam->ParaMesh(); + + ///copy paramesh + + typedef ParamMesh::VertexType VertexType; + typedef ParamMesh::FaceType FaceType; + SplitMidPoint splMd; + EdgePredicate eP; + + ///second step.. test the split if needed + for (unsigned int i=0;iface.size();i++) + { + ///get the current face and test the edges + FaceType * curr=&to_param->face[i]; + InterpData Idata[3]; + bool to_split[3]; +#ifndef _MESHLAB + if ((i%1000)==0) + printf("testing face %d - %d \n",i,i+1000); +#endif + bool is_out=To_Split(curr,border,to_split,Idata); + if (is_out){ + for (int edge=0;edge<3;edge++) + if (to_split[edge]) + InsertInterpData(curr,edge,to_param,Idata[edge]); + } + + } + splMd.isoParam=isoParam; + splMd.alphaMap=&alphaMap; + eP.isoParam=isoParam; + eP.alphaMap=&alphaMap; + + #ifndef _MESHLAB + int f0=to_param->fn; + #endif + bool done=vcg::RefineE,EdgePredicate >(*to_param,splMd,eP); + #ifndef _MESHLAB + printf("FACE ADDED %d \n",to_param->fn-f0); + #endif + return done; + + } + + void SetWedgeCoords(const ScalarType &border) + { + typedef ParamMesh::VertexType VertexType; + typedef ParamMesh::FaceType FaceType; + + ParamMesh *to_param=isoParam->ParaMesh(); + int edge_size=(int)ceil(sqrt((ScalarType)num_diamonds)); + ScalarType edgedim=1.0/(ScalarType)edge_size; + for (unsigned int i=0;iface.size();i++) + { + #ifndef _MESHLAB + if ((i%1000)==0) + printf("setting Wedge coords %d - %d \n",i,i+1000); + #endif + ///get the current face and test the edges + FaceType * curr=&to_param->face[i]; + for (int j=0;j<3;j++) + { + vcg::Point2f QCoord; + vcg::Point2i IntCoord; + int index; + QuadCoord(curr,j,QCoord,index); + IntCoord.X()=index/edge_size; + IntCoord.Y()=index%edge_size; + ///transform from [ -border,1 + border] to [0,1] + QCoord+=vcg::Point2f(border,border); + QCoord/=(ScalarType)1.0+(ScalarType)2.0*border; + assert((QCoord.X()>=0)&&(QCoord.X()<=1)&&(QCoord.Y()>=0)&&(QCoord.Y()<=1)); + + QCoord*=edgedim; + QCoord.X()+=edgedim*(ScalarType)IntCoord.X(); + QCoord.Y()+=edgedim*(ScalarType)IntCoord.Y(); + assert(QCoord.X()<=1); + assert(QCoord.Y()<=1); + curr->WT(j).P()=QCoord; + ///and finally set for global texture coords + } + } + } + + int num_diamonds; + +public: + + std::vector colorDiam; + + ///initialize the parameterization + void Init(IsoParametrization *_isoParam) + { + + isoParam=_isoParam; + + ///COUNT THE NUMBER OF EDGES + num_diamonds=0; + for (unsigned int i=0;iAbsMesh()->face.size();i++) + { + AbstractFace *f=&isoParam->AbsMesh()->face[i]; + for (int j=0;j<3;j++) + if (f->FFp(j)ParaMesh(); + // //vcg::tri::UpdateNormals::PerFaceNormalized(*to_param); + // glDepthRange(0.01,1.0); + // glEnable(GL_LIGHTING); + // glEnable(GL_LIGHT0); + // glEnable(GL_NORMALIZE); + // glBegin(GL_TRIANGLES); + // for (int i=0;iface.size();i++) + // { + + // /*vcg::glColor(to_param->face[i].C());*/ + + // CoordType p0=to_param->face[i].V(0)->P(); + // CoordType p1=to_param->face[i].V(1)->P(); + // CoordType p2=to_param->face[i].V(2)->P(); + // CoordType norm=(p1-p0)^(p2-p0); + // norm.Normalize(); + // vcg::glNormal(norm); + // vcg::Point2f t0=to_param->face[i].WT(0).P(); + // vcg::Point2f t1=to_param->face[i].WT(1).P(); + // vcg::Point2f t2=to_param->face[i].WT(2).P(); + // vcg::Color4b c0,c1,c2; + // if ((t0.X()< 0)||(t0.Y()< 0)||(t0.X()>1.0)||(t0.Y()>1.0)) + // c0=vcg::Color4b(0,0,255,255); + // else + // c0=vcg::Color4b(t0.X()*255.0,t0.Y()*255.0,0,255); + // if ((t1.X()< 0)||(t1.Y()< 0)||(t1.X()>1.0)||(t1.Y()>1.0)) + // c1=vcg::Color4b(0,0,255,255); + // else + // c1=vcg::Color4b(t1.X()*255.0,t1.Y()*255.0,0,255); + // if ((t2.X()< 0)||(t2.Y()< 0)||(t2.X()>1.0)||(t2.Y()>1.0)) + // c2=vcg::Color4b(0,0,255,255); + // else + // c2=vcg::Color4b(t2.X()*255.0,t2.Y()*255.0,0,255); + // vcg::glColor(c0); + // vcg::glVertex(to_param->face[i].V(0)->P()); + // vcg::glColor(c1); + // vcg::glVertex(to_param->face[i].V(1)->P()); + // vcg::glColor(c2); + // vcg::glVertex(to_param->face[i].V(2)->P()); + // } + // glEnd(); + + // /*glDepthRange(0,0.99999); + // glDisable(GL_LIGHTING); + // glDisable(GL_LIGHT0); + // glDisable(GL_NORMALIZE); + // glLineWidth(1); + // glColor3d(0,0,0); + // for (int i=0;iface.size();i++) + // { + // glBegin(GL_LINE_LOOP); + // CoordType p0=to_param->face[i].V(0)->P(); + // CoordType p1=to_param->face[i].V(1)->P(); + // CoordType p2=to_param->face[i].V(2)->P(); + // vcg::glVertex(to_param->face[i].V(0)->P()); + // vcg::glVertex(to_param->face[i].V(1)->P()); + // vcg::glVertex(to_param->face[i].V(2)->P()); + // glEnd(); + // }*/ + // + // glDepthRange(0.0,1.0); + //} + + + + ///set the vertex coordinates + template + void SetCoordinates(MeshType &mesh,const ScalarType &border=0.01) + { + std::vector colorDiam; + + //ParamMesh *to_param=isoParam->ParaMesh(); + + typedef ParamMesh::FaceType FaceType; + typedef ParamMesh::VertexType VertexType; + + bool done=true; + /*int n0=to_param->fn;*/ + int step=0; + while (done) + { + #ifndef _MESHLAB + printf("step %d \n",step); + #endif + AssociateDiamond(); + done=Split(border); + isoParam->Update(); + step++; + } + + AssociateDiamond(); + SetWedgeCoords(border); + + ///copy parametrization to the new mesh + mesh.Clear(); + vcg::tri::Append::Mesh(mesh,*isoParam->ParaMesh()); + + } + +}; +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/diam_topology.h b/src/meshlabplugins/filter_isoparametrization/diam_topology.h index ec53251dc..5563736f1 100644 --- a/src/meshlabplugins/filter_isoparametrization/diam_topology.h +++ b/src/meshlabplugins/filter_isoparametrization/diam_topology.h @@ -1,175 +1,175 @@ -#include -#include -#include -#include -#include -#include - -#ifndef _DIAMONDTOPOLOGY -#define _DIAMONDTOPOLOGY - -class DiamTopology -{ - typedef struct DiamondPatch - { - int FFp[4]; - int FFi[4]; - - AbstractFace *f; - int edgeInd; - - DiamondPatch(){ - FFp[0]=-1; - FFp[1]=-1; - FFp[2]=-1; - FFp[3]=-1; - FFi[0]=-1; - FFi[1]=-1; - FFi[2]=-1; - FFi[3]=-1; - } - }; - - std::vector patches; - IsoParametrization *isoParam; - typedef std::pair TriEdge; - - std::vector DDAdiacency; - std::map edgeMap; - - void InsertEdges() - { - //insert all the edges - AbstractMesh *domain=isoParam->AbsMesh(); - int index=0; - for (int i=0;ifn;i++) - { - AbstractFace *f0=&(domain->face[i]); - if (!f0->IsD()) - { - for(int j=0;j<3;j++) - { - AbstractFace * f1=f0->FFp(j); - if (f1>f0) - { - DDAdiacency.push_back(DiamondPatch()); - DDAdiacency[index].f=f0; - DDAdiacency[index].edgeInd=j; - TriEdge key=TriEdge(f0,j); - edgeMap.insert(std::pair(key,index)); - index++; - } - } - } - - } - } - - - - void SetTopology() - { - - ///data used to calculate topology - typedef std::pair DiamEdge; - struct InfoAdiacency - { - int index_global; - int index_local; - }; - - std::map EdgeDiamMap; - - for (unsigned int i=0;iV0(indexEdge); - AbstractVertex *v1=face->V1(indexEdge); - AbstractFace *f0=face; - AbstractFace *f1=face->FFp(indexEdge); - - ///set right order - if (v1::iterator ItMap=EdgeDiamMap.find(de[j]); - - ///first time insert in the table - if (ItMap==EdgeDiamMap.end()) - { - InfoAdiacency InfAd; - InfAd.index_global=i; - InfAd.index_local=j; - EdgeDiamMap.insert(std::pair(de[j],InfAd)); - } - else - { - int index_global=(*ItMap).second.index_global; - int index_local =(*ItMap).second.index_local; - DDAdiacency[index_global].FFp[index_local]=i; - DDAdiacency[index_global].FFi[index_local]=j; - DDAdiacency[i].FFp[j]=index_global; - DDAdiacency[i].FFi[j]=index_local; - } - } - } - } - - bool TestTopology() - { - for (unsigned int i=0;i +#include +#include +#include +#include +#include + +#ifndef _DIAMONDTOPOLOGY +#define _DIAMONDTOPOLOGY + +class DiamTopology +{ + typedef struct DiamondPatch + { + int FFp[4]; + int FFi[4]; + + AbstractFace *f; + int edgeInd; + + DiamondPatch(){ + FFp[0]=-1; + FFp[1]=-1; + FFp[2]=-1; + FFp[3]=-1; + FFi[0]=-1; + FFi[1]=-1; + FFi[2]=-1; + FFi[3]=-1; + } + }; + + std::vector patches; + IsoParametrization *isoParam; + typedef std::pair TriEdge; + + std::vector DDAdiacency; + std::map edgeMap; + + void InsertEdges() + { + //insert all the edges + AbstractMesh *domain=isoParam->AbsMesh(); + int index=0; + for (int i=0;ifn;i++) + { + AbstractFace *f0=&(domain->face[i]); + if (!f0->IsD()) + { + for(int j=0;j<3;j++) + { + AbstractFace * f1=f0->FFp(j); + if (f1>f0) + { + DDAdiacency.push_back(DiamondPatch()); + DDAdiacency[index].f=f0; + DDAdiacency[index].edgeInd=j; + TriEdge key=TriEdge(f0,j); + edgeMap.insert(std::pair(key,index)); + index++; + } + } + } + + } + } + + + + void SetTopology() + { + + ///data used to calculate topology + typedef std::pair DiamEdge; + struct InfoAdiacency + { + int index_global; + int index_local; + }; + + std::map EdgeDiamMap; + + for (unsigned int i=0;iV0(indexEdge); + AbstractVertex *v1=face->V1(indexEdge); + AbstractFace *f0=face; + AbstractFace *f1=face->FFp(indexEdge); + + ///set right order + if (v1::iterator ItMap=EdgeDiamMap.find(de[j]); + + ///first time insert in the table + if (ItMap==EdgeDiamMap.end()) + { + InfoAdiacency InfAd; + InfAd.index_global=i; + InfAd.index_local=j; + EdgeDiamMap.insert(std::pair(de[j],InfAd)); + } + else + { + int index_global=(*ItMap).second.index_global; + int index_local =(*ItMap).second.index_local; + DDAdiacency[index_global].FFp[index_local]=i; + DDAdiacency[index_global].FFi[index_local]=j; + DDAdiacency[i].FFp[j]=index_global; + DDAdiacency[i].FFi[j]=index_local; + } + } + } + } + + bool TestTopology() + { + for (unsigned int i=0;i -#include - -class DiamSampler{ - typedef IsoParametrization::CoordType CoordType; - typedef IsoParametrization::ScalarType ScalarType; - - std::vector > > SampledPos; - IsoParametrization *isoParam; - unsigned int sampleSize; - - void DeAllocatePos() - { - ///positions - for (unsigned int i=0;iAbsMesh(); - int num_edges=0; - for (unsigned int i=0;iface.size();i++) - { - AbstractFace *f=&domain->face[i]; - for (int j=0;j<3;j++) - if (f->FFp(j)>f) - num_edges++; - } - - SampledPos.resize(num_edges); - for (unsigned int i=0;i &faces, - std::vector &barys) - { - CoordType pos=CoordType(0,0,0); - for (unsigned int i=0;iV(0)->P()*barys[i].X()+ - faces[i]->V(1)->P()*barys[i].Y()+ - faces[i]->V(2)->P()*barys[i].Z()); - } - pos/=(ScalarType)faces.size(); - return pos; - } - - int n_diamonds; - int inFace; - int inEdge; - int inStar; - int n_merged; -public: - - ///initialize the sampler - void Init(IsoParametrization *_isoParam) - { - isoParam=_isoParam; - } - - template - void GetMesh(OutputMesh &SaveMesh) - { - - typedef typename OutputMesh::FaceType MyFace; - typedef typename OutputMesh::VertexType MyVertex; - - SaveMesh.Clear(); - - SaveMesh.vert.reserve(SampledPos.size()* - sampleSize* - sampleSize); - - SaveMesh.face.reserve(SampledPos.size()* - (sampleSize-1)* - (sampleSize-1)*2); - - SaveMesh.vn=0; - SaveMesh.fn=0; - - ///suposed to be the same everywhere - ///allocate space - std::vector > vertMatrix; - vertMatrix.resize(sampleSize); - for (unsigned int i=0;i(SaveMesh,minE,maxE); - /*int num_tri=SampledPos.size()*sampleSize*sampleSize*2; - ScalarType Area_mesh=Area(SaveMesh); - ScalarType Edge=sqrt((((Area_mesh/(ScalarType)num_tri)*4.0)/(ScalarType)sqrt(3.0)));*/ - n_merged=vcg::tri::Clean::MergeCloseVertex(SaveMesh,(ScalarType)minE*(ScalarType)0.9); - vcg::tri::UpdateNormals::PerVertexNormalized(SaveMesh); - /*Log("Merged %d vertices\n",merged);*/ - } - - //typedef enum SampleAttr{SMNormal, SMColor, SMPosition}; - - ///sample the parametrization - bool SamplePos(const int &size) - { - if (size<2) - return false; - sampleSize=size; - DeAllocatePos();//clear old data - AllocatePos(size); ///allocate for new one - inFace=0; - inEdge=0; - inStar=0; - int global=0; - - ///start sampling values - /*Log("Num Diamonds: %d \n",SampledPos.size());*/ - - - for (unsigned int diam=0;diam UVQuad,UV; - UVQuad.X()=(ScalarType)j/(ScalarType)(sampleSize-1); - UVQuad.Y()=(ScalarType)k/(ScalarType)(sampleSize-1); - int I; - //printf("Quad: %d,%f,%f \n",diam,UV.X(),UV.Y()); - ///get coordinate in parametric space - isoParam->inv_GE1Quad(diam,UVQuad,I,UV); - //printf("Alfabeta: %d,%f,%f \n",I,UV.X(),UV.Y()); - ///and sample - std::vector faces; - std::vector barys; - int domain=isoParam->Theta(I,UV,faces,barys); - - if (domain==0) - inFace++; - else - if (domain==1) - inEdge++; - else - if (domain==2) - inStar++; - - global++; - //printf("Find in domain: %d \n",domain); - ///store value - CoordType val=AveragePos(faces,barys); - /*if (domain==2) - val=CoordType(0,0,0);*/ - SampledPos[diam][j][k]=val; - } - return true; - /*#ifndef _MESHLAB - printf("In Face: %f \n",(ScalarType)inFace/(ScalarType)global); - printf("In Diamond: %f \n",(ScalarType)inEdge/(ScalarType)global); - printf("In Star: %f \n",(ScalarType)inStar/(ScalarType)global); - #endif*/ - /*Log("In Face: %f \n",(ScalarType)inFace/(ScalarType)global); - Log("In Diamond: %f \n",(ScalarType)inEdge/(ScalarType)global); - Log("In Star: %f \n",(ScalarType)inStar/(ScalarType)global);*/ - } - - void getResData(int &_n_diamonds,int &_inFace, - int &_inEdge,int &_inStar,int &_n_merged) - { - _n_diamonds=n_diamonds; - _inFace=inFace; - _inEdge=inEdge; - _inStar=inStar; - _n_merged=n_merged; - } - - void GetCoords(std::vector &positions) - { - for (unsigned int diam=0;diam +#include + +class DiamSampler{ + typedef IsoParametrization::CoordType CoordType; + typedef IsoParametrization::ScalarType ScalarType; + + std::vector > > SampledPos; + IsoParametrization *isoParam; + unsigned int sampleSize; + + void DeAllocatePos() + { + ///positions + for (unsigned int i=0;iAbsMesh(); + int num_edges=0; + for (unsigned int i=0;iface.size();i++) + { + AbstractFace *f=&domain->face[i]; + for (int j=0;j<3;j++) + if (f->FFp(j)>f) + num_edges++; + } + + SampledPos.resize(num_edges); + for (unsigned int i=0;i &faces, + std::vector &barys) + { + CoordType pos=CoordType(0,0,0); + for (unsigned int i=0;iV(0)->P()*barys[i].X()+ + faces[i]->V(1)->P()*barys[i].Y()+ + faces[i]->V(2)->P()*barys[i].Z()); + } + pos/=(ScalarType)faces.size(); + return pos; + } + + int n_diamonds; + int inFace; + int inEdge; + int inStar; + int n_merged; +public: + + ///initialize the sampler + void Init(IsoParametrization *_isoParam) + { + isoParam=_isoParam; + } + + template + void GetMesh(OutputMesh &SaveMesh) + { + + typedef typename OutputMesh::FaceType MyFace; + typedef typename OutputMesh::VertexType MyVertex; + + SaveMesh.Clear(); + + SaveMesh.vert.reserve(SampledPos.size()* + sampleSize* + sampleSize); + + SaveMesh.face.reserve(SampledPos.size()* + (sampleSize-1)* + (sampleSize-1)*2); + + SaveMesh.vn=0; + SaveMesh.fn=0; + + ///suposed to be the same everywhere + ///allocate space + std::vector > vertMatrix; + vertMatrix.resize(sampleSize); + for (unsigned int i=0;i(SaveMesh,minE,maxE); + /*int num_tri=SampledPos.size()*sampleSize*sampleSize*2; + ScalarType Area_mesh=Area(SaveMesh); + ScalarType Edge=sqrt((((Area_mesh/(ScalarType)num_tri)*4.0)/(ScalarType)sqrt(3.0)));*/ + n_merged=vcg::tri::Clean::MergeCloseVertex(SaveMesh,(ScalarType)minE*(ScalarType)0.9); + vcg::tri::UpdateNormals::PerVertexNormalized(SaveMesh); + /*Log("Merged %d vertices\n",merged);*/ + } + + //typedef enum SampleAttr{SMNormal, SMColor, SMPosition}; + + ///sample the parametrization + bool SamplePos(const int &size) + { + if (size<2) + return false; + sampleSize=size; + DeAllocatePos();//clear old data + AllocatePos(size); ///allocate for new one + inFace=0; + inEdge=0; + inStar=0; + int global=0; + + ///start sampling values + /*Log("Num Diamonds: %d \n",SampledPos.size());*/ + + + for (unsigned int diam=0;diam UVQuad,UV; + UVQuad.X()=(ScalarType)j/(ScalarType)(sampleSize-1); + UVQuad.Y()=(ScalarType)k/(ScalarType)(sampleSize-1); + int I; + //printf("Quad: %d,%f,%f \n",diam,UV.X(),UV.Y()); + ///get coordinate in parametric space + isoParam->inv_GE1Quad(diam,UVQuad,I,UV); + //printf("Alfabeta: %d,%f,%f \n",I,UV.X(),UV.Y()); + ///and sample + std::vector faces; + std::vector barys; + int domain=isoParam->Theta(I,UV,faces,barys); + + if (domain==0) + inFace++; + else + if (domain==1) + inEdge++; + else + if (domain==2) + inStar++; + + global++; + //printf("Find in domain: %d \n",domain); + ///store value + CoordType val=AveragePos(faces,barys); + /*if (domain==2) + val=CoordType(0,0,0);*/ + SampledPos[diam][j][k]=val; + } + return true; + /*#ifndef _MESHLAB + printf("In Face: %f \n",(ScalarType)inFace/(ScalarType)global); + printf("In Diamond: %f \n",(ScalarType)inEdge/(ScalarType)global); + printf("In Star: %f \n",(ScalarType)inStar/(ScalarType)global); + #endif*/ + /*Log("In Face: %f \n",(ScalarType)inFace/(ScalarType)global); + Log("In Diamond: %f \n",(ScalarType)inEdge/(ScalarType)global); + Log("In Star: %f \n",(ScalarType)inStar/(ScalarType)global);*/ + } + + void getResData(int &_n_diamonds,int &_inFace, + int &_inEdge,int &_inStar,int &_n_merged) + { + _n_diamonds=n_diamonds; + _inFace=inFace; + _inEdge=inEdge; + _inStar=inStar; + _n_merged=n_merged; + } + + void GetCoords(std::vector &positions) + { + for (unsigned int diam=0;diam -#include -#include "defines.h" - -#include "../../common/meshmodel.h" -#include -#include -#include - - -#include -#include - -using namespace std; -using namespace vcg; - -FilterIsoParametrization::FilterIsoParametrization() -{ - typeList << ISOP_PARAM - << ISOP_REMESHING - << ISOP_DIAMPARAM - << ISOP_LOAD - << ISOP_SAVE - << ISOP_TRANSFER; - - FilterIDType tt; - foreach(tt , types()) - actionList << new QAction(filterName(tt), this); - -} - -FilterIsoParametrization::~FilterIsoParametrization() -{ - for (int i = 0; i < actionList.count() ; i++ ) - delete actionList.at(i); -} - -QString FilterIsoParametrization::filterName(FilterIDType filter) const -{ - switch(filter) - { - case ISOP_PARAM : return "Iso Parametrization"; - case ISOP_REMESHING : return "Iso Parametrization Remeshing"; - case ISOP_DIAMPARAM : return "Iso Parametrization Build Atlased Mesh"; - case ISOP_LOAD : return "Iso Parametrization Load Abstract Domain"; - case ISOP_SAVE : return "Iso Parametrization Save Abstract Domain"; - case ISOP_TRANSFER: return "Iso Parametrization transfer between meshes"; - default: assert(0); - } - return QString("error!"); -} - -QString FilterIsoParametrization::filterInfo(FilterIDType filterId) const -{ - switch(filterId) - { - case ISOP_PARAM : return "The filter build the abstract Isoparameterization of a two-manifold triangular mesh
" - "An adaptively chosen abstract domain of the parameterization is built. For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - case ISOP_REMESHING : return "Remeshing based on an Abstract Isoparameterization, each triangle of the domain is recursively subdivided.
" - "For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - case ISOP_DIAMPARAM : return "The filter build a new mesh with a standard atlased per wedge texture. The atlas is simply done by " - "splitting each triangle of the abstract domain
" - "For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - case ISOP_LOAD : return "Load the Isoparameterization from a saved Abstract Mesh
" - "For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - case ISOP_SAVE : return "Save the Isoparameterization on an Abstract Mesh
" - "For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - case ISOP_TRANSFER:return "Transfer the Isoparametrization between two meshes, the two meshes must be reasonably similar and well aligned." - " It is useful to transfer back an isoparam onto the original mesh after having computed it on a dummy, clean watertight model.
" - "For more details see:
" - "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" - "IEEE Transaction of Visualization and Computer Graphics 2010"; - default: assert(0); - } - return QString("error!"); -} - -int FilterIsoParametrization::getRequirements(QAction *action) -{ - (void) action; - /*switch(ID(action)) - { - case CP_SCATTER_PER_MESH : return MeshModel::MM_COLOR; - default : return MeshModel::MM_VERTCOLOR; - }*/ - return MeshModel::MM_UNKNOWN; -} - -void FilterIsoParametrization::initParameterSet(QAction *a, MeshDocument& md, RichParameterSet & par) -{ - - switch(ID(a)) - { - case ISOP_PARAM: - { - par.addParam(new RichInt("targetAbstractMinFaceNum",140,"Abstract Min Mesh Size", - "This number and the following one indicate the range face number of the abstract mesh that is used for the parametrization process.
" - "The algorithm will choose the best abstract mesh with the number of triangles within the specified interval.
" - "If the mesh has a very simple structure this range can be very low and strict;" - "for a roughly spherical object if you can specify a range of [8,8] faces you get a octahedral abstract mesh, e.g. a geometry image.
" - "Large numbers (greater than 400) are usually not of practical use.")); - par.addParam(new RichInt("targetAbstractMaxFaceNum",180,"Abstract Max Mesh Size", "Please notice that a large interval requires huge amount of memory to be allocated, in order save the intermediate results.
" - "An interval of 40 should be fine.")); - QStringList stopCriteriaList; - stopCriteriaList.push_back("Best Heuristic"); - stopCriteriaList.push_back("Area + Angle"); - stopCriteriaList.push_back("Regularity"); - stopCriteriaList.push_back("L2"); - - par.addParam(new RichEnum("stopCriteria", 1, stopCriteriaList, tr("Optimization Criteria"), - tr(//"

" - "Choose a metric to stop the parametrization within the interval
" - "1: Best Heuristic : stop considering both isometry and number of faces of base domain
" - "2: Area + Angle : stop at minimum area and angle distorsion
" - "3: Regularity : stop at minimum number of irregular vertices
" - "4: L2 : stop at minimum OneWay L2 Stretch Eff"))); - - par.addParam(new RichInt("convergenceSpeed",1, "Convergence Precision", "This parameter controls the convergence speed/precision of the optimization of the texture coordinates. Larger the number slower the processing and ,eventually, slighly better results")); - par.addParam(new RichBool("DoubleStep",true,"Double Step","Use this bool to divide the parameterization in 2 steps. Double step makes the overall process faster and robust." - "
Consider to disable this bool in case the object has topologycal noise or small handles.")); - break; - } - case ISOP_REMESHING : - { - par.addParam(new RichInt("SamplingRate",10,"Sampling Rate", "This specify the sampling rate for remeshing.")); - break; - } - case ISOP_DIAMPARAM : - { - par.addParam(new RichDynamicFloat("BorderSize",0.1f,0.01f,0.5f,"BorderSize ratio", - "This parameter controls the amount of space that must be left between each diamond when building the atlas." - "It directly affects how many triangle are splitted during this conversion.
" - "In abstract parametrization mesh triangles can naturally cross the triangles of the abstract domain, so when converting " - "to a standard parametrization we must cut all the triangles that protrudes outside each diamond more than the specified threshold." - "The unit of the threshold is in percentage of the size of the diamond," - "The bigger the threshold the less triangles are splitted, but the more UV space is used (wasted).")); - break; - } - case ISOP_LOAD : - { - QFileInfo fi(md.mm()->fullName()); - QString fileName = fi.baseName(); - - fileName = fileName.append(".abs"); - par.addParam(new RichString("AbsName", fileName, "Abstract Mesh file", "The filename of the abstract mesh that has to be loaded")); - break; - } - case ISOP_SAVE : - { - QFileInfo fi(md.mm()->fullName()); - QString fileName = fi.baseName(); - - fileName = fileName.append(".abs"); - par.addParam(new RichString("AbsName", fileName, "Abstract Mesh file", "The filename where the abstract mesh has to be saved")); - break; - } - case ISOP_TRANSFER: - { - par.addParam(new RichMesh ("sourceMesh",md.mm(),&md, "Source Mesh", "The mesh already having an Isoparameterization")); - par.addParam(new RichMesh ("targetMesh",md.mm(),&md, "Target Mesh", "The mesh to be Isoparameterized")); - } - } -} - -void FilterIsoParametrization::PrintStats(CMeshO *mesh) -{ - tri::UpdateTopology::FaceFace(*mesh); - tri::UpdateTopology::VertexFace(*mesh); - int non_reg=NumRegular(*mesh); - float minE,maxE,avE,stdE; - float minAr,maxAr,avAr,stdAr; - float minAn,maxAn,avAn,stdAn; - int minEi,maxEi,stdEi; - int minAri,maxAri,stdAri; - int minAni,maxAni,stdAni; - - StatEdge(*mesh,minE,maxE,avE,stdE); - StatArea(*mesh,minAr,maxAr,avAr,stdAr); - StatAngle(*mesh,minAn,maxAn,avAn,stdAn); - minE/=avE; - minE*=100.f; - maxE/=avE; - maxE*=100.f; - stdE/=avE; - stdE*=100.f; - - minAn/=avAn; - minAn*=100.f; - maxAn/=avAn; - maxAn*=100.f; - stdAn/=avAn; - stdAn*=100.f; - - minAr/=avAr; - minAr*=100.f; - maxAr/=avAr; - maxAr*=100.f; - stdAr/=avAr; - stdAr*=100.f; - - minEi=(int)minE; - maxEi=(int)maxE; - stdEi=(int)stdE; - - minAni=(int)minAn; - maxAni=(int)maxAn; - stdAni=(int)stdAn; - - minAri=(int)minAr; - maxAri=(int)maxAr; - stdAri=(int)stdAr; - - Log(" REMESHED "); - Log("Irregular Vertices:%d ",non_reg); - Log("stdDev Area:%d",stdAri); - Log("stdDev Angle:%d",stdAni); - Log("stdDev Edge:%d",stdEi); -} - -bool FilterIsoParametrization::applyFilter(QAction *filter, MeshDocument& md, RichParameterSet & par, vcg::CallBackPos *cb) -{ - MeshModel* m = md.mm(); //get current mesh from document - CMeshO *mesh=&m->cm; - switch(ID(filter)) - { - case ISOP_PARAM : - { - int targetAbstractMinFaceNum = par.getInt("targetAbstractMinFaceNum"); - int targetAbstractMaxFaceNum = par.getInt("targetAbstractMaxFaceNum"); - int convergenceSpeed = par.getInt("convergenceSpeed"); - int stopCriteria=par.getEnum("stopCriteria"); - bool doublestep=par.getBool("DoubleStep"); - IsoParametrizator Parametrizator; - - m->updateDataMask(MeshModel::MM_FACEFACETOPO); - m->updateDataMask(MeshModel::MM_VERTQUALITY); // needed to store patch index - - bool isTXTenabled=m->hasDataMask(MeshModel::MM_VERTTEXCOORD); - if (!isTXTenabled) - m->updateDataMask(MeshModel::MM_VERTTEXCOORD); - - bool isVMarkenabled=m->hasDataMask(MeshModel::MM_VERTMARK); - if (!isVMarkenabled) - m->updateDataMask(MeshModel::MM_VERTMARK); - - bool isFMarkenabled=m->hasDataMask(MeshModel::MM_FACEMARK); - if (!isFMarkenabled) - m->updateDataMask(MeshModel::MM_FACEMARK); - - bool isVColorenabled=m->hasDataMask(MeshModel::MM_VERTCOLOR); - if (!isVColorenabled) - m->updateDataMask(MeshModel::MM_VERTCOLOR); - - bool isFColorenabled=m->hasDataMask(MeshModel::MM_FACECOLOR); - if (!isFColorenabled) - m->updateDataMask(MeshModel::MM_FACECOLOR); - int tolerance = targetAbstractMaxFaceNum-targetAbstractMinFaceNum; - switch (stopCriteria) - { - case 0:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; - case 1:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Corr,convergenceSpeed);break; - case 2:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Reg,convergenceSpeed);break; - case 3:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_L2,convergenceSpeed);break; - default:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; - } - IsoParametrizator::ReturnCode ret=Parametrizator.Parametrize(mesh,doublestep); - - if (ret==IsoParametrizator::Done) - { - Parametrizator.PrintAttributes(); - float aggregate,L2; - int n_faces; - Parametrizator.getValues(aggregate,L2,n_faces); - Log("Num Faces of Abstract Domain: %d, One way stretch efficiency: %.4f, Area+Angle Distorsion %.4f ",n_faces,L2,aggregate*100.f); - } - else - { - if (!isTXTenabled) m->clearDataMask(MeshModel::MM_VERTTEXCOORD); - if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); - if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); - if (!isVColorenabled) m->clearDataMask(MeshModel::MM_VERTCOLOR); - if (!isFColorenabled) m->clearDataMask(MeshModel::MM_FACECOLOR); - switch(ret) - { - case IsoParametrizator::MultiComponent: - this->errorMessage="non possible parameterization because of multi componet mesh"; return false; - case IsoParametrizator::NonSizeCons: - this->errorMessage="non possible parameterization because of non size consistent mesh"; return false; - case IsoParametrizator::NonManifoldE: - this->errorMessage="non possible parameterization because of non manifold edges"; return false; - case IsoParametrizator::NonManifoldV: - this->errorMessage="non possible parameterization because of non manifold vertices";return false; - case IsoParametrizator::NonWatertigh: - this->errorMessage="non possible parameterization because of non watertight mesh"; return false; - case IsoParametrizator::FailParam: - this->errorMessage="non possible parameterization cause one of the following reasons:\n Topologycal noise \n Too Low resolution mesh \n Too Bad triangulation \n"; return false; - default: - this->errorMessage="unknown error"; return false; - } - } - // At this point we are sure that everithing went ok so we can allocate surely the abstract - AbstractMesh *abs_mesh = new AbstractMesh(); - ParamMesh *para_mesh = new ParamMesh(); - Parametrizator.ExportMeshes(*para_mesh,*abs_mesh); - CMeshO::PerMeshAttributeHandle isoPHandle; - isoPHandle=tri::Allocator::AddPerMeshAttribute(*mesh,"isoparametrization"); - - bool isOK=isoPHandle().Init(abs_mesh,para_mesh); - - ///copy back to original mesh - isoPHandle().CopyParametrization(mesh); - - if (!isOK) - { - this->errorMessage="Problems gathering parameterization \n"; - return false; - } - if (!isVMarkenabled) - m->clearDataMask(MeshModel::MM_VERTMARK); - if (!isFMarkenabled) - m->clearDataMask(MeshModel::MM_FACEMARK); - return true; - } - case ISOP_REMESHING : - { - CMeshO::PerMeshAttributeHandle isoPHandle = - tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); - - bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); - if (!b) - { - this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; - return false; - } - - - int SamplingRate=par.getInt("SamplingRate"); - if (!SamplingRate>2) - { - this->errorMessage="Sampling rate must be >1"; - return false; - } - MeshModel* mm=md.addNewMesh("","Re-meshed"); - - CMeshO *rem=&mm->cm; - DiamSampler DiamSampl; - DiamSampl.Init(&isoPHandle()); - bool done=DiamSampl.SamplePos(SamplingRate); - assert(done); - DiamSampl.GetMesh(*rem); - - int n_diamonds,inFace,inEdge,inStar,n_merged; - DiamSampl.getResData(n_diamonds,inFace,inEdge,inStar,n_merged); - - Log("INTERPOLATION DOMAINS"); - Log("In Face: %d \n",inFace); - Log("In Diamond: %d \n",inEdge); - Log("In Star: %d \n",inStar); - Log("Merged %d vertices\n",n_merged); - mm->updateDataMask(MeshModel::MM_FACEFACETOPO); - mm->updateDataMask(MeshModel::MM_VERTFACETOPO); - PrintStats(rem); - tri::UpdateNormals::PerFace(*rem); - return true; - } - case ISOP_DIAMPARAM : - { - CMeshO::PerMeshAttributeHandle isoPHandle = - tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); - bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); - if (!b) - { - this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; - return false; - } - - float border_size=par.getDynamicFloat("BorderSize"); - MeshModel* mm=md.addNewMesh("","Diam-Parameterized"); - mm->updateDataMask(MeshModel::MM_WEDGTEXCOORD); - mm->updateDataMask(MeshModel::MM_VERTCOLOR); - CMeshO *rem=&mm->cm; - DiamondParametrizator DiaPara; - DiaPara.Init(&isoPHandle()); - DiaPara.SetCoordinates(*rem,border_size); - tri::UpdateNormals::PerFace(*rem); - return true; - } - case ISOP_LOAD : - { - QString AbsName = par.getString("AbsName"); - m->updateDataMask(MeshModel::MM_WEDGTEXCOORD); - m->updateDataMask(MeshModel::MM_VERTTEXCOORD); - m->updateDataMask(MeshModel::MM_FACECOLOR); - m->updateDataMask(MeshModel::MM_VERTQUALITY); - m->updateDataMask(MeshModel::MM_FACEMARK); - if(!QFile(m->fullName()).exists()) - { - this->errorMessage="File not exists"; - return false; - } - CMeshO::PerMeshAttributeHandle isoPHandle = - tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); - - bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); - if (!b) - isoPHandle=tri::Allocator::AddPerMeshAttribute(*mesh,"isoparametrization"); - - QByteArray ba = AbsName.toLatin1(); - char *path=ba.data(); - AbstractMesh *abs_mesh = new AbstractMesh(); - ParamMesh *para_mesh = new ParamMesh(); - bool Done=isoPHandle().LoadBaseDomain(path,mesh,para_mesh,abs_mesh,true); - if (!Done) - { - this->errorMessage="Abstract domain doesnt fit well with the parametrized mesh"; - delete para_mesh; - delete abs_mesh; - return false; - } - return true; - } - case ISOP_SAVE : - { - m->updateDataMask(MeshModel::MM_VERTQUALITY); - CMeshO::PerMeshAttributeHandle isoPHandle = - tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); - - bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); - if (!b) - { - this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; - return false; - } - /*QString Qpath=m->fullName();*/ - - QString AbsName = par.getString("AbsName"); - - QByteArray ba = AbsName.toLatin1(); - char *path=ba.data(); - isoPHandle().SaveBaseDomain(path); - return true; - } - case ISOP_TRANSFER: - { - MeshModel *mmtrg = par.getMesh("targetMesh"); - MeshModel *mmsrc = par.getMesh("targetMesh"); - CMeshO *trgMesh=&mmtrg->cm; - CMeshO *srcMesh=&mmsrc->cm; - - CMeshO::PerMeshAttributeHandle isoPHandle = - tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); - - bool b=tri::Allocator::IsValidHandle(*srcMesh,isoPHandle); - if (!b) - { - this->errorMessage="Your source mesh must have the abstract isoparametrization. Use the Isoparametrization command."; - return false; - } - IsoTransfer IsoTr; - AbstractMesh *abs_mesh = isoPHandle().AbsMesh(); - ParamMesh *para_mesh = isoPHandle().ParaMesh(); - - mmtrg->updateDataMask(MeshModel::MM_WEDGTEXCOORD); - mmtrg->updateDataMask(MeshModel::MM_VERTTEXCOORD); - mmtrg->updateDataMask(MeshModel::MM_FACECOLOR); - mmtrg->updateDataMask(MeshModel::MM_VERTQUALITY); - mmtrg->updateDataMask(MeshModel::MM_FACEMARK); - IsoTr.Transfer(isoPHandle(),*trgMesh); - - isoPHandle().Clear(); - tri::Allocator::DeletePerMeshAttribute(*srcMesh,isoPHandle); - - isoPHandle=tri::Allocator::AddPerMeshAttribute(*trgMesh,"isoparametrization"); - isoPHandle().AbsMesh()=abs_mesh; - isoPHandle().SetParamMesh(trgMesh,para_mesh); - - return true; - } - } - return false; -} - -MeshFilterInterface::FilterClass FilterIsoParametrization::getClass(QAction *a) -{ - switch(ID(a)) - { - case ISOP_PARAM : return MeshFilterInterface::Remeshing; - case ISOP_REMESHING : return MeshFilterInterface::Remeshing; - case ISOP_DIAMPARAM : return MeshFilterInterface::Remeshing; - default: return MeshFilterInterface::Remeshing; - } -} - -int FilterIsoParametrization::postCondition( QAction* /*filter*/ ) const -{ - return MeshModel::MM_UNKNOWN; -} - -Q_EXPORT_PLUGIN(FilterIsoParametrization) +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2006 \/)\/ * +* 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. * +* * +****************************************************************************/ + +#include +#include +#include "defines.h" + +#include "../../common/meshmodel.h" +#include +#include + + +#include +#include + +using namespace std; +using namespace vcg; + +FilterIsoParametrization::FilterIsoParametrization() +{ + typeList << ISOP_PARAM + << ISOP_REMESHING + << ISOP_DIAMPARAM + << ISOP_LOAD + << ISOP_SAVE + << ISOP_TRANSFER; + + FilterIDType tt; + foreach(tt , types()) + actionList << new QAction(filterName(tt), this); + +} + +FilterIsoParametrization::~FilterIsoParametrization() +{ + for (int i = 0; i < actionList.count() ; i++ ) + delete actionList.at(i); +} + +QString FilterIsoParametrization::filterName(FilterIDType filter) const +{ + switch(filter) + { + case ISOP_PARAM : return "Iso Parametrization"; + case ISOP_REMESHING : return "Iso Parametrization Remeshing"; + case ISOP_DIAMPARAM : return "Iso Parametrization Build Atlased Mesh"; + case ISOP_LOAD : return "Iso Parametrization Load Abstract Domain"; + case ISOP_SAVE : return "Iso Parametrization Save Abstract Domain"; + case ISOP_TRANSFER: return "Iso Parametrization transfer between meshes"; + default: assert(0); + } + return QString("error!"); +} + +QString FilterIsoParametrization::filterInfo(FilterIDType filterId) const +{ + switch(filterId) + { + case ISOP_PARAM : return "The filter build the abstract Isoparameterization of a two-manifold triangular mesh
" + "An adaptively chosen abstract domain of the parameterization is built. For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + case ISOP_REMESHING : return "Remeshing based on an Abstract Isoparameterization, each triangle of the domain is recursively subdivided.
" + "For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + case ISOP_DIAMPARAM : return "The filter build a new mesh with a standard atlased per wedge texture. The atlas is simply done by " + "splitting each triangle of the abstract domain
" + "For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + case ISOP_LOAD : return "Load the Isoparameterization from a saved Abstract Mesh
" + "For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + case ISOP_SAVE : return "Save the Isoparameterization on an Abstract Mesh
" + "For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + case ISOP_TRANSFER:return "Transfer the Isoparametrization between two meshes, the two meshes must be reasonably similar and well aligned." + " It is useful to transfer back an isoparam onto the original mesh after having computed it on a dummy, clean watertight model.
" + "For more details see:
" + "Pietroni, Tarini and Cignoni, 'Almost isometric mesh parameterization through abstract domains'
" + "IEEE Transaction of Visualization and Computer Graphics 2010"; + default: assert(0); + } + return QString("error!"); +} + +int FilterIsoParametrization::getRequirements(QAction *action) +{ + (void) action; + /*switch(ID(action)) + { + case CP_SCATTER_PER_MESH : return MeshModel::MM_COLOR; + default : return MeshModel::MM_VERTCOLOR; + }*/ + return MeshModel::MM_UNKNOWN; +} + +void FilterIsoParametrization::initParameterSet(QAction *a, MeshDocument& md, RichParameterSet & par) +{ + + switch(ID(a)) + { + case ISOP_PARAM: + { + par.addParam(new RichInt("targetAbstractMinFaceNum",140,"Abstract Min Mesh Size", + "This number and the following one indicate the range face number of the abstract mesh that is used for the parametrization process.
" + "The algorithm will choose the best abstract mesh with the number of triangles within the specified interval.
" + "If the mesh has a very simple structure this range can be very low and strict;" + "for a roughly spherical object if you can specify a range of [8,8] faces you get a octahedral abstract mesh, e.g. a geometry image.
" + "Large numbers (greater than 400) are usually not of practical use.")); + par.addParam(new RichInt("targetAbstractMaxFaceNum",180,"Abstract Max Mesh Size", "Please notice that a large interval requires huge amount of memory to be allocated, in order save the intermediate results.
" + "An interval of 40 should be fine.")); + QStringList stopCriteriaList; + stopCriteriaList.push_back("Best Heuristic"); + stopCriteriaList.push_back("Area + Angle"); + stopCriteriaList.push_back("Regularity"); + stopCriteriaList.push_back("L2"); + + par.addParam(new RichEnum("stopCriteria", 1, stopCriteriaList, tr("Optimization Criteria"), + tr(//"

" + "Choose a metric to stop the parametrization within the interval
" + "1: Best Heuristic : stop considering both isometry and number of faces of base domain
" + "2: Area + Angle : stop at minimum area and angle distorsion
" + "3: Regularity : stop at minimum number of irregular vertices
" + "4: L2 : stop at minimum OneWay L2 Stretch Eff"))); + + par.addParam(new RichInt("convergenceSpeed",1, "Convergence Precision", "This parameter controls the convergence speed/precision of the optimization of the texture coordinates. Larger the number slower the processing and ,eventually, slighly better results")); + par.addParam(new RichBool("DoubleStep",true,"Double Step","Use this bool to divide the parameterization in 2 steps. Double step makes the overall process faster and robust." + "
Consider to disable this bool in case the object has topologycal noise or small handles.")); + break; + } + case ISOP_REMESHING : + { + par.addParam(new RichInt("SamplingRate",10,"Sampling Rate", "This specify the sampling rate for remeshing.")); + break; + } + case ISOP_DIAMPARAM : + { + par.addParam(new RichDynamicFloat("BorderSize",0.1f,0.01f,0.5f,"BorderSize ratio", + "This parameter controls the amount of space that must be left between each diamond when building the atlas." + "It directly affects how many triangle are splitted during this conversion.
" + "In abstract parametrization mesh triangles can naturally cross the triangles of the abstract domain, so when converting " + "to a standard parametrization we must cut all the triangles that protrudes outside each diamond more than the specified threshold." + "The unit of the threshold is in percentage of the size of the diamond," + "The bigger the threshold the less triangles are splitted, but the more UV space is used (wasted).")); + break; + } + case ISOP_LOAD : + { + QFileInfo fi(md.mm()->fullName()); + QString fileName = fi.baseName(); + + fileName = fileName.append(".abs"); + par.addParam(new RichString("AbsName", fileName, "Abstract Mesh file", "The filename of the abstract mesh that has to be loaded")); + break; + } + case ISOP_SAVE : + { + QFileInfo fi(md.mm()->fullName()); + QString fileName = fi.baseName(); + + fileName = fileName.append(".abs"); + par.addParam(new RichString("AbsName", fileName, "Abstract Mesh file", "The filename where the abstract mesh has to be saved")); + break; + } + case ISOP_TRANSFER: + { + par.addParam(new RichMesh ("sourceMesh",md.mm(),&md, "Source Mesh", "The mesh already having an Isoparameterization")); + par.addParam(new RichMesh ("targetMesh",md.mm(),&md, "Target Mesh", "The mesh to be Isoparameterized")); + } + } +} + +void FilterIsoParametrization::PrintStats(CMeshO *mesh) +{ + tri::UpdateTopology::FaceFace(*mesh); + tri::UpdateTopology::VertexFace(*mesh); + int non_reg=NumRegular(*mesh); + float minE,maxE,avE,stdE; + float minAr,maxAr,avAr,stdAr; + float minAn,maxAn,avAn,stdAn; + int minEi,maxEi,stdEi; + int minAri,maxAri,stdAri; + int minAni,maxAni,stdAni; + + StatEdge(*mesh,minE,maxE,avE,stdE); + StatArea(*mesh,minAr,maxAr,avAr,stdAr); + StatAngle(*mesh,minAn,maxAn,avAn,stdAn); + minE/=avE; + minE*=100.f; + maxE/=avE; + maxE*=100.f; + stdE/=avE; + stdE*=100.f; + + minAn/=avAn; + minAn*=100.f; + maxAn/=avAn; + maxAn*=100.f; + stdAn/=avAn; + stdAn*=100.f; + + minAr/=avAr; + minAr*=100.f; + maxAr/=avAr; + maxAr*=100.f; + stdAr/=avAr; + stdAr*=100.f; + + minEi=(int)minE; + maxEi=(int)maxE; + stdEi=(int)stdE; + + minAni=(int)minAn; + maxAni=(int)maxAn; + stdAni=(int)stdAn; + + minAri=(int)minAr; + maxAri=(int)maxAr; + stdAri=(int)stdAr; + + Log(" REMESHED "); + Log("Irregular Vertices:%d ",non_reg); + Log("stdDev Area:%d",stdAri); + Log("stdDev Angle:%d",stdAni); + Log("stdDev Edge:%d",stdEi); +} + +bool FilterIsoParametrization::applyFilter(QAction *filter, MeshDocument& md, RichParameterSet & par, vcg::CallBackPos *cb) +{ + MeshModel* m = md.mm(); //get current mesh from document + CMeshO *mesh=&m->cm; + switch(ID(filter)) + { + case ISOP_PARAM : + { + int targetAbstractMinFaceNum = par.getInt("targetAbstractMinFaceNum"); + int targetAbstractMaxFaceNum = par.getInt("targetAbstractMaxFaceNum"); + int convergenceSpeed = par.getInt("convergenceSpeed"); + int stopCriteria=par.getEnum("stopCriteria"); + bool doublestep=par.getBool("DoubleStep"); + IsoParametrizator Parametrizator; + + m->updateDataMask(MeshModel::MM_FACEFACETOPO); + m->updateDataMask(MeshModel::MM_VERTQUALITY); // needed to store patch index + + bool isTXTenabled=m->hasDataMask(MeshModel::MM_VERTTEXCOORD); + if (!isTXTenabled) + m->updateDataMask(MeshModel::MM_VERTTEXCOORD); + + bool isVMarkenabled=m->hasDataMask(MeshModel::MM_VERTMARK); + if (!isVMarkenabled) + m->updateDataMask(MeshModel::MM_VERTMARK); + + bool isFMarkenabled=m->hasDataMask(MeshModel::MM_FACEMARK); + if (!isFMarkenabled) + m->updateDataMask(MeshModel::MM_FACEMARK); + + bool isVColorenabled=m->hasDataMask(MeshModel::MM_VERTCOLOR); + if (!isVColorenabled) + m->updateDataMask(MeshModel::MM_VERTCOLOR); + + bool isFColorenabled=m->hasDataMask(MeshModel::MM_FACECOLOR); + if (!isFColorenabled) + m->updateDataMask(MeshModel::MM_FACECOLOR); + int tolerance = targetAbstractMaxFaceNum-targetAbstractMinFaceNum; + switch (stopCriteria) + { + case 0:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; + case 1:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Corr,convergenceSpeed);break; + case 2:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Reg,convergenceSpeed);break; + case 3:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_L2,convergenceSpeed);break; + default:Parametrizator.SetParameters(cb,targetAbstractMinFaceNum,tolerance,IsoParametrizator::SM_Euristic,convergenceSpeed);break; + } + IsoParametrizator::ReturnCode ret=Parametrizator.Parametrize(mesh,doublestep); + + if (ret==IsoParametrizator::Done) + { + Parametrizator.PrintAttributes(); + float aggregate,L2; + int n_faces; + Parametrizator.getValues(aggregate,L2,n_faces); + Log("Num Faces of Abstract Domain: %d, One way stretch efficiency: %.4f, Area+Angle Distorsion %.4f ",n_faces,L2,aggregate*100.f); + } + else + { + if (!isTXTenabled) m->clearDataMask(MeshModel::MM_VERTTEXCOORD); + if (!isFMarkenabled) m->clearDataMask(MeshModel::MM_FACEMARK); + if (!isVMarkenabled) m->clearDataMask(MeshModel::MM_VERTMARK); + if (!isVColorenabled) m->clearDataMask(MeshModel::MM_VERTCOLOR); + if (!isFColorenabled) m->clearDataMask(MeshModel::MM_FACECOLOR); + switch(ret) + { + case IsoParametrizator::MultiComponent: + this->errorMessage="non possible parameterization because of multi componet mesh"; return false; + case IsoParametrizator::NonSizeCons: + this->errorMessage="non possible parameterization because of non size consistent mesh"; return false; + case IsoParametrizator::NonManifoldE: + this->errorMessage="non possible parameterization because of non manifold edges"; return false; + case IsoParametrizator::NonManifoldV: + this->errorMessage="non possible parameterization because of non manifold vertices";return false; + case IsoParametrizator::NonWatertigh: + this->errorMessage="non possible parameterization because of non watertight mesh"; return false; + case IsoParametrizator::FailParam: + this->errorMessage="non possible parameterization cause one of the following reasons:\n Topologycal noise \n Too Low resolution mesh \n Too Bad triangulation \n"; return false; + default: + this->errorMessage="unknown error"; return false; + } + } + // At this point we are sure that everithing went ok so we can allocate surely the abstract + AbstractMesh *abs_mesh = new AbstractMesh(); + ParamMesh *para_mesh = new ParamMesh(); + Parametrizator.ExportMeshes(*para_mesh,*abs_mesh); + CMeshO::PerMeshAttributeHandle isoPHandle; + isoPHandle=tri::Allocator::AddPerMeshAttribute(*mesh,"isoparametrization"); + + bool isOK=isoPHandle().Init(abs_mesh,para_mesh); + + ///copy back to original mesh + isoPHandle().CopyParametrization(mesh); + + if (!isOK) + { + this->errorMessage="Problems gathering parameterization \n"; + return false; + } + if (!isVMarkenabled) + m->clearDataMask(MeshModel::MM_VERTMARK); + if (!isFMarkenabled) + m->clearDataMask(MeshModel::MM_FACEMARK); + return true; + } + case ISOP_REMESHING : + { + CMeshO::PerMeshAttributeHandle isoPHandle = + tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); + + bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); + if (!b) + { + this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; + return false; + } + + + int SamplingRate=par.getInt("SamplingRate"); + if (!SamplingRate>2) + { + this->errorMessage="Sampling rate must be >1"; + return false; + } + MeshModel* mm=md.addNewMesh("","Re-meshed"); + + CMeshO *rem=&mm->cm; + DiamSampler DiamSampl; + DiamSampl.Init(&isoPHandle()); + bool done=DiamSampl.SamplePos(SamplingRate); + assert(done); + DiamSampl.GetMesh(*rem); + + int n_diamonds,inFace,inEdge,inStar,n_merged; + DiamSampl.getResData(n_diamonds,inFace,inEdge,inStar,n_merged); + + Log("INTERPOLATION DOMAINS"); + Log("In Face: %d \n",inFace); + Log("In Diamond: %d \n",inEdge); + Log("In Star: %d \n",inStar); + Log("Merged %d vertices\n",n_merged); + mm->updateDataMask(MeshModel::MM_FACEFACETOPO); + mm->updateDataMask(MeshModel::MM_VERTFACETOPO); + PrintStats(rem); + tri::UpdateNormals::PerFace(*rem); + return true; + } + case ISOP_DIAMPARAM : + { + CMeshO::PerMeshAttributeHandle isoPHandle = + tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); + bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); + if (!b) + { + this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; + return false; + } + + float border_size=par.getDynamicFloat("BorderSize"); + MeshModel* mm=md.addNewMesh("","Diam-Parameterized"); + mm->updateDataMask(MeshModel::MM_WEDGTEXCOORD); + mm->updateDataMask(MeshModel::MM_VERTCOLOR); + CMeshO *rem=&mm->cm; + DiamondParametrizator DiaPara; + DiaPara.Init(&isoPHandle()); + DiaPara.SetCoordinates(*rem,border_size); + tri::UpdateNormals::PerFace(*rem); + return true; + } + case ISOP_LOAD : + { + QString AbsName = par.getString("AbsName"); + m->updateDataMask(MeshModel::MM_WEDGTEXCOORD); + m->updateDataMask(MeshModel::MM_VERTTEXCOORD); + m->updateDataMask(MeshModel::MM_FACECOLOR); + m->updateDataMask(MeshModel::MM_VERTQUALITY); + m->updateDataMask(MeshModel::MM_FACEMARK); + if(!QFile(m->fullName()).exists()) + { + this->errorMessage="File not exists"; + return false; + } + CMeshO::PerMeshAttributeHandle isoPHandle = + tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); + + bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); + if (!b) + isoPHandle=tri::Allocator::AddPerMeshAttribute(*mesh,"isoparametrization"); + + QByteArray ba = AbsName.toLatin1(); + char *path=ba.data(); + AbstractMesh *abs_mesh = new AbstractMesh(); + ParamMesh *para_mesh = new ParamMesh(); + bool Done=isoPHandle().LoadBaseDomain(path,mesh,para_mesh,abs_mesh,true); + if (!Done) + { + this->errorMessage="Abstract domain doesnt fit well with the parametrized mesh"; + delete para_mesh; + delete abs_mesh; + return false; + } + return true; + } + case ISOP_SAVE : + { + m->updateDataMask(MeshModel::MM_VERTQUALITY); + CMeshO::PerMeshAttributeHandle isoPHandle = + tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); + + bool b=tri::Allocator::IsValidHandle(*mesh,isoPHandle); + if (!b) + { + this->errorMessage="You must compute the Base domain before remeshing. Use the Isoparametrization command."; + return false; + } + /*QString Qpath=m->fullName();*/ + + QString AbsName = par.getString("AbsName"); + + QByteArray ba = AbsName.toLatin1(); + char *path=ba.data(); + isoPHandle().SaveBaseDomain(path); + return true; + } + case ISOP_TRANSFER: + { + MeshModel *mmtrg = par.getMesh("targetMesh"); + MeshModel *mmsrc = par.getMesh("targetMesh"); + CMeshO *trgMesh=&mmtrg->cm; + CMeshO *srcMesh=&mmsrc->cm; + + CMeshO::PerMeshAttributeHandle isoPHandle = + tri::Allocator::GetPerMeshAttribute(*mesh,"isoparametrization"); + + bool b=tri::Allocator::IsValidHandle(*srcMesh,isoPHandle); + if (!b) + { + this->errorMessage="Your source mesh must have the abstract isoparametrization. Use the Isoparametrization command."; + return false; + } + IsoTransfer IsoTr; + AbstractMesh *abs_mesh = isoPHandle().AbsMesh(); + ParamMesh *para_mesh = isoPHandle().ParaMesh(); + + mmtrg->updateDataMask(MeshModel::MM_WEDGTEXCOORD); + mmtrg->updateDataMask(MeshModel::MM_VERTTEXCOORD); + mmtrg->updateDataMask(MeshModel::MM_FACECOLOR); + mmtrg->updateDataMask(MeshModel::MM_VERTQUALITY); + mmtrg->updateDataMask(MeshModel::MM_FACEMARK); + IsoTr.Transfer(isoPHandle(),*trgMesh); + + isoPHandle().Clear(); + tri::Allocator::DeletePerMeshAttribute(*srcMesh,isoPHandle); + + isoPHandle=tri::Allocator::AddPerMeshAttribute(*trgMesh,"isoparametrization"); + isoPHandle().AbsMesh()=abs_mesh; + isoPHandle().SetParamMesh(trgMesh,para_mesh); + + return true; + } + } + return false; +} + +MeshFilterInterface::FilterClass FilterIsoParametrization::getClass(QAction *a) +{ + switch(ID(a)) + { + case ISOP_PARAM : return MeshFilterInterface::Remeshing; + case ISOP_REMESHING : return MeshFilterInterface::Remeshing; + case ISOP_DIAMPARAM : return MeshFilterInterface::Remeshing; + default: return MeshFilterInterface::Remeshing; + } +} + +int FilterIsoParametrization::postCondition( QAction* /*filter*/ ) const +{ + return MeshModel::MM_UNKNOWN; +} + +Q_EXPORT_PLUGIN(FilterIsoParametrization) diff --git a/src/meshlabplugins/filter_isoparametrization/iso_parametrization.h b/src/meshlabplugins/filter_isoparametrization/iso_parametrization.h index 48683ec24..bd6707c78 100644 --- a/src/meshlabplugins/filter_isoparametrization/iso_parametrization.h +++ b/src/meshlabplugins/filter_isoparametrization/iso_parametrization.h @@ -1,2015 +1,2015 @@ -#ifndef TRI_PARAMETRIZATION -#define TRI_PARAMETRIZATION - -// stuff to define the mesh - #include -#include -#include -#include -#include -#include "local_parametrization.h" -#include "uv_grid.h" -#include -#include "param_mesh.h" - -///ABSTRACT MESH THAT MAINTAINS THE WHOLE PARAMETERIZATION -class AbstractVertex; -class AbstractFace; - -class AbstractUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, - vcg::Use::AsFaceType >{}; - - -class AbstractVertex : public vcg::Vertex< AbstractUsedTypes, - vcg::vertex::VFAdj, - vcg::vertex::Coord3f, - vcg::vertex::TexCoord2f, - vcg::vertex::BitFlags> - //vcg::face::Normal3f> -{ -public: - CoordType RPos; - - template < class LeftV> - void ImportData(const LeftV & left ) - { - vcg::Vertex< AbstractUsedTypes, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::TexCoord2f,vcg::vertex::BitFlags>::ImportData( left); - this->RPos = left.RPos; - } -}; - -class AbstractFace : public vcg::Face < AbstractUsedTypes, - vcg::face::VFAdj, - vcg::face::FFAdj, - vcg::face::VertexRef, - vcg::face::Color4b, - vcg::face::BitFlags> -//vcg::face::Normal3f> -{}; - -class AbstractMesh: public vcg::tri::TriMesh, std::vector > { -//public: -// static const bool Has_Auxiliary(){return false;} -}; - -///HIGH RESOLUTION MESH THAT HAS TO BE PARAMETERIZED -class ParamVertex; -class ParamFace; - - -class ParamUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, - vcg::Use::AsFaceType >{}; - - -class ParamVertex: public vcg::Vertex< ParamUsedTypes, - vcg::vertex::Normal3f, vcg::vertex::VFAdj, - vcg::vertex::Coord3f,vcg::vertex::Color4b, - vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, - vcg::vertex::CurvatureDirf, - vcg::vertex::Qualityf> -{ -public: - template < class LeftV> - void ImportData(const LeftV & left ) - { - vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); - } - - - void ImportData(const ParamVertex & left ) - { - vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); - this->RPos = left.RPos; - } - - void ImportData(const BaseVertex & left ) - { - vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); - this->RPos = left.RPos; - } - - CoordType RPos; - static const bool Has_Auxiliary(){return false;} -}; - -class ParamFace: public vcg::Face < ParamUsedTypes, - vcg::face::VFAdj,vcg::face::FFAdj,vcg::face::VertexRef, - vcg::face::Color4b,vcg::face::BitFlags, - vcg::face::Normal3f, - vcg::face::WedgeTexCoord2f, - vcg::face::Mark, - vcg::face::EdgePlane - //, - //vcg::face::Qualityf // not really needed - > -{ -public: - /*template < class LeftV> - void ImportData(const LeftV & left ) - { - vcg::FaceSimp2 < ParamVertex, ParamEdge, ParamFace, - vcg::face::VFAdj,vcg::face::FFAdj,vcg::face::VertexRef, - vcg::face::Color4b,vcg::face::BitFlags, - vcg::face::WedgeTexCoord2f,vcg::face::Normal3f, - vcg::face::Qualityf>::ImportData( left); - }*/ -}; -class ParamMesh: public vcg::tri::TriMesh, std::vector > -{ -//public: - //static const bool Has_Auxiliary(){return false;} -}; - -template -void CopyMeshFromFacesAbs(const std::vector &faces, - std::vector &orderedVertex, - MeshType & new_mesh) -{ - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - - ///get set of faces - std::map vertexmap; - std::vector vertices; - FindVertices(faces,vertices); - - ///initialization of new mesh - new_mesh.Clear(); - new_mesh.vn=0; - new_mesh.fn=0; - new_mesh.face.resize(faces.size()); - new_mesh.vert.resize(vertices.size()); - new_mesh.vn=vertices.size(); - new_mesh.fn=faces.size(); - - ///add new vertices - typename std::vector::const_iterator iteV; - int i=0; - for (iteV=vertices.begin();iteV!=vertices.end();iteV++) - { - ///copy position - assert(!(*iteV)->IsD()); - new_mesh.vert[i].P()=(*iteV)->P(); - new_mesh.vert[i].RPos=(*iteV)->RPos; - new_mesh.vert[i].T().P()=(*iteV)->T().P(); - new_mesh.vert[i].T().N()=(*iteV)->T().N(); - //new_mesh.vert[i].N()=(*iteV)->N(); - ///*assert(new_mesh.vert[i].brother!=NULL);*/ - ////if (MeshType::Has_Auxiliary()) - //new_mesh.vert[i].brother=(*iteV)->brother; - new_mesh.vert[i].ClearFlags(); - - orderedVertex.push_back((*iteV)); - vertexmap.insert(std::pair((*iteV),&new_mesh.vert[i])); - i++; - } - - ///setting of new faces - typename std::vector::const_iterator iteF; - typename std::vector::iterator iteF1; - for (iteF=faces.begin(),iteF1=new_mesh.face.begin() - ;iteF!=faces.end();iteF++,iteF1++) - { - //(*iteF1).areadelta=(*iteF)->areadelta; - /* if ((*iteF1).areadelta>1) - assert(0);*/ - ///for each vertex get new reference - ///and associate face-vertex - for (int j=0;j<3;j++) - { - VertexType* v=(*iteF)->V(j); - typename std::map::iterator iteMap=vertexmap.find(v); - assert(iteMap!=vertexmap.end()); - (*iteF1).V(j)=(*iteMap).second; - } - } -} - -///create a mesh considering just the faces that share all three vertex -template -void CopyMeshFromVerticesAbs(std::vector &vertices, - std::vector &OrderedVertices, - std::vector &OrderedFaces, - MeshType & new_mesh) -{ - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - - typename std::vector::const_iterator iteV; - for (iteV=vertices.begin();iteV!=vertices.end();iteV++) - (*iteV)->ClearV(); - - - - OrderedVertices.clear(); - - ///vertex-vertex reference - std::map vertexmap; - - ///get set of faces - std::vector faces; - - getSharedFace(vertices,faces); - - ///initialization of new mesh - new_mesh.Clear(); - new_mesh.vn=0; - new_mesh.fn=0; - - ///set vertices as selected - - for (iteV=vertices.begin();iteV!=vertices.end();iteV++) - (*iteV)->SetV(); - - ///getting inside faces - typename std::vector::const_iterator iteF; - for (iteF=faces.begin();iteF!=faces.end();iteF++) - { - ///for each vertex get new reference - ///if there isn't one reference means the face does not appartain to group - VertexType* v0=(*iteF)->V(0); - VertexType* v1=(*iteF)->V(1); - VertexType* v2=(*iteF)->V(2); - bool inside=((*v0).IsV()&&(*v1).IsV()&&(*v2).IsV()); - if (inside) - OrderedFaces.push_back((*iteF)); - } - - ///find internal vertices - FindVertices(OrderedFaces,OrderedVertices); - - ///setting size - new_mesh.face.resize(OrderedFaces.size()); - new_mesh.vert.resize(OrderedVertices.size()); - new_mesh.vn=OrderedVertices.size(); - new_mesh.fn=OrderedFaces.size(); - - ///setting of internal vertices - int i=0; - typename std::vector::iterator iteVI; - for (iteVI=OrderedVertices.begin();iteVI!=OrderedVertices.end();iteVI++) - { - ///copy position - assert(!(*iteVI)->IsD()); - new_mesh.vert[i].P()=(*iteVI)->P(); - new_mesh.vert[i].RPos=(*iteVI)->RPos; - new_mesh.vert[i].T().P()=(*iteVI)->T().P(); - new_mesh.vert[i].T().N()=(*iteVI)->T().N(); - new_mesh.vert[i].C()=(*iteVI)->C(); - /*new_mesh.vert[i].father=(*iteVI)->father; - new_mesh.vert[i].Bary=(*iteVI)->Bary;*/ - //new_mesh.vert[i].Damp=(*iteVI)->Damp; - /*new_mesh.vert[i].RestUV=(*iteVI)->RestUV;*/ - //new_mesh.vert[i].N()=(*iteVI)->N(); - //new_mesh.vert[i].C()=(*iteVI)->C(); - /*new_mesh.vert[i].OriginalCol=(*iteVI)->OriginalCol;*/ - new_mesh.vert[i].ClearFlags(); - ///map setting - vertexmap.insert(std::pair((*iteVI),&new_mesh.vert[i])); - i++; - } - - ///setting of new faces - typename std::vector::iterator iteF1; - for (iteF=OrderedFaces.begin(),iteF1=new_mesh.face.begin() - ;iteF!=OrderedFaces.end();iteF++,iteF1++) - { - ///for each vertex get new reference - ///and associate face-vertex - for (int j=0;j<3;j++) - { - VertexType* v=(*iteF)->V(j); - typename std::map::iterator iteMap=vertexmap.find(v); - assert(iteMap!=vertexmap.end()); - (*iteF1).V(j)=(*iteMap).second; - } - } - - ///clear flags - for (iteV=vertices.begin();iteV!=vertices.end();iteV++) - (*iteV)->ClearV(); - -} - - - - -//template -//static int Parametrize(InputMesh &to_param, -// AbstractMesh &AbsMesh, -// InputMesh &Parametrized, -// int &approx_face_num) -//{ -// vcg::tri::UpdateTopology::FaceFace(to_param); -// -// ///test input conditions -// bool b=vcg::tri::Clean::IsTwoManifoldFace(to_param); -// b&=vcg::tri::Clean::IsTwoManifoldVertexFF(to_param); -// int n=vcg::tri::Clean::BorderEdges(to_param); -// b&=(n==0); -// int num=vcg::tri::Clean::ConnectedComponents(to_param); -// b&=(num==1); -// if (!b) -// return -1; -// -// ///then parameteterize -// IsoParametrizator TrImage; -// TrImage.Parametrize(&mesh,num1,num2); -// TrImage.ExportMeshes(to_param,AbsMesh); -// return 0; -//} - -///class that maintains the whole meh parametrerization with relitive operators -class IsoParametrization -{ - AbstractMesh * abstract_mesh; - ParamMesh * param_mesh; - -public: - typedef ParamMesh::ScalarType ScalarType; - typedef ParamMesh::CoordType CoordType; - -private: - - ///this class maintains submeshes and hresolution meshes - ///for the selected parametrization domain - struct param_domain{ - AbstractMesh *domain; - std::vector local_to_global; - - ParamMesh *HresDomain; - UVGrid grid; - std::vector ordered_faces; - - int Local2Global(const int &localFace) - {return local_to_global[localFace];} - - int Global2Local(const int &GlobalFace) - { - int ret=-1; - for (unsigned int i=0;i UV, - std::vector &face, - std::vector &baryVal) - { - std::vector faceParam; - bool found=grid.ProjectPoint(UV,faceParam,baryVal); - if (!found) - return false; - ///calculate the index corresponding to the face - for (unsigned int i=0;iface.begin()); - assert(indexfn); - face.push_back(ordered_faces[index]); - } - return true; - } - - bool getClosest(vcg::Point2 UV, - std::vector &face, - std::vector &baryVal) - { - face.resize(1); - baryVal.resize(1); - bool found=grid.getClosest(UV,face[0],baryVal[0]); - int index=face[0]-&(*HresDomain->face.begin()); - assert(indexfn); - face[0]=ordered_faces[index]; - return found; - } - }; - - ///summeshes and subdomains - std::vector star_meshes; - std::vector diamond_meshes; - std::vector face_meshes; - - typedef std::pair keyEdgeType; - std::map EdgeTab; - - ///temporary structure for face_to_vert adjacency - std::vector > face_to_vert; - - void InitFaceToVert() - { - face_to_vert.resize(abstract_mesh->face.size()); - for (unsigned int i=0;ivert.size();i++) - { - int I=param_mesh->vert[i].T().N(); - face_to_vert[I].push_back(¶m_mesh->vert[i]); - } - } - - - void GetHresVert(int &I,std::vector &HresVert) - { - for (unsigned int k=0;kvert.size();i++) - { - if (!(abstract_mesh->vert[i].IsD())) - { - std::vector starCenter; - starCenter.push_back(&abstract_mesh->vert[i]); - - star_meshes[index].domain=new AbstractMesh(); - star_meshes[index].HresDomain=new ParamMesh(); - - ///create star - std::vector ordered_faces; - std::vector ordered_vert; - //CreateMeshVertexStar(starCenter,ordered_faces,*star_meshes[index].domain); - ///get faces referenced by vertices - getSharedFace(starCenter,ordered_faces); - - CopyMeshFromFacesAbs(ordered_faces,ordered_vert,*star_meshes[index].domain); - - UpdateTopologies(star_meshes[index].domain); - - ///and parametrize it - ParametrizeStarEquilateral(*star_meshes[index].domain,1.0); - - ///set other components as reefrence to original faces - star_meshes[index].local_to_global.resize(star_meshes[index].domain->face.size()); - std::vector HresVert; - for (unsigned int k=0;kface.size();k++) - { - int IndexF; - getFaceIndexFromPointer(ordered_faces[k],IndexF); - star_meshes[index].local_to_global[k]=IndexF; - ///get H res vertex - GetHresVert(IndexF,HresVert); - } - - ///copy Hres mesh - std::vector OrderedVertices; - CopyMeshFromVerticesAbs(HresVert,OrderedVertices,star_meshes[index].ordered_faces,*star_meshes[index].HresDomain); - ///set new parametrization values - for (unsigned int k=0;kvert.size();k++) - { - ParamVertex * v=&star_meshes[index].HresDomain->vert[k]; - CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); - AbstractMesh *paramDomain=star_meshes[index].domain; - ///get the right face on the parametrized domain - int Father=v->T().N(); - int faceNum=-1; - for (unsigned int i=0;iface[faceNum]; - v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); - assert(faceNum!=-1); - } - star_meshes[index].InitGrid(); - index++; - - } - } - } - - - - void InitDiamond(const ScalarType &edge_len=1.0) - { - - ///for each face - int index=0; - EdgeTab.clear(); - for (unsigned int i=0;iface.size();i++) - { - if (!(abstract_mesh->face[i].IsD())) - { - AbstractFace *f0=&abstract_mesh->face[i]; - //for each edge - for (int j=0;j<3;j++) - { - AbstractFace * f1=f0->FFp(j); - if (f1>f0) - { - - int num0=j; - int num1=f0->FFi(j); - - ///add to domain map - AbstractVertex *v0,*v1; - v0=f0->V(j); - v1=f0->V1(j); - keyEdgeType k; - if (v0 entry=std::pair(k,index); - EdgeTab.insert(entry); - - - - ///copy the mesh - std::vector faces; - faces.push_back(f0); - faces.push_back(f1); - - diamond_meshes[index].domain=new AbstractMesh(); - diamond_meshes[index].HresDomain=new ParamMesh(); - - ///create a copy of the mesh - std::vector orderedVertex; - CopyMeshFromFacesAbs(faces,orderedVertex,*diamond_meshes[index].domain); - UpdateTopologies(diamond_meshes[index].domain); - - ///set other components - int index0,index1; - getFaceIndexFromPointer(f0,index0); - getFaceIndexFromPointer(f1,index1); - diamond_meshes[index].local_to_global.resize(2); - diamond_meshes[index].local_to_global[0]=index0; - diamond_meshes[index].local_to_global[1]=index1; - - ///parametrize locally - ParametrizeDiamondEquilateral(*diamond_meshes[index].domain,num0,num1,edge_len); - ///add h resolution vertices - std::vector HresVert; - GetHresVert(index0,HresVert); - GetHresVert(index1,HresVert); - std::vector OrderedVertices; - CopyMeshFromVerticesAbs(HresVert,OrderedVertices,diamond_meshes[index].ordered_faces,*diamond_meshes[index].HresDomain); - ///set new parametrization values - for (unsigned int k=0;kvert.size();k++) - { - ParamVertex * v=&diamond_meshes[index].HresDomain->vert[k]; - CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); - AbstractMesh *paramDomain=diamond_meshes[index].domain; - ///get the rigth face on the parametrized domain - int Father=v->T().N(); - int faceNum=-1; - for (unsigned int i=0;iface[faceNum]; - v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); - - - } - diamond_meshes[index].InitGrid(); - index++; - } - } - } - } - } - - - void InitFace(const ScalarType &edge_len=1) - { - ///for each face - int index=0; - for (unsigned int i=0;iface.size();i++) - { - if (!(abstract_mesh->face[i].IsD())) - { - AbstractFace *f0=&abstract_mesh->face[i]; - - std::vector faces; - faces.push_back(f0); - - ///create the mesh - face_meshes[index].domain=new AbstractMesh(); - face_meshes[index].HresDomain=new ParamMesh(); - - std::vector orderedVertex; - CopyMeshFromFacesAbs(faces,orderedVertex,*face_meshes[index].domain); - - assert(face_meshes[index].domain->vn==3); - assert(face_meshes[index].domain->fn==1); - - ///initialize auxiliary structures - face_meshes[index].local_to_global.resize(1); - face_meshes[index].local_to_global[0]=i; - - ///parametrize it - ParametrizeFaceEquilateral(*face_meshes[index].domain,edge_len); - - ///add h resolution vertices - std::vector HresVert; - GetHresVert(index,HresVert); - std::vector OrderedVertices; - CopyMeshFromVerticesAbs(HresVert,OrderedVertices,face_meshes[index].ordered_faces,*face_meshes[index].HresDomain); - ///set new parametrization values - for (unsigned int k=0;kvert.size();k++) - { - ParamVertex * v=&face_meshes[index].HresDomain->vert[k]; - CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); - AbstractMesh *paramDomain=face_meshes[index].domain; - AbstractFace *faceDom=¶mDomain->face[0]; - v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); - } - - face_meshes[index].InitGrid(); - index++; - } - } - } - - void getFaceIndexFromPointer(AbstractFace * f,int &index) - { - index=f-&(*abstract_mesh->face.begin()); - } - - void getStarFromPointer(AbstractVertex * center,int &index) - { - index=center-&(*abstract_mesh->vert.begin()); - } - - void getDiamondFromPointer(AbstractVertex * v0,AbstractVertex * v1,int &index) - { - assert(v0!=v1); - keyEdgeType key; - if (v0::iterator k=EdgeTab.find(key); - assert(k!=EdgeTab.end()); - index=((*k).second); - } - - - bool Test() - { - /*int index=0;*/ - for (unsigned int i=0;iface.size();i++) - { - if (!(abstract_mesh->face[i].IsD())) - { - AbstractFace *f0=&abstract_mesh->face[i]; - //for each edge - for (int j=0;j<3;j++) - { - AbstractFace * f1=f0->FFp(j); - if (f1>f0) - { - ///add to domain map - AbstractVertex *v0,*v1; - v0=f0->V(j); - v1=f0->V1(j); - keyEdgeType k; - if (v0 entry=std::pair(k,index); - std::map::iterator iteE=EdgeTab.find(k); - - int index0F,index1F; - getFaceIndexFromPointer(f0,index0F); - getFaceIndexFromPointer(f1,index1F); -#ifndef NDEBUG - int edgeIndex=(*iteE).second; - assert(diamond_meshes[edgeIndex].local_to_global[0]==index0F); - assert(diamond_meshes[edgeIndex].local_to_global[1]==index1F); -#endif - } - } - } - } - ///test if for each face there is a right domain - for (unsigned int i=0;iface.size();i++) - { - ParamFace * f=¶m_mesh->face[i]; - vcg::Point2f uvI0,uvI1,uvI2; - int IndexDomain=-1; - int ret=InterpolationSpace(f,uvI0,uvI1,uvI2,IndexDomain); - if (ret==-1) - return false; - } - return true; - } - - int getSharedVertices(AbstractFace *f0,AbstractFace *f1,AbstractFace *f2, - AbstractVertex *shared[3]) - { - AbstractVertex *vert0[3],*vert1[3],*vert2[3]; - - vert0[0]=f0->V(0); - vert0[1]=f0->V(1); - vert0[2]=f0->V(2); - - vert1[0]=f1->V(0); - vert1[1]=f1->V(1); - vert1[2]=f1->V(2); - - vert2[0]=f2->V(0); - vert2[1]=f2->V(1); - vert2[2]=f2->V(2); - - int num=0; - for (int i=0;i<3;i++) - { - AbstractVertex * test=vert0[i]; - bool found0=false,found1=false; - if ((vert1[0]==test)||(vert1[1]==test)||(vert1[2]==test)) - found0=true; - if (found0) - { - if ((vert2[0]==test)||(vert2[1]==test)||(vert2[2]==test)) - found1=true; - } - if ((found0)&&(found1)) - { - shared[num]=test; - num++; - } - } - - return num; - } - - int getSharedVertices(AbstractFace *f0,AbstractFace *f1,AbstractVertex *shared[3]) - { - AbstractVertex *vert0[3],*vert1[3]; - - vert0[0]=f0->V(0); - vert0[1]=f0->V(1); - vert0[2]=f0->V(2); - - vert1[0]=f1->V(0); - vert1[1]=f1->V(1); - vert1[2]=f1->V(2); - - - int num=0; - for (int i=0;i<3;i++) - { - AbstractVertex * test=vert0[i]; - bool found0=false; - if ((vert1[0]==test)||(vert1[1]==test)||(vert1[2]==test)) - found0=true; - if (found0) - { - shared[num]=test; - num++; - } - } - - return num; - } - - int getSharedVertices(const std::vector &I,AbstractVertex *shared[3],int *_num=NULL) - { - ///else test the number of vertices shared - AbstractVertex * shared_vert[3]; - bool sharedB[3]; - int size; - if (_num==NULL) - size=I.size(); - else - size=*_num; - - ///quick test for 2 or 3 cases - if (size==2) - return getSharedVertices(&AbsMesh()->face[I[0]],&AbsMesh()->face[I[1]],shared); - else - if (size==3) - return getSharedVertices(&AbsMesh()->face[I[0]],&AbsMesh()->face[I[1]],&AbsMesh()->face[I[2]],shared); - - AbstractFace* f0=&AbsMesh()->face[I[0]]; - AbstractVertex *v0=f0->V(0); - AbstractVertex *v1=f0->V(1); - AbstractVertex *v2=f0->V(2); - shared_vert[0]=v0; - shared_vert[1]=v1; - shared_vert[2]=v2; - sharedB[0]=true; - sharedB[1]=true; - sharedB[2]=true; - //for each face - for (int i=1;iface[I[i]]; - //for each vertex - for (int j=0;j<3;j++) - { - if (sharedB[j]) - { - AbstractVertex *v_test=shared_vert[j]; - if (!((v_test==f->V(0))||(v_test==f->V(1))||(v_test==f->V(2)))) - sharedB[j]=false; - } - } - } - - ///return vertices correctly - int num=0; - for (int i=0;i<3;i++) - if (sharedB[i]) - { - shared[num]=shared_vert[i]; - num++; - } - return num; - } - - - void Clamp(vcg::Point2f &UV) - { - float eps=0.00001f; - if ((UV.X()-eps)) - UV.X()=0; - if ((UV.X()<1+eps)&&(UV.X()>1-eps)) - UV.X()=1; - if ((UV.Y()-eps)) - UV.Y()=0; - if ((UV.Y()<1+eps)&&(UV.Y()>1-eps)) - UV.Y()=1; - } - - - float Area3d; - float AbstractArea; - -public: - - ///return the minimum interpolation space shared by a face changing coordinates - ///return 0 if is a face 1 is a diamaond and 2 is a star - int InterpolationSpace(ParamFace *f, - vcg::Point2f &uvI0, - vcg::Point2f &uvI1, - vcg::Point2f &uvI2, - int &IndexDomain) - { - ParamVertex *v0=f->V(0); - ParamVertex *v1=f->V(1); - ParamVertex *v2=f->V(2); - - int I0=v0->T().N(); - int I1=v1->T().N(); - int I2=v2->T().N(); - - vcg::Point2f UV0=v0->T().P(); - vcg::Point2f UV1=v1->T().P(); - vcg::Point2f UV2=v2->T().P(); - - ///if they are equal it's is triavially the interpolation of UV coords - ///and the same face I as the domain - if ((I0==I1)&&(I1==I2)) - { - GE2(I0,UV0,uvI0); - GE2(I1,UV1,uvI1); - GE2(I2,UV2,uvI2); - IndexDomain=I0; - return 0; - } - - ///else find the right interpolation domain in which the face belongs - ///test if they share an edge then use half diamond - AbstractFace *f0=&abstract_mesh->face[I0]; - AbstractFace *f1=&abstract_mesh->face[I1]; - AbstractFace *f2=&abstract_mesh->face[I2]; - AbstractVertex *shared[3]; - - int num=getSharedVertices(f0,f1,f2,shared); - if (num<1) - { - return -1; - } - //assert((num==1)||(num==2)); - if (num==2)///ude diamond - { - AbstractVertex* v0=shared[0]; - AbstractVertex* v1=shared[1]; - int EdgeIndex; - - getDiamondFromPointer(v0,v1,EdgeIndex); - - GE1(I0,UV0,EdgeIndex,uvI0); - GE1(I1,UV1,EdgeIndex,uvI1); - GE1(I2,UV2,EdgeIndex,uvI2); - - IndexDomain=EdgeIndex; - return 1; - } - - ///use the star domain - - AbstractVertex* center=shared[0]; - int StarIndex; - getStarFromPointer(center,StarIndex); - bool b0=GE0(I0,UV0,StarIndex,uvI0); - bool b1=GE0(I1,UV1,StarIndex,uvI1); - bool b2=GE0(I2,UV2,StarIndex,uvI2); - IndexDomain=StarIndex; - if ((!b0)||(!b1)||(!b2)) - { - printf("AZZZ 1\n"); - return -1; - } - assert((uvI0.X()>=-1)&&(uvI0.Y()>=-1)&&(uvI0.X()<=1)&&(uvI0.Y()<=1)); - assert((uvI1.X()>=-1)&&(uvI1.Y()>=-1)&&(uvI1.X()<=1)&&(uvI1.Y()<=1)); - assert((uvI2.X()>=-1)&&(uvI2.Y()>=-1)&&(uvI2.X()<=1)&&(uvI2.Y()<=1)); - - - - return 2; - - } - - ///return the minimum interpolation space shared by two faces of abstarct domain - ///return 0 if is a face 1 is a diamaond and 2 is a star - int InterpolationSpace(const int &I0,const int &I1,int &IndexDomain) - { - ///that case is the face itself - if (I0==I1) - { - IndexDomain=I0; - return 0; - } - AbstractFace* f0=&AbsMesh()->face[I0]; - AbstractFace* f1=&AbsMesh()->face[I1]; - /* AbstractVertex *v0=f0->V(0); - AbstractVertex *v1=f0->V(1); - AbstractVertex *v2=f0->V(2); - AbstractVertex *v3=f1->V(0); - AbstractVertex *v4=f1->V(1); - AbstractVertex *v5=f1->V(2);*/ - - - AbstractVertex *shared[3]; - - int num=getSharedVertices(f0,f1,shared); - if (!((num==1)||(num==2))) - return -1; - if (num==2)///use diamond - { - AbstractVertex* v0=shared[0]; - AbstractVertex* v1=shared[1]; - int EdgeIndex; - - getDiamondFromPointer(v0,v1,EdgeIndex); - - IndexDomain=EdgeIndex; - return 1; - } - - ///use the star domain - - AbstractVertex* center=shared[0]; - int StarIndex; - getStarFromPointer(center,StarIndex); - IndexDomain=StarIndex; - - return 2; - - } - - ///return 0 if is a face 1 is a diamaond and 2 is a star - int InterpolationSpace(const std::vector &I,int &IndexDomain,int *_num=NULL) - { - int size; - if (_num==NULL) - size=I.size(); - else - size=*_num; - - ///simple cases - assert(I.size()>0); - ///1 element - if (size==1) - { - IndexDomain=I[0]; - return 0; - } - ///2 elements - if (size==2) - return InterpolationSpace(I[0],I[1],IndexDomain); - - ///test if they all are the same - ///that case is the face itself - bool sameface=true; - int i=1; - int I0=I[0]; - while ((i &UV) - { - int vertStar=2; - CoordType bary=CoordType(UV.X(),UV.Y(),(ScalarType)1.0-UV.X()-UV.Y()); - - if ((bary.X()>bary.Y())&&(bary.X()>bary.Z())) - vertStar=0; - else - if ((bary.Y()>bary.X())&&(bary.Y()>bary.Z())) - vertStar=1; - - AbstractFace *f=&abstract_mesh->face[I]; - AbstractVertex *Center=f->V(vertStar); - - int StarIndex; - getStarFromPointer(Center,StarIndex); - return StarIndex; - } - - int getHDiamIndex(const int &I, - const vcg::Point2 &UV) - { - CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); - ScalarType sum0=bary.X()+bary.Y(); - ScalarType sum1=bary.Y()+bary.Z(); - ScalarType sum2=bary.X()+bary.Z(); - int edge=2; - if ((sum0>sum1)&&(sum0>sum2)) - edge=0; - else - if ((sum1>sum0)&&(sum1>sum2)) - edge=1; - - ///get the half-diamond mesh - int DiamIndex; - getDiamondFromPointer(abstract_mesh->face[I].V(edge),abstract_mesh->face[I].V1(edge),DiamIndex); - return(DiamIndex); - } - - ///give the face and barycentric coordinate return I and UV coordinates - void Phi(const ParamFace *f, - const CoordType &bary3D, - int &I, - vcg::Point2 &UV) - { -#ifndef NDEBUG - float eps=0.00001f; -#endif - ///control right domain - int I0=f->V(0)->T().N(); - int I1=f->V(1)->T().N(); - int I2=f->V(2)->T().N(); - - ///if they are equal it's is triavially the interpolation of UV coords - ///and the same face I as the domain - if ((I0==I1)&&(I1==I2)) - { - UV=bary3D.X()*f->V(0)->T().P()+bary3D.Y()*f->V(1)->T().P()+bary3D.Z()*f->V(2)->T().P(); - Clamp(UV); - assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1)); - I=I0; - return; - } - - - ///else find the right interpolation domain in which the face belongs - ///test if they share an edge then use half diamond - AbstractFace *f0=&abstract_mesh->face[I0]; - AbstractFace *f1=&abstract_mesh->face[I1]; - AbstractFace *f2=&abstract_mesh->face[I2]; - AbstractVertex *shared[3]; - - int num=getSharedVertices(f0,f1,f2,shared); - - /*///if num==1 - if (num==0) - { - float alpha=bary3D.X(); - float beta =bary3D.Y(); - float gamma=bary3D.Z(); -#ifndef _MESHLAB - printf("problems with interpolation, solved..."); -#endif - if ((alpha>beta)&&(alpha>gamma)) - { - I=I0; - UV=f->V(0)->T().P(); - } - else - if ((beta>alpha)&&(beta>gamma)) - { - I=I1; - UV=f->V(1)->T().P(); - } - else - { - I=I2; - UV=f->V(2)->T().P(); - } - - return; - }*/ - - assert((num==1)||(num==2)); - if ((num!=1)&&(num!=2)) - { - printf("DOMAIN %d\n",num); - assert(0); - } - if (num==1)///use the star domain - { - //printf("phi 0\n"); - AbstractVertex* center=shared[0]; - int StarIndex; - getStarFromPointer(center,StarIndex); - vcg::Point2 UVs0,UVs1,UVs2; - vcg::Point2 UV0=f->V(0)->T().P(); - vcg::Point2 UV1=f->V(1)->T().P(); - vcg::Point2 UV2=f->V(2)->T().P(); - - GE0(I0,UV0,StarIndex,UVs0); - GE0(I1,UV1,StarIndex,UVs1); - GE0(I2,UV2,StarIndex,UVs2); - assert((UVs0.X()>=-1)&&(UVs0.Y()>=-1)&&(UVs0.X()<=1)&&(UVs0.Y()<=1)); - assert((UVs1.X()>=-1)&&(UVs1.Y()>=-1)&&(UVs1.X()<=1)&&(UVs1.Y()<=1)); - assert((UVs2.X()>=-1)&&(UVs2.Y()>=-1)&&(UVs2.X()<=1)&&(UVs2.Y()<=1)); - - ///interpolate star value - vcg::Point2 UV_interp=bary3D.X()*UVs0+bary3D.Y()*UVs1+bary3D.Z()*UVs2; - inv_GE0(StarIndex,UV_interp,I,UV); - Clamp(UV); - assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); - return; - } - else ///use the diamond domain - { - //printf("phi 1\n"); - //std::set::iterator it=temp2.begin(); - //std::vector::iterator it=shared[0]; - AbstractVertex* v0=shared[0]; - //it++; - AbstractVertex* v1=shared[1]; - int EdgeIndex; - getDiamondFromPointer(v0,v1,EdgeIndex); - - vcg::Point2 UVd0,UVd1,UVd2; - vcg::Point2 UV0=f->V(0)->T().P(); - vcg::Point2 UV1=f->V(1)->T().P(); - vcg::Point2 UV2=f->V(2)->T().P(); - - GE1(I0,UV0,EdgeIndex,UVd0); - GE1(I1,UV1,EdgeIndex,UVd1); - GE1(I2,UV2,EdgeIndex,UVd2); - - ///interpolate star value - vcg::Point2 UV_interp=bary3D.X()*UVd0+bary3D.Y()*UVd1+bary3D.Z()*UVd2; - inv_GE1(EdgeIndex,UV_interp,I,UV); - Clamp(UV); - assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); - assert((I==I0)||(I==I1)||(I==I2)); - return; - } - - } - - ///given the I and UV coordinates return the face and barycentric coords - ///return the domain used for interpolation 0=face 1=half diam 2=half star - int Theta(const int &I, - const vcg::Point2 &UV, // alphaBeta - std::vector &face, - std::vector &baryVal) - { - #ifndef NDEBUG - const ScalarType eps=(ScalarType)0.0001; - #endif - assert(UV.X()<=1); - assert(UV.Y()<=1); - assert(UV.X()>=0); - assert(UV.Y()>=0); - //printf("%f,%f \n",UV.X(),UV.Y()); - assert((UV.X()+UV.Y())<=(1+eps)); - - //printf("%f,%f \n",UV.X(),UV.Y()); - ///FACE SEARCH - ///first test if is in the face domain - //printf("face\n"); - bool found=false; - int indexFace=I; - /*if (indexFace>=face_meshes.size()) - printf("B");*/ - - vcg::Point2 UVFace; - GE2(indexFace,UV,UVFace); - found=face_meshes[indexFace].Project(UVFace,face,baryVal); - if (found) - return 0; - - ///DIAMOND SEARCH - ///search in the diamond domain - //printf("diam\n"); - int indexDiam=getHDiamIndex(I,UV);///get diamond index - vcg::Point2 UVDiam; - ///transform UV coordids in diamond - GE1(I,UV,indexDiam,UVDiam); - /*if (indexDiam>=diamond_meshes.size())*/ - /*printf("C");*/ - found=diamond_meshes[indexDiam].Project(UVDiam,face,baryVal); - if (found) - return 1; - - ///STAR SEARCH - //printf("star\n"); - int indexStar=getHStarIndex(I,UV);///get star index - vcg::Point2 UVStar; - ///transform UV coords in star - GE0(I,UV,indexStar,UVStar); - found=star_meshes[indexStar].Project(UVStar,face,baryVal); - if (!found) - { - //printf("\n problems projecting u,v:%lf,%lf (RESOLVED)\n",UV.X(),UV.Y()); -#ifndef NDEBUG - bool found=star_meshes[indexStar].getClosest(UVStar,face,baryVal); - assert(found); -#else - star_meshes[indexStar].getClosest(UVStar,face,baryVal); - /*printf("D");*/ -#endif - } - return 2; - } - - ///given the I and UV coordinates return the face and barycentric coords - ///return the domain used for interpolation 0=face 1=half diam 2=half star - int Theta(const int &I, - const vcg::Point2 &UV, // alphaBeta - ParamFace* &face, - CoordType &baryVal) - { - std::vector faces; - std::vector baryVals; - int ret=Theta(I,UV,faces,baryVals); - if (ret!=-1) - { - face=faces[0]; - baryVal=baryVals[0]; - } - return ret; - } - - ///given the I and UV coordinates return the face and barycentric coords - ///return the domain used for interpolation 0=face 1=half diam 2=half star - ///and 3D Coordinates - int Theta(const int &I, - const vcg::Point2 &UV, - CoordType &pos3D) - { - std::vector face; - std::vector baryVal; - - int ret=Theta(I,UV,face,baryVal); - - pos3D=CoordType(0,0,0); - for (int i=0;i<(int)face.size();i++) - { - CoordType pos=face[i]->V(0)->P()*baryVal[i].X()+ - face[i]->V(1)->P()*baryVal[i].Y()+ - face[i]->V(2)->P()*baryVal[i].Z(); - pos3D+=pos; - } - - pos3D/=(ScalarType)face.size(); - return ret; - } - - ///return the coordinate on the half star domain - bool GE0(const int &I, - const vcg::Point2 &UV, - const int &StarIndex, - vcg::Point2 &UVHstar) - { - //int vertStar=2; - CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); - - ///then transform to the star domain - - ///get star mesh - AbstractMesh* star_domain=star_meshes[StarIndex].domain; - int LocalIndex=star_meshes[StarIndex].Global2Local(I); - if (LocalIndex==-1) - return false; - - GetUV(&star_domain->face[LocalIndex],bary,UVHstar.X(),UVHstar.Y()); - return true; - } - - ///return the coordinate on the half star domain - bool inv_GE0(int &StarIndex, - vcg::Point2 &UVHstar, - int &I, - vcg::Point2 &UV) - { - AbstractMesh* star_domain=star_meshes[StarIndex].domain; - CoordType bary; - int index; - bool done=GetBaryFaceFromUV(*star_domain,UVHstar.X(),UVHstar.Y(),bary,index); - if (!done) - return false; - UV.X()=bary.X(); - UV.Y()=bary.Y(); - I=star_meshes[StarIndex].Local2Global(index); - return done; - } - - - void InterpParam(vcg::Point2f p1,vcg::Point2f p2,vcg::Point2f p3,vcg::Point2f p_test, - ScalarType &b1,ScalarType &b2,ScalarType &b3) - { - ScalarType x0=p_test.X(); - ScalarType y0=p_test.Y(); - ScalarType x1=p1.X(); - ScalarType y1=p1.Y(); - ScalarType x2=p2.X(); - ScalarType y2=p2.Y(); - ScalarType x3=p3.X(); - ScalarType y3=p3.Y(); - - ScalarType b0 = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); - b1 = ((x2 - x0) * (y3 - y0) - (x3 - x0) * (y2 - y0)) / b0; - b2 = ((x3 - x0) * (y1 - y0) - (x1 - x0) * (y3 - y0)) / b0; - b3 = ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)) / b0; - } - - ///return the coordinate on the half diamond domain - void GE1(const int &I, - const vcg::Point2 &UV, - const int &DiamIndex, - vcg::Point2 &UVDiam) - { - ///get the right edge index - CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); - - ///then transform to the half-diamond domain - ///get egde mesh - AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; - int LocalIndex=diamond_meshes[DiamIndex].Global2Local(I); - if(LocalIndex!=-1) - { - GetUV(&diam_domain->face[LocalIndex],bary,UVDiam.X(),UVDiam.Y()); - return; - } - ///if ! found seach in the star space - else - { - AbstractFace *f_diam=&diam_domain->face[0]; - int indexF0=diamond_meshes[DiamIndex].Local2Global(0); - int indexF1=diamond_meshes[DiamIndex].Local2Global(1); - - //getFaceIndexFromPointer(f0,indexF0); - vcg::Point2 UVHstar; - //int StarIndex=getHStarIndex(I,UV); - int StarIndex=getHStarIndex(I,UV); - ///get star coordinates -#ifndef NDEBUG - bool found=GE0(I,UV,StarIndex,UVHstar); - assert(found); -#else - GE0(I,UV,StarIndex,UVHstar); -#endif - - ///then find which face is in the star - int indexParam; - int indexParam0=star_meshes[StarIndex].Global2Local(indexF0); - int indexParam1=star_meshes[StarIndex].Global2Local(indexF1); - if(indexParam0==-1) - indexParam=indexParam1; - else - indexParam=indexParam0; - - AbstractFace *f_param=&star_meshes[StarIndex].domain->face[indexParam]; - vcg::Point2f p0=f_param->V(0)->T().P(); - vcg::Point2f p1=f_param->V(1)->T().P(); - vcg::Point2f p2=f_param->V(2)->T().P(); - - vcg::Point3f coord; - //bool inside=vcg::InterpolationParameters2(p0,p1,p2,UVHstar,coord); - InterpParam(p0,p1,p2,UVHstar,coord.X(),coord.Y(),coord.Z()); - ///finally reinterpolate in diamond space - UVDiam=coord.X()*f_diam->V(0)->T().P()+coord.Y()*f_diam->V(1)->T().P()+coord.Z()*f_diam->V(2)->T().P(); - return; - } - //CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); - - } - - ///given the diamond coordinates return the coordinates in the parametrization space - void inv_GE1(const int &DiamIndex, - const vcg::Point2 &UVDiam, - int &I, - vcg::Point2 &UV) - { - AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; - CoordType bary; - int index; -#ifndef NDEBUG - bool done=GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); - assert(done); -#else - GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); -#endif - UV.X()=bary.X(); - UV.Y()=bary.Y(); - I=diamond_meshes[DiamIndex].Local2Global(index); - - } - - ///given the diamond coordinates return the coordinates in the parametrization space - ///in this case I is fixed and should falls also outside the face I - void inv_GE1_fixedI(const int &DiamIndex, - const vcg::Point2 &UVDiam, - const int &I, - vcg::Point2 &bary) - { - /*AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain;*/ - //int index; - CoordType bary3d; - ///then find barycentryc coordinates with respect to such face - int local_face=diamond_meshes[DiamIndex].Global2Local(I); - AbstractFace* f=&diamond_meshes[DiamIndex].domain->face[local_face]; - vcg::Point2 p0=f->V(0)->T().P(); - vcg::Point2 p1=f->V(1)->T().P(); - vcg::Point2 p2=f->V(2)->T().P(); - InterpParam(p0,p1,p2,UVDiam,bary3d.X(),bary3d.Y(),bary3d.Z()); - bary.X()=bary3d.X(); - bary.Y()=bary3d.Y(); - } - - ///given the star return the coordinates in the parametrization space - ///in this case I is fixed and should falls also outside the face I - void inv_GE0_fixedI(const int &StarIndex, - const vcg::Point2 &UVStar, - const int &I, - vcg::Point2 &bary) - { - //AbstractMesh* star_domain=star_meshes[StarIndex].domain; - /*int index;*/ - CoordType bary3d; - ///then find barycentryc coordinates with respect to such face - int local_face=star_meshes[StarIndex].Global2Local(I); - AbstractFace* f=&star_meshes[StarIndex].domain->face[local_face]; - vcg::Point2 p0=f->V(0)->T().P(); - vcg::Point2 p1=f->V(1)->T().P(); - vcg::Point2 p2=f->V(2)->T().P(); - InterpParam(p0,p1,p2,UVStar,bary3d.X(),bary3d.Y(),bary3d.Z()); - bary.X()=bary3d.X(); - bary.Y()=bary3d.Y(); - } - - ///given the diamond coordinates AS A QUAD return the coordinates in the parametrization space - void inv_GE1Quad(const int &DiamIndex, - const vcg::Point2 &UVQuad, - int &I, - vcg::Point2 &UV) - { - assert((UVQuad.X()>=0)&&(UVQuad.X()<=1)); - assert((UVQuad.Y()>=0)&&(UVQuad.Y()<=1)); - - ///get the abstract mesh - AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; - ///get the 4 vertices on the full diamond - - ///transform in diamond coordinates - vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); - vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); - vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - - ///get 2 directions - vcg::Point2 v0=c1-c0; - //v0.Normalize(); - vcg::Point2 v1=c3-c0; - //v1.Normalize(); - - ///value in diamond coordinates - vcg::Point2 UVDiam=c0+UVQuad.X()*v0; - vcg::Point2 diry=UVQuad.Y()*v1; - UVDiam=UVDiam+diry; - - //printf("Diamond: %d,%f,%f \n",DiamIndex,UVDiam.X(),UVDiam.Y()); - - int index; - CoordType bary; -#ifndef NDEBUG - bool done=GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); -#else - GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); -#endif - UV.X()=bary.X(); - UV.Y()=bary.Y(); - - I=diamond_meshes[DiamIndex].Local2Global(index); - assert(done); - } - - ///TO RESCALE? - ///given the coordinates in the parametrization space return return the coordinates AS A QUAD - void GE1Quad(const int &I, - const vcg::Point2 &UV, - int &DiamIndex, - vcg::Point2 &UVQuad) - { - ///first get the right half diamond index - DiamIndex=getHDiamIndex(I,UV); - - ///transform in diamond space - vcg::Point2 UVDiam; - GE1(I,UV,DiamIndex,UVDiam); - - ///transform in diamond coordinates - vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); - vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); - vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - - ///get 2 directions - vcg::Point2 v0=c1-c0; - //v0.Normalize(); - vcg::Point2 v1=c3-c0; - //v1.Normalize(); - - ///translate respect to zero - UVDiam-=c0; - - ///then transform in new coordspace - UVQuad.X()=v0.X()*UVDiam.X()+v0.Y()*UVDiam.Y(); - UVQuad.Y()=v1.X()*UVDiam.X()+v1.Y()*UVDiam.Y(); - - } - - ///given the diamond coordinates return return the coordinates AS A QUAD - void GE1Quad(const int &/*DiamIndex*/, - const vcg::Point2 &UVDiam, - vcg::Point2 &UVQuad) - { - //assert(UVDiam.Y()<0); - ///transform in diamond coordinates - vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); - vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); - vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); - - ///get 2 directions - vcg::Point2 v0=c1-c0; - vcg::Point2 v1=c3-c0; - - ///translate respect to zero - vcg::Point2 temp=UVDiam; - //temp=c3; - temp-=c0; - ScalarType det=(ScalarType)1.0/(v0.X()*v1.Y()-v1.X()*v0.Y()); - ///then transform in new coordspace - UVQuad.X()=v1.Y()*temp.X()-v1.X()*temp.Y(); - UVQuad.Y()=-v0.Y()*temp.X()+v0.X()*temp.Y(); - UVQuad.X()*=det; - UVQuad.Y()*=det; - /* printf("UVtr1=%f, %f \n",UVQuad.X(),UVQuad.Y()); - system("pause");*/ - } - - ///return the coordinate on the face domain - void GE2(const int &I, - const vcg::Point2 &UV, - vcg::Point2 &UVFace) - { - ///get the right edge index - CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); - - ///then transform to the face domain - ///get face mesh - AbstractMesh* face_domain=face_meshes[I].domain; - AbstractFace* f=&(face_domain->face[0]); - - UVFace=bary.X()*f->V(0)->T().P()+bary.Y()*f->V(1)->T().P()+bary.Z()*f->V(2)->T().P(); - } - - ///given the face coordinates return the coordinates in the parametrization space - void inv_GE2(const int &FaceIndex, - const vcg::Point2 &UVFace, - vcg::Point2 &UV) - { - AbstractMesh* face_domain=face_meshes[FaceIndex].domain; - CoordType bary; - int index; -#ifndef NDEBUG - bool done=GetBaryFaceFromUV(*face_domain,UVFace.X(),UVFace.Y(),bary,index); - assert(done); -#else - GetBaryFaceFromUV(*face_domain,UVFace.X(),UVFace.Y(),bary,index); -#endif - UV.X()=bary.X(); - UV.Y()=bary.Y(); - - } - - void Clear() - { - face_to_vert.clear(); - star_meshes.clear(); - face_meshes.clear(); - diamond_meshes.clear(); - } - - bool Update(bool test=true) - { - UpdateTopologies(abstract_mesh); - UpdateTopologies(param_mesh); - float fix_num=sqrt((ScalarType)3.0)/(ScalarType)4.0; - - int edge_count=0; - ///cont number of edges - for (unsigned int i=0;iface.size();i++) - { - if (!(abstract_mesh->face[i].IsD())) - { - AbstractFace *f0=&abstract_mesh->face[i]; - //for each edge - for (int j=0;j<3;j++) - { - AbstractFace * f1=f0->FFp(j); - if (f1>f0) - edge_count++; - } - } - } - - ///test param mesh - for (unsigned int i=0;ivert.size();i++) - { - if (!(param_mesh->vert[i].IsD())) - { - ParamVertex *v0=¶m_mesh->vert[i]; - ParamMesh::CoordType bary=ParamMesh::CoordType(v0->T().U(),v0->T().V(),1-v0->T().U()-v0->T().V()); - int patchNum=v0->T().N(); - if (!testBaryCoords(bary)) - return false; - if (patchNum<0) - return false; - if (patchNum>AbsMesh()->fn) - return false; - } - } - Area3d=vcg::tri::Stat::ComputeMeshArea(*param_mesh); - AbstractArea=(ScalarType)abstract_mesh->fn*fix_num; - - face_to_vert.clear(); - star_meshes.clear(); - face_meshes.clear(); - diamond_meshes.clear(); - star_meshes.resize(abstract_mesh->vn); - face_meshes.resize(abstract_mesh->fn); - diamond_meshes.resize(edge_count); - InitFaceToVert(); - InitFace(); - InitDiamond(); - InitStar(); - if (test) - return (Test()); - return true; - } - - bool Init(AbstractMesh * _abstract_mesh, - ParamMesh * _param_mesh,bool test=true) - { - - abstract_mesh=_abstract_mesh; - param_mesh=_param_mesh; - - UpdateTopologies(abstract_mesh); - UpdateTopologies(param_mesh); - - return (Update(test)); - } - - AbstractMesh *&AbsMesh(){return abstract_mesh;} - ParamMesh *&ParaMesh(){return param_mesh;} - - ///given the index of face and the index of the edge return the - ///index of diamond - int GetDiamond(const int &I,const int & edge) - { - AbstractVertex *v0=AbsMesh()->face[I].V0(edge); - AbstractVertex *v1=AbsMesh()->face[I].V1(edge); - int index; - getDiamondFromPointer(v0,v1,index); - return index; - } - - int GetStarIndex(const int &I,const int & indexV) - { - AbstractVertex *v=AbsMesh()->face[I].V(indexV); - int index; - getStarFromPointer(v,index); - return index; - } - - void SaveBaseDomain(char *pathname) - { - /*vcg::tri::io::ExporterPLY::Save(*AbsMesh(),pathname);*/ - /*Warp(0);*/ - FILE *f; - f=fopen(pathname,"w+"); - - std::map vertexmap; - typedef std::map::iterator iteMapVert; - - ///add vertices - fprintf(f,"%d,%d \n",AbsMesh()->fn,AbsMesh()->vn); - int index=0; - for (unsigned int i=0;ivert.size();i++) - { - AbstractVertex* vert=&AbsMesh()->vert[i]; - if (!vert->IsD()) - { - vertexmap.insert(std::pair(vert,index)); - CoordType pos=vert->P(); - CoordType RPos=vert->RPos; - fprintf(f,"%f,%f,%f;\n",pos.X(),pos.Y(),pos.Z()); - index++; - } - } - - ///add faces - for (unsigned int i=0;iface.size();i++) - { - AbstractFace* face=&AbsMesh()->face[i]; - if (!face->IsD()) - { - AbstractVertex* v0=face->V(0); - AbstractVertex* v1=face->V(1); - AbstractVertex* v2=face->V(2); - iteMapVert vertIte; - vertIte=vertexmap.find(v0); - assert(vertIte!=vertexmap.end()); - int index0=(*vertIte).second; - vertIte=vertexmap.find(v1); - assert(vertIte!=vertexmap.end()); - int index1=(*vertIte).second; - vertIte=vertexmap.find(v2); - assert(vertIte!=vertexmap.end()); - int index2=(*vertIte).second; - assert((index0!=index1)&&(index1!=index2)); - fprintf(f,"%d,%d,%d \n",index0,index1,index2); - } - } - fclose(f); - } - - template - bool SetParamMesh(MeshType *_input_mesh, - ParamMesh * _param_mesh) - { - param_mesh=_param_mesh; - param_mesh->Clear(); - vcg::tri::Append::Mesh(*param_mesh,*_input_mesh); - return(Update(true)); - } - - template - bool LoadBaseDomain(char *pathname, - MeshType *_input_mesh, - ParamMesh * _param_mesh, - AbstractMesh *_absMesh, - bool test=true) -// bool use_quality=true) - { - param_mesh=_param_mesh; - param_mesh->Clear(); - /*vcg::tri::Allocator::CompactVertexVector(*_input_mesh); - vcg::tri::Allocator::CompactFaceVector(*_input_mesh);*/ - vcg::tri::Append::Mesh(*param_mesh,*_input_mesh); - /*UpdateStructures(param_mesh);*/ - - ///quality copy to index of texture - for (size_t i=0;ivert.size();i++) - { - int val0=(int)param_mesh->vert[i].Q(); - //int val1=param_mesh->vert[i].T().N();*/ - param_mesh->vert[i].T().N()=val0; - assert(param_mesh->vert[i].T().N()>=0); - } - /*if (AbsMesh()!=NULL) - delete(AbsMesh());*/ - - //AbsMesh()=new AbstractMesh(); - AbsMesh()=_absMesh; - AbsMesh()->Clear(); - - FILE *f=NULL; - f=fopen(pathname,"r"); - if (f==NULL) - return -1; - - ///read vertices - fscanf(f,"%d,%d \n",&abstract_mesh->fn,&abstract_mesh->vn); - abstract_mesh->vert.resize(abstract_mesh->vn); - abstract_mesh->face.resize(abstract_mesh->fn); - - for (unsigned int i=0;ivert.size();i++) - { - AbstractVertex* vert=&abstract_mesh->vert[i]; - CoordType pos; - fscanf(f,"%f,%f,%f;\n",&pos.X(),&pos.Y(),&pos.Z()); - vert->P()=pos; - } - - ///add faces - for (unsigned int i=0;iface.size();i++) - { - AbstractFace* face=&abstract_mesh->face[i]; - if (!face->IsD()) - { - int index0,index1,index2; - fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); - abstract_mesh->face[i].V(0)=&abstract_mesh->vert[index0]; - abstract_mesh->face[i].V(1)=&abstract_mesh->vert[index1]; - abstract_mesh->face[i].V(2)=&abstract_mesh->vert[index2]; - } - } - UpdateTopologies(AbsMesh()); - fclose(f); - - return (Update(test)); - } - - template - void CopyParametrization(MeshType * _param_mesh) - { - for (size_t i=0;i<_param_mesh->vert.size();i++) - { - _param_mesh->vert[i].T().P()=ParaMesh()->vert[i].T().P(); - _param_mesh->vert[i].T().N()=ParaMesh()->vert[i].T().N(); - _param_mesh->vert[i].Q()=(typename MeshType::ScalarType)ParaMesh()->vert[i].T().N(); - } - } - - template - int LoadMCP(AbstractMesh * _abstract_mesh, - ParamMesh * _param_mesh, - char* filename,MeshType *coloredMesh=NULL) - { - abstract_mesh=_abstract_mesh; - param_mesh=_param_mesh; - - FILE *f=NULL; - f=fopen(filename,"r"); - if (f==NULL) - return -1; - - - ///add vertices - abstract_mesh->Clear(); - fscanf(f,"%d,%d \n",&abstract_mesh->fn,&abstract_mesh->vn); - abstract_mesh->vert.resize(abstract_mesh->vn); - abstract_mesh->face.resize(abstract_mesh->fn); - - for (unsigned int i=0;ivert.size();i++) - { - AbstractVertex* vert=&abstract_mesh->vert[i]; - CoordType pos; - CoordType RPos; - fscanf(f,"%f,%f,%f;%f,%f,%f \n",&pos.X(),&pos.Y(),&pos.Z(),&RPos.X(),&RPos.Y(),&RPos.Z()); - vert->P()=pos; - //vert->RPos=RPos; - } - - - - ///add faces - for (unsigned int i=0;iface.size();i++) - { - AbstractFace* face=&abstract_mesh->face[i]; - if (!face->IsD()) - { - int index0,index1,index2; - fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); - abstract_mesh->face[i].V(0)=&abstract_mesh->vert[index0]; - abstract_mesh->face[i].V(1)=&abstract_mesh->vert[index1]; - abstract_mesh->face[i].V(2)=&abstract_mesh->vert[index2]; - } - } - - ///high resolution mesh - fscanf(f,"%d,%d \n",¶m_mesh->fn,¶m_mesh->vn); - param_mesh->vert.resize(param_mesh->vn); - param_mesh->face.resize(param_mesh->fn); - - ///add vertices - for (unsigned int i=0;ivert.size();i++) - { - ParamVertex* vert=¶m_mesh->vert[i]; - CoordType pos; - CoordType bary; - vcg::Color4b col; - int index_face; - int col0,col1,col2; - fscanf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n", - &pos.X(),&pos.Y(),&pos.Z(), - &bary.X(),&bary.Y(),&bary.Z(), - &col0,&col1,&col2, - &index_face); - vert->P()=pos; - //vert->RPos=pos; - vert->T().P()=vcg::Point2(bary.X(),bary.Y()); - vert->T().N()=index_face; - if (coloredMesh!=NULL) - { - vcg::Color4b col=coloredMesh->vert[i].C(); - vert->C()=col; - } - } - - ///add faces - for (unsigned int i=0;iface.size();i++) - { - //BaseFace* face=&final_mesh.face[i]; - - int index0,index1,index2; - fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); - param_mesh->face[i].V(0)=¶m_mesh->vert[index0]; - param_mesh->face[i].V(1)=¶m_mesh->vert[index1]; - param_mesh->face[i].V(2)=¶m_mesh->vert[index2]; - - } - fclose(f); - - ///update structures - vcg::tri::UpdateBounding::Box(*abstract_mesh); - vcg::tri::UpdateTopology::FaceFace(*abstract_mesh); - vcg::tri::UpdateTopology::VertexFace(*abstract_mesh); - - vcg::tri::UpdateBounding::Box(*param_mesh); - vcg::tri::UpdateTopology::FaceFace(*param_mesh); - vcg::tri::UpdateTopology::VertexFace(*param_mesh); - - - Update(); - - return 0; - } -}; - - -#endif +#ifndef TRI_PARAMETRIZATION +#define TRI_PARAMETRIZATION + +// stuff to define the mesh + #include +#include +#include +#include +#include +#include "local_parametrization.h" +#include "uv_grid.h" +#include +#include "param_mesh.h" + +///ABSTRACT MESH THAT MAINTAINS THE WHOLE PARAMETERIZATION +class AbstractVertex; +class AbstractFace; + +class AbstractUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, + vcg::Use::AsFaceType >{}; + + +class AbstractVertex : public vcg::Vertex< AbstractUsedTypes, + vcg::vertex::VFAdj, + vcg::vertex::Coord3f, + vcg::vertex::TexCoord2f, + vcg::vertex::BitFlags> + //vcg::face::Normal3f> +{ +public: + CoordType RPos; + + template < class LeftV> + void ImportData(const LeftV & left ) + { + vcg::Vertex< AbstractUsedTypes, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::TexCoord2f,vcg::vertex::BitFlags>::ImportData( left); + this->RPos = left.RPos; + } +}; + +class AbstractFace : public vcg::Face < AbstractUsedTypes, + vcg::face::VFAdj, + vcg::face::FFAdj, + vcg::face::VertexRef, + vcg::face::Color4b, + vcg::face::BitFlags> +//vcg::face::Normal3f> +{}; + +class AbstractMesh: public vcg::tri::TriMesh, std::vector > { +//public: +// static const bool Has_Auxiliary(){return false;} +}; + +///HIGH RESOLUTION MESH THAT HAS TO BE PARAMETERIZED +class ParamVertex; +class ParamFace; + + +class ParamUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, + vcg::Use::AsFaceType >{}; + + +class ParamVertex: public vcg::Vertex< ParamUsedTypes, + vcg::vertex::Normal3f, vcg::vertex::VFAdj, + vcg::vertex::Coord3f,vcg::vertex::Color4b, + vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, + vcg::vertex::CurvatureDirf, + vcg::vertex::Qualityf> +{ +public: + template < class LeftV> + void ImportData(const LeftV & left ) + { + vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); + } + + + void ImportData(const ParamVertex & left ) + { + vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); + this->RPos = left.RPos; + } + + void ImportData(const BaseVertex & left ) + { + vcg::Vertex< ParamUsedTypes, vcg::vertex::Normal3f, vcg::vertex::VFAdj, vcg::vertex::Coord3f,vcg::vertex::Color4b, vcg::vertex::TexCoord2f,vcg::vertex::BitFlags, vcg::vertex::CurvatureDirf,vcg::vertex::Qualityf >::ImportData( left); + this->RPos = left.RPos; + } + + CoordType RPos; + static const bool Has_Auxiliary(){return false;} +}; + +class ParamFace: public vcg::Face < ParamUsedTypes, + vcg::face::VFAdj,vcg::face::FFAdj,vcg::face::VertexRef, + vcg::face::Color4b,vcg::face::BitFlags, + vcg::face::Normal3f, + vcg::face::WedgeTexCoord2f, + vcg::face::Mark, + vcg::face::EdgePlane + //, + //vcg::face::Qualityf // not really needed + > +{ +public: + /*template < class LeftV> + void ImportData(const LeftV & left ) + { + vcg::FaceSimp2 < ParamVertex, ParamEdge, ParamFace, + vcg::face::VFAdj,vcg::face::FFAdj,vcg::face::VertexRef, + vcg::face::Color4b,vcg::face::BitFlags, + vcg::face::WedgeTexCoord2f,vcg::face::Normal3f, + vcg::face::Qualityf>::ImportData( left); + }*/ +}; +class ParamMesh: public vcg::tri::TriMesh, std::vector > +{ +//public: + //static const bool Has_Auxiliary(){return false;} +}; + +template +void CopyMeshFromFacesAbs(const std::vector &faces, + std::vector &orderedVertex, + MeshType & new_mesh) +{ + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::FaceType FaceType; + + ///get set of faces + std::map vertexmap; + std::vector vertices; + FindVertices(faces,vertices); + + ///initialization of new mesh + new_mesh.Clear(); + new_mesh.vn=0; + new_mesh.fn=0; + new_mesh.face.resize(faces.size()); + new_mesh.vert.resize(vertices.size()); + new_mesh.vn=vertices.size(); + new_mesh.fn=faces.size(); + + ///add new vertices + typename std::vector::const_iterator iteV; + int i=0; + for (iteV=vertices.begin();iteV!=vertices.end();iteV++) + { + ///copy position + assert(!(*iteV)->IsD()); + new_mesh.vert[i].P()=(*iteV)->P(); + new_mesh.vert[i].RPos=(*iteV)->RPos; + new_mesh.vert[i].T().P()=(*iteV)->T().P(); + new_mesh.vert[i].T().N()=(*iteV)->T().N(); + //new_mesh.vert[i].N()=(*iteV)->N(); + ///*assert(new_mesh.vert[i].brother!=NULL);*/ + ////if (MeshType::Has_Auxiliary()) + //new_mesh.vert[i].brother=(*iteV)->brother; + new_mesh.vert[i].ClearFlags(); + + orderedVertex.push_back((*iteV)); + vertexmap.insert(std::pair((*iteV),&new_mesh.vert[i])); + i++; + } + + ///setting of new faces + typename std::vector::const_iterator iteF; + typename std::vector::iterator iteF1; + for (iteF=faces.begin(),iteF1=new_mesh.face.begin() + ;iteF!=faces.end();iteF++,iteF1++) + { + //(*iteF1).areadelta=(*iteF)->areadelta; + /* if ((*iteF1).areadelta>1) + assert(0);*/ + ///for each vertex get new reference + ///and associate face-vertex + for (int j=0;j<3;j++) + { + VertexType* v=(*iteF)->V(j); + typename std::map::iterator iteMap=vertexmap.find(v); + assert(iteMap!=vertexmap.end()); + (*iteF1).V(j)=(*iteMap).second; + } + } +} + +///create a mesh considering just the faces that share all three vertex +template +void CopyMeshFromVerticesAbs(std::vector &vertices, + std::vector &OrderedVertices, + std::vector &OrderedFaces, + MeshType & new_mesh) +{ + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::FaceType FaceType; + + typename std::vector::const_iterator iteV; + for (iteV=vertices.begin();iteV!=vertices.end();iteV++) + (*iteV)->ClearV(); + + + + OrderedVertices.clear(); + + ///vertex-vertex reference + std::map vertexmap; + + ///get set of faces + std::vector faces; + + getSharedFace(vertices,faces); + + ///initialization of new mesh + new_mesh.Clear(); + new_mesh.vn=0; + new_mesh.fn=0; + + ///set vertices as selected + + for (iteV=vertices.begin();iteV!=vertices.end();iteV++) + (*iteV)->SetV(); + + ///getting inside faces + typename std::vector::const_iterator iteF; + for (iteF=faces.begin();iteF!=faces.end();iteF++) + { + ///for each vertex get new reference + ///if there isn't one reference means the face does not appartain to group + VertexType* v0=(*iteF)->V(0); + VertexType* v1=(*iteF)->V(1); + VertexType* v2=(*iteF)->V(2); + bool inside=((*v0).IsV()&&(*v1).IsV()&&(*v2).IsV()); + if (inside) + OrderedFaces.push_back((*iteF)); + } + + ///find internal vertices + FindVertices(OrderedFaces,OrderedVertices); + + ///setting size + new_mesh.face.resize(OrderedFaces.size()); + new_mesh.vert.resize(OrderedVertices.size()); + new_mesh.vn=OrderedVertices.size(); + new_mesh.fn=OrderedFaces.size(); + + ///setting of internal vertices + int i=0; + typename std::vector::iterator iteVI; + for (iteVI=OrderedVertices.begin();iteVI!=OrderedVertices.end();iteVI++) + { + ///copy position + assert(!(*iteVI)->IsD()); + new_mesh.vert[i].P()=(*iteVI)->P(); + new_mesh.vert[i].RPos=(*iteVI)->RPos; + new_mesh.vert[i].T().P()=(*iteVI)->T().P(); + new_mesh.vert[i].T().N()=(*iteVI)->T().N(); + new_mesh.vert[i].C()=(*iteVI)->C(); + /*new_mesh.vert[i].father=(*iteVI)->father; + new_mesh.vert[i].Bary=(*iteVI)->Bary;*/ + //new_mesh.vert[i].Damp=(*iteVI)->Damp; + /*new_mesh.vert[i].RestUV=(*iteVI)->RestUV;*/ + //new_mesh.vert[i].N()=(*iteVI)->N(); + //new_mesh.vert[i].C()=(*iteVI)->C(); + /*new_mesh.vert[i].OriginalCol=(*iteVI)->OriginalCol;*/ + new_mesh.vert[i].ClearFlags(); + ///map setting + vertexmap.insert(std::pair((*iteVI),&new_mesh.vert[i])); + i++; + } + + ///setting of new faces + typename std::vector::iterator iteF1; + for (iteF=OrderedFaces.begin(),iteF1=new_mesh.face.begin() + ;iteF!=OrderedFaces.end();iteF++,iteF1++) + { + ///for each vertex get new reference + ///and associate face-vertex + for (int j=0;j<3;j++) + { + VertexType* v=(*iteF)->V(j); + typename std::map::iterator iteMap=vertexmap.find(v); + assert(iteMap!=vertexmap.end()); + (*iteF1).V(j)=(*iteMap).second; + } + } + + ///clear flags + for (iteV=vertices.begin();iteV!=vertices.end();iteV++) + (*iteV)->ClearV(); + +} + + + + +//template +//static int Parametrize(InputMesh &to_param, +// AbstractMesh &AbsMesh, +// InputMesh &Parametrized, +// int &approx_face_num) +//{ +// vcg::tri::UpdateTopology::FaceFace(to_param); +// +// ///test input conditions +// bool b=vcg::tri::Clean::IsTwoManifoldFace(to_param); +// b&=vcg::tri::Clean::IsTwoManifoldVertexFF(to_param); +// int n=vcg::tri::Clean::BorderEdges(to_param); +// b&=(n==0); +// int num=vcg::tri::Clean::ConnectedComponents(to_param); +// b&=(num==1); +// if (!b) +// return -1; +// +// ///then parameteterize +// IsoParametrizator TrImage; +// TrImage.Parametrize(&mesh,num1,num2); +// TrImage.ExportMeshes(to_param,AbsMesh); +// return 0; +//} + +///class that maintains the whole meh parametrerization with relitive operators +class IsoParametrization +{ + AbstractMesh * abstract_mesh; + ParamMesh * param_mesh; + +public: + typedef ParamMesh::ScalarType ScalarType; + typedef ParamMesh::CoordType CoordType; + +private: + + ///this class maintains submeshes and hresolution meshes + ///for the selected parametrization domain + struct param_domain{ + AbstractMesh *domain; + std::vector local_to_global; + + ParamMesh *HresDomain; + UVGrid grid; + std::vector ordered_faces; + + int Local2Global(const int &localFace) + {return local_to_global[localFace];} + + int Global2Local(const int &GlobalFace) + { + int ret=-1; + for (unsigned int i=0;i UV, + std::vector &face, + std::vector &baryVal) + { + std::vector faceParam; + bool found=grid.ProjectPoint(UV,faceParam,baryVal); + if (!found) + return false; + ///calculate the index corresponding to the face + for (unsigned int i=0;iface.begin()); + assert(indexfn); + face.push_back(ordered_faces[index]); + } + return true; + } + + bool getClosest(vcg::Point2 UV, + std::vector &face, + std::vector &baryVal) + { + face.resize(1); + baryVal.resize(1); + bool found=grid.getClosest(UV,face[0],baryVal[0]); + int index=face[0]-&(*HresDomain->face.begin()); + assert(indexfn); + face[0]=ordered_faces[index]; + return found; + } + }; + + ///summeshes and subdomains + std::vector star_meshes; + std::vector diamond_meshes; + std::vector face_meshes; + + typedef std::pair keyEdgeType; + std::map EdgeTab; + + ///temporary structure for face_to_vert adjacency + std::vector > face_to_vert; + + void InitFaceToVert() + { + face_to_vert.resize(abstract_mesh->face.size()); + for (unsigned int i=0;ivert.size();i++) + { + int I=param_mesh->vert[i].T().N(); + face_to_vert[I].push_back(¶m_mesh->vert[i]); + } + } + + + void GetHresVert(int &I,std::vector &HresVert) + { + for (unsigned int k=0;kvert.size();i++) + { + if (!(abstract_mesh->vert[i].IsD())) + { + std::vector starCenter; + starCenter.push_back(&abstract_mesh->vert[i]); + + star_meshes[index].domain=new AbstractMesh(); + star_meshes[index].HresDomain=new ParamMesh(); + + ///create star + std::vector ordered_faces; + std::vector ordered_vert; + //CreateMeshVertexStar(starCenter,ordered_faces,*star_meshes[index].domain); + ///get faces referenced by vertices + getSharedFace(starCenter,ordered_faces); + + CopyMeshFromFacesAbs(ordered_faces,ordered_vert,*star_meshes[index].domain); + + UpdateTopologies(star_meshes[index].domain); + + ///and parametrize it + ParametrizeStarEquilateral(*star_meshes[index].domain,1.0); + + ///set other components as reefrence to original faces + star_meshes[index].local_to_global.resize(star_meshes[index].domain->face.size()); + std::vector HresVert; + for (unsigned int k=0;kface.size();k++) + { + int IndexF; + getFaceIndexFromPointer(ordered_faces[k],IndexF); + star_meshes[index].local_to_global[k]=IndexF; + ///get H res vertex + GetHresVert(IndexF,HresVert); + } + + ///copy Hres mesh + std::vector OrderedVertices; + CopyMeshFromVerticesAbs(HresVert,OrderedVertices,star_meshes[index].ordered_faces,*star_meshes[index].HresDomain); + ///set new parametrization values + for (unsigned int k=0;kvert.size();k++) + { + ParamVertex * v=&star_meshes[index].HresDomain->vert[k]; + CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); + AbstractMesh *paramDomain=star_meshes[index].domain; + ///get the right face on the parametrized domain + int Father=v->T().N(); + int faceNum=-1; + for (unsigned int i=0;iface[faceNum]; + v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); + assert(faceNum!=-1); + } + star_meshes[index].InitGrid(); + index++; + + } + } + } + + + + void InitDiamond(const ScalarType &edge_len=1.0) + { + + ///for each face + int index=0; + EdgeTab.clear(); + for (unsigned int i=0;iface.size();i++) + { + if (!(abstract_mesh->face[i].IsD())) + { + AbstractFace *f0=&abstract_mesh->face[i]; + //for each edge + for (int j=0;j<3;j++) + { + AbstractFace * f1=f0->FFp(j); + if (f1>f0) + { + + int num0=j; + int num1=f0->FFi(j); + + ///add to domain map + AbstractVertex *v0,*v1; + v0=f0->V(j); + v1=f0->V1(j); + keyEdgeType k; + if (v0 entry=std::pair(k,index); + EdgeTab.insert(entry); + + + + ///copy the mesh + std::vector faces; + faces.push_back(f0); + faces.push_back(f1); + + diamond_meshes[index].domain=new AbstractMesh(); + diamond_meshes[index].HresDomain=new ParamMesh(); + + ///create a copy of the mesh + std::vector orderedVertex; + CopyMeshFromFacesAbs(faces,orderedVertex,*diamond_meshes[index].domain); + UpdateTopologies(diamond_meshes[index].domain); + + ///set other components + int index0,index1; + getFaceIndexFromPointer(f0,index0); + getFaceIndexFromPointer(f1,index1); + diamond_meshes[index].local_to_global.resize(2); + diamond_meshes[index].local_to_global[0]=index0; + diamond_meshes[index].local_to_global[1]=index1; + + ///parametrize locally + ParametrizeDiamondEquilateral(*diamond_meshes[index].domain,num0,num1,edge_len); + ///add h resolution vertices + std::vector HresVert; + GetHresVert(index0,HresVert); + GetHresVert(index1,HresVert); + std::vector OrderedVertices; + CopyMeshFromVerticesAbs(HresVert,OrderedVertices,diamond_meshes[index].ordered_faces,*diamond_meshes[index].HresDomain); + ///set new parametrization values + for (unsigned int k=0;kvert.size();k++) + { + ParamVertex * v=&diamond_meshes[index].HresDomain->vert[k]; + CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); + AbstractMesh *paramDomain=diamond_meshes[index].domain; + ///get the rigth face on the parametrized domain + int Father=v->T().N(); + int faceNum=-1; + for (unsigned int i=0;iface[faceNum]; + v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); + + + } + diamond_meshes[index].InitGrid(); + index++; + } + } + } + } + } + + + void InitFace(const ScalarType &edge_len=1) + { + ///for each face + int index=0; + for (unsigned int i=0;iface.size();i++) + { + if (!(abstract_mesh->face[i].IsD())) + { + AbstractFace *f0=&abstract_mesh->face[i]; + + std::vector faces; + faces.push_back(f0); + + ///create the mesh + face_meshes[index].domain=new AbstractMesh(); + face_meshes[index].HresDomain=new ParamMesh(); + + std::vector orderedVertex; + CopyMeshFromFacesAbs(faces,orderedVertex,*face_meshes[index].domain); + + assert(face_meshes[index].domain->vn==3); + assert(face_meshes[index].domain->fn==1); + + ///initialize auxiliary structures + face_meshes[index].local_to_global.resize(1); + face_meshes[index].local_to_global[0]=i; + + ///parametrize it + ParametrizeFaceEquilateral(*face_meshes[index].domain,edge_len); + + ///add h resolution vertices + std::vector HresVert; + GetHresVert(index,HresVert); + std::vector OrderedVertices; + CopyMeshFromVerticesAbs(HresVert,OrderedVertices,face_meshes[index].ordered_faces,*face_meshes[index].HresDomain); + ///set new parametrization values + for (unsigned int k=0;kvert.size();k++) + { + ParamVertex * v=&face_meshes[index].HresDomain->vert[k]; + CoordType bary=CoordType(v->T().U(),v->T().V(),1-v->T().U()-v->T().V()); + AbstractMesh *paramDomain=face_meshes[index].domain; + AbstractFace *faceDom=¶mDomain->face[0]; + v->T().P()=(faceDom->V(0)->T().P())*bary.X()+(faceDom->V(1)->T().P())*bary.Y()+(faceDom->V(2)->T().P())*bary.Z(); + } + + face_meshes[index].InitGrid(); + index++; + } + } + } + + void getFaceIndexFromPointer(AbstractFace * f,int &index) + { + index=f-&(*abstract_mesh->face.begin()); + } + + void getStarFromPointer(AbstractVertex * center,int &index) + { + index=center-&(*abstract_mesh->vert.begin()); + } + + void getDiamondFromPointer(AbstractVertex * v0,AbstractVertex * v1,int &index) + { + assert(v0!=v1); + keyEdgeType key; + if (v0::iterator k=EdgeTab.find(key); + assert(k!=EdgeTab.end()); + index=((*k).second); + } + + + bool Test() + { + /*int index=0;*/ + for (unsigned int i=0;iface.size();i++) + { + if (!(abstract_mesh->face[i].IsD())) + { + AbstractFace *f0=&abstract_mesh->face[i]; + //for each edge + for (int j=0;j<3;j++) + { + AbstractFace * f1=f0->FFp(j); + if (f1>f0) + { + ///add to domain map + AbstractVertex *v0,*v1; + v0=f0->V(j); + v1=f0->V1(j); + keyEdgeType k; + if (v0 entry=std::pair(k,index); + std::map::iterator iteE=EdgeTab.find(k); + + int index0F,index1F; + getFaceIndexFromPointer(f0,index0F); + getFaceIndexFromPointer(f1,index1F); +#ifndef NDEBUG + int edgeIndex=(*iteE).second; + assert(diamond_meshes[edgeIndex].local_to_global[0]==index0F); + assert(diamond_meshes[edgeIndex].local_to_global[1]==index1F); +#endif + } + } + } + } + ///test if for each face there is a right domain + for (unsigned int i=0;iface.size();i++) + { + ParamFace * f=¶m_mesh->face[i]; + vcg::Point2f uvI0,uvI1,uvI2; + int IndexDomain=-1; + int ret=InterpolationSpace(f,uvI0,uvI1,uvI2,IndexDomain); + if (ret==-1) + return false; + } + return true; + } + + int getSharedVertices(AbstractFace *f0,AbstractFace *f1,AbstractFace *f2, + AbstractVertex *shared[3]) + { + AbstractVertex *vert0[3],*vert1[3],*vert2[3]; + + vert0[0]=f0->V(0); + vert0[1]=f0->V(1); + vert0[2]=f0->V(2); + + vert1[0]=f1->V(0); + vert1[1]=f1->V(1); + vert1[2]=f1->V(2); + + vert2[0]=f2->V(0); + vert2[1]=f2->V(1); + vert2[2]=f2->V(2); + + int num=0; + for (int i=0;i<3;i++) + { + AbstractVertex * test=vert0[i]; + bool found0=false,found1=false; + if ((vert1[0]==test)||(vert1[1]==test)||(vert1[2]==test)) + found0=true; + if (found0) + { + if ((vert2[0]==test)||(vert2[1]==test)||(vert2[2]==test)) + found1=true; + } + if ((found0)&&(found1)) + { + shared[num]=test; + num++; + } + } + + return num; + } + + int getSharedVertices(AbstractFace *f0,AbstractFace *f1,AbstractVertex *shared[3]) + { + AbstractVertex *vert0[3],*vert1[3]; + + vert0[0]=f0->V(0); + vert0[1]=f0->V(1); + vert0[2]=f0->V(2); + + vert1[0]=f1->V(0); + vert1[1]=f1->V(1); + vert1[2]=f1->V(2); + + + int num=0; + for (int i=0;i<3;i++) + { + AbstractVertex * test=vert0[i]; + bool found0=false; + if ((vert1[0]==test)||(vert1[1]==test)||(vert1[2]==test)) + found0=true; + if (found0) + { + shared[num]=test; + num++; + } + } + + return num; + } + + int getSharedVertices(const std::vector &I,AbstractVertex *shared[3],int *_num=NULL) + { + ///else test the number of vertices shared + AbstractVertex * shared_vert[3]; + bool sharedB[3]; + int size; + if (_num==NULL) + size=I.size(); + else + size=*_num; + + ///quick test for 2 or 3 cases + if (size==2) + return getSharedVertices(&AbsMesh()->face[I[0]],&AbsMesh()->face[I[1]],shared); + else + if (size==3) + return getSharedVertices(&AbsMesh()->face[I[0]],&AbsMesh()->face[I[1]],&AbsMesh()->face[I[2]],shared); + + AbstractFace* f0=&AbsMesh()->face[I[0]]; + AbstractVertex *v0=f0->V(0); + AbstractVertex *v1=f0->V(1); + AbstractVertex *v2=f0->V(2); + shared_vert[0]=v0; + shared_vert[1]=v1; + shared_vert[2]=v2; + sharedB[0]=true; + sharedB[1]=true; + sharedB[2]=true; + //for each face + for (int i=1;iface[I[i]]; + //for each vertex + for (int j=0;j<3;j++) + { + if (sharedB[j]) + { + AbstractVertex *v_test=shared_vert[j]; + if (!((v_test==f->V(0))||(v_test==f->V(1))||(v_test==f->V(2)))) + sharedB[j]=false; + } + } + } + + ///return vertices correctly + int num=0; + for (int i=0;i<3;i++) + if (sharedB[i]) + { + shared[num]=shared_vert[i]; + num++; + } + return num; + } + + + void Clamp(vcg::Point2f &UV) + { + float eps=0.00001f; + if ((UV.X()-eps)) + UV.X()=0; + if ((UV.X()<1+eps)&&(UV.X()>1-eps)) + UV.X()=1; + if ((UV.Y()-eps)) + UV.Y()=0; + if ((UV.Y()<1+eps)&&(UV.Y()>1-eps)) + UV.Y()=1; + } + + + float Area3d; + float AbstractArea; + +public: + + ///return the minimum interpolation space shared by a face changing coordinates + ///return 0 if is a face 1 is a diamaond and 2 is a star + int InterpolationSpace(ParamFace *f, + vcg::Point2f &uvI0, + vcg::Point2f &uvI1, + vcg::Point2f &uvI2, + int &IndexDomain) + { + ParamVertex *v0=f->V(0); + ParamVertex *v1=f->V(1); + ParamVertex *v2=f->V(2); + + int I0=v0->T().N(); + int I1=v1->T().N(); + int I2=v2->T().N(); + + vcg::Point2f UV0=v0->T().P(); + vcg::Point2f UV1=v1->T().P(); + vcg::Point2f UV2=v2->T().P(); + + ///if they are equal it's is triavially the interpolation of UV coords + ///and the same face I as the domain + if ((I0==I1)&&(I1==I2)) + { + GE2(I0,UV0,uvI0); + GE2(I1,UV1,uvI1); + GE2(I2,UV2,uvI2); + IndexDomain=I0; + return 0; + } + + ///else find the right interpolation domain in which the face belongs + ///test if they share an edge then use half diamond + AbstractFace *f0=&abstract_mesh->face[I0]; + AbstractFace *f1=&abstract_mesh->face[I1]; + AbstractFace *f2=&abstract_mesh->face[I2]; + AbstractVertex *shared[3]; + + int num=getSharedVertices(f0,f1,f2,shared); + if (num<1) + { + return -1; + } + //assert((num==1)||(num==2)); + if (num==2)///ude diamond + { + AbstractVertex* v0=shared[0]; + AbstractVertex* v1=shared[1]; + int EdgeIndex; + + getDiamondFromPointer(v0,v1,EdgeIndex); + + GE1(I0,UV0,EdgeIndex,uvI0); + GE1(I1,UV1,EdgeIndex,uvI1); + GE1(I2,UV2,EdgeIndex,uvI2); + + IndexDomain=EdgeIndex; + return 1; + } + + ///use the star domain + + AbstractVertex* center=shared[0]; + int StarIndex; + getStarFromPointer(center,StarIndex); + bool b0=GE0(I0,UV0,StarIndex,uvI0); + bool b1=GE0(I1,UV1,StarIndex,uvI1); + bool b2=GE0(I2,UV2,StarIndex,uvI2); + IndexDomain=StarIndex; + if ((!b0)||(!b1)||(!b2)) + { + printf("AZZZ 1\n"); + return -1; + } + assert((uvI0.X()>=-1)&&(uvI0.Y()>=-1)&&(uvI0.X()<=1)&&(uvI0.Y()<=1)); + assert((uvI1.X()>=-1)&&(uvI1.Y()>=-1)&&(uvI1.X()<=1)&&(uvI1.Y()<=1)); + assert((uvI2.X()>=-1)&&(uvI2.Y()>=-1)&&(uvI2.X()<=1)&&(uvI2.Y()<=1)); + + + + return 2; + + } + + ///return the minimum interpolation space shared by two faces of abstarct domain + ///return 0 if is a face 1 is a diamaond and 2 is a star + int InterpolationSpace(const int &I0,const int &I1,int &IndexDomain) + { + ///that case is the face itself + if (I0==I1) + { + IndexDomain=I0; + return 0; + } + AbstractFace* f0=&AbsMesh()->face[I0]; + AbstractFace* f1=&AbsMesh()->face[I1]; + /* AbstractVertex *v0=f0->V(0); + AbstractVertex *v1=f0->V(1); + AbstractVertex *v2=f0->V(2); + AbstractVertex *v3=f1->V(0); + AbstractVertex *v4=f1->V(1); + AbstractVertex *v5=f1->V(2);*/ + + + AbstractVertex *shared[3]; + + int num=getSharedVertices(f0,f1,shared); + if (!((num==1)||(num==2))) + return -1; + if (num==2)///use diamond + { + AbstractVertex* v0=shared[0]; + AbstractVertex* v1=shared[1]; + int EdgeIndex; + + getDiamondFromPointer(v0,v1,EdgeIndex); + + IndexDomain=EdgeIndex; + return 1; + } + + ///use the star domain + + AbstractVertex* center=shared[0]; + int StarIndex; + getStarFromPointer(center,StarIndex); + IndexDomain=StarIndex; + + return 2; + + } + + ///return 0 if is a face 1 is a diamaond and 2 is a star + int InterpolationSpace(const std::vector &I,int &IndexDomain,int *_num=NULL) + { + int size; + if (_num==NULL) + size=I.size(); + else + size=*_num; + + ///simple cases + assert(I.size()>0); + ///1 element + if (size==1) + { + IndexDomain=I[0]; + return 0; + } + ///2 elements + if (size==2) + return InterpolationSpace(I[0],I[1],IndexDomain); + + ///test if they all are the same + ///that case is the face itself + bool sameface=true; + int i=1; + int I0=I[0]; + while ((i &UV) + { + int vertStar=2; + CoordType bary=CoordType(UV.X(),UV.Y(),(ScalarType)1.0-UV.X()-UV.Y()); + + if ((bary.X()>bary.Y())&&(bary.X()>bary.Z())) + vertStar=0; + else + if ((bary.Y()>bary.X())&&(bary.Y()>bary.Z())) + vertStar=1; + + AbstractFace *f=&abstract_mesh->face[I]; + AbstractVertex *Center=f->V(vertStar); + + int StarIndex; + getStarFromPointer(Center,StarIndex); + return StarIndex; + } + + int getHDiamIndex(const int &I, + const vcg::Point2 &UV) + { + CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); + ScalarType sum0=bary.X()+bary.Y(); + ScalarType sum1=bary.Y()+bary.Z(); + ScalarType sum2=bary.X()+bary.Z(); + int edge=2; + if ((sum0>sum1)&&(sum0>sum2)) + edge=0; + else + if ((sum1>sum0)&&(sum1>sum2)) + edge=1; + + ///get the half-diamond mesh + int DiamIndex; + getDiamondFromPointer(abstract_mesh->face[I].V(edge),abstract_mesh->face[I].V1(edge),DiamIndex); + return(DiamIndex); + } + + ///give the face and barycentric coordinate return I and UV coordinates + void Phi(const ParamFace *f, + const CoordType &bary3D, + int &I, + vcg::Point2 &UV) + { +#ifndef NDEBUG + float eps=0.00001f; +#endif + ///control right domain + int I0=f->V(0)->T().N(); + int I1=f->V(1)->T().N(); + int I2=f->V(2)->T().N(); + + ///if they are equal it's is triavially the interpolation of UV coords + ///and the same face I as the domain + if ((I0==I1)&&(I1==I2)) + { + UV=bary3D.X()*f->V(0)->T().P()+bary3D.Y()*f->V(1)->T().P()+bary3D.Z()*f->V(2)->T().P(); + Clamp(UV); + assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1)); + I=I0; + return; + } + + + ///else find the right interpolation domain in which the face belongs + ///test if they share an edge then use half diamond + AbstractFace *f0=&abstract_mesh->face[I0]; + AbstractFace *f1=&abstract_mesh->face[I1]; + AbstractFace *f2=&abstract_mesh->face[I2]; + AbstractVertex *shared[3]; + + int num=getSharedVertices(f0,f1,f2,shared); + + /*///if num==1 + if (num==0) + { + float alpha=bary3D.X(); + float beta =bary3D.Y(); + float gamma=bary3D.Z(); +#ifndef _MESHLAB + printf("problems with interpolation, solved..."); +#endif + if ((alpha>beta)&&(alpha>gamma)) + { + I=I0; + UV=f->V(0)->T().P(); + } + else + if ((beta>alpha)&&(beta>gamma)) + { + I=I1; + UV=f->V(1)->T().P(); + } + else + { + I=I2; + UV=f->V(2)->T().P(); + } + + return; + }*/ + + assert((num==1)||(num==2)); + if ((num!=1)&&(num!=2)) + { + printf("DOMAIN %d\n",num); + assert(0); + } + if (num==1)///use the star domain + { + //printf("phi 0\n"); + AbstractVertex* center=shared[0]; + int StarIndex; + getStarFromPointer(center,StarIndex); + vcg::Point2 UVs0,UVs1,UVs2; + vcg::Point2 UV0=f->V(0)->T().P(); + vcg::Point2 UV1=f->V(1)->T().P(); + vcg::Point2 UV2=f->V(2)->T().P(); + + GE0(I0,UV0,StarIndex,UVs0); + GE0(I1,UV1,StarIndex,UVs1); + GE0(I2,UV2,StarIndex,UVs2); + assert((UVs0.X()>=-1)&&(UVs0.Y()>=-1)&&(UVs0.X()<=1)&&(UVs0.Y()<=1)); + assert((UVs1.X()>=-1)&&(UVs1.Y()>=-1)&&(UVs1.X()<=1)&&(UVs1.Y()<=1)); + assert((UVs2.X()>=-1)&&(UVs2.Y()>=-1)&&(UVs2.X()<=1)&&(UVs2.Y()<=1)); + + ///interpolate star value + vcg::Point2 UV_interp=bary3D.X()*UVs0+bary3D.Y()*UVs1+bary3D.Z()*UVs2; + inv_GE0(StarIndex,UV_interp,I,UV); + Clamp(UV); + assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); + return; + } + else ///use the diamond domain + { + //printf("phi 1\n"); + //std::set::iterator it=temp2.begin(); + //std::vector::iterator it=shared[0]; + AbstractVertex* v0=shared[0]; + //it++; + AbstractVertex* v1=shared[1]; + int EdgeIndex; + getDiamondFromPointer(v0,v1,EdgeIndex); + + vcg::Point2 UVd0,UVd1,UVd2; + vcg::Point2 UV0=f->V(0)->T().P(); + vcg::Point2 UV1=f->V(1)->T().P(); + vcg::Point2 UV2=f->V(2)->T().P(); + + GE1(I0,UV0,EdgeIndex,UVd0); + GE1(I1,UV1,EdgeIndex,UVd1); + GE1(I2,UV2,EdgeIndex,UVd2); + + ///interpolate star value + vcg::Point2 UV_interp=bary3D.X()*UVd0+bary3D.Y()*UVd1+bary3D.Z()*UVd2; + inv_GE1(EdgeIndex,UV_interp,I,UV); + Clamp(UV); + assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps)); + assert((I==I0)||(I==I1)||(I==I2)); + return; + } + + } + + ///given the I and UV coordinates return the face and barycentric coords + ///return the domain used for interpolation 0=face 1=half diam 2=half star + int Theta(const int &I, + const vcg::Point2 &UV, // alphaBeta + std::vector &face, + std::vector &baryVal) + { + #ifndef NDEBUG + const ScalarType eps=(ScalarType)0.0001; + #endif + assert(UV.X()<=1); + assert(UV.Y()<=1); + assert(UV.X()>=0); + assert(UV.Y()>=0); + //printf("%f,%f \n",UV.X(),UV.Y()); + assert((UV.X()+UV.Y())<=(1+eps)); + + //printf("%f,%f \n",UV.X(),UV.Y()); + ///FACE SEARCH + ///first test if is in the face domain + //printf("face\n"); + bool found=false; + int indexFace=I; + /*if (indexFace>=face_meshes.size()) + printf("B");*/ + + vcg::Point2 UVFace; + GE2(indexFace,UV,UVFace); + found=face_meshes[indexFace].Project(UVFace,face,baryVal); + if (found) + return 0; + + ///DIAMOND SEARCH + ///search in the diamond domain + //printf("diam\n"); + int indexDiam=getHDiamIndex(I,UV);///get diamond index + vcg::Point2 UVDiam; + ///transform UV coordids in diamond + GE1(I,UV,indexDiam,UVDiam); + /*if (indexDiam>=diamond_meshes.size())*/ + /*printf("C");*/ + found=diamond_meshes[indexDiam].Project(UVDiam,face,baryVal); + if (found) + return 1; + + ///STAR SEARCH + //printf("star\n"); + int indexStar=getHStarIndex(I,UV);///get star index + vcg::Point2 UVStar; + ///transform UV coords in star + GE0(I,UV,indexStar,UVStar); + found=star_meshes[indexStar].Project(UVStar,face,baryVal); + if (!found) + { + //printf("\n problems projecting u,v:%lf,%lf (RESOLVED)\n",UV.X(),UV.Y()); +#ifndef NDEBUG + bool found=star_meshes[indexStar].getClosest(UVStar,face,baryVal); + assert(found); +#else + star_meshes[indexStar].getClosest(UVStar,face,baryVal); + /*printf("D");*/ +#endif + } + return 2; + } + + ///given the I and UV coordinates return the face and barycentric coords + ///return the domain used for interpolation 0=face 1=half diam 2=half star + int Theta(const int &I, + const vcg::Point2 &UV, // alphaBeta + ParamFace* &face, + CoordType &baryVal) + { + std::vector faces; + std::vector baryVals; + int ret=Theta(I,UV,faces,baryVals); + if (ret!=-1) + { + face=faces[0]; + baryVal=baryVals[0]; + } + return ret; + } + + ///given the I and UV coordinates return the face and barycentric coords + ///return the domain used for interpolation 0=face 1=half diam 2=half star + ///and 3D Coordinates + int Theta(const int &I, + const vcg::Point2 &UV, + CoordType &pos3D) + { + std::vector face; + std::vector baryVal; + + int ret=Theta(I,UV,face,baryVal); + + pos3D=CoordType(0,0,0); + for (int i=0;i<(int)face.size();i++) + { + CoordType pos=face[i]->V(0)->P()*baryVal[i].X()+ + face[i]->V(1)->P()*baryVal[i].Y()+ + face[i]->V(2)->P()*baryVal[i].Z(); + pos3D+=pos; + } + + pos3D/=(ScalarType)face.size(); + return ret; + } + + ///return the coordinate on the half star domain + bool GE0(const int &I, + const vcg::Point2 &UV, + const int &StarIndex, + vcg::Point2 &UVHstar) + { + //int vertStar=2; + CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); + + ///then transform to the star domain + + ///get star mesh + AbstractMesh* star_domain=star_meshes[StarIndex].domain; + int LocalIndex=star_meshes[StarIndex].Global2Local(I); + if (LocalIndex==-1) + return false; + + GetUV(&star_domain->face[LocalIndex],bary,UVHstar.X(),UVHstar.Y()); + return true; + } + + ///return the coordinate on the half star domain + bool inv_GE0(int &StarIndex, + vcg::Point2 &UVHstar, + int &I, + vcg::Point2 &UV) + { + AbstractMesh* star_domain=star_meshes[StarIndex].domain; + CoordType bary; + int index; + bool done=GetBaryFaceFromUV(*star_domain,UVHstar.X(),UVHstar.Y(),bary,index); + if (!done) + return false; + UV.X()=bary.X(); + UV.Y()=bary.Y(); + I=star_meshes[StarIndex].Local2Global(index); + return done; + } + + + void InterpParam(vcg::Point2f p1,vcg::Point2f p2,vcg::Point2f p3,vcg::Point2f p_test, + ScalarType &b1,ScalarType &b2,ScalarType &b3) + { + ScalarType x0=p_test.X(); + ScalarType y0=p_test.Y(); + ScalarType x1=p1.X(); + ScalarType y1=p1.Y(); + ScalarType x2=p2.X(); + ScalarType y2=p2.Y(); + ScalarType x3=p3.X(); + ScalarType y3=p3.Y(); + + ScalarType b0 = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); + b1 = ((x2 - x0) * (y3 - y0) - (x3 - x0) * (y2 - y0)) / b0; + b2 = ((x3 - x0) * (y1 - y0) - (x1 - x0) * (y3 - y0)) / b0; + b3 = ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)) / b0; + } + + ///return the coordinate on the half diamond domain + void GE1(const int &I, + const vcg::Point2 &UV, + const int &DiamIndex, + vcg::Point2 &UVDiam) + { + ///get the right edge index + CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); + + ///then transform to the half-diamond domain + ///get egde mesh + AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; + int LocalIndex=diamond_meshes[DiamIndex].Global2Local(I); + if(LocalIndex!=-1) + { + GetUV(&diam_domain->face[LocalIndex],bary,UVDiam.X(),UVDiam.Y()); + return; + } + ///if ! found seach in the star space + else + { + AbstractFace *f_diam=&diam_domain->face[0]; + int indexF0=diamond_meshes[DiamIndex].Local2Global(0); + int indexF1=diamond_meshes[DiamIndex].Local2Global(1); + + //getFaceIndexFromPointer(f0,indexF0); + vcg::Point2 UVHstar; + //int StarIndex=getHStarIndex(I,UV); + int StarIndex=getHStarIndex(I,UV); + ///get star coordinates +#ifndef NDEBUG + bool found=GE0(I,UV,StarIndex,UVHstar); + assert(found); +#else + GE0(I,UV,StarIndex,UVHstar); +#endif + + ///then find which face is in the star + int indexParam; + int indexParam0=star_meshes[StarIndex].Global2Local(indexF0); + int indexParam1=star_meshes[StarIndex].Global2Local(indexF1); + if(indexParam0==-1) + indexParam=indexParam1; + else + indexParam=indexParam0; + + AbstractFace *f_param=&star_meshes[StarIndex].domain->face[indexParam]; + vcg::Point2f p0=f_param->V(0)->T().P(); + vcg::Point2f p1=f_param->V(1)->T().P(); + vcg::Point2f p2=f_param->V(2)->T().P(); + + vcg::Point3f coord; + //bool inside=vcg::InterpolationParameters2(p0,p1,p2,UVHstar,coord); + InterpParam(p0,p1,p2,UVHstar,coord.X(),coord.Y(),coord.Z()); + ///finally reinterpolate in diamond space + UVDiam=coord.X()*f_diam->V(0)->T().P()+coord.Y()*f_diam->V(1)->T().P()+coord.Z()*f_diam->V(2)->T().P(); + return; + } + //CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); + + } + + ///given the diamond coordinates return the coordinates in the parametrization space + void inv_GE1(const int &DiamIndex, + const vcg::Point2 &UVDiam, + int &I, + vcg::Point2 &UV) + { + AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; + CoordType bary; + int index; +#ifndef NDEBUG + bool done=GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); + assert(done); +#else + GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); +#endif + UV.X()=bary.X(); + UV.Y()=bary.Y(); + I=diamond_meshes[DiamIndex].Local2Global(index); + + } + + ///given the diamond coordinates return the coordinates in the parametrization space + ///in this case I is fixed and should falls also outside the face I + void inv_GE1_fixedI(const int &DiamIndex, + const vcg::Point2 &UVDiam, + const int &I, + vcg::Point2 &bary) + { + /*AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain;*/ + //int index; + CoordType bary3d; + ///then find barycentryc coordinates with respect to such face + int local_face=diamond_meshes[DiamIndex].Global2Local(I); + AbstractFace* f=&diamond_meshes[DiamIndex].domain->face[local_face]; + vcg::Point2 p0=f->V(0)->T().P(); + vcg::Point2 p1=f->V(1)->T().P(); + vcg::Point2 p2=f->V(2)->T().P(); + InterpParam(p0,p1,p2,UVDiam,bary3d.X(),bary3d.Y(),bary3d.Z()); + bary.X()=bary3d.X(); + bary.Y()=bary3d.Y(); + } + + ///given the star return the coordinates in the parametrization space + ///in this case I is fixed and should falls also outside the face I + void inv_GE0_fixedI(const int &StarIndex, + const vcg::Point2 &UVStar, + const int &I, + vcg::Point2 &bary) + { + //AbstractMesh* star_domain=star_meshes[StarIndex].domain; + /*int index;*/ + CoordType bary3d; + ///then find barycentryc coordinates with respect to such face + int local_face=star_meshes[StarIndex].Global2Local(I); + AbstractFace* f=&star_meshes[StarIndex].domain->face[local_face]; + vcg::Point2 p0=f->V(0)->T().P(); + vcg::Point2 p1=f->V(1)->T().P(); + vcg::Point2 p2=f->V(2)->T().P(); + InterpParam(p0,p1,p2,UVStar,bary3d.X(),bary3d.Y(),bary3d.Z()); + bary.X()=bary3d.X(); + bary.Y()=bary3d.Y(); + } + + ///given the diamond coordinates AS A QUAD return the coordinates in the parametrization space + void inv_GE1Quad(const int &DiamIndex, + const vcg::Point2 &UVQuad, + int &I, + vcg::Point2 &UV) + { + assert((UVQuad.X()>=0)&&(UVQuad.X()<=1)); + assert((UVQuad.Y()>=0)&&(UVQuad.Y()<=1)); + + ///get the abstract mesh + AbstractMesh* diam_domain=diamond_meshes[DiamIndex].domain; + ///get the 4 vertices on the full diamond + + ///transform in diamond coordinates + vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); + vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); + vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + + ///get 2 directions + vcg::Point2 v0=c1-c0; + //v0.Normalize(); + vcg::Point2 v1=c3-c0; + //v1.Normalize(); + + ///value in diamond coordinates + vcg::Point2 UVDiam=c0+UVQuad.X()*v0; + vcg::Point2 diry=UVQuad.Y()*v1; + UVDiam=UVDiam+diry; + + //printf("Diamond: %d,%f,%f \n",DiamIndex,UVDiam.X(),UVDiam.Y()); + + int index; + CoordType bary; +#ifndef NDEBUG + bool done=GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); +#else + GetBaryFaceFromUV(*diam_domain,UVDiam.X(),UVDiam.Y(),bary,index); +#endif + UV.X()=bary.X(); + UV.Y()=bary.Y(); + + I=diamond_meshes[DiamIndex].Local2Global(index); + assert(done); + } + + ///TO RESCALE? + ///given the coordinates in the parametrization space return return the coordinates AS A QUAD + void GE1Quad(const int &I, + const vcg::Point2 &UV, + int &DiamIndex, + vcg::Point2 &UVQuad) + { + ///first get the right half diamond index + DiamIndex=getHDiamIndex(I,UV); + + ///transform in diamond space + vcg::Point2 UVDiam; + GE1(I,UV,DiamIndex,UVDiam); + + ///transform in diamond coordinates + vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); + vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); + vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + + ///get 2 directions + vcg::Point2 v0=c1-c0; + //v0.Normalize(); + vcg::Point2 v1=c3-c0; + //v1.Normalize(); + + ///translate respect to zero + UVDiam-=c0; + + ///then transform in new coordspace + UVQuad.X()=v0.X()*UVDiam.X()+v0.Y()*UVDiam.Y(); + UVQuad.Y()=v1.X()*UVDiam.X()+v1.Y()*UVDiam.Y(); + + } + + ///given the diamond coordinates return return the coordinates AS A QUAD + void GE1Quad(const int &/*DiamIndex*/, + const vcg::Point2 &UVDiam, + vcg::Point2 &UVQuad) + { + //assert(UVDiam.Y()<0); + ///transform in diamond coordinates + vcg::Point2 c0=vcg::Point2(0,(ScalarType)-0.5); + vcg::Point2 c1=vcg::Point2((sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + vcg::Point2 c2=vcg::Point2(0,(ScalarType)0.5); + vcg::Point2 c3=vcg::Point2(-(sqrt((ScalarType)3.0)/(ScalarType)6.0),0); + + ///get 2 directions + vcg::Point2 v0=c1-c0; + vcg::Point2 v1=c3-c0; + + ///translate respect to zero + vcg::Point2 temp=UVDiam; + //temp=c3; + temp-=c0; + ScalarType det=(ScalarType)1.0/(v0.X()*v1.Y()-v1.X()*v0.Y()); + ///then transform in new coordspace + UVQuad.X()=v1.Y()*temp.X()-v1.X()*temp.Y(); + UVQuad.Y()=-v0.Y()*temp.X()+v0.X()*temp.Y(); + UVQuad.X()*=det; + UVQuad.Y()*=det; + /* printf("UVtr1=%f, %f \n",UVQuad.X(),UVQuad.Y()); + system("pause");*/ + } + + ///return the coordinate on the face domain + void GE2(const int &I, + const vcg::Point2 &UV, + vcg::Point2 &UVFace) + { + ///get the right edge index + CoordType bary=CoordType(UV.X(),UV.Y(),1-UV.X()-UV.Y()); + + ///then transform to the face domain + ///get face mesh + AbstractMesh* face_domain=face_meshes[I].domain; + AbstractFace* f=&(face_domain->face[0]); + + UVFace=bary.X()*f->V(0)->T().P()+bary.Y()*f->V(1)->T().P()+bary.Z()*f->V(2)->T().P(); + } + + ///given the face coordinates return the coordinates in the parametrization space + void inv_GE2(const int &FaceIndex, + const vcg::Point2 &UVFace, + vcg::Point2 &UV) + { + AbstractMesh* face_domain=face_meshes[FaceIndex].domain; + CoordType bary; + int index; +#ifndef NDEBUG + bool done=GetBaryFaceFromUV(*face_domain,UVFace.X(),UVFace.Y(),bary,index); + assert(done); +#else + GetBaryFaceFromUV(*face_domain,UVFace.X(),UVFace.Y(),bary,index); +#endif + UV.X()=bary.X(); + UV.Y()=bary.Y(); + + } + + void Clear() + { + face_to_vert.clear(); + star_meshes.clear(); + face_meshes.clear(); + diamond_meshes.clear(); + } + + bool Update(bool test=true) + { + UpdateTopologies(abstract_mesh); + UpdateTopologies(param_mesh); + float fix_num=sqrt((ScalarType)3.0)/(ScalarType)4.0; + + int edge_count=0; + ///cont number of edges + for (unsigned int i=0;iface.size();i++) + { + if (!(abstract_mesh->face[i].IsD())) + { + AbstractFace *f0=&abstract_mesh->face[i]; + //for each edge + for (int j=0;j<3;j++) + { + AbstractFace * f1=f0->FFp(j); + if (f1>f0) + edge_count++; + } + } + } + + ///test param mesh + for (unsigned int i=0;ivert.size();i++) + { + if (!(param_mesh->vert[i].IsD())) + { + ParamVertex *v0=¶m_mesh->vert[i]; + ParamMesh::CoordType bary=ParamMesh::CoordType(v0->T().U(),v0->T().V(),1-v0->T().U()-v0->T().V()); + int patchNum=v0->T().N(); + if (!testBaryCoords(bary)) + return false; + if (patchNum<0) + return false; + if (patchNum>AbsMesh()->fn) + return false; + } + } + Area3d=vcg::tri::Stat::ComputeMeshArea(*param_mesh); + AbstractArea=(ScalarType)abstract_mesh->fn*fix_num; + + face_to_vert.clear(); + star_meshes.clear(); + face_meshes.clear(); + diamond_meshes.clear(); + star_meshes.resize(abstract_mesh->vn); + face_meshes.resize(abstract_mesh->fn); + diamond_meshes.resize(edge_count); + InitFaceToVert(); + InitFace(); + InitDiamond(); + InitStar(); + if (test) + return (Test()); + return true; + } + + bool Init(AbstractMesh * _abstract_mesh, + ParamMesh * _param_mesh,bool test=true) + { + + abstract_mesh=_abstract_mesh; + param_mesh=_param_mesh; + + UpdateTopologies(abstract_mesh); + UpdateTopologies(param_mesh); + + return (Update(test)); + } + + AbstractMesh *&AbsMesh(){return abstract_mesh;} + ParamMesh *&ParaMesh(){return param_mesh;} + + ///given the index of face and the index of the edge return the + ///index of diamond + int GetDiamond(const int &I,const int & edge) + { + AbstractVertex *v0=AbsMesh()->face[I].V0(edge); + AbstractVertex *v1=AbsMesh()->face[I].V1(edge); + int index; + getDiamondFromPointer(v0,v1,index); + return index; + } + + int GetStarIndex(const int &I,const int & indexV) + { + AbstractVertex *v=AbsMesh()->face[I].V(indexV); + int index; + getStarFromPointer(v,index); + return index; + } + + void SaveBaseDomain(char *pathname) + { + /*vcg::tri::io::ExporterPLY::Save(*AbsMesh(),pathname);*/ + /*Warp(0);*/ + FILE *f; + f=fopen(pathname,"w+"); + + std::map vertexmap; + typedef std::map::iterator iteMapVert; + + ///add vertices + fprintf(f,"%d,%d \n",AbsMesh()->fn,AbsMesh()->vn); + int index=0; + for (unsigned int i=0;ivert.size();i++) + { + AbstractVertex* vert=&AbsMesh()->vert[i]; + if (!vert->IsD()) + { + vertexmap.insert(std::pair(vert,index)); + CoordType pos=vert->P(); + CoordType RPos=vert->RPos; + fprintf(f,"%f,%f,%f;\n",pos.X(),pos.Y(),pos.Z()); + index++; + } + } + + ///add faces + for (unsigned int i=0;iface.size();i++) + { + AbstractFace* face=&AbsMesh()->face[i]; + if (!face->IsD()) + { + AbstractVertex* v0=face->V(0); + AbstractVertex* v1=face->V(1); + AbstractVertex* v2=face->V(2); + iteMapVert vertIte; + vertIte=vertexmap.find(v0); + assert(vertIte!=vertexmap.end()); + int index0=(*vertIte).second; + vertIte=vertexmap.find(v1); + assert(vertIte!=vertexmap.end()); + int index1=(*vertIte).second; + vertIte=vertexmap.find(v2); + assert(vertIte!=vertexmap.end()); + int index2=(*vertIte).second; + assert((index0!=index1)&&(index1!=index2)); + fprintf(f,"%d,%d,%d \n",index0,index1,index2); + } + } + fclose(f); + } + + template + bool SetParamMesh(MeshType *_input_mesh, + ParamMesh * _param_mesh) + { + param_mesh=_param_mesh; + param_mesh->Clear(); + vcg::tri::Append::Mesh(*param_mesh,*_input_mesh); + return(Update(true)); + } + + template + bool LoadBaseDomain(char *pathname, + MeshType *_input_mesh, + ParamMesh * _param_mesh, + AbstractMesh *_absMesh, + bool test=true) +// bool use_quality=true) + { + param_mesh=_param_mesh; + param_mesh->Clear(); + /*vcg::tri::Allocator::CompactVertexVector(*_input_mesh); + vcg::tri::Allocator::CompactFaceVector(*_input_mesh);*/ + vcg::tri::Append::Mesh(*param_mesh,*_input_mesh); + /*UpdateStructures(param_mesh);*/ + + ///quality copy to index of texture + for (size_t i=0;ivert.size();i++) + { + int val0=(int)param_mesh->vert[i].Q(); + //int val1=param_mesh->vert[i].T().N();*/ + param_mesh->vert[i].T().N()=val0; + assert(param_mesh->vert[i].T().N()>=0); + } + /*if (AbsMesh()!=NULL) + delete(AbsMesh());*/ + + //AbsMesh()=new AbstractMesh(); + AbsMesh()=_absMesh; + AbsMesh()->Clear(); + + FILE *f=NULL; + f=fopen(pathname,"r"); + if (f==NULL) + return -1; + + ///read vertices + fscanf(f,"%d,%d \n",&abstract_mesh->fn,&abstract_mesh->vn); + abstract_mesh->vert.resize(abstract_mesh->vn); + abstract_mesh->face.resize(abstract_mesh->fn); + + for (unsigned int i=0;ivert.size();i++) + { + AbstractVertex* vert=&abstract_mesh->vert[i]; + CoordType pos; + fscanf(f,"%f,%f,%f;\n",&pos.X(),&pos.Y(),&pos.Z()); + vert->P()=pos; + } + + ///add faces + for (unsigned int i=0;iface.size();i++) + { + AbstractFace* face=&abstract_mesh->face[i]; + if (!face->IsD()) + { + int index0,index1,index2; + fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); + abstract_mesh->face[i].V(0)=&abstract_mesh->vert[index0]; + abstract_mesh->face[i].V(1)=&abstract_mesh->vert[index1]; + abstract_mesh->face[i].V(2)=&abstract_mesh->vert[index2]; + } + } + UpdateTopologies(AbsMesh()); + fclose(f); + + return (Update(test)); + } + + template + void CopyParametrization(MeshType * _param_mesh) + { + for (size_t i=0;i<_param_mesh->vert.size();i++) + { + _param_mesh->vert[i].T().P()=ParaMesh()->vert[i].T().P(); + _param_mesh->vert[i].T().N()=ParaMesh()->vert[i].T().N(); + _param_mesh->vert[i].Q()=(typename MeshType::ScalarType)ParaMesh()->vert[i].T().N(); + } + } + + template + int LoadMCP(AbstractMesh * _abstract_mesh, + ParamMesh * _param_mesh, + char* filename,MeshType *coloredMesh=NULL) + { + abstract_mesh=_abstract_mesh; + param_mesh=_param_mesh; + + FILE *f=NULL; + f=fopen(filename,"r"); + if (f==NULL) + return -1; + + + ///add vertices + abstract_mesh->Clear(); + fscanf(f,"%d,%d \n",&abstract_mesh->fn,&abstract_mesh->vn); + abstract_mesh->vert.resize(abstract_mesh->vn); + abstract_mesh->face.resize(abstract_mesh->fn); + + for (unsigned int i=0;ivert.size();i++) + { + AbstractVertex* vert=&abstract_mesh->vert[i]; + CoordType pos; + CoordType RPos; + fscanf(f,"%f,%f,%f;%f,%f,%f \n",&pos.X(),&pos.Y(),&pos.Z(),&RPos.X(),&RPos.Y(),&RPos.Z()); + vert->P()=pos; + //vert->RPos=RPos; + } + + + + ///add faces + for (unsigned int i=0;iface.size();i++) + { + AbstractFace* face=&abstract_mesh->face[i]; + if (!face->IsD()) + { + int index0,index1,index2; + fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); + abstract_mesh->face[i].V(0)=&abstract_mesh->vert[index0]; + abstract_mesh->face[i].V(1)=&abstract_mesh->vert[index1]; + abstract_mesh->face[i].V(2)=&abstract_mesh->vert[index2]; + } + } + + ///high resolution mesh + fscanf(f,"%d,%d \n",¶m_mesh->fn,¶m_mesh->vn); + param_mesh->vert.resize(param_mesh->vn); + param_mesh->face.resize(param_mesh->fn); + + ///add vertices + for (unsigned int i=0;ivert.size();i++) + { + ParamVertex* vert=¶m_mesh->vert[i]; + CoordType pos; + CoordType bary; + vcg::Color4b col; + int index_face; + int col0,col1,col2; + fscanf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n", + &pos.X(),&pos.Y(),&pos.Z(), + &bary.X(),&bary.Y(),&bary.Z(), + &col0,&col1,&col2, + &index_face); + vert->P()=pos; + //vert->RPos=pos; + vert->T().P()=vcg::Point2(bary.X(),bary.Y()); + vert->T().N()=index_face; + if (coloredMesh!=NULL) + { + vcg::Color4b col=coloredMesh->vert[i].C(); + vert->C()=col; + } + } + + ///add faces + for (unsigned int i=0;iface.size();i++) + { + //BaseFace* face=&final_mesh.face[i]; + + int index0,index1,index2; + fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); + param_mesh->face[i].V(0)=¶m_mesh->vert[index0]; + param_mesh->face[i].V(1)=¶m_mesh->vert[index1]; + param_mesh->face[i].V(2)=¶m_mesh->vert[index2]; + + } + fclose(f); + + ///update structures + vcg::tri::UpdateBounding::Box(*abstract_mesh); + vcg::tri::UpdateTopology::FaceFace(*abstract_mesh); + vcg::tri::UpdateTopology::VertexFace(*abstract_mesh); + + vcg::tri::UpdateBounding::Box(*param_mesh); + vcg::tri::UpdateTopology::FaceFace(*param_mesh); + vcg::tri::UpdateTopology::VertexFace(*param_mesh); + + + Update(); + + return 0; + } +}; + + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/iso_transfer.h b/src/meshlabplugins/filter_isoparametrization/iso_transfer.h index 3a0ccab86..9538d215b 100644 --- a/src/meshlabplugins/filter_isoparametrization/iso_transfer.h +++ b/src/meshlabplugins/filter_isoparametrization/iso_transfer.h @@ -1,135 +1,135 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _ISO_TRANSFER -#define _ISO_TRANSFER - -class IsoTransfer -{ - typedef vcg::GridStaticPtr TriMeshGrid; - typedef ParamMesh::CoordType CoordType; - typedef ParamMesh::ScalarType ScalarType; - TriMeshGrid TRGrid; - - void Clamp(CoordType &bary) - { - /* float eps=0.01;*/ - float sum=0; - int bigger=0; - int lower=0; - /* for (int i=0;i<3;i++) - { - if ((bary.V(i)-eps)) - bary.V(i)=0; - if ((bary.V(i)<1+eps)&&(bary.V(i)>1-eps)) - bary.V(i)=1; - - sum+=bary.V(i); - - if (bary.V(i)>bary.V(bigger)) - bigger=i; - if (bary.V(i)(1.0+eps)) - { - float diff=sum-1.0; - bary.V(bigger)-=diff; - } - else - if (sum<(1.0-eps)) - { - float diff=1.0-sum; - bary.V(lower)+=diff; - }*/ - for (int i=0;i<3;i++) - { - if (bary.V(i)<0) - bary.V(i)=0; - if (bary.V(i)>1) - bary.V(i)=1; - - sum+=bary.V(i); - - if (bary.V(i)>bary.V(bigger)) - bigger=i; - if (bary.V(i)(1.0)) - { - float diff=sum-1.0; - bary.V(bigger)-=diff; - } - else - if (sum<(1.0)) - { - float diff=1.0-sum; - bary.V(lower)+=diff; - } - } - - public: - template - void Transfer(IsoParametrization &IsoParam, - MeshType &to_assing) - { - ///put the mesh in the grid - typedef typename MeshType::ScalarType ScalarType; - vcg::tri::UpdateBounding::Box(*IsoParam.ParaMesh()); - vcg::tri::UpdateNormals::PerFaceNormalized(*IsoParam.ParaMesh()); - vcg::tri::UpdateNormals::PerVertexAngleWeighted(*IsoParam.ParaMesh()); - vcg::tri::UpdateNormals::NormalizeVertex(*IsoParam.ParaMesh()); - vcg::tri::UpdateEdges::Set(*IsoParam.ParaMesh()); - vcg::tri::UpdateFlags::FaceProjection(*IsoParam.ParaMesh()); - - TRGrid.Set(IsoParam.ParaMesh()->face.begin(),IsoParam.ParaMesh()->face.end()); - ScalarType maxDist=IsoParam.ParaMesh()->bbox.Diag(); - ///then for each vertex find the closest - for (size_t i=0;iIsD()) - { - ScalarType dist; - CoordType closest,norm,bary; - ParamMesh::FaceType * f=NULL; - f=GetClosestFace(*IsoParam.ParaMesh(),TRGrid,vert->P(), maxDist,dist,closest,norm,bary); - assert(f!=NULL); - - ///then find back the coordinates - if (!((bary.X()>=0)&&(bary.X()<=1)&& - (bary.Y()>=0)&&(bary.Y()<=1)&& - (bary.Z()>=0)&&(bary.Z()<=1))) - { - printf("%i,%3.3f,%3.3f,%3.3f",int(i),bary.X(),bary.Y(),bary.Z()); - system("pause"); - } - Clamp(bary); - int I; - vcg::Point2 UV; - IsoParam.Phi(f,bary,I,UV); - ///and finally set to the vertex - assert(I>=0); - vert->T().P()=UV; - vert->T().N()=I; - vert->Q()=(typename MeshType::ScalarType)I; - } - } - } - -}; - -#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _ISO_TRANSFER +#define _ISO_TRANSFER + +class IsoTransfer +{ + typedef vcg::GridStaticPtr TriMeshGrid; + typedef ParamMesh::CoordType CoordType; + typedef ParamMesh::ScalarType ScalarType; + TriMeshGrid TRGrid; + + void Clamp(CoordType &bary) + { + /* float eps=0.01;*/ + float sum=0; + int bigger=0; + int lower=0; + /* for (int i=0;i<3;i++) + { + if ((bary.V(i)-eps)) + bary.V(i)=0; + if ((bary.V(i)<1+eps)&&(bary.V(i)>1-eps)) + bary.V(i)=1; + + sum+=bary.V(i); + + if (bary.V(i)>bary.V(bigger)) + bigger=i; + if (bary.V(i)(1.0+eps)) + { + float diff=sum-1.0; + bary.V(bigger)-=diff; + } + else + if (sum<(1.0-eps)) + { + float diff=1.0-sum; + bary.V(lower)+=diff; + }*/ + for (int i=0;i<3;i++) + { + if (bary.V(i)<0) + bary.V(i)=0; + if (bary.V(i)>1) + bary.V(i)=1; + + sum+=bary.V(i); + + if (bary.V(i)>bary.V(bigger)) + bigger=i; + if (bary.V(i)(1.0)) + { + float diff=sum-1.0; + bary.V(bigger)-=diff; + } + else + if (sum<(1.0)) + { + float diff=1.0-sum; + bary.V(lower)+=diff; + } + } + + public: + template + void Transfer(IsoParametrization &IsoParam, + MeshType &to_assing) + { + ///put the mesh in the grid + typedef typename MeshType::ScalarType ScalarType; + vcg::tri::UpdateBounding::Box(*IsoParam.ParaMesh()); + vcg::tri::UpdateNormals::PerFaceNormalized(*IsoParam.ParaMesh()); + vcg::tri::UpdateNormals::PerVertexAngleWeighted(*IsoParam.ParaMesh()); + vcg::tri::UpdateNormals::NormalizeVertex(*IsoParam.ParaMesh()); + vcg::tri::UpdateEdges::Set(*IsoParam.ParaMesh()); + vcg::tri::UpdateFlags::FaceProjection(*IsoParam.ParaMesh()); + + TRGrid.Set(IsoParam.ParaMesh()->face.begin(),IsoParam.ParaMesh()->face.end()); + ScalarType maxDist=IsoParam.ParaMesh()->bbox.Diag(); + ///then for each vertex find the closest + for (size_t i=0;iIsD()) + { + ScalarType dist; + CoordType closest,norm,bary; + ParamMesh::FaceType * f=NULL; + f=GetClosestFace(*IsoParam.ParaMesh(),TRGrid,vert->P(), maxDist,dist,closest,norm,bary); + assert(f!=NULL); + + ///then find back the coordinates + if (!((bary.X()>=0)&&(bary.X()<=1)&& + (bary.Y()>=0)&&(bary.Y()<=1)&& + (bary.Z()>=0)&&(bary.Z()<=1))) + { + printf("%i,%3.3f,%3.3f,%3.3f",int(i),bary.X(),bary.Y(),bary.Z()); + system("pause"); + } + Clamp(bary); + int I; + vcg::Point2 UV; + IsoParam.Phi(f,bary,I,UV); + ///and finally set to the vertex + assert(I>=0); + vert->T().P()=UV; + vert->T().N()=I; + vert->Q()=(typename MeshType::ScalarType)I; + } + } + } + +}; + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/local_parametrization.h b/src/meshlabplugins/filter_isoparametrization/local_parametrization.h index 166938165..eae7152d3 100644 --- a/src/meshlabplugins/filter_isoparametrization/local_parametrization.h +++ b/src/meshlabplugins/filter_isoparametrization/local_parametrization.h @@ -1,1378 +1,1378 @@ - - -#include "defines.h" -///fitting -#include -#include -#include -#include "texcoord_optimization.h" -#include "mesh_operators.h" - -#ifndef LOCAL_PARAMETRIZATION -#define LOCAL_PARAMETRIZATION - -//#include - -//#define samples_area 80 - -template -void ParametrizeExternal(MeshType &to_parametrize) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - std::vector vertices; - - ///find first border vertex - VertexType* Start=NULL; - typename MeshType::VertexIterator Vi=to_parametrize.vert.begin(); - - while ((Start==NULL)&&(Vi(to_parametrize,Start,vertices); - - //assert(vertices.size()>=4); - - ///find perimeter - ScalarType perimeter=0; - int size=vertices.size(); - for (int i=0;iP()-vertices[(i+1)%size]->P()).Norm(); - - ///find scaling factor - /*ScalarType Sperimeter=(2.0*M_PI)/perimeter;*/ - - ///set default texCoords - for (Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) - { - (*Vi).T().U()=-2; - (*Vi).T().V()=-2; - } - - ///set border vertices - typename std::vector::iterator iteV; - /*ScalarType curr_perim=0;*/ - ScalarType curr_angle=0; - vertices[0]->T().U()=cos(curr_angle); - vertices[0]->T().V()=sin(curr_angle); - //for (int i=1;iP()-vertices[(i-1)]->P()).Norm(); - // //curr_perim+=perimeter/(ScalarType)size; - // curr_angle=curr_perim*Sperimeter; - // vertices[i]->T().U()=cos(curr_angle); - // vertices[i]->T().V()=sin(curr_angle); - // assert((vertices[i]->T().U()>=-1)&&(vertices[i]->T().U()<=1)); - // assert((vertices[i]->T().V()>=-1)&&(vertices[i]->T().V()<=1)); - //} - ScalarType anglediv=(2.0*M_PI)/(ScalarType)(vertices.size()); - curr_angle=0; - for (unsigned int i=1;iT().U()=cos(curr_angle); - vertices[i]->T().V()=sin(curr_angle); - assert((vertices[i]->T().U()>=-1)&&(vertices[i]->T().U()<=1)); - assert((vertices[i]->T().V()>=-1)&&(vertices[i]->T().V()<=1)); - } -} - -template -void ParametrizeInternal(MeshType &to_parametrize) -{ - typedef typename MeshType::ScalarType ScalarType; - const ScalarType Eps=(ScalarType)0.0001; - ///set internal vertices - for (typename MeshType::VertexIterator Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) - { - //assert(!Vi->IsD()); - if ((!Vi->IsB())&&(!Vi->IsD())) - { - ///find kernel - std::vector star; - getVertexStar(&(*Vi),star); - ScalarType kernel=0; - for (unsigned int k=0;kIsB()) - { - ScalarType dist=((*Vi).P()-star[k]->P()).Norm(); - if (dist0); - ///then find factor - kernel=1.0/kernel; - - (*Vi).T().U()=0; - (*Vi).T().V()=0; - - int num=0; - ///find weighted media - for (unsigned int k=0;kIsB()) - { - ScalarType dist=((*Vi).P()-star[k]->P()).Norm(); - if (dist0); - (*Vi).T().U()+=kval*star[k]->T().U(); - (*Vi).T().V()+=kval*star[k]->T().V(); - num++; - } - ////on border case 2 neighbors - ///go next to the center - /*if (num==2) - { - (*Vi).T().U()/=2.0; - (*Vi).T().V()/=2.0; - }*/ - /*ScalarType u=(*Vi).T().U(); - ScalarType v=(*Vi).T().V();*/ - assert(((*Vi).T().U()>=-1)&&((*Vi).T().U()<=1)); - assert(((*Vi).T().V()>=-1)&&((*Vi).T().V()<=1)); - } - } - ///smoothing of txcoords - InitDampRestUV(to_parametrize); - for (typename MeshType::VertexIterator Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) - { - if ((!Vi->IsB())&&(!Vi->IsD())) - { - std::vector star; - getVertexStar(&(*Vi),star); - vcg::Point2 UV=vcg::Point2(0,0); - for (unsigned int k=0;kRestUV; - UV/=(ScalarType)star.size(); - (*Vi).T().P()=UV; - } - } -} - - -template -typename FaceType::CoordType InterpolatePos -(FaceType* f, const typename FaceType::CoordType &bary) -{return (f->V(0)->P()*bary.X()+f->V(1)->P()*bary.Y()+f->V(2)->P()*bary.Z());} - -template -typename FaceType::CoordType InterpolateRPos -(FaceType* f,const typename FaceType::CoordType &bary) -{ - return (f->V(0)->RPos*bary.X()+f->V(1)->RPos*bary.Y()+f->V(2)->RPos*bary.Z()); -} - -template -typename FaceType::CoordType InterpolateNorm -(FaceType* f, const typename FaceType::CoordType &bary) -{ - typedef typename FaceType::CoordType CoordType; - CoordType n0=f->V(0)->N(); - CoordType n1=f->V(1)->N(); - CoordType n2=f->V(2)->N(); - return (n0*bary.X()+n1*bary.Y()+n2*bary.Z()); -} - -template -int Approx(const ScalarType &value) -{ - ScalarType val0=floor(value); - ScalarType val1=ceil(value); - if (fabs(val0-value) -vcg::Point3i InterpolateColor -(FaceType* f,const typename FaceType::CoordType &bary) -{ - typedef typename FaceType::ScalarType ScalarType; - vcg::Color4b c0=f->V(0)->C(); - vcg::Color4b c1=f->V(1)->C(); - vcg::Color4b c2=f->V(2)->C(); - double R=(ScalarType)c0.X()*bary.X()+(ScalarType)c1.X()*bary.Y()+(ScalarType)c2.X()*bary.Z(); - double G=(ScalarType)c0.Y()*bary.X()+(ScalarType)c1.Y()*bary.Y()+(ScalarType)c2.Y()*bary.Z(); - double B=(ScalarType)c0.Z()*bary.X()+(ScalarType)c1.Z()*bary.Y()+(ScalarType)c2.Z()*bary.Z(); - - vcg::Point3i p=vcg::Point3i(Approx(R),Approx(G),Approx(B)); - - assert(p.X()<=255); - assert(p.Y()<=255); - assert(p.Z()<=255); - - return (p); -} - -template -typename VertexType::CoordType ProjectPos(const VertexType &v) -{ - typedef typename VertexType::FaceType FaceType; - typedef typename VertexType::CoordType CoordType; - - FaceType *f=v.father; - CoordType b=v.Bary; - return (InterpolatePos(f,b)); -} - -template -typename VertexType::CoordType Warp(const VertexType* v) -{ - typename VertexType::FaceType * father=v->father; - typename VertexType::CoordType proj=father->P(0)*v->Bary.X()+father->P(1)*v->Bary.Y()+father->P(2)*v->Bary.Z(); - return proj; -} - -template -typename VertexType::CoordType WarpRpos(const VertexType* v) -{ - typename VertexType::FaceType * father=v->father; - typename VertexType::CoordType proj=father->V(0)->RPos*v->Bary.X()+father->V(1)->RPos*v->Bary.Y()+father->V(2)->RPos*v->Bary.Z(); - return proj; -} - -template -typename MeshType::ScalarType EstimateLenghtByParam - (const typename MeshType::VertexType* v0, - const typename MeshType::VertexType* v1, - typename MeshType::FaceType* on_edge[2]) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::ScalarType ScalarType; - -// assert((on_edge.size()==0)||(on_edge.size()==1)); - ScalarType estimated[2]={0,0}; - int num[2]={0,0}; - - for (int i=0;i<2;i++) - { - FaceType *test_face=on_edge[i]; - - int edge_index=EdgeIndex(test_face,v0,v1); - FaceType *Fopp=test_face->FFp(edge_index); - - if (test_face->vertices_bary.size()<2) - { - ScalarType dist=Distance(v0->RPos,v1->RPos); - //#pragma omp atomic - estimated[i]+=dist; - num[i]=0; - continue; - } - - ///collect vertices - std::vector vertices; - vertices.reserve(test_face->vertices_bary.size()); - for (unsigned int k=0;kvertices_bary.size();k++) - vertices.push_back(test_face->vertices_bary[k].first); - - - ///collect faces - std::vector faces; - getSharedFace(vertices,faces); - - ///get border edges - std::vector > edges; - for (unsigned int j=0;jV0(k)->father==test_face)&& - (f->V1(k)->father==test_face)&& - (f->V2(k)->father==Fopp)) - { - edges.push_back(std::pair(f->V0(k),f->V1(k))); - found=true; - } - k++; - } - } - - ///find if there's ant edge return inital lenght - if (edges.size()==0) - { - estimated[i]+=(Distance(v0->RPos,v1->RPos)); - num[i]=0; - continue; - } - else - { - //get edge direction - ///store the two nearest for each vertex - /*VertexType *n0=edges[0].first; - VertexType *n1=edges[0].second; - ScalarType d0=(Warp(n0)-v0->P()).Norm(); - ScalarType d1=(Warp(n1)-v1->P()).Norm();*/ - - //CoordType edgedir=v0->cP()-v1->cP(); - CoordType edgedir=v0->RPos-v1->RPos; - edgedir.Normalize(); - num[i]=edges.size(); - for (unsigned int e=0;eP()-vH1->P()).Norm()); - //#pragma omp atomic - estimated[i]+=fabs(dirproj*edgedir)*((vH0->RPos-vH1->RPos).Norm()); - - } - } - } - - ///media of estimated values - ScalarType alpha0,alpha1; - ScalarType max_num=abstraction_num; - - if (num[0]>=max_num) - alpha0=1; - else - alpha0=num[0]/max_num; - - if (num[1]>=max_num) - alpha1=1; - else - alpha1=num[1]/max_num; - - estimated[0]=alpha0*estimated[0]+(1.0-alpha0)*(Distance(v0->RPos,v1->RPos)); - estimated[1]=alpha1*estimated[1]+(1.0-alpha1)*(Distance(v0->RPos,v1->RPos)); - return((estimated[0]+estimated[1])/2.0); -} - -template -void MeanVal(const std::vector > &Points, - std::vector &Lamda, - typename MeshType::CoordType &p) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - - int size=Points.size(); - Lamda.resize(size); - - ScalarType sum=0; - for (int i=0;i Pcurr=Points[i]; - vcg::Point2 Pprev=Points[(i+(size-1))%size]; - vcg::Point2 Pnext=Points[(i+1)%size]; - - CoordType v0=Pprev-p; - CoordType v1=Pcurr-p; - CoordType v2=Pnext-p; - ScalarType l=v1.Norm(); - v0.Normalize(); - v1.Normalize(); - v2.Normalize(); - - ScalarType Alpha0=acos(v0*v1); - ScalarType Alpha1=acos(v1*v2); - - Lamda[i]=(tan(Alpha0/2.0)+tan(Alpha1/2.0))/l; - sum+=Lamda[i]; - } - - ///normalization - for (int i=0;i -typename FaceType::ScalarType EstimateAreaByParam(const FaceType* f) -{ - typedef typename FaceType::VertexType VertexType; - typedef typename FaceType::ScalarType ScalarType; - - int num=0; - ScalarType estimated=0; - for (unsigned int k=0;kvertices_bary.size();k++) - { - VertexType *HresVert=f->vertices_bary[k].first; - estimated+=HresVert->area; - num++; - } - - ///media of estimated values - ScalarType alpha; - ScalarType max_num=abstraction_num; - - if (num>=max_num) - alpha=1; - else - alpha=num/max_num; - - ScalarType Rarea=((f->V(1)->RPos-f->V(0)->RPos)^(f->V(2)->RPos-f->V(0)->RPos)).Norm()/2.0; - estimated=alpha*estimated+(1.0-alpha)*Rarea; - - return(estimated); -} - -template -typename MeshType::ScalarType EstimateAreaByParam - (const typename MeshType::VertexType* v0, - const typename MeshType::VertexType* v1, - typename MeshType::FaceType* on_edge[2]) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::ScalarType ScalarType; - - //MeshType::PerVertexAttributeHandle handle = vcg::tri::Allocator::GetPerVertexAttribute(mesh,"AuxiliaryVertData"); - - ScalarType estimated[2]={0,0}; - int num[2]={0,0}; - VertexType *v2[2]; - for (int i=0;i<2;i++) - { - FaceType *test_face=on_edge[i]; - - for (int k=0;k<3;k++) - if ((test_face->V(k)!=v0)&&(test_face->V(k)!=v1)) - v2[i]=test_face->V(k); - - for (unsigned int k=0;kvertices_bary.size();k++) - { - VertexType *brother=test_face->vertices_bary[k].first; - estimated[i]+=brother->area; - //estimated[i]+=handle[brother].area; - num[i]++; - } - } - - ///media of estimated values - ScalarType alpha0,alpha1; - ScalarType max_num=abstraction_num;//20 - - if (num[0]>=max_num) - alpha0=1; - else - alpha0=num[0]/max_num; - - if (num[1]>=max_num) - alpha1=1; - else - alpha1=num[1]/max_num; - ScalarType Rarea0=((on_edge[0]->V(1)->RPos-on_edge[0]->V(0)->RPos)^(on_edge[0]->V(2)->RPos-on_edge[0]->V(0)->RPos)).Norm()/2.0; - ScalarType Rarea1=((on_edge[1]->V(1)->RPos-on_edge[1]->V(0)->RPos)^(on_edge[1]->V(2)->RPos-on_edge[1]->V(0)->RPos)).Norm()/2.0; - estimated[0]=alpha0*estimated[0]+(1.0-alpha0)*Rarea0; - estimated[1]=alpha1*estimated[1]+(1.0-alpha1)*Rarea1; - return((estimated[0]+estimated[1])/2.0); -} - -///template class used to sample surface -template -class VertexSampler{ - typedef typename FaceType::CoordType CoordType; -public: - std::vector points; - - void AddFace(const FaceType &f,const CoordType & bary) - {points.push_back(f.P(0)*bary.X()+f.P(1)*bary.Y()+f.P(2)*bary.Z());} -}; - - -///sample 3d vertex possible's position -///using area criterion -//template -//void SamplingPoints(MeshType &mesh, -// std::vector &pos) -//{ -// typedef typename MeshType::CoordType CoordType; -// typedef VertexSampler Sampler; -// pos.reserve(samples_area); -// Sampler ps; -// ps.points.reserve(samples_area); -// -// vcg::tri::SurfaceSampling::Montecarlo(mesh,ps,samples_area); -// pos=std::vector(ps.points.begin(),ps.points.end()); -//} - -template -void InitDampRestUV(MeshType &m) -{ - for (unsigned int i=0;i -void RestoreRestUV(MeshType &m) -{ - for (unsigned int i=0;i -void ParametrizeLocally(MeshType ¶metrized, - bool fix_boundary=true, - bool init_border=true) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - - //const ScalarType epsilon=(ScalarType)0.0001; - - - ///save old positions - - std::vector positions; - positions.resize(parametrized.vert.size()); - ///set rest position - for (unsigned int i=0;i opt(parametrized); - //vcg::tri::WachspressTexCoordOptimization opt(parametrized); - vcg::tri::AreaPreservingTexCoordOptimization opt1(parametrized); - opt.SetSpeed((ScalarType)0.0005); - InitDampRestUV(parametrized); - if (fix_boundary) - { - opt.TargetEquilateralGeometry(); - //opt.TargetCurrentGeometry(); - opt.SetBorderAsFixed(); - opt.IterateUntilConvergence((ScalarType)0.000001,100); - /*opt.Iterate(); - opt.Iterate();*/ - } - else - { - opt1.TargetCurrentGeometry(); - //opt1.SetBorderAsFixed(); - opt1.IterateUntilConvergence((ScalarType)0.000001,200); - } - - ///assert parametrization - for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); -#ifndef NDEBUG - ScalarType area=(tex1-tex0)^(tex2-tex0); - assert(area>0); -#endif -//#ifndef _MESHLAB -// if (area<0){ -// vcg::tri::io::ExporterPLY::Save(parametrized,"case0.ply"); -// -// for (int j=0;j::Save(parametrized,"case1.ply"); -// assert(0); -// } -//#endif - } - ///restore position - for (unsigned int i=0;i -void ForceInParam(vcg::Point2 &UV,MeshType &domain) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - ScalarType minDist=(ScalarType)1000.0; - vcg::Point2 closest; - vcg::Point2 center=vcg::Point2(0,0); - for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - center+=tex0; - center+=tex1; - center+=tex2; - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType dist; - vcg::Point2 temp; - t2d.PointDistance(UV,dist,temp); - if (dist -bool testParamCoords(VertexType *v) -{ - typedef typename VertexType::ScalarType ScalarType; - ScalarType eps=(ScalarType)0.00001; - if (!(((v->T().P().X()>=-1-eps)&&(v->T().P().X()<=1+eps)&& - (v->T().P().Y()>=-1-eps)&&(v->T().P().Y()<=1+eps)))) - return (false); - - return true; -} - -template -bool testParamCoords(MeshType &domain) -{ - for (unsigned int i=0;i(v); - if (!b) - { - #ifndef _MESHLAB - printf("\n position %lf,%lf \n",v->T().U(),v->T().V()); - #endif - return false; - } - } - return true; -} - -template -bool testBaryCoords(CoordType &bary) -{ - typedef typename CoordType::ScalarType ScalarType; - ///test - float eps=(ScalarType)0.0001; - if(!(fabs(bary.X()+bary.Y()+bary.Z()-1.0)=-eps)&&(bary.Y()<=1.0)&&(bary.Y()>=-eps)&&(bary.Z()<=1.0)&&(bary.Z()>=-eps))) - return false; - return true; -} - -template -bool NormalizeBaryCoords(CoordType &bary) -{ - bool isOK=testBaryCoords(bary); - if (!isOK) - return false; - - typedef typename CoordType::ScalarType ScalarType; - - ///test <0 - if (bary.X()<0) - bary.X()=0; - if (bary.Y()<0) - bary.Y()=0; - if (bary.Z()<0) - bary.Z()=0; - - ///test >1 - if (bary.X()>1.0) - bary.X()=1.0; - if (bary.Y()>1.0) - bary.Y()=1.0; - if (bary.Z()>1.0) - bary.Z()=1.0; - - ///test sum - ScalarType diff=bary.X()+bary.Y()+bary.Z()-1.0; - bary.X()-=diff; - - if (bary.X()<0) - bary.X()=0; - return true; -} - -template -void AssingFather(typename MeshType::VertexType &v, - typename MeshType::FaceType *father, - typename MeshType::CoordType &bary, - MeshType & domain) -{ -#ifdef _DEBUG - const typename MeshType::ScalarType eps=(typename MeshType::ScalarType)0.00001; - assert((father-&(*domain.face.begin()))<(int)domain.face.size()); - assert(!(father->IsD())); - assert(!(father==NULL)); - assert((bary.X()>=0)&&(bary.X()<=1)&& - (bary.Y()>=0)&&(bary.Y()<=1)&& - (bary.Z()>=0)&&(bary.Z()<=1)&& - ((bary.X()+bary.Y()+bary.Z())<=1+eps)&& - ((bary.X()+bary.Y()+bary.Z())>=1-eps)); -#endif - v.father=father; - v.Bary=bary; -} - -template -bool testParametrization(MeshType &domain, - MeshType &Hlev) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - bool is_good=true; - int num_del=0; - int num_null=0; - int fath_son=0; - int wrong_address=0; - for (unsigned int i=0;ifather-&(*domain.face.begin()))>=(int)domain.face.size()) - { - printf("\n ADDRESS EXCEEDS OF %d \n",v->father-&(*domain.face.begin())); - wrong_address++; - is_good=false; - isGoodAddr=false; - } - if ((isGoodAddr)&&(v->father==NULL)) - { - //printf("\n PAR ERROR : father NULL\n"); - num_null++; - is_good=false; - } - if ((isGoodAddr)&&(v->father->IsD())) - { - //printf("\n PAR ERROR : father DELETED \n"); - num_del++; - is_good=false; - } - if ((isGoodAddr)&&(!(((v->Bary.X()>=0)&&(v->Bary.X()<=1))&& - ((v->Bary.Y()>=0)&&(v->Bary.Y()<=1))&& - ((v->Bary.Z()>=0)&&(v->Bary.Z()<=1))))) - { - printf("\n PAR ERROR : bary coords exceeds: %f,%f,%f \n",v->Bary.X(),v->Bary.Y(),v->Bary.Z()); - is_good=false; - } - } - for (unsigned int i=0;iIsD()) - { - for (unsigned int j=0;jvertices_bary.size();j++) - { - VertexType *v=face->vertices_bary[j].first; - if (v->father!=face) - { - //printf("\n PAR ERROR : Father<->son \n"); - fath_son++; - v->father=face; - is_good=false; - } - } - } - } - - if (num_del>0) - printf("\n PAR ERROR %d Father isDel \n",num_del); - if (num_null>0) - printf("\n PAR ERROR %d Father isNull \n",num_null); - if (fath_son>0) - printf("\n PAR ERROR %d Father<->son \n",fath_son); - if (wrong_address>0) - { - printf("\n PAR ERROR %d Wrong Address Num Faces %d\n",wrong_address,domain.fn); - /*system("pause");*/ - } - return (is_good); -} - -template -bool NonFolded(MeshType ¶metrized) -{ - //const ScalarType epsilon=0.00001; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - ///assert parametrization - for (unsigned int i=0;iV(0)->IsB())&&(f->V(1)->IsB())&&(f->V(2)->IsB()))) - { - - vcg::Point2 tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType area=(tex1-tex0)^(tex2-tex0); - if (area<=0) - return false; - } - } - return true; -} - -template -bool NonFolded(MeshType ¶metrized,std::vector &folded) -{ - - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - const ScalarType epsilon=(ScalarType)0.00001; - folded.resize(0); - ///assert parametrization - for (unsigned int i=0;iV(0)->IsB())&&(f->V(1)->IsB())&&(f->V(2)->IsB()))) - { - - vcg::Point2 tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType area=(tex1-tex0)^(tex2-tex0); - if (area<=epsilon) - folded.push_back(f); - } - } - return (folded.size()==0); -} -//getFoldedFaces(std::vector) -///parametrize a submesh from trinagles that are incident on vertices with equi-area subdivision -template -void ParametrizeStarEquilateral(MeshType ¶metrized, - const typename MeshType::ScalarType &radius=1) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - UpdateTopologies(¶metrized); - - //set borders - - ///find first border & non border vertex - std::vector non_border; - VertexType* Start=NULL; - for (unsigned int i=0;iIsB())) - Start=vert; - - if (!vert->IsB()) - non_border.push_back(vert); - } - assert(non_border.size()!=0); - - ///get sorted border vertices - std::vector vertices; - FindSortedBorderVertices(parametrized,Start,vertices); - - ///set border vertices - int num=vertices.size(); - typename std::vector::iterator iteV; - ScalarType curr_angle=0; - vertices[0]->T().U()=cos(curr_angle)*radius; - vertices[0]->T().V()=sin(curr_angle)*radius; - ScalarType division=(2*M_PI)/(ScalarType)num; - ///set border - for (unsigned int i=1;iT().U()=radius*cos(curr_angle); - vertices[i]->T().V()=radius*sin(curr_angle); - } - - if (non_border.size()==1) - { - ///if non-border vertex is one then set it to zero otherwise - ///set it to the average of neighbors - non_border[0]->T().P()=vcg::Point2(0,0); - } - else - { - ///set media of star vertices - assert(non_border.size()==2); - for (unsigned int i=0;iT().P()=vcg::Point2(0,0); - int ariety_vert=0; - std::vector star; - getVertexStar(v,star); - for (unsigned int k=0;kIsD())&&(star[k]->IsB())) - { - v->T().P()+=star[k]->T().P(); - ariety_vert++; - } - } - v->T().P()/=(ScalarType)ariety_vert; - } - ///test particular cases - if (!NonFolded(parametrized)) - { - std::vector shared; - getSharedVertexStar(non_border[0],non_border[1],shared); - - assert(shared.size()==2); - assert(shared[0]->IsB()); - assert(shared[1]->IsB()); - assert(shared[0]!=shared[1]); - - //ScalarType epsilon=(ScalarType)0.001; - ///then get the media of two shared vertices - vcg::Point2 uvAve=shared[0]->T().P()+shared[1]->T().P(); - assert(uvAve.Norm()>(ScalarType)0.001); - uvAve.Normalize(); - vcg::Point2 p0=uvAve*(ScalarType)0.3; - vcg::Point2 p1=uvAve*(ScalarType)(-0.3); - ///then test and set right assignement - non_border[0]->T().P()=p0; - non_border[1]->T().P()=p1; - if (!NonFolded(parametrized)){ - non_border[0]->T().P()=p1; - non_border[1]->T().P()=p0; - } - } - } - - ///final assert parametrization - assert(NonFolded(parametrized)); - -} - -///given the mesh and the two edges (same) seen from face[0] and face[1] of the mesh construct -///a diamond parametrization using equilateral triangles of edge edge_len -template -void ParametrizeDiamondEquilateral(MeshType ¶metrized, - const int &edge0,const int &edge1, - const typename MeshType::ScalarType &edge_len=1) -{ - - typedef typename MeshType::FaceType FaceType; - typedef typename FaceType::CoordType CoordType; - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::VertexType VertexType; - - ScalarType h=(sqrt(3.0)/2.0)*edge_len; - - FaceType *fd0=¶metrized.face[0]; -#ifndef NDEBUG - FaceType *fd1=¶metrized.face[1]; -#endif - assert(fd0->FFp(edge0)==fd1); - assert(fd1->FFp(edge1)==fd0); - - ///get 2 vertex on the edge - VertexType *v0=fd0->V(edge0); - VertexType *v1=fd0->V((edge0+1)%3); - -#ifndef NDEBUG - VertexType *vtest0=fd1->V(edge1); - VertexType *vtest1=fd1->V((edge1+1)%3); - - assert(v0!=v1); - assert(vtest0!=vtest1); - assert(((v0==vtest0)&&(v1==vtest1))||((v1==vtest0)&&(v0==vtest1))); -#endif - - ///other 2 vertex - VertexType *v2=parametrized.face[0].V((edge0+2)%3); - VertexType *v3=parametrized.face[1].V((edge1+2)%3); - assert((v2!=v3)&&(v0!=v2)&&(v0!=v3)&&(v1!=v2)&&(v1!=v3)); - - ///assing texcoords - v0->T().P()=vcg::Point2(0,-edge_len/2.0); - v1->T().P()=vcg::Point2(0,edge_len/2.0); - v2->T().P()=vcg::Point2(-h,0); - v3->T().P()=vcg::Point2(h,0); - - ///test - assert(NonFolded(parametrized)); -} - -///given the mesh and the two edges (same) seen from face[0] and face[1] of the mesh construct -///a diamond parametrization using equilateral triangles of edge edge_len -template -void ParametrizeFaceEquilateral(MeshType ¶metrized, - const typename MeshType::ScalarType &edge_len=1) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename FaceType::CoordType CoordType; - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::VertexType VertexType; - - ScalarType h=(sqrt(3.0)/2.0)*edge_len; - - FaceType *f_param=&(parametrized.face[0]); - - f_param->V(0)->T().P()=vcg::Point2(edge_len/2.0,0); - f_param->V(1)->T().P()=vcg::Point2(0,h); - f_param->V(2)->T().P()=vcg::Point2(-edge_len/2.0,0); -} - - -///parametrize and create a submesh from trinagles that are incident on -/// vertices .... seturn a vetor of original faces -template -void ParametrizeLocally(MeshType ¶metrized, - const std::vector &subset, - std::vector &orderedFaces, - std::vector &orderedVertex) -{ - typedef typename MeshType::FaceType FaceType; - typedef typename FaceType::CoordType CoordType; - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::VertexType VertexType; - - orderedFaces.clear(); - std::vector vertices; - - - ///get faces referenced by vertices - getSharedFace(subset,orderedFaces); - - ///do a first copy of the mesh - ///and parametrize it - ///NB: order of faces is mantained - CopyMeshFromFaces(orderedFaces,orderedVertex,parametrized); - - //CreateMeshVertexStar(subset,orderedFaces,parametrized); - ParametrizeLocally(parametrized); - -} - - - -template -void GetUV(const typename MeshType::FaceType* f, - const typename MeshType::CoordType &bary, - typename MeshType::ScalarType &U, - typename MeshType::ScalarType &V) -{ - U=bary.X()*f->V(0)->T().U()+bary.Y()*f->V(1)->T().U()+bary.Z()*f->V(2)->T().U(); - V=bary.X()*f->V(0)->T().V()+bary.Y()*f->V(1)->T().V()+bary.Z()*f->V(2)->T().V(); - /*if ((!((U>=-1)&&(U<=1)))||(!((V>=-1)&&(V<=1)))) - { - printf("Bary:%f,%f,%f \n",bary.X(),bary.Y(),bary.Z()); - printf("texCoord:%f,%f \n",U,V); - assert(0); - }*/ - //assert ((U>=-1)&&(U<=1)); - //assert ((V>=-1)&&(V<=1)); -} - -template -bool GetBaryFaceFromUV(const MeshType &m, - const typename MeshType::ScalarType &U, - const typename MeshType::ScalarType &V, - typename MeshType::CoordType &bary, - int &index) -{ - typedef typename MeshType::ScalarType ScalarType; - const ScalarType _EPSILON = ScalarType(0.0000001); - /*assert ((U>=-1)&&(U<=1)); - assert ((V>=-1)&&(V<=1));*/ - for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - - vcg::Point2 test=vcg::Point2(U,V); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType area=(tex1-tex0)^(tex2-tex0); - //assert(area>-_EPSILON); - ///then find if the point 2d falls inside - if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) - { - index=i; - ///approximation errors - ScalarType sum=0; - for (int x=0;x<3;x++) - { - if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) - bary[x]=0; - else - if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) - bary[x]=1; - sum+=bary[x]; - } - if (sum==0) - printf("error SUM %f \n",sum); - - bary/=sum; - return true; - } - } - - return (false); -} - -template -bool GetBaryFaceFromUV(std::vector faces, - const typename FaceType::ScalarType &U, - const typename FaceType::ScalarType &V, - typename FaceType::CoordType &bary, - int &index) -{ - typedef typename FaceType::CoordType CoordType; - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::VertexType VertexType; - typedef typename FaceType::ScalarType ScalarType; - const ScalarType _EPSILON = ScalarType(0.0000001); - /*assert ((U>=-1)&&(U<=1)); - assert ((V>=-1)&&(V<=1));*/ - for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - - vcg::Point2 test=vcg::Point2(U,V); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType area=fabs((tex1-tex0)^(tex2-tex0)); - //assert(area>-_EPSILON); - ///then find if the point 2d falls inside - if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) - { - index=i; - - ///approximation errors - ScalarType sum=0; - for (int x=0;x<3;x++) - { - if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) - bary[x]=0; - else - if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) - bary[x]=1; - sum+=fabs(bary[x]); - } - if (sum==0) - printf("error SUM %f \n",sum); - - bary/=sum; - /*if (!((bary.X()>=0)&& (bary.X()<=1))) - printf("error %f \n",bary.X());*/ - /*ScalarType diff=(1.0-bary.X()-bary.Y()-bary.Z()); - bary.X()+=diff;*/ - return true; - } - } - - return (false); -} - -template -bool GetBaryFaceFromUV(const MeshType &m, - const typename MeshType::ScalarType &U, - const typename MeshType::ScalarType &V, - const std::vector &orderedFaces, - typename MeshType::CoordType &bary, - typename MeshType::FaceType* &chosen) -{ - int index; - bool found=GetBaryFaceFromUV(m,U,V,bary,index); - if(!found) { - chosen=0; - return false; - } - chosen=orderedFaces[index]; - return true; -} - -template -bool GetCoordFromUV(const MeshType &m, - const typename MeshType::ScalarType &U, - const typename MeshType::ScalarType &V, - typename MeshType::CoordType &val, - bool rpos=false) -{ - typedef typename MeshType::ScalarType ScalarType; - const ScalarType _EPSILON = (ScalarType)0.00001; - for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); - vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); - vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); - - vcg::Point2 test=vcg::Point2(U,V); - vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); - ScalarType area=(tex1-tex0)^(tex2-tex0); - ///then find if the point 2d falls inside - typename MeshType::CoordType bary; - if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) - { - ///approximation errors - for (int x=0;x<3;x++) - { - if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) - bary[x]=0; - else - if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) - bary[x]=1; - } - ScalarType diff=(1.0-bary.X()-bary.Y()-bary.Z()); - bary.X()+=diff; - if (!rpos) - val=f->P(0)*bary.X()+f->P(1)*bary.Y()+f->P(0)*bary.Z(); - else - val=f->V(0)->RPos*bary.X()+f->V(1)->RPos*bary.Y()+f->V(2)->RPos*bary.Z(); - - return true; - } - } - return false; -} - -template -typename MeshType::ScalarType GetSmallestUVEdgeSize(const MeshType &m) -{ - typedef typename MeshType::ScalarType ScalarType; - - ScalarType smallest=100.f; - assert(m.fn>0); - for (int i=0;i uv0=m.face[i].V(j)->T().P(); - vcg::Point2 uv1=m.face[i].V((j+1)%3)->T().P(); - ScalarType test=(uv0-uv1).Norm(); - if (test -typename MeshType::ScalarType GetSmallestUVHeight(const MeshType &m) -{ - typedef typename MeshType::ScalarType ScalarType; - ScalarType smallest=(ScalarType)100.0; - ScalarType eps=(ScalarType)0.0001; - assert(m.fn>0); - for (unsigned int i=0;i uv0=f->V(j)->cT().P(); - vcg::Point2 uv1=f->V1(j)->cT().P(); - vcg::Point2 uv2=f->V2(j)->cT().P(); - ScalarType area=fabs((uv1-uv0)^(uv2-uv0)); - ScalarType base=(uv1-uv2).Norm(); - ScalarType h_test=area/base; - if (h_test(ScalarType)0.05) - smallest=(ScalarType)0.05; - return smallest; -} - -template -void ParametrizeStarEquilateral(typename MeshType::VertexType *center, - bool /*subvertices=true*/) -{ - ///initialize domain - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::CoordType CoordType; - - MeshType parametrized; - std::vector vertices,ordVert; - std::vector HresVert; - std::vector faces; - vertices.push_back(center); - getSharedFace(vertices,faces); - CopyMeshFromFaces(faces,ordVert,parametrized); - - ///parametrize and then copy back - ParametrizeStarEquilateral(parametrized); - for (unsigned int i=0;iT().P()=parametrized.vert[i].T().P(); - - ///initialize sub-vertices - getHresVertex(faces,HresVert); - for (unsigned int i=0;ifather; - CoordType Bary=HresVert[i]->Bary; - GetUV(father,Bary,HresVert[i]->T().U(),HresVert[i]->T().V()); - } -} - -#endif + + +#include "defines.h" +///fitting +#include +#include +#include +#include "texcoord_optimization.h" +#include "mesh_operators.h" + +#ifndef LOCAL_PARAMETRIZATION +#define LOCAL_PARAMETRIZATION + +//#include + +//#define samples_area 80 + +template +void ParametrizeExternal(MeshType &to_parametrize) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + std::vector vertices; + + ///find first border vertex + VertexType* Start=NULL; + typename MeshType::VertexIterator Vi=to_parametrize.vert.begin(); + + while ((Start==NULL)&&(Vi(to_parametrize,Start,vertices); + + //assert(vertices.size()>=4); + + ///find perimeter + ScalarType perimeter=0; + int size=vertices.size(); + for (int i=0;iP()-vertices[(i+1)%size]->P()).Norm(); + + ///find scaling factor + /*ScalarType Sperimeter=(2.0*M_PI)/perimeter;*/ + + ///set default texCoords + for (Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) + { + (*Vi).T().U()=-2; + (*Vi).T().V()=-2; + } + + ///set border vertices + typename std::vector::iterator iteV; + /*ScalarType curr_perim=0;*/ + ScalarType curr_angle=0; + vertices[0]->T().U()=cos(curr_angle); + vertices[0]->T().V()=sin(curr_angle); + //for (int i=1;iP()-vertices[(i-1)]->P()).Norm(); + // //curr_perim+=perimeter/(ScalarType)size; + // curr_angle=curr_perim*Sperimeter; + // vertices[i]->T().U()=cos(curr_angle); + // vertices[i]->T().V()=sin(curr_angle); + // assert((vertices[i]->T().U()>=-1)&&(vertices[i]->T().U()<=1)); + // assert((vertices[i]->T().V()>=-1)&&(vertices[i]->T().V()<=1)); + //} + ScalarType anglediv=(2.0*M_PI)/(ScalarType)(vertices.size()); + curr_angle=0; + for (unsigned int i=1;iT().U()=cos(curr_angle); + vertices[i]->T().V()=sin(curr_angle); + assert((vertices[i]->T().U()>=-1)&&(vertices[i]->T().U()<=1)); + assert((vertices[i]->T().V()>=-1)&&(vertices[i]->T().V()<=1)); + } +} + +template +void ParametrizeInternal(MeshType &to_parametrize) +{ + typedef typename MeshType::ScalarType ScalarType; + const ScalarType Eps=(ScalarType)0.0001; + ///set internal vertices + for (typename MeshType::VertexIterator Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) + { + //assert(!Vi->IsD()); + if ((!Vi->IsB())&&(!Vi->IsD())) + { + ///find kernel + std::vector star; + getVertexStar(&(*Vi),star); + ScalarType kernel=0; + for (unsigned int k=0;kIsB()) + { + ScalarType dist=((*Vi).P()-star[k]->P()).Norm(); + if (dist0); + ///then find factor + kernel=1.0/kernel; + + (*Vi).T().U()=0; + (*Vi).T().V()=0; + + int num=0; + ///find weighted media + for (unsigned int k=0;kIsB()) + { + ScalarType dist=((*Vi).P()-star[k]->P()).Norm(); + if (dist0); + (*Vi).T().U()+=kval*star[k]->T().U(); + (*Vi).T().V()+=kval*star[k]->T().V(); + num++; + } + ////on border case 2 neighbors + ///go next to the center + /*if (num==2) + { + (*Vi).T().U()/=2.0; + (*Vi).T().V()/=2.0; + }*/ + /*ScalarType u=(*Vi).T().U(); + ScalarType v=(*Vi).T().V();*/ + assert(((*Vi).T().U()>=-1)&&((*Vi).T().U()<=1)); + assert(((*Vi).T().V()>=-1)&&((*Vi).T().V()<=1)); + } + } + ///smoothing of txcoords + InitDampRestUV(to_parametrize); + for (typename MeshType::VertexIterator Vi=to_parametrize.vert.begin();Vi!=to_parametrize.vert.end();Vi++) + { + if ((!Vi->IsB())&&(!Vi->IsD())) + { + std::vector star; + getVertexStar(&(*Vi),star); + vcg::Point2 UV=vcg::Point2(0,0); + for (unsigned int k=0;kRestUV; + UV/=(ScalarType)star.size(); + (*Vi).T().P()=UV; + } + } +} + + +template +typename FaceType::CoordType InterpolatePos +(FaceType* f, const typename FaceType::CoordType &bary) +{return (f->V(0)->P()*bary.X()+f->V(1)->P()*bary.Y()+f->V(2)->P()*bary.Z());} + +template +typename FaceType::CoordType InterpolateRPos +(FaceType* f,const typename FaceType::CoordType &bary) +{ + return (f->V(0)->RPos*bary.X()+f->V(1)->RPos*bary.Y()+f->V(2)->RPos*bary.Z()); +} + +template +typename FaceType::CoordType InterpolateNorm +(FaceType* f, const typename FaceType::CoordType &bary) +{ + typedef typename FaceType::CoordType CoordType; + CoordType n0=f->V(0)->N(); + CoordType n1=f->V(1)->N(); + CoordType n2=f->V(2)->N(); + return (n0*bary.X()+n1*bary.Y()+n2*bary.Z()); +} + +template +int Approx(const ScalarType &value) +{ + ScalarType val0=floor(value); + ScalarType val1=ceil(value); + if (fabs(val0-value) +vcg::Point3i InterpolateColor +(FaceType* f,const typename FaceType::CoordType &bary) +{ + typedef typename FaceType::ScalarType ScalarType; + vcg::Color4b c0=f->V(0)->C(); + vcg::Color4b c1=f->V(1)->C(); + vcg::Color4b c2=f->V(2)->C(); + double R=(ScalarType)c0.X()*bary.X()+(ScalarType)c1.X()*bary.Y()+(ScalarType)c2.X()*bary.Z(); + double G=(ScalarType)c0.Y()*bary.X()+(ScalarType)c1.Y()*bary.Y()+(ScalarType)c2.Y()*bary.Z(); + double B=(ScalarType)c0.Z()*bary.X()+(ScalarType)c1.Z()*bary.Y()+(ScalarType)c2.Z()*bary.Z(); + + vcg::Point3i p=vcg::Point3i(Approx(R),Approx(G),Approx(B)); + + assert(p.X()<=255); + assert(p.Y()<=255); + assert(p.Z()<=255); + + return (p); +} + +template +typename VertexType::CoordType ProjectPos(const VertexType &v) +{ + typedef typename VertexType::FaceType FaceType; + typedef typename VertexType::CoordType CoordType; + + FaceType *f=v.father; + CoordType b=v.Bary; + return (InterpolatePos(f,b)); +} + +template +typename VertexType::CoordType Warp(const VertexType* v) +{ + typename VertexType::FaceType * father=v->father; + typename VertexType::CoordType proj=father->P(0)*v->Bary.X()+father->P(1)*v->Bary.Y()+father->P(2)*v->Bary.Z(); + return proj; +} + +template +typename VertexType::CoordType WarpRpos(const VertexType* v) +{ + typename VertexType::FaceType * father=v->father; + typename VertexType::CoordType proj=father->V(0)->RPos*v->Bary.X()+father->V(1)->RPos*v->Bary.Y()+father->V(2)->RPos*v->Bary.Z(); + return proj; +} + +template +typename MeshType::ScalarType EstimateLenghtByParam + (const typename MeshType::VertexType* v0, + const typename MeshType::VertexType* v1, + typename MeshType::FaceType* on_edge[2]) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::ScalarType ScalarType; + +// assert((on_edge.size()==0)||(on_edge.size()==1)); + ScalarType estimated[2]={0,0}; + int num[2]={0,0}; + + for (int i=0;i<2;i++) + { + FaceType *test_face=on_edge[i]; + + int edge_index=EdgeIndex(test_face,v0,v1); + FaceType *Fopp=test_face->FFp(edge_index); + + if (test_face->vertices_bary.size()<2) + { + ScalarType dist=Distance(v0->RPos,v1->RPos); + //#pragma omp atomic + estimated[i]+=dist; + num[i]=0; + continue; + } + + ///collect vertices + std::vector vertices; + vertices.reserve(test_face->vertices_bary.size()); + for (unsigned int k=0;kvertices_bary.size();k++) + vertices.push_back(test_face->vertices_bary[k].first); + + + ///collect faces + std::vector faces; + getSharedFace(vertices,faces); + + ///get border edges + std::vector > edges; + for (unsigned int j=0;jV0(k)->father==test_face)&& + (f->V1(k)->father==test_face)&& + (f->V2(k)->father==Fopp)) + { + edges.push_back(std::pair(f->V0(k),f->V1(k))); + found=true; + } + k++; + } + } + + ///find if there's ant edge return inital lenght + if (edges.size()==0) + { + estimated[i]+=(Distance(v0->RPos,v1->RPos)); + num[i]=0; + continue; + } + else + { + //get edge direction + ///store the two nearest for each vertex + /*VertexType *n0=edges[0].first; + VertexType *n1=edges[0].second; + ScalarType d0=(Warp(n0)-v0->P()).Norm(); + ScalarType d1=(Warp(n1)-v1->P()).Norm();*/ + + //CoordType edgedir=v0->cP()-v1->cP(); + CoordType edgedir=v0->RPos-v1->RPos; + edgedir.Normalize(); + num[i]=edges.size(); + for (unsigned int e=0;eP()-vH1->P()).Norm()); + //#pragma omp atomic + estimated[i]+=fabs(dirproj*edgedir)*((vH0->RPos-vH1->RPos).Norm()); + + } + } + } + + ///media of estimated values + ScalarType alpha0,alpha1; + ScalarType max_num=abstraction_num; + + if (num[0]>=max_num) + alpha0=1; + else + alpha0=num[0]/max_num; + + if (num[1]>=max_num) + alpha1=1; + else + alpha1=num[1]/max_num; + + estimated[0]=alpha0*estimated[0]+(1.0-alpha0)*(Distance(v0->RPos,v1->RPos)); + estimated[1]=alpha1*estimated[1]+(1.0-alpha1)*(Distance(v0->RPos,v1->RPos)); + return((estimated[0]+estimated[1])/2.0); +} + +template +void MeanVal(const std::vector > &Points, + std::vector &Lamda, + typename MeshType::CoordType &p) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + + int size=Points.size(); + Lamda.resize(size); + + ScalarType sum=0; + for (int i=0;i Pcurr=Points[i]; + vcg::Point2 Pprev=Points[(i+(size-1))%size]; + vcg::Point2 Pnext=Points[(i+1)%size]; + + CoordType v0=Pprev-p; + CoordType v1=Pcurr-p; + CoordType v2=Pnext-p; + ScalarType l=v1.Norm(); + v0.Normalize(); + v1.Normalize(); + v2.Normalize(); + + ScalarType Alpha0=acos(v0*v1); + ScalarType Alpha1=acos(v1*v2); + + Lamda[i]=(tan(Alpha0/2.0)+tan(Alpha1/2.0))/l; + sum+=Lamda[i]; + } + + ///normalization + for (int i=0;i +typename FaceType::ScalarType EstimateAreaByParam(const FaceType* f) +{ + typedef typename FaceType::VertexType VertexType; + typedef typename FaceType::ScalarType ScalarType; + + int num=0; + ScalarType estimated=0; + for (unsigned int k=0;kvertices_bary.size();k++) + { + VertexType *HresVert=f->vertices_bary[k].first; + estimated+=HresVert->area; + num++; + } + + ///media of estimated values + ScalarType alpha; + ScalarType max_num=abstraction_num; + + if (num>=max_num) + alpha=1; + else + alpha=num/max_num; + + ScalarType Rarea=((f->V(1)->RPos-f->V(0)->RPos)^(f->V(2)->RPos-f->V(0)->RPos)).Norm()/2.0; + estimated=alpha*estimated+(1.0-alpha)*Rarea; + + return(estimated); +} + +template +typename MeshType::ScalarType EstimateAreaByParam + (const typename MeshType::VertexType* v0, + const typename MeshType::VertexType* v1, + typename MeshType::FaceType* on_edge[2]) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::ScalarType ScalarType; + + //MeshType::PerVertexAttributeHandle handle = vcg::tri::Allocator::GetPerVertexAttribute(mesh,"AuxiliaryVertData"); + + ScalarType estimated[2]={0,0}; + int num[2]={0,0}; + VertexType *v2[2]; + for (int i=0;i<2;i++) + { + FaceType *test_face=on_edge[i]; + + for (int k=0;k<3;k++) + if ((test_face->V(k)!=v0)&&(test_face->V(k)!=v1)) + v2[i]=test_face->V(k); + + for (unsigned int k=0;kvertices_bary.size();k++) + { + VertexType *brother=test_face->vertices_bary[k].first; + estimated[i]+=brother->area; + //estimated[i]+=handle[brother].area; + num[i]++; + } + } + + ///media of estimated values + ScalarType alpha0,alpha1; + ScalarType max_num=abstraction_num;//20 + + if (num[0]>=max_num) + alpha0=1; + else + alpha0=num[0]/max_num; + + if (num[1]>=max_num) + alpha1=1; + else + alpha1=num[1]/max_num; + ScalarType Rarea0=((on_edge[0]->V(1)->RPos-on_edge[0]->V(0)->RPos)^(on_edge[0]->V(2)->RPos-on_edge[0]->V(0)->RPos)).Norm()/2.0; + ScalarType Rarea1=((on_edge[1]->V(1)->RPos-on_edge[1]->V(0)->RPos)^(on_edge[1]->V(2)->RPos-on_edge[1]->V(0)->RPos)).Norm()/2.0; + estimated[0]=alpha0*estimated[0]+(1.0-alpha0)*Rarea0; + estimated[1]=alpha1*estimated[1]+(1.0-alpha1)*Rarea1; + return((estimated[0]+estimated[1])/2.0); +} + +///template class used to sample surface +template +class VertexSampler{ + typedef typename FaceType::CoordType CoordType; +public: + std::vector points; + + void AddFace(const FaceType &f,const CoordType & bary) + {points.push_back(f.P(0)*bary.X()+f.P(1)*bary.Y()+f.P(2)*bary.Z());} +}; + + +///sample 3d vertex possible's position +///using area criterion +//template +//void SamplingPoints(MeshType &mesh, +// std::vector &pos) +//{ +// typedef typename MeshType::CoordType CoordType; +// typedef VertexSampler Sampler; +// pos.reserve(samples_area); +// Sampler ps; +// ps.points.reserve(samples_area); +// +// vcg::tri::SurfaceSampling::Montecarlo(mesh,ps,samples_area); +// pos=std::vector(ps.points.begin(),ps.points.end()); +//} + +template +void InitDampRestUV(MeshType &m) +{ + for (unsigned int i=0;i +void RestoreRestUV(MeshType &m) +{ + for (unsigned int i=0;i +void ParametrizeLocally(MeshType ¶metrized, + bool fix_boundary=true, + bool init_border=true) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + + //const ScalarType epsilon=(ScalarType)0.0001; + + + ///save old positions + + std::vector positions; + positions.resize(parametrized.vert.size()); + ///set rest position + for (unsigned int i=0;i opt(parametrized); + //vcg::tri::WachspressTexCoordOptimization opt(parametrized); + vcg::tri::AreaPreservingTexCoordOptimization opt1(parametrized); + opt.SetSpeed((ScalarType)0.0005); + InitDampRestUV(parametrized); + if (fix_boundary) + { + opt.TargetEquilateralGeometry(); + //opt.TargetCurrentGeometry(); + opt.SetBorderAsFixed(); + opt.IterateUntilConvergence((ScalarType)0.000001,100); + /*opt.Iterate(); + opt.Iterate();*/ + } + else + { + opt1.TargetCurrentGeometry(); + //opt1.SetBorderAsFixed(); + opt1.IterateUntilConvergence((ScalarType)0.000001,200); + } + + ///assert parametrization + for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); +#ifndef NDEBUG + ScalarType area=(tex1-tex0)^(tex2-tex0); + assert(area>0); +#endif +//#ifndef _MESHLAB +// if (area<0){ +// vcg::tri::io::ExporterPLY::Save(parametrized,"case0.ply"); +// +// for (int j=0;j::Save(parametrized,"case1.ply"); +// assert(0); +// } +//#endif + } + ///restore position + for (unsigned int i=0;i +void ForceInParam(vcg::Point2 &UV,MeshType &domain) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + ScalarType minDist=(ScalarType)1000.0; + vcg::Point2 closest; + vcg::Point2 center=vcg::Point2(0,0); + for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + center+=tex0; + center+=tex1; + center+=tex2; + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType dist; + vcg::Point2 temp; + t2d.PointDistance(UV,dist,temp); + if (dist +bool testParamCoords(VertexType *v) +{ + typedef typename VertexType::ScalarType ScalarType; + ScalarType eps=(ScalarType)0.00001; + if (!(((v->T().P().X()>=-1-eps)&&(v->T().P().X()<=1+eps)&& + (v->T().P().Y()>=-1-eps)&&(v->T().P().Y()<=1+eps)))) + return (false); + + return true; +} + +template +bool testParamCoords(MeshType &domain) +{ + for (unsigned int i=0;i(v); + if (!b) + { + #ifndef _MESHLAB + printf("\n position %lf,%lf \n",v->T().U(),v->T().V()); + #endif + return false; + } + } + return true; +} + +template +bool testBaryCoords(CoordType &bary) +{ + typedef typename CoordType::ScalarType ScalarType; + ///test + float eps=(ScalarType)0.0001; + if(!(fabs(bary.X()+bary.Y()+bary.Z()-1.0)=-eps)&&(bary.Y()<=1.0)&&(bary.Y()>=-eps)&&(bary.Z()<=1.0)&&(bary.Z()>=-eps))) + return false; + return true; +} + +template +bool NormalizeBaryCoords(CoordType &bary) +{ + bool isOK=testBaryCoords(bary); + if (!isOK) + return false; + + typedef typename CoordType::ScalarType ScalarType; + + ///test <0 + if (bary.X()<0) + bary.X()=0; + if (bary.Y()<0) + bary.Y()=0; + if (bary.Z()<0) + bary.Z()=0; + + ///test >1 + if (bary.X()>1.0) + bary.X()=1.0; + if (bary.Y()>1.0) + bary.Y()=1.0; + if (bary.Z()>1.0) + bary.Z()=1.0; + + ///test sum + ScalarType diff=bary.X()+bary.Y()+bary.Z()-1.0; + bary.X()-=diff; + + if (bary.X()<0) + bary.X()=0; + return true; +} + +template +void AssingFather(typename MeshType::VertexType &v, + typename MeshType::FaceType *father, + typename MeshType::CoordType &bary, + MeshType & domain) +{ +#ifdef _DEBUG + const typename MeshType::ScalarType eps=(typename MeshType::ScalarType)0.00001; + assert((father-&(*domain.face.begin()))<(int)domain.face.size()); + assert(!(father->IsD())); + assert(!(father==NULL)); + assert((bary.X()>=0)&&(bary.X()<=1)&& + (bary.Y()>=0)&&(bary.Y()<=1)&& + (bary.Z()>=0)&&(bary.Z()<=1)&& + ((bary.X()+bary.Y()+bary.Z())<=1+eps)&& + ((bary.X()+bary.Y()+bary.Z())>=1-eps)); +#endif + v.father=father; + v.Bary=bary; +} + +template +bool testParametrization(MeshType &domain, + MeshType &Hlev) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + bool is_good=true; + int num_del=0; + int num_null=0; + int fath_son=0; + int wrong_address=0; + for (unsigned int i=0;ifather-&(*domain.face.begin()))>=(int)domain.face.size()) + { + printf("\n ADDRESS EXCEEDS OF %d \n",v->father-&(*domain.face.begin())); + wrong_address++; + is_good=false; + isGoodAddr=false; + } + if ((isGoodAddr)&&(v->father==NULL)) + { + //printf("\n PAR ERROR : father NULL\n"); + num_null++; + is_good=false; + } + if ((isGoodAddr)&&(v->father->IsD())) + { + //printf("\n PAR ERROR : father DELETED \n"); + num_del++; + is_good=false; + } + if ((isGoodAddr)&&(!(((v->Bary.X()>=0)&&(v->Bary.X()<=1))&& + ((v->Bary.Y()>=0)&&(v->Bary.Y()<=1))&& + ((v->Bary.Z()>=0)&&(v->Bary.Z()<=1))))) + { + printf("\n PAR ERROR : bary coords exceeds: %f,%f,%f \n",v->Bary.X(),v->Bary.Y(),v->Bary.Z()); + is_good=false; + } + } + for (unsigned int i=0;iIsD()) + { + for (unsigned int j=0;jvertices_bary.size();j++) + { + VertexType *v=face->vertices_bary[j].first; + if (v->father!=face) + { + //printf("\n PAR ERROR : Father<->son \n"); + fath_son++; + v->father=face; + is_good=false; + } + } + } + } + + if (num_del>0) + printf("\n PAR ERROR %d Father isDel \n",num_del); + if (num_null>0) + printf("\n PAR ERROR %d Father isNull \n",num_null); + if (fath_son>0) + printf("\n PAR ERROR %d Father<->son \n",fath_son); + if (wrong_address>0) + { + printf("\n PAR ERROR %d Wrong Address Num Faces %d\n",wrong_address,domain.fn); + /*system("pause");*/ + } + return (is_good); +} + +template +bool NonFolded(MeshType ¶metrized) +{ + //const ScalarType epsilon=0.00001; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + ///assert parametrization + for (unsigned int i=0;iV(0)->IsB())&&(f->V(1)->IsB())&&(f->V(2)->IsB()))) + { + + vcg::Point2 tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType area=(tex1-tex0)^(tex2-tex0); + if (area<=0) + return false; + } + } + return true; +} + +template +bool NonFolded(MeshType ¶metrized,std::vector &folded) +{ + + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + const ScalarType epsilon=(ScalarType)0.00001; + folded.resize(0); + ///assert parametrization + for (unsigned int i=0;iV(0)->IsB())&&(f->V(1)->IsB())&&(f->V(2)->IsB()))) + { + + vcg::Point2 tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType area=(tex1-tex0)^(tex2-tex0); + if (area<=epsilon) + folded.push_back(f); + } + } + return (folded.size()==0); +} +//getFoldedFaces(std::vector) +///parametrize a submesh from trinagles that are incident on vertices with equi-area subdivision +template +void ParametrizeStarEquilateral(MeshType ¶metrized, + const typename MeshType::ScalarType &radius=1) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + UpdateTopologies(¶metrized); + + //set borders + + ///find first border & non border vertex + std::vector non_border; + VertexType* Start=NULL; + for (unsigned int i=0;iIsB())) + Start=vert; + + if (!vert->IsB()) + non_border.push_back(vert); + } + assert(non_border.size()!=0); + + ///get sorted border vertices + std::vector vertices; + FindSortedBorderVertices(parametrized,Start,vertices); + + ///set border vertices + int num=vertices.size(); + typename std::vector::iterator iteV; + ScalarType curr_angle=0; + vertices[0]->T().U()=cos(curr_angle)*radius; + vertices[0]->T().V()=sin(curr_angle)*radius; + ScalarType division=(2*M_PI)/(ScalarType)num; + ///set border + for (unsigned int i=1;iT().U()=radius*cos(curr_angle); + vertices[i]->T().V()=radius*sin(curr_angle); + } + + if (non_border.size()==1) + { + ///if non-border vertex is one then set it to zero otherwise + ///set it to the average of neighbors + non_border[0]->T().P()=vcg::Point2(0,0); + } + else + { + ///set media of star vertices + assert(non_border.size()==2); + for (unsigned int i=0;iT().P()=vcg::Point2(0,0); + int ariety_vert=0; + std::vector star; + getVertexStar(v,star); + for (unsigned int k=0;kIsD())&&(star[k]->IsB())) + { + v->T().P()+=star[k]->T().P(); + ariety_vert++; + } + } + v->T().P()/=(ScalarType)ariety_vert; + } + ///test particular cases + if (!NonFolded(parametrized)) + { + std::vector shared; + getSharedVertexStar(non_border[0],non_border[1],shared); + + assert(shared.size()==2); + assert(shared[0]->IsB()); + assert(shared[1]->IsB()); + assert(shared[0]!=shared[1]); + + //ScalarType epsilon=(ScalarType)0.001; + ///then get the media of two shared vertices + vcg::Point2 uvAve=shared[0]->T().P()+shared[1]->T().P(); + assert(uvAve.Norm()>(ScalarType)0.001); + uvAve.Normalize(); + vcg::Point2 p0=uvAve*(ScalarType)0.3; + vcg::Point2 p1=uvAve*(ScalarType)(-0.3); + ///then test and set right assignement + non_border[0]->T().P()=p0; + non_border[1]->T().P()=p1; + if (!NonFolded(parametrized)){ + non_border[0]->T().P()=p1; + non_border[1]->T().P()=p0; + } + } + } + + ///final assert parametrization + assert(NonFolded(parametrized)); + +} + +///given the mesh and the two edges (same) seen from face[0] and face[1] of the mesh construct +///a diamond parametrization using equilateral triangles of edge edge_len +template +void ParametrizeDiamondEquilateral(MeshType ¶metrized, + const int &edge0,const int &edge1, + const typename MeshType::ScalarType &edge_len=1) +{ + + typedef typename MeshType::FaceType FaceType; + typedef typename FaceType::CoordType CoordType; + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::VertexType VertexType; + + ScalarType h=(sqrt(3.0)/2.0)*edge_len; + + FaceType *fd0=¶metrized.face[0]; +#ifndef NDEBUG + FaceType *fd1=¶metrized.face[1]; +#endif + assert(fd0->FFp(edge0)==fd1); + assert(fd1->FFp(edge1)==fd0); + + ///get 2 vertex on the edge + VertexType *v0=fd0->V(edge0); + VertexType *v1=fd0->V((edge0+1)%3); + +#ifndef NDEBUG + VertexType *vtest0=fd1->V(edge1); + VertexType *vtest1=fd1->V((edge1+1)%3); + + assert(v0!=v1); + assert(vtest0!=vtest1); + assert(((v0==vtest0)&&(v1==vtest1))||((v1==vtest0)&&(v0==vtest1))); +#endif + + ///other 2 vertex + VertexType *v2=parametrized.face[0].V((edge0+2)%3); + VertexType *v3=parametrized.face[1].V((edge1+2)%3); + assert((v2!=v3)&&(v0!=v2)&&(v0!=v3)&&(v1!=v2)&&(v1!=v3)); + + ///assing texcoords + v0->T().P()=vcg::Point2(0,-edge_len/2.0); + v1->T().P()=vcg::Point2(0,edge_len/2.0); + v2->T().P()=vcg::Point2(-h,0); + v3->T().P()=vcg::Point2(h,0); + + ///test + assert(NonFolded(parametrized)); +} + +///given the mesh and the two edges (same) seen from face[0] and face[1] of the mesh construct +///a diamond parametrization using equilateral triangles of edge edge_len +template +void ParametrizeFaceEquilateral(MeshType ¶metrized, + const typename MeshType::ScalarType &edge_len=1) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename FaceType::CoordType CoordType; + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::VertexType VertexType; + + ScalarType h=(sqrt(3.0)/2.0)*edge_len; + + FaceType *f_param=&(parametrized.face[0]); + + f_param->V(0)->T().P()=vcg::Point2(edge_len/2.0,0); + f_param->V(1)->T().P()=vcg::Point2(0,h); + f_param->V(2)->T().P()=vcg::Point2(-edge_len/2.0,0); +} + + +///parametrize and create a submesh from trinagles that are incident on +/// vertices .... seturn a vetor of original faces +template +void ParametrizeLocally(MeshType ¶metrized, + const std::vector &subset, + std::vector &orderedFaces, + std::vector &orderedVertex) +{ + typedef typename MeshType::FaceType FaceType; + typedef typename FaceType::CoordType CoordType; + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::VertexType VertexType; + + orderedFaces.clear(); + std::vector vertices; + + + ///get faces referenced by vertices + getSharedFace(subset,orderedFaces); + + ///do a first copy of the mesh + ///and parametrize it + ///NB: order of faces is mantained + CopyMeshFromFaces(orderedFaces,orderedVertex,parametrized); + + //CreateMeshVertexStar(subset,orderedFaces,parametrized); + ParametrizeLocally(parametrized); + +} + + + +template +void GetUV(const typename MeshType::FaceType* f, + const typename MeshType::CoordType &bary, + typename MeshType::ScalarType &U, + typename MeshType::ScalarType &V) +{ + U=bary.X()*f->V(0)->T().U()+bary.Y()*f->V(1)->T().U()+bary.Z()*f->V(2)->T().U(); + V=bary.X()*f->V(0)->T().V()+bary.Y()*f->V(1)->T().V()+bary.Z()*f->V(2)->T().V(); + /*if ((!((U>=-1)&&(U<=1)))||(!((V>=-1)&&(V<=1)))) + { + printf("Bary:%f,%f,%f \n",bary.X(),bary.Y(),bary.Z()); + printf("texCoord:%f,%f \n",U,V); + assert(0); + }*/ + //assert ((U>=-1)&&(U<=1)); + //assert ((V>=-1)&&(V<=1)); +} + +template +bool GetBaryFaceFromUV(const MeshType &m, + const typename MeshType::ScalarType &U, + const typename MeshType::ScalarType &V, + typename MeshType::CoordType &bary, + int &index) +{ + typedef typename MeshType::ScalarType ScalarType; + const ScalarType _EPSILON = ScalarType(0.0000001); + /*assert ((U>=-1)&&(U<=1)); + assert ((V>=-1)&&(V<=1));*/ + for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + + vcg::Point2 test=vcg::Point2(U,V); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType area=(tex1-tex0)^(tex2-tex0); + //assert(area>-_EPSILON); + ///then find if the point 2d falls inside + if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) + { + index=i; + ///approximation errors + ScalarType sum=0; + for (int x=0;x<3;x++) + { + if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) + bary[x]=0; + else + if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) + bary[x]=1; + sum+=bary[x]; + } + if (sum==0) + printf("error SUM %f \n",sum); + + bary/=sum; + return true; + } + } + + return (false); +} + +template +bool GetBaryFaceFromUV(std::vector faces, + const typename FaceType::ScalarType &U, + const typename FaceType::ScalarType &V, + typename FaceType::CoordType &bary, + int &index) +{ + typedef typename FaceType::CoordType CoordType; + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::VertexType VertexType; + typedef typename FaceType::ScalarType ScalarType; + const ScalarType _EPSILON = ScalarType(0.0000001); + /*assert ((U>=-1)&&(U<=1)); + assert ((V>=-1)&&(V<=1));*/ + for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + + vcg::Point2 test=vcg::Point2(U,V); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType area=fabs((tex1-tex0)^(tex2-tex0)); + //assert(area>-_EPSILON); + ///then find if the point 2d falls inside + if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) + { + index=i; + + ///approximation errors + ScalarType sum=0; + for (int x=0;x<3;x++) + { + if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) + bary[x]=0; + else + if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) + bary[x]=1; + sum+=fabs(bary[x]); + } + if (sum==0) + printf("error SUM %f \n",sum); + + bary/=sum; + /*if (!((bary.X()>=0)&& (bary.X()<=1))) + printf("error %f \n",bary.X());*/ + /*ScalarType diff=(1.0-bary.X()-bary.Y()-bary.Z()); + bary.X()+=diff;*/ + return true; + } + } + + return (false); +} + +template +bool GetBaryFaceFromUV(const MeshType &m, + const typename MeshType::ScalarType &U, + const typename MeshType::ScalarType &V, + const std::vector &orderedFaces, + typename MeshType::CoordType &bary, + typename MeshType::FaceType* &chosen) +{ + int index; + bool found=GetBaryFaceFromUV(m,U,V,bary,index); + if(!found) { + chosen=0; + return false; + } + chosen=orderedFaces[index]; + return true; +} + +template +bool GetCoordFromUV(const MeshType &m, + const typename MeshType::ScalarType &U, + const typename MeshType::ScalarType &V, + typename MeshType::CoordType &val, + bool rpos=false) +{ + typedef typename MeshType::ScalarType ScalarType; + const ScalarType _EPSILON = (ScalarType)0.00001; + for (unsigned int i=0;i tex0=vcg::Point2(f->V(0)->T().U(),f->V(0)->T().V()); + vcg::Point2 tex1=vcg::Point2(f->V(1)->T().U(),f->V(1)->T().V()); + vcg::Point2 tex2=vcg::Point2(f->V(2)->T().U(),f->V(2)->T().V()); + + vcg::Point2 test=vcg::Point2(U,V); + vcg::Triangle2 t2d=vcg::Triangle2(tex0,tex1,tex2); + ScalarType area=(tex1-tex0)^(tex2-tex0); + ///then find if the point 2d falls inside + typename MeshType::CoordType bary; + if ((area>_EPSILON)&&(t2d.InterpolationParameters(test,bary.X(),bary.Y(),bary.Z()))) + { + ///approximation errors + for (int x=0;x<3;x++) + { + if (((bary[x])<=0)&&(bary[x]>=-_EPSILON)) + bary[x]=0; + else + if (((bary[x])>=1)&&(bary[x]<=1+_EPSILON)) + bary[x]=1; + } + ScalarType diff=(1.0-bary.X()-bary.Y()-bary.Z()); + bary.X()+=diff; + if (!rpos) + val=f->P(0)*bary.X()+f->P(1)*bary.Y()+f->P(0)*bary.Z(); + else + val=f->V(0)->RPos*bary.X()+f->V(1)->RPos*bary.Y()+f->V(2)->RPos*bary.Z(); + + return true; + } + } + return false; +} + +template +typename MeshType::ScalarType GetSmallestUVEdgeSize(const MeshType &m) +{ + typedef typename MeshType::ScalarType ScalarType; + + ScalarType smallest=100.f; + assert(m.fn>0); + for (int i=0;i uv0=m.face[i].V(j)->T().P(); + vcg::Point2 uv1=m.face[i].V((j+1)%3)->T().P(); + ScalarType test=(uv0-uv1).Norm(); + if (test +typename MeshType::ScalarType GetSmallestUVHeight(const MeshType &m) +{ + typedef typename MeshType::ScalarType ScalarType; + ScalarType smallest=(ScalarType)100.0; + ScalarType eps=(ScalarType)0.0001; + assert(m.fn>0); + for (unsigned int i=0;i uv0=f->V(j)->cT().P(); + vcg::Point2 uv1=f->V1(j)->cT().P(); + vcg::Point2 uv2=f->V2(j)->cT().P(); + ScalarType area=fabs((uv1-uv0)^(uv2-uv0)); + ScalarType base=(uv1-uv2).Norm(); + ScalarType h_test=area/base; + if (h_test(ScalarType)0.05) + smallest=(ScalarType)0.05; + return smallest; +} + +template +void ParametrizeStarEquilateral(typename MeshType::VertexType *center, + bool /*subvertices=true*/) +{ + ///initialize domain + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::CoordType CoordType; + + MeshType parametrized; + std::vector vertices,ordVert; + std::vector HresVert; + std::vector faces; + vertices.push_back(center); + getSharedFace(vertices,faces); + CopyMeshFromFaces(faces,ordVert,parametrized); + + ///parametrize and then copy back + ParametrizeStarEquilateral(parametrized); + for (unsigned int i=0;iT().P()=parametrized.vert[i].T().P(); + + ///initialize sub-vertices + getHresVertex(faces,HresVert); + for (unsigned int i=0;ifather; + CoordType Bary=HresVert[i]->Bary; + GetUV(father,Bary,HresVert[i]->T().U(),HresVert[i]->T().V()); + } +} + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/mesh_operators.h b/src/meshlabplugins/filter_isoparametrization/mesh_operators.h index fc458e270..f60dad6a6 100644 --- a/src/meshlabplugins/filter_isoparametrization/mesh_operators.h +++ b/src/meshlabplugins/filter_isoparametrization/mesh_operators.h @@ -1,11 +1,11 @@ #ifndef MESH_OPERATORS #define MESH_OPERATORS #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/meshlabplugins/filter_isoparametrization/param_collapse.h b/src/meshlabplugins/filter_isoparametrization/param_collapse.h index 7564f2ea9..53e45c9ff 100644 --- a/src/meshlabplugins/filter_isoparametrization/param_collapse.h +++ b/src/meshlabplugins/filter_isoparametrization/param_collapse.h @@ -1,702 +1,702 @@ -#ifndef PARAM_COLLAPSE -#define PARAM_COLLAPSE - -#include - -// local optimization -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "opt_patch.h" -#include "local_optimization.h" - -template -class ParamEdgeCollapse: public vcg::tri::TriEdgeCollapse > { -public: - typedef vcg::tri::TriEdgeCollapse > Super; - typedef typename BaseMesh::VertexType::EdgeType EdgeType; - typedef typename BaseMesh::VertexType VertexType; - typedef typename BaseMesh::VertexType BaseVertex; - typedef typename BaseMesh::FaceType BaseFace; - typedef typename BaseMesh::FaceType FaceType; - typedef typename BaseMesh::ScalarType ScalarType; - typedef typename BaseMesh::CoordType CoordType; - typedef BaseMesh TriMeshType; - - static EnergyType &EType(){static EnergyType E;return E;}; - - inline ParamEdgeCollapse(const EdgeType &p, int mark) - { - Super::localMark = mark; - Super::pos=p; - Super::_priority = ComputePriority(); - } - - inline ScalarType Cost() - { - std::vector on_edge,faces1,faces2; - getSharedFace(Super::pos.V(0),Super::pos.V(1),on_edge,faces1,faces2); - - FaceType* edgeF[2]; - edgeF[0]=on_edge[0]; - edgeF[1]=on_edge[1]; - ScalarType costArea=EstimateAreaByParam(Super::pos.V(0),Super::pos.V(1),edgeF); - ScalarType lenght=EstimateLenghtByParam(Super::pos.V(0),Super::pos.V(1),edgeF); - - if (costArea<0) - assert(0); - assert(lenght>=0); - return (pow(lenght,2)+costArea); - } - - inline bool IsFeasible(){ - return LinkConditions(Super::pos); - } - - inline void SetHlevMeshUV(const std::vector &LowFace, - std::vector &HiFace, - std::vector &HiVertex) - { - - ///interpolate parametric u & v values into the face - for (unsigned int index=0;indexIsD()); - for (unsigned int i=0;ivertices_bary.size();i++) - { - VertexType *brother=test_face->vertices_bary[i].first; - CoordType bary=test_face->vertices_bary[i].second; - GetUV(test_face,bary,brother->T().U(),brother->T().V()); - //printf("%f , %f \n",brother->T().U(),brother->T().V()); - assert(brother!=NULL); - HiVertex.push_back(brother); - } - } - - ///add brother of the domain mesh - std::vector LowVertices; - getSharedVertex(LowFace,LowVertices); - for (unsigned int index=0;indexIsD()); - if (LowVertices[index]->brother!=NULL) - { - VertexType* b=LowVertices[index]->brother; - assert(b!=NULL); - HiVertex.push_back(b); - b->T().P()=LowVertices[index]->T().P(); - } - } - - ///then return pointer to hight level faces - getSharedFace(HiVertex,HiFace); - } - - static void SetBaryFromUV(BaseMesh &domain, - std::vector &vertices) - { - ///set a vector of pointer to face - std::vector OrdFace; - for (unsigned int h=0;hT().U(); - ScalarType v=vertices[i]->T().V(); - GetBaryFaceFromUV(domain,u,v,OrdFace,bary1,chosen); - assert(fabs(bary1.X()+bary1.Y()+bary1.Z()-1.0)<=0.0001); - /*vertices[i]->father=chosen; - assert(!chosen->IsD()); - vertices[i]->Bary=bary1;*/ - AssingFather(vertices[i],chosen,bary1,domain); - } - } - - - struct minInfo0 - { - public: - BaseMesh *domain; - BaseMesh *collapsed; - BaseVertex *central; - CoordType middle; - std::vector HiFace; - std::vector HiVertex; - ScalarType original_area; - }; - - - static void energy0(double *p, double *x, int/* m*/, int /*n*/, void *data) - { - minInfo0 &inf = *(minInfo0 *)data; - - ///assing coordinate to the face - inf.central->P().X()=p[0]; - inf.central->P().Y()=p[1]; - inf.central->P().Z()=p[2]; - - ///find aspect ratio - x[0]=(1.0/AspectRatio(*inf.collapsed)); - - ScalarType areadelta=0; - for (unsigned int i=0;iface.size();i++) - areadelta+=inf.domain->face[i].areadelta; - - ScalarType area0=Area(*inf.collapsed); - ScalarType area1=Area(*inf.domain)+areadelta; - - x[1]=pow(area0/area1+area1/area0,2);//2.0*pow((area0-area1)/area1,2); - - x[2]=AreaDispersion(*inf.collapsed); - x[3]=0;//(inf.middle-inf.central->P()).SquaredNorm()/area1; - } - - ///find best position - inline CoordType FindBestPos(BaseMesh &m) - { - minInfo0 Minf; - ///create the submesh - VertexType *v0=Super::pos.V(0); - VertexType *v1=Super::pos.V(1); - - - std::vector star; - std::vector orderedFaces; - star.push_back(v0); - star.push_back(v1); - BaseMesh created,domain; - - ///DISTORSION - BaseMesh HLcreated; - ///DISTORSION - - CreateMeshVertexStar(star,orderedFaces,created); - /*if (created.face[1].areadelta>1) - assert(0);*/ - UpdateTopologies(&created); - - //ParametrizeLocally(created); - - /////copy uv values on ordered faces - //for (int i=0;iV(j)->T().P()=created.face[i].V(j)->T().P(); - - /////set parametric position respect to new part of submesh - ///*std::vector HiFace; - //std::vector HiVertex;*/ - //SetHlevMeshUV(orderedFaces,Minf.HiFace,Minf.HiVertex); - - ///save previous values - std::vector > swap; - typename std::vector::iterator iteVP; - for (iteVP=Minf.HiVertex.begin();iteVP!=Minf.HiVertex.end();iteVP++) - swap.push_back(std::pair ((*iteVP)->father,(*iteVP)->Bary)); - ///DISTORSION - - ///create pos - EdgeType posEdge; - std::vector vertEdge; - FindNotBorderVertices(created,vertEdge); - - posEdge.V(0)=std::max(vertEdge[1],vertEdge[0]); - posEdge.V(1)=std::min(vertEdge[1],vertEdge[0]); - - ///simulate collapse - CoordType newPos=(v0->P()+v1->P())/2.0; - - ///copy domain - vcg::tri::Append::Mesh(domain,created); - for (unsigned int i=0;i(&created); - - /////parametrize domain - //ParametrizeLocally(created); - //ParametrizeLocally(domain); - - ///minimization - double p[3]; - p[0]=newPos.X(); - p[1]=newPos.Y(); - p[2]=newPos.Z(); - - /*minInfo Minf;*/ - Minf.domain=&domain; - Minf.collapsed=&created; - Minf.central=posEdge.V(1); - Minf.middle=newPos; - - double x[4]; - x[0]=0; - x[1]=0; - x[2]=0; - x[3]=0; - /*x[4]=0;*/ - - double opts[LM_OPTS_SZ], info[LM_INFO_SZ]; - opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20; - opts[4]=LM_DIFF_DELTA; - - //energy0(p,x,3,4,Minf); - - /*int num=*/dlevmar_dif(energy0,p,x,3,4,1000,opts,info,NULL,NULL,&Minf); - - ///find back the value - - CoordType bestPos; - bestPos.X()=p[0]; - bestPos.Y()=p[1]; - bestPos.Z()=p[2]; - - - for (unsigned int i=0;ifather=swap[i].first; - assert(!swap[i].first->IsD()); - Minf.HiVertex[i]->Bary=swap[i].second;*/ - AssingFather(*Minf.HiVertex[i],swap[i].first,swap[i].second,m); - } - - return (bestPos); - } - - inline ScalarType ComputePriority() - { - return (Cost()); - //return( Distance(pos.V(0)->cP(),pos.V(1)->cP())); - } - - CoordType ComputeMinimal(BaseMesh &m) - { - CoordType bestPos=FindBestPos(m); - return bestPos; - } - - void UpdateFF(EdgeType &posEdge) - { - std::vector shared; - std::vector in_v0; - std::vector in_v1; - ///then reupdate topology - getSharedFace(posEdge.V(0),posEdge.V(1),shared,in_v0,in_v1); - - ///find the edge shared between them - for (unsigned int j=0;jV(0)==posEdge.V(0))&&(face->V(1)==posEdge.V(1)))|| - (face->V(0)==posEdge.V(1))&&(face->V(1)==posEdge.V(0))) - iedge=0; - else - if (((face->V(1)==posEdge.V(0))&&(face->V(2)==posEdge.V(1)))|| - (face->V(1)==posEdge.V(1))&&(face->V(2)==posEdge.V(0))) - iedge=1; - else - if (((face->V(2)==posEdge.V(0))&&(face->V(0)==posEdge.V(1)))|| - (face->V(2)==posEdge.V(1))&&(face->V(0)==posEdge.V(0))) - iedge=2; - assert (iedge!=-1); - - ///then update topology for the two other faces - int edge0=(iedge+1)%3; - int edge1=(iedge+2)%3; - - ///get opposEdgeite faces and indexes - FaceType* f0=face->FFp(edge0); - FaceType* f1=face->FFp(edge1); - - int indexopp0=face->FFi(edge0); - int indexopp1=face->FFi(edge1); - ///control if they are border - if ((f0==face)&&(f1==face)) - { - printf("border"); - } - else - if (f0==face) - { - f1->FFp(indexopp1)=f1; - f1->FFi(indexopp1)=-1; - printf("border"); - } - else - if (f1==face) - { - f0->FFp(indexopp0)=f0; - f0->FFi(indexopp0)=-1; - printf("border"); - } - else///otherwise attache two other faces - { - ///the reassing adiacency - f0->FFp(indexopp0)=f1; - f1->FFp(indexopp1)=f0; - f0->FFi(indexopp0)=indexopp1; - f1->FFi(indexopp1)=indexopp0; - assert( f0->FFp(indexopp0)->FFp(f0->FFi(indexopp0))==f0 ); - assert( f1->FFp(indexopp1)->FFp(f1->FFi(indexopp1))==f1 ); - } - - } - } - - -///create a copy the submesh for a collapse and parameterize it -void CreatePreCollapseSubmesh(EdgeType &pos, - BaseMesh ¶m, - std::vector &orderedVertex, - std::vector &orderedFaces) -{ - std::vector vert_star; - vert_star.push_back(pos.V(0)); - vert_star.push_back(pos.V(1)); - - ///get a copy of the mesh - CreateMeshVertexStar(vert_star,orderedFaces,orderedVertex,param); - UpdateTopologies(¶m); - InitDampRestUV(param); - - ParametrizeLocally(param); - - ///store UV coordinates in original vertex to copy - ///for post collapsed surface parametrization - for (unsigned int i=0;iT().P()=param.vert[i].T().P(); -} - -///create a copy the submesh after the collapse that is already parameterized -/// only the central vertex has to be set to (0,0) -void CreatePostCollapseSubmesh(EdgeType &pos, - BaseMesh ¶m_post, - std::vector &orderedVertex, - std::vector &orderedFaces) -{ - std::vector vert_star; - vert_star.push_back(pos.V(1)); - - CreateMeshVertexStar(vert_star,orderedFaces,orderedVertex,param_post); - UpdateTopologies(¶m_post); - InitDampRestUV(param_post); - - ///set to zero the star center (non border) - bool found=false; - unsigned int i=0; - while ((i(0,0); - -} - -void AphaBetaToUV(EdgeType &pos, - std::vector &orderedFaces, - BaseMesh ¶m, - std::vector &HresVert) -{ - /*const ScalarType eps=(ScalarType)0.00001;*/ - ///VERTEX ON FACE REPROJECTING - //transform from Alpha Beta to UV - for (unsigned int index=0;indexvertices_bary.size();i++) - { - ///get brother vertex - VertexType *brother=test_face->vertices_bary[i].first; - assert(brother!=NULL); - - ///get his barycentric coordinates - CoordType bary=test_face->vertices_bary[i].second; - - ///transform to UV - ScalarType u,v; - GetUV(parametric_face,bary,u,v); - ///and assing - brother->T().U()=u; - brother->T().V()=v; - - /*///testing coordinates - if (!((u>-1.0-eps)&&(u<1.0+eps)&& - (v>-1.0-eps)&&(v<1.0+eps))) - { - printf("Error 0 Uv :%f,%f \n",u,v); - printf("Bary :%f,%f %f \n",bary.X(),bary.Y(),bary.Z()); - system("pause"); - }*/ - - ///save high res vertices - HresVert.push_back(brother); - } - /*///clear - test_face->vertices_bary.clear();*/ - } - - ///add the two collapsed vertex - ///and set UV coordinates - for (int i=0;i<2;i++) - { - if (pos.V(i)->brother!=NULL) - { - HresVert.push_back(pos.V(i)->brother); - ///set his coordinates - pos.V(i)->brother->T().P()=pos.V(i)->T().P(); - - //param_pos.push_back(vert_star0[i]->T().P()); - ///color for flip test - - ///set his brother as null - pos.V(i)->brother=NULL; - } - } - -} - -void UVToAlphaBeta(std::vector &HresVert, - BaseMesh ¶m,std::vector &orderedFaces, - BaseMesh &base_mesh) -{ - ///for each parametrized vertex - for (unsigned int i=0;iT().U(); - ScalarType v=HresVert[i]->T().V(); - int index; - - ////found the face and its barycentric coordinates form the parametrized mesh - bool found=GetBaryFaceFromUV(param,u,v,bary1,index); - - ///test for approximation errors - if (!found) - { - printf("Error 1\n"); - printf("Old Uv :%f,%f \n",u,v); - while (!found) - { - ///put next to the center - u*=(ScalarType)0.9; - v*=(ScalarType)0.9; - found=GetBaryFaceFromUV(param,u,v,bary1,index);//(param1,u,v,orderedFaces1,bary1,chosen); - } - printf("New Uv %f,%f \n",u,v); - } - - ///get the face from original mesh - assert(found); - chosen=orderedFaces[index]; - //if (!(fabs(bary1.X()+bary1.Y()+bary1.Z()-1.0)<=0.0001)) - //{ - // printf("Error 2 Uv :%f,%f \n",u,v); - // system("pause"); - // bary1=CoordType(0.3333,0.3333,0.3333); - // chosen=orderedFaces[0]; - // //assert(0); - //} - ///set father-son relation - chosen->vertices_bary.push_back(std::pair(brother,bary1)); - - AssingFather(*brother,chosen,bary1,base_mesh); - /*brother->father=chosen; - assert(!chosen->IsD()); - brother->Bary=bary1;*/ - - ///set new parametrization value - GetUV(¶m.face[index],bary1,u,v); - HresVert[i]->T().U()=u; - HresVert[i]->T().V()=v; - } -} - -void ClearVert_Bary(std::vector &orderedFaces) -{ - for (unsigned int index=0;indexvertices_bary.clear(); - } -} - -void AssignRPos(VertexType* &to_assign, - ScalarType &U, - ScalarType &V, - std::vector &orderedFaces, - BaseMesh ¶m) -{ - CoordType val; - - ////set rest positions for survived vertex - ///create h resolution mesh - BaseMesh hlev_mesh; - std::vector ord_vertex; - CopyHlevMesh(orderedFaces,hlev_mesh,ord_vertex); - ///first interpolate in h_res then proceed to lowres if doesn't find - bool found; - found=GetCoordFromUV(hlev_mesh,U,V,val,true); - if (!found) - found=GetCoordFromUV(param,U,V,val,true); - - assert (found); - - to_assign->RPos=val; -} - -void Execute(BaseMesh &m) - { - typedef typename BaseMesh::FaceType FaceType; - typedef typename BaseMesh::VertexType VertexType; - typedef typename BaseMesh::ScalarType ScalarType; - typedef typename BaseMesh::CoordType CoordType; - - assert(this->pos.V(0)!=this->pos.V(1)); - assert(!this->pos.V(0)->IsD()); - assert(!this->pos.V(1)->IsD()); - assert(size_t((this->pos.V(0)-&(*m.vert.begin())))pos.V(1)-&(*m.vert.begin()))) result; - std::vector in_v0; - std::vector in_v1; - -#ifndef NDEBUG - getSharedFace(this->pos.V(0),this->pos.V(1),result,in_v0,in_v1); - assert(result.size()==2); -#endif - - ///compute new position - CoordType oldRPos=(this->pos.V(0)->RPos+this->pos.V(1)->RPos)/2.0; - CoordType newPos; - newPos=ComputeMinimal(m);// - //vcg::tri::UpdateTopology::TestVertexFace(m); ///TEST - - BaseMesh param0,param1; - //std::vector vert_star0,vert_star1; - std::vector orderedFaces0,orderedFaces1; - std::vector orderedVertex0,orderedVertex1; - - ///create a parametrized submesh pre-collapse - CreatePreCollapseSubmesh(Super::pos,param0,orderedVertex0,orderedFaces0); - -//---------------------------/// - ///update FF topology post-collapse - UpdateFF(this->pos); - - ///INITIAL AREA - ScalarType area0=Area(orderedFaces0); - - ///do the collapse - DoCollapse(m, this->pos, newPos); // v0 is deleted and v1 take the new position - //vcg::tri::UpdateTopology::TestVertexFace(m); ///TEST - //---------------------------/// - ///create a parametrized submesh post-collapse #1 - CreatePostCollapseSubmesh(this->pos,param1,orderedVertex1,orderedFaces1); - - //---------------------------/// - ///FINAL AREA - ScalarType area1=Area(orderedFaces1); - - ////save error - ScalarType areadelta=(area0-area1)/(ScalarType)orderedFaces1.size(); - for (unsigned int i=0;iareadelta=areadelta; - - ///VERTEX ON FACE REPROJECTING #2 - //---------------------------/// - /////collect all vertices with respective param coords - std::vector HresVert; - - //TRANSFORM TO UV - AphaBetaToUV(this->pos,orderedFaces0,param0,HresVert); - - //DELETE SONS - ClearVert_Bary(orderedFaces0); -//---------------------------/// - - ///UPTIMIZE UV - //OptimizeUV(¶m0,¶m1,HresVert); - -//---------------------------/// - ///REPROJECT BACK TO ORIGINAL FATHER #3 - - UVToAlphaBeta(HresVert,param1,orderedFaces1,m); - - - /*PatchesOptimizer::OptimizeUV(this->pos.V(1),m);*/ - -//---------------------------/// - ///get the non border one that is the one survived - unsigned int k=0; - while ((param1.vert[k].IsB())&&(kpos.V(1)->RPos=oldRPos; - - /*bool b=*/SmartOptimizeStar(this->pos.V(1),m,Accuracy(),EType()); - - /*int t1=clock(); - time_opt+=(t1-t0);*/ - } - -public: - static int &Accuracy() - { - static int _acc; - return _acc; - } - - static BaseMesh* &HresMesh() - { - static BaseMesh* mesh; - return mesh; - } - - BaseVertex *getV(int num) - { - assert((num>=0)&&(num<2)); - return this->pos.V(num); - } -}; - -#endif +#ifndef PARAM_COLLAPSE +#define PARAM_COLLAPSE + +#include + +// local optimization +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "opt_patch.h" +#include "local_optimization.h" + +template +class ParamEdgeCollapse: public vcg::tri::TriEdgeCollapse > { +public: + typedef vcg::tri::TriEdgeCollapse > Super; + typedef typename BaseMesh::VertexType::EdgeType EdgeType; + typedef typename BaseMesh::VertexType VertexType; + typedef typename BaseMesh::VertexType BaseVertex; + typedef typename BaseMesh::FaceType BaseFace; + typedef typename BaseMesh::FaceType FaceType; + typedef typename BaseMesh::ScalarType ScalarType; + typedef typename BaseMesh::CoordType CoordType; + typedef BaseMesh TriMeshType; + + static EnergyType &EType(){static EnergyType E;return E;}; + + inline ParamEdgeCollapse(const EdgeType &p, int mark) + { + Super::localMark = mark; + Super::pos=p; + Super::_priority = ComputePriority(); + } + + inline ScalarType Cost() + { + std::vector on_edge,faces1,faces2; + getSharedFace(Super::pos.V(0),Super::pos.V(1),on_edge,faces1,faces2); + + FaceType* edgeF[2]; + edgeF[0]=on_edge[0]; + edgeF[1]=on_edge[1]; + ScalarType costArea=EstimateAreaByParam(Super::pos.V(0),Super::pos.V(1),edgeF); + ScalarType lenght=EstimateLenghtByParam(Super::pos.V(0),Super::pos.V(1),edgeF); + + if (costArea<0) + assert(0); + assert(lenght>=0); + return (pow(lenght,2)+costArea); + } + + inline bool IsFeasible(){ + return LinkConditions(Super::pos); + } + + inline void SetHlevMeshUV(const std::vector &LowFace, + std::vector &HiFace, + std::vector &HiVertex) + { + + ///interpolate parametric u & v values into the face + for (unsigned int index=0;indexIsD()); + for (unsigned int i=0;ivertices_bary.size();i++) + { + VertexType *brother=test_face->vertices_bary[i].first; + CoordType bary=test_face->vertices_bary[i].second; + GetUV(test_face,bary,brother->T().U(),brother->T().V()); + //printf("%f , %f \n",brother->T().U(),brother->T().V()); + assert(brother!=NULL); + HiVertex.push_back(brother); + } + } + + ///add brother of the domain mesh + std::vector LowVertices; + getSharedVertex(LowFace,LowVertices); + for (unsigned int index=0;indexIsD()); + if (LowVertices[index]->brother!=NULL) + { + VertexType* b=LowVertices[index]->brother; + assert(b!=NULL); + HiVertex.push_back(b); + b->T().P()=LowVertices[index]->T().P(); + } + } + + ///then return pointer to hight level faces + getSharedFace(HiVertex,HiFace); + } + + static void SetBaryFromUV(BaseMesh &domain, + std::vector &vertices) + { + ///set a vector of pointer to face + std::vector OrdFace; + for (unsigned int h=0;hT().U(); + ScalarType v=vertices[i]->T().V(); + GetBaryFaceFromUV(domain,u,v,OrdFace,bary1,chosen); + assert(fabs(bary1.X()+bary1.Y()+bary1.Z()-1.0)<=0.0001); + /*vertices[i]->father=chosen; + assert(!chosen->IsD()); + vertices[i]->Bary=bary1;*/ + AssingFather(vertices[i],chosen,bary1,domain); + } + } + + + struct minInfo0 + { + public: + BaseMesh *domain; + BaseMesh *collapsed; + BaseVertex *central; + CoordType middle; + std::vector HiFace; + std::vector HiVertex; + ScalarType original_area; + }; + + + static void energy0(double *p, double *x, int/* m*/, int /*n*/, void *data) + { + minInfo0 &inf = *(minInfo0 *)data; + + ///assing coordinate to the face + inf.central->P().X()=p[0]; + inf.central->P().Y()=p[1]; + inf.central->P().Z()=p[2]; + + ///find aspect ratio + x[0]=(1.0/AspectRatio(*inf.collapsed)); + + ScalarType areadelta=0; + for (unsigned int i=0;iface.size();i++) + areadelta+=inf.domain->face[i].areadelta; + + ScalarType area0=Area(*inf.collapsed); + ScalarType area1=Area(*inf.domain)+areadelta; + + x[1]=pow(area0/area1+area1/area0,2);//2.0*pow((area0-area1)/area1,2); + + x[2]=AreaDispersion(*inf.collapsed); + x[3]=0;//(inf.middle-inf.central->P()).SquaredNorm()/area1; + } + + ///find best position + inline CoordType FindBestPos(BaseMesh &m) + { + minInfo0 Minf; + ///create the submesh + VertexType *v0=Super::pos.V(0); + VertexType *v1=Super::pos.V(1); + + + std::vector star; + std::vector orderedFaces; + star.push_back(v0); + star.push_back(v1); + BaseMesh created,domain; + + ///DISTORSION + BaseMesh HLcreated; + ///DISTORSION + + CreateMeshVertexStar(star,orderedFaces,created); + /*if (created.face[1].areadelta>1) + assert(0);*/ + UpdateTopologies(&created); + + //ParametrizeLocally(created); + + /////copy uv values on ordered faces + //for (int i=0;iV(j)->T().P()=created.face[i].V(j)->T().P(); + + /////set parametric position respect to new part of submesh + ///*std::vector HiFace; + //std::vector HiVertex;*/ + //SetHlevMeshUV(orderedFaces,Minf.HiFace,Minf.HiVertex); + + ///save previous values + std::vector > swap; + typename std::vector::iterator iteVP; + for (iteVP=Minf.HiVertex.begin();iteVP!=Minf.HiVertex.end();iteVP++) + swap.push_back(std::pair ((*iteVP)->father,(*iteVP)->Bary)); + ///DISTORSION + + ///create pos + EdgeType posEdge; + std::vector vertEdge; + FindNotBorderVertices(created,vertEdge); + + posEdge.V(0)=std::max(vertEdge[1],vertEdge[0]); + posEdge.V(1)=std::min(vertEdge[1],vertEdge[0]); + + ///simulate collapse + CoordType newPos=(v0->P()+v1->P())/2.0; + + ///copy domain + vcg::tri::Append::Mesh(domain,created); + for (unsigned int i=0;i(&created); + + /////parametrize domain + //ParametrizeLocally(created); + //ParametrizeLocally(domain); + + ///minimization + double p[3]; + p[0]=newPos.X(); + p[1]=newPos.Y(); + p[2]=newPos.Z(); + + /*minInfo Minf;*/ + Minf.domain=&domain; + Minf.collapsed=&created; + Minf.central=posEdge.V(1); + Minf.middle=newPos; + + double x[4]; + x[0]=0; + x[1]=0; + x[2]=0; + x[3]=0; + /*x[4]=0;*/ + + double opts[LM_OPTS_SZ], info[LM_INFO_SZ]; + opts[0]=LM_INIT_MU; opts[1]=1E-15; opts[2]=1E-15; opts[3]=1E-20; + opts[4]=LM_DIFF_DELTA; + + //energy0(p,x,3,4,Minf); + + /*int num=*/dlevmar_dif(energy0,p,x,3,4,1000,opts,info,NULL,NULL,&Minf); + + ///find back the value + + CoordType bestPos; + bestPos.X()=p[0]; + bestPos.Y()=p[1]; + bestPos.Z()=p[2]; + + + for (unsigned int i=0;ifather=swap[i].first; + assert(!swap[i].first->IsD()); + Minf.HiVertex[i]->Bary=swap[i].second;*/ + AssingFather(*Minf.HiVertex[i],swap[i].first,swap[i].second,m); + } + + return (bestPos); + } + + inline ScalarType ComputePriority() + { + return (Cost()); + //return( Distance(pos.V(0)->cP(),pos.V(1)->cP())); + } + + CoordType ComputeMinimal(BaseMesh &m) + { + CoordType bestPos=FindBestPos(m); + return bestPos; + } + + void UpdateFF(EdgeType &posEdge) + { + std::vector shared; + std::vector in_v0; + std::vector in_v1; + ///then reupdate topology + getSharedFace(posEdge.V(0),posEdge.V(1),shared,in_v0,in_v1); + + ///find the edge shared between them + for (unsigned int j=0;jV(0)==posEdge.V(0))&&(face->V(1)==posEdge.V(1)))|| + (face->V(0)==posEdge.V(1))&&(face->V(1)==posEdge.V(0))) + iedge=0; + else + if (((face->V(1)==posEdge.V(0))&&(face->V(2)==posEdge.V(1)))|| + (face->V(1)==posEdge.V(1))&&(face->V(2)==posEdge.V(0))) + iedge=1; + else + if (((face->V(2)==posEdge.V(0))&&(face->V(0)==posEdge.V(1)))|| + (face->V(2)==posEdge.V(1))&&(face->V(0)==posEdge.V(0))) + iedge=2; + assert (iedge!=-1); + + ///then update topology for the two other faces + int edge0=(iedge+1)%3; + int edge1=(iedge+2)%3; + + ///get opposEdgeite faces and indexes + FaceType* f0=face->FFp(edge0); + FaceType* f1=face->FFp(edge1); + + int indexopp0=face->FFi(edge0); + int indexopp1=face->FFi(edge1); + ///control if they are border + if ((f0==face)&&(f1==face)) + { + printf("border"); + } + else + if (f0==face) + { + f1->FFp(indexopp1)=f1; + f1->FFi(indexopp1)=-1; + printf("border"); + } + else + if (f1==face) + { + f0->FFp(indexopp0)=f0; + f0->FFi(indexopp0)=-1; + printf("border"); + } + else///otherwise attache two other faces + { + ///the reassing adiacency + f0->FFp(indexopp0)=f1; + f1->FFp(indexopp1)=f0; + f0->FFi(indexopp0)=indexopp1; + f1->FFi(indexopp1)=indexopp0; + assert( f0->FFp(indexopp0)->FFp(f0->FFi(indexopp0))==f0 ); + assert( f1->FFp(indexopp1)->FFp(f1->FFi(indexopp1))==f1 ); + } + + } + } + + +///create a copy the submesh for a collapse and parameterize it +void CreatePreCollapseSubmesh(EdgeType &pos, + BaseMesh ¶m, + std::vector &orderedVertex, + std::vector &orderedFaces) +{ + std::vector vert_star; + vert_star.push_back(pos.V(0)); + vert_star.push_back(pos.V(1)); + + ///get a copy of the mesh + CreateMeshVertexStar(vert_star,orderedFaces,orderedVertex,param); + UpdateTopologies(¶m); + InitDampRestUV(param); + + ParametrizeLocally(param); + + ///store UV coordinates in original vertex to copy + ///for post collapsed surface parametrization + for (unsigned int i=0;iT().P()=param.vert[i].T().P(); +} + +///create a copy the submesh after the collapse that is already parameterized +/// only the central vertex has to be set to (0,0) +void CreatePostCollapseSubmesh(EdgeType &pos, + BaseMesh ¶m_post, + std::vector &orderedVertex, + std::vector &orderedFaces) +{ + std::vector vert_star; + vert_star.push_back(pos.V(1)); + + CreateMeshVertexStar(vert_star,orderedFaces,orderedVertex,param_post); + UpdateTopologies(¶m_post); + InitDampRestUV(param_post); + + ///set to zero the star center (non border) + bool found=false; + unsigned int i=0; + while ((i(0,0); + +} + +void AphaBetaToUV(EdgeType &pos, + std::vector &orderedFaces, + BaseMesh ¶m, + std::vector &HresVert) +{ + /*const ScalarType eps=(ScalarType)0.00001;*/ + ///VERTEX ON FACE REPROJECTING + //transform from Alpha Beta to UV + for (unsigned int index=0;indexvertices_bary.size();i++) + { + ///get brother vertex + VertexType *brother=test_face->vertices_bary[i].first; + assert(brother!=NULL); + + ///get his barycentric coordinates + CoordType bary=test_face->vertices_bary[i].second; + + ///transform to UV + ScalarType u,v; + GetUV(parametric_face,bary,u,v); + ///and assing + brother->T().U()=u; + brother->T().V()=v; + + /*///testing coordinates + if (!((u>-1.0-eps)&&(u<1.0+eps)&& + (v>-1.0-eps)&&(v<1.0+eps))) + { + printf("Error 0 Uv :%f,%f \n",u,v); + printf("Bary :%f,%f %f \n",bary.X(),bary.Y(),bary.Z()); + system("pause"); + }*/ + + ///save high res vertices + HresVert.push_back(brother); + } + /*///clear + test_face->vertices_bary.clear();*/ + } + + ///add the two collapsed vertex + ///and set UV coordinates + for (int i=0;i<2;i++) + { + if (pos.V(i)->brother!=NULL) + { + HresVert.push_back(pos.V(i)->brother); + ///set his coordinates + pos.V(i)->brother->T().P()=pos.V(i)->T().P(); + + //param_pos.push_back(vert_star0[i]->T().P()); + ///color for flip test + + ///set his brother as null + pos.V(i)->brother=NULL; + } + } + +} + +void UVToAlphaBeta(std::vector &HresVert, + BaseMesh ¶m,std::vector &orderedFaces, + BaseMesh &base_mesh) +{ + ///for each parametrized vertex + for (unsigned int i=0;iT().U(); + ScalarType v=HresVert[i]->T().V(); + int index; + + ////found the face and its barycentric coordinates form the parametrized mesh + bool found=GetBaryFaceFromUV(param,u,v,bary1,index); + + ///test for approximation errors + if (!found) + { + printf("Error 1\n"); + printf("Old Uv :%f,%f \n",u,v); + while (!found) + { + ///put next to the center + u*=(ScalarType)0.9; + v*=(ScalarType)0.9; + found=GetBaryFaceFromUV(param,u,v,bary1,index);//(param1,u,v,orderedFaces1,bary1,chosen); + } + printf("New Uv %f,%f \n",u,v); + } + + ///get the face from original mesh + assert(found); + chosen=orderedFaces[index]; + //if (!(fabs(bary1.X()+bary1.Y()+bary1.Z()-1.0)<=0.0001)) + //{ + // printf("Error 2 Uv :%f,%f \n",u,v); + // system("pause"); + // bary1=CoordType(0.3333,0.3333,0.3333); + // chosen=orderedFaces[0]; + // //assert(0); + //} + ///set father-son relation + chosen->vertices_bary.push_back(std::pair(brother,bary1)); + + AssingFather(*brother,chosen,bary1,base_mesh); + /*brother->father=chosen; + assert(!chosen->IsD()); + brother->Bary=bary1;*/ + + ///set new parametrization value + GetUV(¶m.face[index],bary1,u,v); + HresVert[i]->T().U()=u; + HresVert[i]->T().V()=v; + } +} + +void ClearVert_Bary(std::vector &orderedFaces) +{ + for (unsigned int index=0;indexvertices_bary.clear(); + } +} + +void AssignRPos(VertexType* &to_assign, + ScalarType &U, + ScalarType &V, + std::vector &orderedFaces, + BaseMesh ¶m) +{ + CoordType val; + + ////set rest positions for survived vertex + ///create h resolution mesh + BaseMesh hlev_mesh; + std::vector ord_vertex; + CopyHlevMesh(orderedFaces,hlev_mesh,ord_vertex); + ///first interpolate in h_res then proceed to lowres if doesn't find + bool found; + found=GetCoordFromUV(hlev_mesh,U,V,val,true); + if (!found) + found=GetCoordFromUV(param,U,V,val,true); + + assert (found); + + to_assign->RPos=val; +} + +void Execute(BaseMesh &m) + { + typedef typename BaseMesh::FaceType FaceType; + typedef typename BaseMesh::VertexType VertexType; + typedef typename BaseMesh::ScalarType ScalarType; + typedef typename BaseMesh::CoordType CoordType; + + assert(this->pos.V(0)!=this->pos.V(1)); + assert(!this->pos.V(0)->IsD()); + assert(!this->pos.V(1)->IsD()); + assert(size_t((this->pos.V(0)-&(*m.vert.begin())))pos.V(1)-&(*m.vert.begin()))) result; + std::vector in_v0; + std::vector in_v1; + +#ifndef NDEBUG + getSharedFace(this->pos.V(0),this->pos.V(1),result,in_v0,in_v1); + assert(result.size()==2); +#endif + + ///compute new position + CoordType oldRPos=(this->pos.V(0)->RPos+this->pos.V(1)->RPos)/2.0; + CoordType newPos; + newPos=ComputeMinimal(m);// + //vcg::tri::UpdateTopology::TestVertexFace(m); ///TEST + + BaseMesh param0,param1; + //std::vector vert_star0,vert_star1; + std::vector orderedFaces0,orderedFaces1; + std::vector orderedVertex0,orderedVertex1; + + ///create a parametrized submesh pre-collapse + CreatePreCollapseSubmesh(Super::pos,param0,orderedVertex0,orderedFaces0); + +//---------------------------/// + ///update FF topology post-collapse + UpdateFF(this->pos); + + ///INITIAL AREA + ScalarType area0=Area(orderedFaces0); + + ///do the collapse + DoCollapse(m, this->pos, newPos); // v0 is deleted and v1 take the new position + //vcg::tri::UpdateTopology::TestVertexFace(m); ///TEST + //---------------------------/// + ///create a parametrized submesh post-collapse #1 + CreatePostCollapseSubmesh(this->pos,param1,orderedVertex1,orderedFaces1); + + //---------------------------/// + ///FINAL AREA + ScalarType area1=Area(orderedFaces1); + + ////save error + ScalarType areadelta=(area0-area1)/(ScalarType)orderedFaces1.size(); + for (unsigned int i=0;iareadelta=areadelta; + + ///VERTEX ON FACE REPROJECTING #2 + //---------------------------/// + /////collect all vertices with respective param coords + std::vector HresVert; + + //TRANSFORM TO UV + AphaBetaToUV(this->pos,orderedFaces0,param0,HresVert); + + //DELETE SONS + ClearVert_Bary(orderedFaces0); +//---------------------------/// + + ///UPTIMIZE UV + //OptimizeUV(¶m0,¶m1,HresVert); + +//---------------------------/// + ///REPROJECT BACK TO ORIGINAL FATHER #3 + + UVToAlphaBeta(HresVert,param1,orderedFaces1,m); + + + /*PatchesOptimizer::OptimizeUV(this->pos.V(1),m);*/ + +//---------------------------/// + ///get the non border one that is the one survived + unsigned int k=0; + while ((param1.vert[k].IsB())&&(kpos.V(1)->RPos=oldRPos; + + /*bool b=*/SmartOptimizeStar(this->pos.V(1),m,Accuracy(),EType()); + + /*int t1=clock(); + time_opt+=(t1-t0);*/ + } + +public: + static int &Accuracy() + { + static int _acc; + return _acc; + } + + static BaseMesh* &HresMesh() + { + static BaseMesh* mesh; + return mesh; + } + + BaseVertex *getV(int num) + { + assert((num>=0)&&(num<2)); + return this->pos.V(num); + } +}; + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/param_flip.h b/src/meshlabplugins/filter_isoparametrization/param_flip.h index 8f1674208..f635fcc83 100644 --- a/src/meshlabplugins/filter_isoparametrization/param_flip.h +++ b/src/meshlabplugins/filter_isoparametrization/param_flip.h @@ -1,315 +1,315 @@ -#ifndef PARAM_FLIP -#define PARAM_FLIP - -#include - -///Flip function -template -class ParamEdgeFlip : public vcg::tri::PlanarEdgeFlip > -{ - typedef typename BaseMesh::VertexType::EdgeType EdgeType; - typedef typename BaseMesh::VertexType BaseVertex; - typedef typename BaseMesh::VertexType VertexType; - typedef typename BaseMesh::FaceType BaseFace; - typedef typename BaseMesh::FaceType FaceType; - typedef typename BaseMesh::CoordType CoordType; - typedef typename BaseMesh::ScalarType ScalarType; - typedef vcg::tri::PlanarEdgeFlip > Super; - ScalarType diff; - - public: - - static EnergyType &EType(){static EnergyType E;return E;}; - - bool savedomain; - - bool IsFeasible() - { - if(!vcg::face::CheckFlipEdge(*this->_pos.F(), this->_pos.E())) - return false; - - return (this->_priority>0); - } - - inline ParamEdgeFlip() {} - - /*! - * Constructor with pos type - */ - inline ParamEdgeFlip(const typename Super::PosType pos, int mark) - { - this->_pos = pos; - this->_localMark = mark; - this->_priority = this->ComputePriority(); - savedomain=false; - } - - ///do the effective flip - void ExecuteFlip(FaceType &f, const int &edge, BaseMesh *base_domain=NULL) - { - std::vector faces; - faces.push_back(&f); - faces.push_back(f.FFp(edge)); - std::vector HresVert; - getHresVertex(faces,HresVert); - ///parametrize H_res mesh respect to diamond - for (unsigned int i=0;ifather; - CoordType bary=v->Bary; - assert((father==faces[0])||(father==faces[1])); - vcg::Point2 t0=father->V(0)->T().P(); - vcg::Point2 t1=father->V(1)->T().P(); - vcg::Point2 t2=father->V(2)->T().P(); - - //assert(testBaryCoords(bary)); - if(!testBaryCoords(bary)) - { - printf("BAry0 :%lf,%lf,%lf",bary.X(),bary.Y(),bary.Z()); - //system("pause"); - } - - GetUV(father,bary,v->T().U(),v->T().V()); - } - - ///update VF topology - FaceType *f1=f.FFp(edge); - FaceType *f0=&f; - vcg::face::VFDetach(*f1,0); - vcg::face::VFDetach(*f1,1); - vcg::face::VFDetach(*f1,2); - vcg::face::VFDetach(*f0,0); - vcg::face::VFDetach(*f0,1); - vcg::face::VFDetach(*f0,2); - ///then do the effective flip - - vcg::face::FlipEdge(f,edge); - - - - vcg::face::VFAppend(f1,0); - vcg::face::VFAppend(f1,1); - vcg::face::VFAppend(f1,2); - vcg::face::VFAppend(f0,0); - vcg::face::VFAppend(f0,1); - vcg::face::VFAppend(f0,2); - ///edh updating topology - - - ///set son->father new link - for (unsigned int i=0;iT().U(); - ScalarType V=v->T().V(); - CoordType bary; - int index; - bool found=GetBaryFaceFromUV(faces,U,V,bary,index); - if (!found) - { - printf("\n U : %lf; V : %lf \n",U,V); - //system("pause"); - } - //assert(found); - assert(testBaryCoords(bary)); - if (base_domain!=NULL) - AssingFather(*v,faces[index],bary,*base_domain); - else - { - v->father=faces[index]; - assert(!faces[index]->IsD()); - v->Bary=bary; - } - } - - - - ///set father->son new link - for (unsigned int i=0;ivertices_bary.clear(); - - for (unsigned int i=0;ifather; - CoordType bary=son->Bary; - father->vertices_bary.push_back(std::pair(son,bary)); - } - - } - - ScalarType EdgeDiff() - { - /* - 1 - /|\ - / | \ - 2 f0|f1 3 - \ | / - \|/ - 0 - */ - - VertexType *v0, *v1, *v2, *v3; - int edge0 = this->_pos.E(); - v0 = this->_pos.F()->V0(edge0); - v1 = this->_pos.F()->V1(edge0); - v2 = this->_pos.F()->V2(edge0); - v3 = this->_pos.F()->FFp(edge0)->V2(this->_pos.F()->FFi(edge0)); - int edge1=this->_pos.F()->FFi(edge0); - FaceType* f0=this->_pos.F(); - FaceType* f1=this->_pos.F()->FFp(edge0); - - ///parametrize all possible diamonds - ///diam0 & diam1 - ///make a copy of the mesh - std::vector OrdFace; - OrdFace.push_back(f0); - OrdFace.push_back(f1); - - BaseMesh Diam; - BaseMesh DiamHres; - - ///create a copy of the domain and of the H resolution - CopySubMeshLevels(OrdFace,Diam,DiamHres); - - ///parametrize domains - ParametrizeDiamondEquilateral(Diam,edge0,edge1); - - ///copy parametrization on original mesh - - FaceType* on_edge[2]; - on_edge[0]=&Diam.face[0]; - on_edge[1]=&Diam.face[1]; - assert(Diam.face[0].FFp(edge0)==&Diam.face[1]);///test - assert(Diam.face[1].FFp(edge1)==&Diam.face[0]);///test - - ///Evaluate lenght of shared edge - ScalarType L0=EstimateLenghtByParam(Diam.face[0].V(edge0),Diam.face[0].V((edge0+1)%3),on_edge); - - ///do the flip on the copied mesh do not affect the original mesh - ExecuteFlip(Diam.face[0],edge0); - - UpdateTopologies(&Diam); - - ///get the non border edge of face0 - int NB_edge=-1; - if (!Diam.face[0].IsB(0)) - NB_edge=0; - else - if (!Diam.face[0].IsB(1)) - NB_edge=1; - else - if (!Diam.face[0].IsB(2)) - NB_edge=2; - assert(NB_edge!=-1); - - ScalarType L1=EstimateLenghtByParam(Diam.face[0].V(NB_edge),Diam.face[0].V((NB_edge+1)%3),on_edge); - - ScalarType value=L0-L1; - diff=value; - this->_priority = 1.0/value; - return (this->_priority); - } - - - void Execute(BaseMesh &m) - { - - assert(this->_priority>0); - /* - 1 - /|\ - / | \ - 2 f0|f1 3 - \ | / - \|/ - 0 - */ - VertexType *v0, *v1, *v2, *v3; - int edge0 = this->_pos.E(); - v0 = this->_pos.F()->V0(edge0); - v1 = this->_pos.F()->V1(edge0); - v2 = this->_pos.F()->V2(edge0); - v3 = this->_pos.F()->FFp(edge0)->V2(this->_pos.F()->FFi(edge0)); - ///assing texcoords - ScalarType h=(sqrt((ScalarType)3.0)/(ScalarType)2.0); - v0->T().P()=vcg::Point2(0,(ScalarType)-0.5); - v1->T().P()=vcg::Point2(0,(ScalarType)0.5); - v2->T().P()=vcg::Point2(-h,0); - v3->T().P()=vcg::Point2(h,0); - -#ifndef _MESHLAB - ///save domain if need for demos - if (savedomain) - { - BaseMesh hlev_mesh; - std::vector faces; - FaceType* f=this->_pos.F(); - int edge=this->_pos.E(); - faces.push_back(f); - faces.push_back(f->FFp(edge)); - std::vector HresVert; - getHresVertex(faces,HresVert); - - ///parametrize H_res mesh respect to diamond - std::vector OrderedVertices; - std::vector OrderedFaces; - CopyMeshFromVertices(HresVert,OrderedVertices,OrderedFaces,hlev_mesh); - //for (int i=0;i::Save(hlev_mesh,"c:/export_submeshes/FLIPHlev3D.ply",vcg::tri::io::Mask::IOM_VERTCOLOR); - for (unsigned int i=0;i::Save(hlev_mesh,"c:/export_submeshes/FLIPHlevUV.ply",vcg::tri::io::Mask::IOM_VERTCOLOR); - } -#endif - - ExecuteFlip(*this->_pos.F(),this->_pos.E(),&m); - - UpdateTopologies(&m); - - ///stars optimization - /*int t0=clock();*/ - /*OptimizeStar(v0); - OptimizeStar(v1); - OptimizeStar(v2); - OptimizeStar(v3);*/ - - SmartOptimizeStar(v0,m,Accuracy(),EType()); - SmartOptimizeStar(v1,m,Accuracy(),EType()); - SmartOptimizeStar(v2,m,Accuracy(),EType()); - SmartOptimizeStar(v3,m,Accuracy(),EType()); - /*int t1=clock(); - time_opt+=(t1-t0);*/ - } - - ScalarType ComputePriority() - { - this->_priority=EdgeDiff(); - return this->_priority; - } - - BaseFace *getF() - {return this->_pos.F();} - - int getE() - {return this->_pos.E();} - - public: - static int &Accuracy() - { - static int _acc; - return _acc; - } - -}; - -#endif +#ifndef PARAM_FLIP +#define PARAM_FLIP + +#include + +///Flip function +template +class ParamEdgeFlip : public vcg::tri::PlanarEdgeFlip > +{ + typedef typename BaseMesh::VertexType::EdgeType EdgeType; + typedef typename BaseMesh::VertexType BaseVertex; + typedef typename BaseMesh::VertexType VertexType; + typedef typename BaseMesh::FaceType BaseFace; + typedef typename BaseMesh::FaceType FaceType; + typedef typename BaseMesh::CoordType CoordType; + typedef typename BaseMesh::ScalarType ScalarType; + typedef vcg::tri::PlanarEdgeFlip > Super; + ScalarType diff; + + public: + + static EnergyType &EType(){static EnergyType E;return E;}; + + bool savedomain; + + bool IsFeasible() + { + if(!vcg::face::CheckFlipEdge(*this->_pos.F(), this->_pos.E())) + return false; + + return (this->_priority>0); + } + + inline ParamEdgeFlip() {} + + /*! + * Constructor with pos type + */ + inline ParamEdgeFlip(const typename Super::PosType pos, int mark) + { + this->_pos = pos; + this->_localMark = mark; + this->_priority = this->ComputePriority(); + savedomain=false; + } + + ///do the effective flip + void ExecuteFlip(FaceType &f, const int &edge, BaseMesh *base_domain=NULL) + { + std::vector faces; + faces.push_back(&f); + faces.push_back(f.FFp(edge)); + std::vector HresVert; + getHresVertex(faces,HresVert); + ///parametrize H_res mesh respect to diamond + for (unsigned int i=0;ifather; + CoordType bary=v->Bary; + assert((father==faces[0])||(father==faces[1])); + vcg::Point2 t0=father->V(0)->T().P(); + vcg::Point2 t1=father->V(1)->T().P(); + vcg::Point2 t2=father->V(2)->T().P(); + + //assert(testBaryCoords(bary)); + if(!testBaryCoords(bary)) + { + printf("BAry0 :%lf,%lf,%lf",bary.X(),bary.Y(),bary.Z()); + //system("pause"); + } + + GetUV(father,bary,v->T().U(),v->T().V()); + } + + ///update VF topology + FaceType *f1=f.FFp(edge); + FaceType *f0=&f; + vcg::face::VFDetach(*f1,0); + vcg::face::VFDetach(*f1,1); + vcg::face::VFDetach(*f1,2); + vcg::face::VFDetach(*f0,0); + vcg::face::VFDetach(*f0,1); + vcg::face::VFDetach(*f0,2); + ///then do the effective flip + + vcg::face::FlipEdge(f,edge); + + + + vcg::face::VFAppend(f1,0); + vcg::face::VFAppend(f1,1); + vcg::face::VFAppend(f1,2); + vcg::face::VFAppend(f0,0); + vcg::face::VFAppend(f0,1); + vcg::face::VFAppend(f0,2); + ///edh updating topology + + + ///set son->father new link + for (unsigned int i=0;iT().U(); + ScalarType V=v->T().V(); + CoordType bary; + int index; + bool found=GetBaryFaceFromUV(faces,U,V,bary,index); + if (!found) + { + printf("\n U : %lf; V : %lf \n",U,V); + //system("pause"); + } + //assert(found); + assert(testBaryCoords(bary)); + if (base_domain!=NULL) + AssingFather(*v,faces[index],bary,*base_domain); + else + { + v->father=faces[index]; + assert(!faces[index]->IsD()); + v->Bary=bary; + } + } + + + + ///set father->son new link + for (unsigned int i=0;ivertices_bary.clear(); + + for (unsigned int i=0;ifather; + CoordType bary=son->Bary; + father->vertices_bary.push_back(std::pair(son,bary)); + } + + } + + ScalarType EdgeDiff() + { + /* + 1 + /|\ + / | \ + 2 f0|f1 3 + \ | / + \|/ + 0 + */ + + VertexType *v0, *v1, *v2, *v3; + int edge0 = this->_pos.E(); + v0 = this->_pos.F()->V0(edge0); + v1 = this->_pos.F()->V1(edge0); + v2 = this->_pos.F()->V2(edge0); + v3 = this->_pos.F()->FFp(edge0)->V2(this->_pos.F()->FFi(edge0)); + int edge1=this->_pos.F()->FFi(edge0); + FaceType* f0=this->_pos.F(); + FaceType* f1=this->_pos.F()->FFp(edge0); + + ///parametrize all possible diamonds + ///diam0 & diam1 + ///make a copy of the mesh + std::vector OrdFace; + OrdFace.push_back(f0); + OrdFace.push_back(f1); + + BaseMesh Diam; + BaseMesh DiamHres; + + ///create a copy of the domain and of the H resolution + CopySubMeshLevels(OrdFace,Diam,DiamHres); + + ///parametrize domains + ParametrizeDiamondEquilateral(Diam,edge0,edge1); + + ///copy parametrization on original mesh + + FaceType* on_edge[2]; + on_edge[0]=&Diam.face[0]; + on_edge[1]=&Diam.face[1]; + assert(Diam.face[0].FFp(edge0)==&Diam.face[1]);///test + assert(Diam.face[1].FFp(edge1)==&Diam.face[0]);///test + + ///Evaluate lenght of shared edge + ScalarType L0=EstimateLenghtByParam(Diam.face[0].V(edge0),Diam.face[0].V((edge0+1)%3),on_edge); + + ///do the flip on the copied mesh do not affect the original mesh + ExecuteFlip(Diam.face[0],edge0); + + UpdateTopologies(&Diam); + + ///get the non border edge of face0 + int NB_edge=-1; + if (!Diam.face[0].IsB(0)) + NB_edge=0; + else + if (!Diam.face[0].IsB(1)) + NB_edge=1; + else + if (!Diam.face[0].IsB(2)) + NB_edge=2; + assert(NB_edge!=-1); + + ScalarType L1=EstimateLenghtByParam(Diam.face[0].V(NB_edge),Diam.face[0].V((NB_edge+1)%3),on_edge); + + ScalarType value=L0-L1; + diff=value; + this->_priority = 1.0/value; + return (this->_priority); + } + + + void Execute(BaseMesh &m) + { + + assert(this->_priority>0); + /* + 1 + /|\ + / | \ + 2 f0|f1 3 + \ | / + \|/ + 0 + */ + VertexType *v0, *v1, *v2, *v3; + int edge0 = this->_pos.E(); + v0 = this->_pos.F()->V0(edge0); + v1 = this->_pos.F()->V1(edge0); + v2 = this->_pos.F()->V2(edge0); + v3 = this->_pos.F()->FFp(edge0)->V2(this->_pos.F()->FFi(edge0)); + ///assing texcoords + ScalarType h=(sqrt((ScalarType)3.0)/(ScalarType)2.0); + v0->T().P()=vcg::Point2(0,(ScalarType)-0.5); + v1->T().P()=vcg::Point2(0,(ScalarType)0.5); + v2->T().P()=vcg::Point2(-h,0); + v3->T().P()=vcg::Point2(h,0); + +#ifndef _MESHLAB + ///save domain if need for demos + if (savedomain) + { + BaseMesh hlev_mesh; + std::vector faces; + FaceType* f=this->_pos.F(); + int edge=this->_pos.E(); + faces.push_back(f); + faces.push_back(f->FFp(edge)); + std::vector HresVert; + getHresVertex(faces,HresVert); + + ///parametrize H_res mesh respect to diamond + std::vector OrderedVertices; + std::vector OrderedFaces; + CopyMeshFromVertices(HresVert,OrderedVertices,OrderedFaces,hlev_mesh); + //for (int i=0;i::Save(hlev_mesh,"c:/export_submeshes/FLIPHlev3D.ply",vcg::tri::io::Mask::IOM_VERTCOLOR); + for (unsigned int i=0;i::Save(hlev_mesh,"c:/export_submeshes/FLIPHlevUV.ply",vcg::tri::io::Mask::IOM_VERTCOLOR); + } +#endif + + ExecuteFlip(*this->_pos.F(),this->_pos.E(),&m); + + UpdateTopologies(&m); + + ///stars optimization + /*int t0=clock();*/ + /*OptimizeStar(v0); + OptimizeStar(v1); + OptimizeStar(v2); + OptimizeStar(v3);*/ + + SmartOptimizeStar(v0,m,Accuracy(),EType()); + SmartOptimizeStar(v1,m,Accuracy(),EType()); + SmartOptimizeStar(v2,m,Accuracy(),EType()); + SmartOptimizeStar(v3,m,Accuracy(),EType()); + /*int t1=clock(); + time_opt+=(t1-t0);*/ + } + + ScalarType ComputePriority() + { + this->_priority=EdgeDiff(); + return this->_priority; + } + + BaseFace *getF() + {return this->_pos.F();} + + int getE() + {return this->_pos.E();} + + public: + static int &Accuracy() + { + static int _acc; + return _acc; + } + +}; + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/param_mesh.h b/src/meshlabplugins/filter_isoparametrization/param_mesh.h index b4ad05baf..d5118fcf1 100644 --- a/src/meshlabplugins/filter_isoparametrization/param_mesh.h +++ b/src/meshlabplugins/filter_isoparametrization/param_mesh.h @@ -1,184 +1,184 @@ -#ifndef PARAM_MESH -#define PARAM_MESH - -// stuff to define the mesh -#include -#include -#include "iso_parametrization.h" - -class BaseVertex; -class BaseEdge; -class BaseFace; - -class BaseUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, - vcg::Use::AsEdgeType, - vcg::Use::AsFaceType >{}; - - -///AUXILIARY STRUCTURES USED FOR PARAMETRIZATION COMPUTATION -class BaseVertex : public vcg::Vertex< BaseUsedTypes, - vcg::vertex::VFAdj, - vcg::vertex::Coord3f, - vcg::vertex::Normal3f, - vcg::vertex::Mark, - vcg::vertex::BitFlags, - vcg::vertex::Color4b, - vcg::vertex::TexCoord2f> -{ -public: - - ScalarType area; - CoordType RPos; - BaseVertex *brother; - BaseFace *father; - CoordType Bary; - //ScalarType Damp; - - BaseVertex() - { - brother=NULL; - //Damp=1; - //num_collapse=1; - } - - static const bool Has_Auxiliary(){return true;} - - vcg::Point2 RestUV; - - vcg::Color4b OriginalCol; - //int num_collapse; - - void ImportData(const BaseVertex & left ) - { - vcg::Vertex< BaseUsedTypes, - vcg::vertex::VFAdj, - vcg::vertex::Coord3f, - vcg::vertex::Normal3f, - vcg::vertex::Mark, - vcg::vertex::BitFlags, - vcg::vertex::Color4b, - vcg::vertex::TexCoord2f>::ImportData(left); - - this->area=left.area; - this->RPos=left.RPos; - this->brother=left.brother; - this->father=left.father; - this->Bary=left.Bary; - } - - template < class LeftV> - void ImportData(const LeftV & left ) - { - vcg::Vertex< BaseUsedTypes, - vcg::vertex::VFAdj, - vcg::vertex::Coord3f, - vcg::vertex::Normal3f, - vcg::vertex::Mark, - vcg::vertex::BitFlags, - vcg::vertex::Color4b, - vcg::vertex::TexCoord2f>::ImportData(left); - } - - -}; - -///class maintaing additional auxiliary data used during the parameterization -class AuxiliaryVertData{ -public: - BaseVertex::ScalarType area; - BaseVertex::CoordType RPos; - BaseVertex *brother; - BaseFace *father; - BaseVertex::CoordType Bary; - - vcg::Point2 RestUV; - - vcg::Color4b OriginalCol; - - AuxiliaryVertData() - {brother=NULL;} -}; - -class AuxiliaryFaceData -{ -public: - std::vector > vertices_bary; - typedef std::vector >::iterator IteVBary; - vcg::Color4b group; - BaseVertex::ScalarType areadelta; - vcg::Color4b colorDivision; -}; - -class BaseFace; - -class BaseEdge : public vcg::Edge { -public: - inline BaseEdge() {}; - inline BaseEdge( BaseVertex * v0, BaseVertex * v1) - { - V(0)=v0; - V(1)=v1; - } - //EdgeBase(v0,v1){}; - static inline BaseEdge OrderedEdge(BaseVertex* v0,BaseVertex* v1){ - if(v0 -{ -public: - std::vector > vertices_bary; - typedef std::vector >::iterator IteVBary; - vcg::Color4b group; - ScalarType areadelta; - vcg::Color4b colorDivision; - - template < class LeftV> - void ImportData(const LeftV & left ) - { - vcg::Face < BaseUsedTypes, - vcg::face::VFAdj, - vcg::face::FFAdj, - vcg::face::VertexRef, - vcg::face::BitFlags, - vcg::face::EdgePlane, - vcg::face::Mark, - vcg::face::Normal3f, - vcg::face::Color4b>::ImportData(left); - } - - void ImportData(const BaseFace & left ) - { - vcg::Face < BaseUsedTypes, - vcg::face::VFAdj, - vcg::face::FFAdj, - vcg::face::VertexRef, - vcg::face::BitFlags, - vcg::face::EdgePlane, - vcg::face::Mark, - vcg::face::Normal3f, - vcg::face::Color4b>::ImportData(left); - this->vertices_bary = std::vector > (left.vertices_bary); - this->group=left.group; - this->areadelta=left.areadelta; - this->colorDivision=left.colorDivision; - } - - -}; - -/// the main mesh class -class BaseMesh: public vcg::tri::TriMesh, std::vector > {}; - -#endif +#ifndef PARAM_MESH +#define PARAM_MESH + +// stuff to define the mesh +#include +#include +#include "iso_parametrization.h" + +class BaseVertex; +class BaseEdge; +class BaseFace; + +class BaseUsedTypes: public vcg::UsedTypes < vcg::Use::AsVertexType, + vcg::Use::AsEdgeType, + vcg::Use::AsFaceType >{}; + + +///AUXILIARY STRUCTURES USED FOR PARAMETRIZATION COMPUTATION +class BaseVertex : public vcg::Vertex< BaseUsedTypes, + vcg::vertex::VFAdj, + vcg::vertex::Coord3f, + vcg::vertex::Normal3f, + vcg::vertex::Mark, + vcg::vertex::BitFlags, + vcg::vertex::Color4b, + vcg::vertex::TexCoord2f> +{ +public: + + ScalarType area; + CoordType RPos; + BaseVertex *brother; + BaseFace *father; + CoordType Bary; + //ScalarType Damp; + + BaseVertex() + { + brother=NULL; + //Damp=1; + //num_collapse=1; + } + + static const bool Has_Auxiliary(){return true;} + + vcg::Point2 RestUV; + + vcg::Color4b OriginalCol; + //int num_collapse; + + void ImportData(const BaseVertex & left ) + { + vcg::Vertex< BaseUsedTypes, + vcg::vertex::VFAdj, + vcg::vertex::Coord3f, + vcg::vertex::Normal3f, + vcg::vertex::Mark, + vcg::vertex::BitFlags, + vcg::vertex::Color4b, + vcg::vertex::TexCoord2f>::ImportData(left); + + this->area=left.area; + this->RPos=left.RPos; + this->brother=left.brother; + this->father=left.father; + this->Bary=left.Bary; + } + + template < class LeftV> + void ImportData(const LeftV & left ) + { + vcg::Vertex< BaseUsedTypes, + vcg::vertex::VFAdj, + vcg::vertex::Coord3f, + vcg::vertex::Normal3f, + vcg::vertex::Mark, + vcg::vertex::BitFlags, + vcg::vertex::Color4b, + vcg::vertex::TexCoord2f>::ImportData(left); + } + + +}; + +///class maintaing additional auxiliary data used during the parameterization +class AuxiliaryVertData{ +public: + BaseVertex::ScalarType area; + BaseVertex::CoordType RPos; + BaseVertex *brother; + BaseFace *father; + BaseVertex::CoordType Bary; + + vcg::Point2 RestUV; + + vcg::Color4b OriginalCol; + + AuxiliaryVertData() + {brother=NULL;} +}; + +class AuxiliaryFaceData +{ +public: + std::vector > vertices_bary; + typedef std::vector >::iterator IteVBary; + vcg::Color4b group; + BaseVertex::ScalarType areadelta; + vcg::Color4b colorDivision; +}; + +class BaseFace; + +class BaseEdge : public vcg::Edge { +public: + inline BaseEdge() {}; + inline BaseEdge( BaseVertex * v0, BaseVertex * v1) + { + V(0)=v0; + V(1)=v1; + } + //EdgeBase(v0,v1){}; + static inline BaseEdge OrderedEdge(BaseVertex* v0,BaseVertex* v1){ + if(v0 +{ +public: + std::vector > vertices_bary; + typedef std::vector >::iterator IteVBary; + vcg::Color4b group; + ScalarType areadelta; + vcg::Color4b colorDivision; + + template < class LeftV> + void ImportData(const LeftV & left ) + { + vcg::Face < BaseUsedTypes, + vcg::face::VFAdj, + vcg::face::FFAdj, + vcg::face::VertexRef, + vcg::face::BitFlags, + vcg::face::EdgePlane, + vcg::face::Mark, + vcg::face::Normal3f, + vcg::face::Color4b>::ImportData(left); + } + + void ImportData(const BaseFace & left ) + { + vcg::Face < BaseUsedTypes, + vcg::face::VFAdj, + vcg::face::FFAdj, + vcg::face::VertexRef, + vcg::face::BitFlags, + vcg::face::EdgePlane, + vcg::face::Mark, + vcg::face::Normal3f, + vcg::face::Color4b>::ImportData(left); + this->vertices_bary = std::vector > (left.vertices_bary); + this->group=left.group; + this->areadelta=left.areadelta; + this->colorDivision=left.colorDivision; + } + + +}; + +/// the main mesh class +class BaseMesh: public vcg::tri::TriMesh, std::vector > {}; + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/parametrizator.h b/src/meshlabplugins/filter_isoparametrization/parametrizator.h index 1ae81b060..25593df32 100644 --- a/src/meshlabplugins/filter_isoparametrization/parametrizator.h +++ b/src/meshlabplugins/filter_isoparametrization/parametrizator.h @@ -1,1277 +1,1277 @@ -#ifndef _PARAMETRIZATOR -#define _PARAMETRIZATOR - -#include - - -#include -#include - - -#include -#include - -///auxiliary structures - -#include -#include -#include -#include -#include - -// update topology -#include -#include -#include - - -// local optimization -#include - - -#include -#include -#include -#include -#include -#include -#ifndef _MESHLAB -#include -#endif -//#include - -#include -#include -#include -#include - -//extern int step_global; -// -//int time_opt; - -///Flip function -class MyTriEdgeFlip : public ParamEdgeFlip{}; -class MyTriEdgeCollapse: public ParamEdgeCollapse{}; - -///THIS CLASS MAINTAINS STRUCTURES WICH ARE USED FOR PARAMETRIZATION -///TOGHETHER WITH METHOD FOR COLORIZATION FOR VISUALIZATION PURPOSES - -class IsoParametrizator{ - -public: - enum ReturnCode{MultiComponent, - NonSizeCons, - NonManifoldE, - NonManifoldV, - NonWatertigh, - FailParam,Done}; - - - BaseMesh final_mesh; - BaseMesh base_mesh; - typedef BaseMesh::ScalarType ScalarType; - typedef BaseMesh::CoordType CoordType; - vcg::CallBackPos *cb; - EnergyType EType; -private: - - void InitVoronoiArea() - { - ///area deviation respect to original - for (unsigned int i=0;iV(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/2.0; - f->V(0)->area+=areaf/(ScalarType)3.0; - f->V(1)->area+=areaf/(ScalarType)3.0; - f->V(2)->area+=areaf/(ScalarType)3.0; - } - } - - template - void InitializeStructures(MeshType *mesh) - { - ///cleaning of initial mesh - /*int dup = */vcg::tri::Clean::RemoveDuplicateVertex(*mesh); - /*int unref = */vcg::tri::Clean::RemoveUnreferencedVertex(*mesh); - - vcg::tri::Allocator::CompactFaceVector(*mesh); - vcg::tri::Allocator::CompactVertexVector(*mesh); - - ///copy - base_mesh.Clear(); - final_mesh.Clear(); - vcg::tri::Append::Mesh(base_mesh,*mesh); - vcg::tri::Append::Mesh(final_mesh,*mesh); - - ///update auxiliary structures - UpdateStructures(&base_mesh); - UpdateStructures(&final_mesh); - vcg::tri::UpdateTopology::TestFaceFace(base_mesh); - vcg::tri::UpdateTopology::TestFaceFace(final_mesh); - - ///initialization of statistics - //stat.Init(&base_mesh,&final_mesh); - - ///copy original color - for (unsigned int i=0;iIsD()); - CoordType bary=CoordType(0,0,0); - bary.V(base_mesh.vert[i].VFi())=1; - //final_mesh.vert[i].Bary=bary; - AssingFather(final_mesh.vert[i],base_mesh.vert[i].VFp(),bary,base_mesh); - } - - ///initialize area per vertex - - for (unsigned int i=0;ivertices_bary.push_back(std::pair(&final_mesh.vert[i],bary)); - } - - ///testing everithing is ok - for (unsigned int i=0;i DeciSession(base_mesh); - DeciSession.Init(); - MyTriEdgeCollapse::Accuracy()=accuracy; - MyTriEdgeCollapse::HresMesh()=&final_mesh; - PatchesOptimizer::HresMesh()=&final_mesh; - PatchesOptimizer::BaseMesh()=&base_mesh; - - MyTriEdgeFlip::Accuracy()=accuracy; - - int flip_todo=4; - int next_flip_num=targetFaces; - std::vector stop_points; - - if (execute_flip) - { - stop_points.resize(flip_todo+2);///number of flips + save stack point + final stop - - for (int i=0;itargetFaces)&&(not_heap_empty)) - { - do_flip=false; - - int curr_num=base_mesh.fn; - - int next_num; - if (!save_status) - next_num=curr_num-1000; - else - next_num=curr_num-2; - - if ((curr_limit>=0)&&(next_num::FaceFace(base_mesh); - vcg::tri::UpdateTopology::VertexFace(base_mesh); - InitIMark(); - DeciSession.h.clear(); - DeciSession.Init(); - if (flip_todo>0) - { - next_flip_num=(int)(((ScalarType)next_flip_num)/flip_factor); - flip_todo--; - } - } - /*#ifndef _MESHLAB - - #endif*/ - PrintAttributes(); - if (save_status) - { - #ifndef _MESHLAB - printf("SAVING CURRENT STATUS....face_num: %d\n",curr_num); - #endif - SaveCurrentStatus(); - InitIMark(); - DeciSession.h.clear(); - DeciSession.Init(); - } - - testParametrization(base_mesh,final_mesh); - - } - - - } - - ///ASSOCIATE SURVIVED VERTEX FROM DECIMATION - void AssociateRemaining() - { - printf("\n ASSOCIATE REMAINING \n"); - for (unsigned int i=0;ibrother; - vcg::face::VFIterator vfi2(v); - ///take the face that has lower number of vertices - BaseFace *fmin=vfi2.F(); - int index=vfi2.I(); - size_t sizeMin=fmin->vertices_bary.size(); - while (!vfi2.End()) - { - BaseFace *f=vfi2.F(); - if (f->vertices_bary.size()vertices_bary.size(); - fmin=f; - index=vfi2.I(); - } - ++vfi2; - } - CoordType bary=CoordType(0,0,0); - bary[index]=1.f; - fmin->vertices_bary.push_back(std::pair(vb,bary)); - AssingFather(*vb,fmin,bary,base_mesh); - /*vb->father=f; - assert(!f->IsD()); - vb->Bary=bary;*/ - v->brother=NULL; - } - } - - struct vert_para - { - ScalarType dist; - BaseVertex *v; - bool operator <(const vert_para &other) const - {return (dist>other.dist);} - }; - - void FinalOptimization() - { - char ret[200]; - sprintf(ret," PERFORM GLOBAL OPTIMIZATION initializing... "); - (*cb)(0,ret); - - - - std::vector ord_vertex; - ord_vertex.resize(base_mesh.vn); - for (unsigned int i=0;i(&base_mesh.vert[i]); - //printf("i: %d\n",i); - ord_vertex[i].dist=val; - ord_vertex[i].v=v; - } - - std::sort(ord_vertex.begin(),ord_vertex.end()); - for (unsigned int i=0;i(ord_vertex[i].v,base_mesh,MyTriEdgeCollapse::Accuracy(),EType); - } - } - - - template - ReturnCode InitBaseMesh(MeshType *mesh, - const int &targetFaces, - const int &interval, - bool execute_flip=true, - bool test_interpolation=true) - { - vcg::tri::UpdateFlags::VertexClearV(*mesh); - vcg::tri::UpdateFlags::FaceClearV(*mesh); - - ///TEST PRECONDITIONS - ReturnCode ret=Preconditions(*mesh); - - if (ret!=Done) return ret; - - ///INITIALIZATION - InitializeStructures(mesh); - - ///DECIMATION & PARAMETRIZATION - ParaDecimate(targetFaces,interval,execute_flip); - - ///SET BEST FIND STOP POINT - bool isOK=SetBestStatus(test_interpolation); - if ((!isOK)&&(test_interpolation)) - return FailParam; - - ///THEN CLEAR STACK - ClearStack(); - - ///LAST FLIP STEP - if (execute_flip) - FlipStep(); - - vcg::tri::UpdateTopology::FaceFace(base_mesh); - vcg::tri::UpdateTopology::VertexFace(base_mesh); - vcg::tri::UpdateTopology::TestVertexFace(base_mesh); ///TEST - - UpdateStructures(&base_mesh); - #ifndef _MESHLAB - if (execute_flip) - { - printf("\n POST LAST FLIP: \n"); - PrintAttributes(); - } - #endif - - ///ASSOCIATE REMAINING VERTICES TO ONE FACE - AssociateRemaining(); - - ///LAST OPTIMIZATION STEP ON STARS - if (execute_flip) - FinalOptimization(); - - #ifndef _MESHLAB - if (execute_flip) - { - printf("\n POST STAR OPT: \n"); - PrintAttributes(); - } - #endif - return Done; - } - - void CompactBaseDomain() - { - /*testParametrization(base_mesh,final_mesh); - system("pause");*/ - vcg::tri::Allocator::CompactVertexVector(base_mesh); - vcg::tri::Allocator::CompactFaceVector(base_mesh); - UpdateStructures(&base_mesh); - ///reassing - //for (int i=0;i<(int)base_mesh.face.size();i++) - for (int i=0;i<(int)base_mesh.face.size();i++) - { - int size=base_mesh.face[i].vertices_bary.size(); - /*assert(size>0);*/ - for (int j=0;jfather=&base_mesh.face[i]; - assert(!base_mesh.face[i].IsD()); - son->Bary=bary;*/ - AssingFather(*son,&base_mesh.face[i],bary,base_mesh); - } - } - /*testParametrization(base_mesh,final_mesh); - system("pause");*/ - } - - ///save the current status of the parameterization - void SaveCurrentStatus() - { - ///copy - ParaStack.push_back(ParaInfo()); - ParaStack.back().AbsMesh=new BaseMesh(); - BaseMesh *mesh=ParaStack.back().AbsMesh; - CompactBaseDomain(); - - vcg::tri::Append::Mesh(*mesh,base_mesh); - - - for (unsigned int i=0;ivert[i].RPos=base_mesh.vert[i].RPos; - - ///copy linking for parameterization informations - int k=0; - for (unsigned int i=0;iface[k].vertices_bary.resize(size); - for (int j=0;jface[k].vertices_bary[j].first=base_mesh.face[i].vertices_bary[j].first; - mesh->face[k].vertices_bary[j].second=base_mesh.face[i].vertices_bary[j].second; - } - k++; - } - } - //ParaStack.push_back(ParaInfo()); - /*ParaStack.back().AbsMesh=mesh;*/ - ScalarType valL2=ApproxL2Error(final_mesh); - ParaStack.back().L2=valL2; - ScalarType val0=ApproxAreaDistortion(final_mesh,mesh->fn); - ParaStack.back().AreaDist=val0; - ScalarType val1=ApproxAngleDistortion(final_mesh); - ParaStack.back().AngleDist=val1; - ParaStack.back().AggrDist=geomAverage(val0+(ScalarType)1.0,val1+(ScalarType)1.0,3,1)-(ScalarType)1; - ParaStack.back().Regular=NumRegular(*mesh); - //ParaStack.back().distorsion=geomAverage(val0,val1,3,1); - ScalarType val2=ParaStack.back().AggrDist; - ParaStack.back().num_faces=mesh->fn; - ParaStack.back().ratio=val2*sqrt((ScalarType)mesh->fn); - } - - void RestoreStatus(const int &index_status) - { - ///delete current base mesh - base_mesh.Clear(); - BaseMesh *to_restore=ParaStack[index_status].AbsMesh; - - ///restore saved abstract mesh and link - vcg::tri::Append::Mesh(base_mesh,*to_restore); - for (unsigned int i=0;iface.size();i++) - { - int size=to_restore->face[i].vertices_bary.size(); - base_mesh.face[i].vertices_bary.resize(size); - for (int j=0;jface[i].vertices_bary[j].first; - CoordType bary=to_restore->face[i].vertices_bary[j].second; -#ifdef _DEBUG - bool done=NormalizeBaryCoords(bary); - assert(done); -#else - NormalizeBaryCoords(bary); -#endif - base_mesh.face[i].vertices_bary[j].first=vert; - base_mesh.face[i].vertices_bary[j].second=bary; - - AssingFather(*vert,&base_mesh.face[i],bary,base_mesh); - - //vert->father=&base_mesh.face[i]; - //assert(!base_mesh.face[i].IsD()); - //vert->Bary=bary; - } - } - UpdateTopologies(&base_mesh); - - ///copy rest pos - for (unsigned int i=0;ivert.size();i++) - { - base_mesh.vert[i].RPos=to_restore->vert[i].RPos; - base_mesh.vert[i].P()=to_restore->vert[i].P(); - } - /*///clear stack of meshes - ClearStack();*/ - } - - ///clear the durrent stack - void ClearStack() - { - for (unsigned int i=0;i *BaryOptDemo; - vcg::LocalOptimization *FlipSession; - - int TimeStepDeci,TimeStepFlip; - - struct ParaInfo - { - ScalarType AggrDist; - ScalarType AreaDist; - ScalarType AngleDist; - int Regular; - int num_faces; - ScalarType ratio; - ScalarType L2; - BaseMesh * AbsMesh; - - static StopMode& SM() - { - static StopMode S; - return S; - } - - inline bool operator < (const ParaInfo &P_info) const{ - switch (SM()) - { - case (SM_Area): return AreaDist ParaStack; - - ///PRECONDITIONS - template - ReturnCode Preconditions(MeshType &mesh) - { - bool b; - vcg::tri::UpdateTopology::FaceFace(mesh); - if(vcg::tri::Clean::CountNonManifoldEdgeFF(mesh)>0 ) return NonManifoldE; - if(vcg::tri::Clean::CountNonManifoldVertexFF(mesh)>0 ) return NonManifoldV; - - b=vcg::tri::Clean::IsSizeConsistent(mesh); - if (!b) return NonSizeCons; - - int cc=vcg::tri::Clean::CountConnectedComponents(mesh); - if(cc>1) return MultiComponent; - - int boundaryEdgeNum, internalEdgeNum; - vcg::tri::Clean::CountEdges(mesh,internalEdgeNum,boundaryEdgeNum); - if(boundaryEdgeNum>0) return NonWatertigh; - - return Done; - } - - ///perform a global optimization step - void GlobalOptimizeStep() - { -#ifndef _MESHLAB - printf("\n GLOBAL OPTIMIZATION \n"); -#endif - BaryOptimizatorDual BaryOpt; - BaryOpt.Init(base_mesh,final_mesh,cb,accuracy,EType); - BaryOpt.Optimize(4.0/(double)accuracy,accuracy*4); -#ifndef _MESHLAB - printf("\n POST DUAL OPT: \n"); - PrintAttributes(); -#endif - } - - template - void ScaleMesh(MeshType &m, - const ScalarType &factor) - { - for (size_t i=0;i - void TranslateMesh(MeshType &m,const typename MeshType::CoordType &vect) - { - for (size_t i=0;i - ReturnCode Parametrize(MeshType *mesh,bool Two_steps=true,EnergyType _EType=EN_EXTMips) - { - EType=_EType; - MyTriEdgeCollapse::EType()=EType; - MyTriEdgeFlip::EType()=EType; - - ///clean unreferenced vertices - vcg::tri::Clean::RemoveUnreferencedVertex(*mesh); - /*bool done;*/ - const int limit0=15000;//00; - const int limit1=30000; - - vcg::tri::UpdateBounding::Box(*mesh); - ScalarType factor=100.0/mesh->bbox.Diag(); - CoordType transl=-mesh->bbox.Center(); - TranslateMesh(*mesh,transl); - ScaleMesh(*mesh,factor); - if ((!Two_steps)||(lower_limit>limit0)||(mesh->fn(mesh,lower_limit,interval,true,true); - ScaleMesh(*mesh,1.0/factor); - TranslateMesh(*mesh,-transl); - if (res!=Done) - return res; - } - else - { - ///do a first parametrization step - printf("\n STEP 1 \n"); - InitVoronoiArea(); - ReturnCode res=InitBaseMesh(mesh,limit0,1,false,false); - ScaleMesh(*mesh,1.0/factor); - TranslateMesh(*mesh,-transl); - if (res!=Done) - return res; - - ParamMesh para_mesh0; - AbstractMesh abs_mesh0; - //AbstractMesh abs_mesh_test; - ExportMeshes(para_mesh0,abs_mesh0); - - printf("\n STEP 2 \n"); - res=InitBaseMesh(&abs_mesh0,lower_limit,interval,true,true); - if (res!=Done) - return res; - - - ParamMesh para_mesh1; - AbstractMesh abs_mesh1; - ExportMeshes(para_mesh1,abs_mesh1); - - - - ///constrauct an ISOPARAM - printf("\n STEP 2.5 \n"); - IsoParametrization IsoParam1; - bool done=IsoParam1.Init(&abs_mesh1,¶_mesh1,true); - - if (!done) - return FailParam; - - printf("\n merging 0 \n"); - ///copy initial mesh - final_mesh.Clear(); - base_mesh.Clear(); - vcg::tri::Append::Mesh(final_mesh,para_mesh0); - vcg::tri::Append::Mesh(base_mesh,abs_mesh1); - ///scale by a factor - - UpdateTopologies(&final_mesh); - UpdateTopologies(&base_mesh); - - for (int i=0;i<(int)base_mesh.vert.size();i++) - base_mesh.vert[i].RPos=abs_mesh1.vert[i].P(); - for (int i=0;i<(int)final_mesh.vert.size();i++) - final_mesh.vert[i].RPos=para_mesh0.vert[i].P(); - - ///finally merge in between - for (int i=0;i<(int)para_mesh0.vert.size();i++) - { - ///get the index of the first parametrization process - int Index0=para_mesh0.vert[i].T().N(); - ///find the parametrization coordinates - vcg::Point2 p2bary=para_mesh0.vert[i].T().P(); - CoordType bary0=CoordType (p2bary.X(),p2bary.Y(),1-p2bary.X()-p2bary.Y()); - bool isOK=NormalizeBaryCoords(bary0); - assert(isOK); - assert(size_t(Index0) UV_final; - IsoParam1.Phi(f1,bary0,I_final,UV_final); - assert(size_t(I_final)=0)&&(bary.Y()>=0)); - assert((bary.X()<=1)&&(bary.Y()<=1)); - assert(bary.X()+bary.Y()<=1.0001); - base_f->vertices_bary.push_back(std::pair(&final_mesh.vert[i],bary)); - } - InitVoronoiArea(); - FinalOptimization(); - printf("STEP 3 \n"); - } - ///finally perform the final optimization step - InitVoronoiArea(); - //FinalOptimization(); - GlobalOptimizeStep(); - - ScaleMesh(final_mesh,1.0/factor); - TranslateMesh(final_mesh,-transl); - ScaleMesh(base_mesh,1.0/factor); - TranslateMesh(base_mesh,-transl); - return Done; - } - - ///perform one or more flip steps - void FlipStep() - { -#ifndef _MESHLAB - printf("\n STARTING FLIP SESSION \n"); -#endif - InitIMark(); - FlipSession=new vcg::LocalOptimization(base_mesh); - FlipSession->Init(); - /*bool b=*/FlipSession->DoOptimization(); -#ifndef _MESHLAB - printf("\n END FLIP SESSION %d edges \n",FlipSession->nPerfmormedOps); -#endif - UpdateTopologies(&base_mesh); - } - - ///equilateralize patch lenght and areas - void EquiPatches() - { - PatchesOptimizer DomOpt(base_mesh,final_mesh); - DomOpt.OptimizePatches(); - PrintAttributes(); - } - - /// I/O FUNCTIONS - void SaveMCP(char* filename) - { - /*Warp(0);*/ - FILE *f; - f=fopen(filename,"w+"); - std::map facemap; - std::map vertexmap; - typedef std::map::iterator iteMapVert; - typedef std::map::iterator iteMapFace; - - ///add vertices - fprintf(f,"%d,%d \n",base_mesh.fn,base_mesh.vn); - int index=0; - for (unsigned int i=0;iIsD()) - { - vertexmap.insert(std::pair(vert,index)); - CoordType pos=vert->P(); - CoordType RPos=vert->RPos; - fprintf(f,"%f,%f,%f;%f,%f,%f \n",pos.X(),pos.Y(),pos.Z(),RPos.X(),RPos.Y(),RPos.Z()); - index++; - } - } - - ///add faces - index=0; - for (unsigned int i=0;iIsD()) - { - BaseVertex* v0=face->V(0); - BaseVertex* v1=face->V(1); - BaseVertex* v2=face->V(2); - iteMapVert vertIte; - vertIte=vertexmap.find(v0); - assert(vertIte!=vertexmap.end()); - int index0=(*vertIte).second; - vertIte=vertexmap.find(v1); - assert(vertIte!=vertexmap.end()); - int index1=(*vertIte).second; - vertIte=vertexmap.find(v2); - assert(vertIte!=vertexmap.end()); - int index2=(*vertIte).second; - assert((index0!=index1)&&(index1!=index2)); - fprintf(f,"%d,%d,%d \n",index0,index1,index2); - facemap.insert(std::pair(face,index)); - index++; - } - } - - ///high resolution mesh - fprintf(f,"%d,%d \n",final_mesh.fn,final_mesh.vn); - - ///add vertices - vertexmap.clear(); - index=0; - for (unsigned int i=0;iIsD()) - { - vertexmap.insert(std::pair(vert,index)); - CoordType pos=vert->P(); - CoordType bary=vert->Bary; - BaseFace* father=vert->father; - iteMapFace IteF=facemap.find(father); - assert (IteF!=facemap.end()); - int indexface=(*IteF).second; - fprintf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n", - pos.X(),pos.Y(),pos.Z(),bary.X(),bary.Y(),bary.Z(), - vert->OriginalCol.X(),vert->OriginalCol.Y(),vert->OriginalCol.Z(), - indexface); - index++; - } - } - - ///add faces - for (unsigned int i=0;iIsD()) - { - BaseVertex* v0=face->V(0); - BaseVertex* v1=face->V(1); - BaseVertex* v2=face->V(2); - iteMapVert vertIte; - vertIte=vertexmap.find(v0); - assert(vertIte!=vertexmap.end()); - int index0=(*vertIte).second; - vertIte=vertexmap.find(v1); - assert(vertIte!=vertexmap.end()); - int index1=(*vertIte).second; - vertIte=vertexmap.find(v2); - assert(vertIte!=vertexmap.end()); - int index2=(*vertIte).second; - assert((index0!=index1)&&(index1!=index2)); - fprintf(f,"%d,%d,%d \n",index0,index1,index2); - } - } - fclose(f); - } - - int LoadMCP(char* filename) - { - FILE *f=NULL; - f=fopen(filename,"r"); - if (f==NULL) - return -1; - /*std::map facemap; - std::map vertexmap; - typedef std::map::iterator iteMapVert; - typedef std::map::iterator iteMapFace;*/ - - - - ///add vertices - base_mesh.Clear(); - fscanf(f,"%d,%d \n",&base_mesh.fn,&base_mesh.vn); - base_mesh.vert.resize(base_mesh.vn); - base_mesh.face.resize(base_mesh.fn); - - for (unsigned int i=0;iP()=pos; - vert->RPos=RPos; - } - - - - ///add faces - for (unsigned int i=0;iIsD()) - { - int index0,index1,index2; - fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); - base_mesh.face[i].V(0)=&base_mesh.vert[index0]; - base_mesh.face[i].V(1)=&base_mesh.vert[index1]; - base_mesh.face[i].V(2)=&base_mesh.vert[index2]; - base_mesh.face[i].group=vcg::Color4b(rand()%200,rand()%200,rand()%200,255); - } - } - - ///high resolution mesh - fscanf(f,"%d,%d \n",&final_mesh.fn,&final_mesh.vn); - final_mesh.vert.resize(final_mesh.vn); - final_mesh.face.resize(final_mesh.fn); - - ///add vertices - for (unsigned int i=0;iP()=pos; - vert->RPos=pos; - vert->Bary=bary; - vert->father=&base_mesh.face[index_face]; - assert(!base_mesh.face[index_face].IsD()); - col=vcg::Color4b(col0,col1,col2,255); - vert->OriginalCol=col; - /*if (i==final_mesh.vert.size()-1) - { - printf("sukka %d \n",index_face); - char test; - scanf ("%c",&test); - }*/ - - } - - ///add faces - for (unsigned int i=0;ifather; - CoordType bary=v->Bary; - f->vertices_bary.push_back(std::pair(v,bary)); - } - - //ColorByParametrization(); - PrintAttributes(); - //printf("faces:%5d AREA distorsion:%lf\n",base_mesh.fn,ApproxAreaDistortion(final_mesh,base_mesh.fn)); - //printf("faces:%5d ANGLE distorsion:%lf\n",base_mesh.fn,ApproxAngleDistortion(final_mesh)); - - vcg::tri::UpdateBounding::Box(final_mesh); - - ///area perr vertex - for (unsigned int i=0;iV(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/(ScalarType)2.0; - /*AuxHPara[f->V(0)].area+=areaf/3.0; - AuxHPara[f->V(1)].area+=areaf/3.0; - AuxHPara[f->V(2)].area+=areaf/3.0;*/ - f->V(0)->area+=areaf/(ScalarType)3.0; - f->V(1)->area+=areaf/(ScalarType)3.0; - f->V(2)->area+=areaf/(ScalarType)3.0; - } - - return 0; - } - - void ExportMeshes(ParamMesh ¶_mesh,AbstractMesh &abs_mesh) - { - para_mesh.Clear(); - abs_mesh.Clear(); - - ///copy meshes - vcg::tri::Append::Mesh(abs_mesh,base_mesh); - vcg::tri::Append::Mesh(para_mesh,final_mesh); - - ///copy additional values - for (unsigned int i=0;i faceMap; - for (unsigned int i=0;i(&base_mesh.face[i],i)); - - ///then reassing with new mesh - for (unsigned int i=0;i::iterator cur = faceMap.find(final_mesh.vert[i].father); - assert(cur!= faceMap.end()); - CoordType bary=final_mesh.vert[i].Bary; - int index=(*cur).second; - para_mesh.vert[i].T().N()=index; -#ifdef _DEBUG - bool done=NormalizeBaryCoords(bary); - assert(done); -#else - NormalizeBaryCoords(bary); -#endif - para_mesh.vert[i].T().U()=bary.X(); - para_mesh.vert[i].T().V()=bary.Y(); - - } - } - - //int draw_mode; - - void PrintAttributes() - { - int done=(final_mesh.fn-base_mesh.fn); - int total=(final_mesh.fn-lower_limit); - ScalarType ratio=(ScalarType)done/total; - ratio=pow(ratio,3); - int percent=(int)(ratio*(ScalarType)100); - ScalarType areaD=ApproxAreaDistortion(final_mesh,base_mesh.fn); - ScalarType angleD=ApproxAngleDistortion(final_mesh); - char ret[200]; - sprintf(ret," GATHERING ABSTRACT DOMAIN faces:%5d AREA distorsion:%4f ; ANGLE distorsion:%4f ",base_mesh.fn,areaD,angleD); - (*cb)(percent,ret); - } - - void SetParameters(vcg::CallBackPos *_cb, - const int &_lower_limit=100, - const int &_interval=50, - StopMode _SMode=SM_Euristic, - const int &_accuracy=1) - { - lower_limit=_lower_limit; - interval=_interval; - accuracy=_accuracy; - SMode=_SMode; - ParaInfo::SM()=_SMode; - cb=_cb; - } - - void getValues(ScalarType &aggregate, - ScalarType &L2, - int &n_faces) - { - L2=ApproxL2Error(final_mesh); - ScalarType val0=ApproxAreaDistortion(final_mesh,base_mesh.fn); - ScalarType val1=ApproxAngleDistortion(final_mesh); - aggregate=geomAverage(val0+1.0,val1+1.0,3,1)-1; - n_faces=base_mesh.fn; - } - - IsoParametrizator() - { - ///parameters - SMode=SM_Euristic; - lower_limit=40; - interval=50; - accuracy=1; - } - -}; - -#endif +#ifndef _PARAMETRIZATOR +#define _PARAMETRIZATOR + +#include + + +#include +#include + + +#include +#include + +///auxiliary structures + +#include +#include +#include +#include +#include + +// update topology +#include +#include +#include + + +// local optimization +#include + + +#include +#include +#include +#include +#include +#include +#ifndef _MESHLAB +#include +#endif +//#include + +#include +#include +#include +#include + +//extern int step_global; +// +//int time_opt; + +///Flip function +class MyTriEdgeFlip : public ParamEdgeFlip{}; +class MyTriEdgeCollapse: public ParamEdgeCollapse{}; + +///THIS CLASS MAINTAINS STRUCTURES WICH ARE USED FOR PARAMETRIZATION +///TOGHETHER WITH METHOD FOR COLORIZATION FOR VISUALIZATION PURPOSES + +class IsoParametrizator{ + +public: + enum ReturnCode{MultiComponent, + NonSizeCons, + NonManifoldE, + NonManifoldV, + NonWatertigh, + FailParam,Done}; + + + BaseMesh final_mesh; + BaseMesh base_mesh; + typedef BaseMesh::ScalarType ScalarType; + typedef BaseMesh::CoordType CoordType; + vcg::CallBackPos *cb; + EnergyType EType; +private: + + void InitVoronoiArea() + { + ///area deviation respect to original + for (unsigned int i=0;iV(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/2.0; + f->V(0)->area+=areaf/(ScalarType)3.0; + f->V(1)->area+=areaf/(ScalarType)3.0; + f->V(2)->area+=areaf/(ScalarType)3.0; + } + } + + template + void InitializeStructures(MeshType *mesh) + { + ///cleaning of initial mesh + /*int dup = */vcg::tri::Clean::RemoveDuplicateVertex(*mesh); + /*int unref = */vcg::tri::Clean::RemoveUnreferencedVertex(*mesh); + + vcg::tri::Allocator::CompactFaceVector(*mesh); + vcg::tri::Allocator::CompactVertexVector(*mesh); + + ///copy + base_mesh.Clear(); + final_mesh.Clear(); + vcg::tri::Append::Mesh(base_mesh,*mesh); + vcg::tri::Append::Mesh(final_mesh,*mesh); + + ///update auxiliary structures + UpdateStructures(&base_mesh); + UpdateStructures(&final_mesh); + vcg::tri::UpdateTopology::TestFaceFace(base_mesh); + vcg::tri::UpdateTopology::TestFaceFace(final_mesh); + + ///initialization of statistics + //stat.Init(&base_mesh,&final_mesh); + + ///copy original color + for (unsigned int i=0;iIsD()); + CoordType bary=CoordType(0,0,0); + bary.V(base_mesh.vert[i].VFi())=1; + //final_mesh.vert[i].Bary=bary; + AssingFather(final_mesh.vert[i],base_mesh.vert[i].VFp(),bary,base_mesh); + } + + ///initialize area per vertex + + for (unsigned int i=0;ivertices_bary.push_back(std::pair(&final_mesh.vert[i],bary)); + } + + ///testing everithing is ok + for (unsigned int i=0;i DeciSession(base_mesh); + DeciSession.Init(); + MyTriEdgeCollapse::Accuracy()=accuracy; + MyTriEdgeCollapse::HresMesh()=&final_mesh; + PatchesOptimizer::HresMesh()=&final_mesh; + PatchesOptimizer::BaseMesh()=&base_mesh; + + MyTriEdgeFlip::Accuracy()=accuracy; + + int flip_todo=4; + int next_flip_num=targetFaces; + std::vector stop_points; + + if (execute_flip) + { + stop_points.resize(flip_todo+2);///number of flips + save stack point + final stop + + for (int i=0;itargetFaces)&&(not_heap_empty)) + { + do_flip=false; + + int curr_num=base_mesh.fn; + + int next_num; + if (!save_status) + next_num=curr_num-1000; + else + next_num=curr_num-2; + + if ((curr_limit>=0)&&(next_num::FaceFace(base_mesh); + vcg::tri::UpdateTopology::VertexFace(base_mesh); + InitIMark(); + DeciSession.h.clear(); + DeciSession.Init(); + if (flip_todo>0) + { + next_flip_num=(int)(((ScalarType)next_flip_num)/flip_factor); + flip_todo--; + } + } + /*#ifndef _MESHLAB + + #endif*/ + PrintAttributes(); + if (save_status) + { + #ifndef _MESHLAB + printf("SAVING CURRENT STATUS....face_num: %d\n",curr_num); + #endif + SaveCurrentStatus(); + InitIMark(); + DeciSession.h.clear(); + DeciSession.Init(); + } + + testParametrization(base_mesh,final_mesh); + + } + + + } + + ///ASSOCIATE SURVIVED VERTEX FROM DECIMATION + void AssociateRemaining() + { + printf("\n ASSOCIATE REMAINING \n"); + for (unsigned int i=0;ibrother; + vcg::face::VFIterator vfi2(v); + ///take the face that has lower number of vertices + BaseFace *fmin=vfi2.F(); + int index=vfi2.I(); + size_t sizeMin=fmin->vertices_bary.size(); + while (!vfi2.End()) + { + BaseFace *f=vfi2.F(); + if (f->vertices_bary.size()vertices_bary.size(); + fmin=f; + index=vfi2.I(); + } + ++vfi2; + } + CoordType bary=CoordType(0,0,0); + bary[index]=1.f; + fmin->vertices_bary.push_back(std::pair(vb,bary)); + AssingFather(*vb,fmin,bary,base_mesh); + /*vb->father=f; + assert(!f->IsD()); + vb->Bary=bary;*/ + v->brother=NULL; + } + } + + struct vert_para + { + ScalarType dist; + BaseVertex *v; + bool operator <(const vert_para &other) const + {return (dist>other.dist);} + }; + + void FinalOptimization() + { + char ret[200]; + sprintf(ret," PERFORM GLOBAL OPTIMIZATION initializing... "); + (*cb)(0,ret); + + + + std::vector ord_vertex; + ord_vertex.resize(base_mesh.vn); + for (unsigned int i=0;i(&base_mesh.vert[i]); + //printf("i: %d\n",i); + ord_vertex[i].dist=val; + ord_vertex[i].v=v; + } + + std::sort(ord_vertex.begin(),ord_vertex.end()); + for (unsigned int i=0;i(ord_vertex[i].v,base_mesh,MyTriEdgeCollapse::Accuracy(),EType); + } + } + + + template + ReturnCode InitBaseMesh(MeshType *mesh, + const int &targetFaces, + const int &interval, + bool execute_flip=true, + bool test_interpolation=true) + { + vcg::tri::UpdateFlags::VertexClearV(*mesh); + vcg::tri::UpdateFlags::FaceClearV(*mesh); + + ///TEST PRECONDITIONS + ReturnCode ret=Preconditions(*mesh); + + if (ret!=Done) return ret; + + ///INITIALIZATION + InitializeStructures(mesh); + + ///DECIMATION & PARAMETRIZATION + ParaDecimate(targetFaces,interval,execute_flip); + + ///SET BEST FIND STOP POINT + bool isOK=SetBestStatus(test_interpolation); + if ((!isOK)&&(test_interpolation)) + return FailParam; + + ///THEN CLEAR STACK + ClearStack(); + + ///LAST FLIP STEP + if (execute_flip) + FlipStep(); + + vcg::tri::UpdateTopology::FaceFace(base_mesh); + vcg::tri::UpdateTopology::VertexFace(base_mesh); + vcg::tri::UpdateTopology::TestVertexFace(base_mesh); ///TEST + + UpdateStructures(&base_mesh); + #ifndef _MESHLAB + if (execute_flip) + { + printf("\n POST LAST FLIP: \n"); + PrintAttributes(); + } + #endif + + ///ASSOCIATE REMAINING VERTICES TO ONE FACE + AssociateRemaining(); + + ///LAST OPTIMIZATION STEP ON STARS + if (execute_flip) + FinalOptimization(); + + #ifndef _MESHLAB + if (execute_flip) + { + printf("\n POST STAR OPT: \n"); + PrintAttributes(); + } + #endif + return Done; + } + + void CompactBaseDomain() + { + /*testParametrization(base_mesh,final_mesh); + system("pause");*/ + vcg::tri::Allocator::CompactVertexVector(base_mesh); + vcg::tri::Allocator::CompactFaceVector(base_mesh); + UpdateStructures(&base_mesh); + ///reassing + //for (int i=0;i<(int)base_mesh.face.size();i++) + for (int i=0;i<(int)base_mesh.face.size();i++) + { + int size=base_mesh.face[i].vertices_bary.size(); + /*assert(size>0);*/ + for (int j=0;jfather=&base_mesh.face[i]; + assert(!base_mesh.face[i].IsD()); + son->Bary=bary;*/ + AssingFather(*son,&base_mesh.face[i],bary,base_mesh); + } + } + /*testParametrization(base_mesh,final_mesh); + system("pause");*/ + } + + ///save the current status of the parameterization + void SaveCurrentStatus() + { + ///copy + ParaStack.push_back(ParaInfo()); + ParaStack.back().AbsMesh=new BaseMesh(); + BaseMesh *mesh=ParaStack.back().AbsMesh; + CompactBaseDomain(); + + vcg::tri::Append::Mesh(*mesh,base_mesh); + + + for (unsigned int i=0;ivert[i].RPos=base_mesh.vert[i].RPos; + + ///copy linking for parameterization informations + int k=0; + for (unsigned int i=0;iface[k].vertices_bary.resize(size); + for (int j=0;jface[k].vertices_bary[j].first=base_mesh.face[i].vertices_bary[j].first; + mesh->face[k].vertices_bary[j].second=base_mesh.face[i].vertices_bary[j].second; + } + k++; + } + } + //ParaStack.push_back(ParaInfo()); + /*ParaStack.back().AbsMesh=mesh;*/ + ScalarType valL2=ApproxL2Error(final_mesh); + ParaStack.back().L2=valL2; + ScalarType val0=ApproxAreaDistortion(final_mesh,mesh->fn); + ParaStack.back().AreaDist=val0; + ScalarType val1=ApproxAngleDistortion(final_mesh); + ParaStack.back().AngleDist=val1; + ParaStack.back().AggrDist=geomAverage(val0+(ScalarType)1.0,val1+(ScalarType)1.0,3,1)-(ScalarType)1; + ParaStack.back().Regular=NumRegular(*mesh); + //ParaStack.back().distorsion=geomAverage(val0,val1,3,1); + ScalarType val2=ParaStack.back().AggrDist; + ParaStack.back().num_faces=mesh->fn; + ParaStack.back().ratio=val2*sqrt((ScalarType)mesh->fn); + } + + void RestoreStatus(const int &index_status) + { + ///delete current base mesh + base_mesh.Clear(); + BaseMesh *to_restore=ParaStack[index_status].AbsMesh; + + ///restore saved abstract mesh and link + vcg::tri::Append::Mesh(base_mesh,*to_restore); + for (unsigned int i=0;iface.size();i++) + { + int size=to_restore->face[i].vertices_bary.size(); + base_mesh.face[i].vertices_bary.resize(size); + for (int j=0;jface[i].vertices_bary[j].first; + CoordType bary=to_restore->face[i].vertices_bary[j].second; +#ifdef _DEBUG + bool done=NormalizeBaryCoords(bary); + assert(done); +#else + NormalizeBaryCoords(bary); +#endif + base_mesh.face[i].vertices_bary[j].first=vert; + base_mesh.face[i].vertices_bary[j].second=bary; + + AssingFather(*vert,&base_mesh.face[i],bary,base_mesh); + + //vert->father=&base_mesh.face[i]; + //assert(!base_mesh.face[i].IsD()); + //vert->Bary=bary; + } + } + UpdateTopologies(&base_mesh); + + ///copy rest pos + for (unsigned int i=0;ivert.size();i++) + { + base_mesh.vert[i].RPos=to_restore->vert[i].RPos; + base_mesh.vert[i].P()=to_restore->vert[i].P(); + } + /*///clear stack of meshes + ClearStack();*/ + } + + ///clear the durrent stack + void ClearStack() + { + for (unsigned int i=0;i *BaryOptDemo; + vcg::LocalOptimization *FlipSession; + + int TimeStepDeci,TimeStepFlip; + + struct ParaInfo + { + ScalarType AggrDist; + ScalarType AreaDist; + ScalarType AngleDist; + int Regular; + int num_faces; + ScalarType ratio; + ScalarType L2; + BaseMesh * AbsMesh; + + static StopMode& SM() + { + static StopMode S; + return S; + } + + inline bool operator < (const ParaInfo &P_info) const{ + switch (SM()) + { + case (SM_Area): return AreaDist ParaStack; + + ///PRECONDITIONS + template + ReturnCode Preconditions(MeshType &mesh) + { + bool b; + vcg::tri::UpdateTopology::FaceFace(mesh); + if(vcg::tri::Clean::CountNonManifoldEdgeFF(mesh)>0 ) return NonManifoldE; + if(vcg::tri::Clean::CountNonManifoldVertexFF(mesh)>0 ) return NonManifoldV; + + b=vcg::tri::Clean::IsSizeConsistent(mesh); + if (!b) return NonSizeCons; + + int cc=vcg::tri::Clean::CountConnectedComponents(mesh); + if(cc>1) return MultiComponent; + + int boundaryEdgeNum, internalEdgeNum; + vcg::tri::Clean::CountEdges(mesh,internalEdgeNum,boundaryEdgeNum); + if(boundaryEdgeNum>0) return NonWatertigh; + + return Done; + } + + ///perform a global optimization step + void GlobalOptimizeStep() + { +#ifndef _MESHLAB + printf("\n GLOBAL OPTIMIZATION \n"); +#endif + BaryOptimizatorDual BaryOpt; + BaryOpt.Init(base_mesh,final_mesh,cb,accuracy,EType); + BaryOpt.Optimize(4.0/(double)accuracy,accuracy*4); +#ifndef _MESHLAB + printf("\n POST DUAL OPT: \n"); + PrintAttributes(); +#endif + } + + template + void ScaleMesh(MeshType &m, + const ScalarType &factor) + { + for (size_t i=0;i + void TranslateMesh(MeshType &m,const typename MeshType::CoordType &vect) + { + for (size_t i=0;i + ReturnCode Parametrize(MeshType *mesh,bool Two_steps=true,EnergyType _EType=EN_EXTMips) + { + EType=_EType; + MyTriEdgeCollapse::EType()=EType; + MyTriEdgeFlip::EType()=EType; + + ///clean unreferenced vertices + vcg::tri::Clean::RemoveUnreferencedVertex(*mesh); + /*bool done;*/ + const int limit0=15000;//00; + const int limit1=30000; + + vcg::tri::UpdateBounding::Box(*mesh); + ScalarType factor=100.0/mesh->bbox.Diag(); + CoordType transl=-mesh->bbox.Center(); + TranslateMesh(*mesh,transl); + ScaleMesh(*mesh,factor); + if ((!Two_steps)||(lower_limit>limit0)||(mesh->fn(mesh,lower_limit,interval,true,true); + ScaleMesh(*mesh,1.0/factor); + TranslateMesh(*mesh,-transl); + if (res!=Done) + return res; + } + else + { + ///do a first parametrization step + printf("\n STEP 1 \n"); + InitVoronoiArea(); + ReturnCode res=InitBaseMesh(mesh,limit0,1,false,false); + ScaleMesh(*mesh,1.0/factor); + TranslateMesh(*mesh,-transl); + if (res!=Done) + return res; + + ParamMesh para_mesh0; + AbstractMesh abs_mesh0; + //AbstractMesh abs_mesh_test; + ExportMeshes(para_mesh0,abs_mesh0); + + printf("\n STEP 2 \n"); + res=InitBaseMesh(&abs_mesh0,lower_limit,interval,true,true); + if (res!=Done) + return res; + + + ParamMesh para_mesh1; + AbstractMesh abs_mesh1; + ExportMeshes(para_mesh1,abs_mesh1); + + + + ///constrauct an ISOPARAM + printf("\n STEP 2.5 \n"); + IsoParametrization IsoParam1; + bool done=IsoParam1.Init(&abs_mesh1,¶_mesh1,true); + + if (!done) + return FailParam; + + printf("\n merging 0 \n"); + ///copy initial mesh + final_mesh.Clear(); + base_mesh.Clear(); + vcg::tri::Append::Mesh(final_mesh,para_mesh0); + vcg::tri::Append::Mesh(base_mesh,abs_mesh1); + ///scale by a factor + + UpdateTopologies(&final_mesh); + UpdateTopologies(&base_mesh); + + for (int i=0;i<(int)base_mesh.vert.size();i++) + base_mesh.vert[i].RPos=abs_mesh1.vert[i].P(); + for (int i=0;i<(int)final_mesh.vert.size();i++) + final_mesh.vert[i].RPos=para_mesh0.vert[i].P(); + + ///finally merge in between + for (int i=0;i<(int)para_mesh0.vert.size();i++) + { + ///get the index of the first parametrization process + int Index0=para_mesh0.vert[i].T().N(); + ///find the parametrization coordinates + vcg::Point2 p2bary=para_mesh0.vert[i].T().P(); + CoordType bary0=CoordType (p2bary.X(),p2bary.Y(),1-p2bary.X()-p2bary.Y()); + bool isOK=NormalizeBaryCoords(bary0); + assert(isOK); + assert(size_t(Index0) UV_final; + IsoParam1.Phi(f1,bary0,I_final,UV_final); + assert(size_t(I_final)=0)&&(bary.Y()>=0)); + assert((bary.X()<=1)&&(bary.Y()<=1)); + assert(bary.X()+bary.Y()<=1.0001); + base_f->vertices_bary.push_back(std::pair(&final_mesh.vert[i],bary)); + } + InitVoronoiArea(); + FinalOptimization(); + printf("STEP 3 \n"); + } + ///finally perform the final optimization step + InitVoronoiArea(); + //FinalOptimization(); + GlobalOptimizeStep(); + + ScaleMesh(final_mesh,1.0/factor); + TranslateMesh(final_mesh,-transl); + ScaleMesh(base_mesh,1.0/factor); + TranslateMesh(base_mesh,-transl); + return Done; + } + + ///perform one or more flip steps + void FlipStep() + { +#ifndef _MESHLAB + printf("\n STARTING FLIP SESSION \n"); +#endif + InitIMark(); + FlipSession=new vcg::LocalOptimization(base_mesh); + FlipSession->Init(); + /*bool b=*/FlipSession->DoOptimization(); +#ifndef _MESHLAB + printf("\n END FLIP SESSION %d edges \n",FlipSession->nPerfmormedOps); +#endif + UpdateTopologies(&base_mesh); + } + + ///equilateralize patch lenght and areas + void EquiPatches() + { + PatchesOptimizer DomOpt(base_mesh,final_mesh); + DomOpt.OptimizePatches(); + PrintAttributes(); + } + + /// I/O FUNCTIONS + void SaveMCP(char* filename) + { + /*Warp(0);*/ + FILE *f; + f=fopen(filename,"w+"); + std::map facemap; + std::map vertexmap; + typedef std::map::iterator iteMapVert; + typedef std::map::iterator iteMapFace; + + ///add vertices + fprintf(f,"%d,%d \n",base_mesh.fn,base_mesh.vn); + int index=0; + for (unsigned int i=0;iIsD()) + { + vertexmap.insert(std::pair(vert,index)); + CoordType pos=vert->P(); + CoordType RPos=vert->RPos; + fprintf(f,"%f,%f,%f;%f,%f,%f \n",pos.X(),pos.Y(),pos.Z(),RPos.X(),RPos.Y(),RPos.Z()); + index++; + } + } + + ///add faces + index=0; + for (unsigned int i=0;iIsD()) + { + BaseVertex* v0=face->V(0); + BaseVertex* v1=face->V(1); + BaseVertex* v2=face->V(2); + iteMapVert vertIte; + vertIte=vertexmap.find(v0); + assert(vertIte!=vertexmap.end()); + int index0=(*vertIte).second; + vertIte=vertexmap.find(v1); + assert(vertIte!=vertexmap.end()); + int index1=(*vertIte).second; + vertIte=vertexmap.find(v2); + assert(vertIte!=vertexmap.end()); + int index2=(*vertIte).second; + assert((index0!=index1)&&(index1!=index2)); + fprintf(f,"%d,%d,%d \n",index0,index1,index2); + facemap.insert(std::pair(face,index)); + index++; + } + } + + ///high resolution mesh + fprintf(f,"%d,%d \n",final_mesh.fn,final_mesh.vn); + + ///add vertices + vertexmap.clear(); + index=0; + for (unsigned int i=0;iIsD()) + { + vertexmap.insert(std::pair(vert,index)); + CoordType pos=vert->P(); + CoordType bary=vert->Bary; + BaseFace* father=vert->father; + iteMapFace IteF=facemap.find(father); + assert (IteF!=facemap.end()); + int indexface=(*IteF).second; + fprintf(f,"%f,%f,%f;%f,%f,%f;%d,%d,%d;%d \n", + pos.X(),pos.Y(),pos.Z(),bary.X(),bary.Y(),bary.Z(), + vert->OriginalCol.X(),vert->OriginalCol.Y(),vert->OriginalCol.Z(), + indexface); + index++; + } + } + + ///add faces + for (unsigned int i=0;iIsD()) + { + BaseVertex* v0=face->V(0); + BaseVertex* v1=face->V(1); + BaseVertex* v2=face->V(2); + iteMapVert vertIte; + vertIte=vertexmap.find(v0); + assert(vertIte!=vertexmap.end()); + int index0=(*vertIte).second; + vertIte=vertexmap.find(v1); + assert(vertIte!=vertexmap.end()); + int index1=(*vertIte).second; + vertIte=vertexmap.find(v2); + assert(vertIte!=vertexmap.end()); + int index2=(*vertIte).second; + assert((index0!=index1)&&(index1!=index2)); + fprintf(f,"%d,%d,%d \n",index0,index1,index2); + } + } + fclose(f); + } + + int LoadMCP(char* filename) + { + FILE *f=NULL; + f=fopen(filename,"r"); + if (f==NULL) + return -1; + /*std::map facemap; + std::map vertexmap; + typedef std::map::iterator iteMapVert; + typedef std::map::iterator iteMapFace;*/ + + + + ///add vertices + base_mesh.Clear(); + fscanf(f,"%d,%d \n",&base_mesh.fn,&base_mesh.vn); + base_mesh.vert.resize(base_mesh.vn); + base_mesh.face.resize(base_mesh.fn); + + for (unsigned int i=0;iP()=pos; + vert->RPos=RPos; + } + + + + ///add faces + for (unsigned int i=0;iIsD()) + { + int index0,index1,index2; + fscanf(f,"%d,%d,%d \n",&index0,&index1,&index2); + base_mesh.face[i].V(0)=&base_mesh.vert[index0]; + base_mesh.face[i].V(1)=&base_mesh.vert[index1]; + base_mesh.face[i].V(2)=&base_mesh.vert[index2]; + base_mesh.face[i].group=vcg::Color4b(rand()%200,rand()%200,rand()%200,255); + } + } + + ///high resolution mesh + fscanf(f,"%d,%d \n",&final_mesh.fn,&final_mesh.vn); + final_mesh.vert.resize(final_mesh.vn); + final_mesh.face.resize(final_mesh.fn); + + ///add vertices + for (unsigned int i=0;iP()=pos; + vert->RPos=pos; + vert->Bary=bary; + vert->father=&base_mesh.face[index_face]; + assert(!base_mesh.face[index_face].IsD()); + col=vcg::Color4b(col0,col1,col2,255); + vert->OriginalCol=col; + /*if (i==final_mesh.vert.size()-1) + { + printf("sukka %d \n",index_face); + char test; + scanf ("%c",&test); + }*/ + + } + + ///add faces + for (unsigned int i=0;ifather; + CoordType bary=v->Bary; + f->vertices_bary.push_back(std::pair(v,bary)); + } + + //ColorByParametrization(); + PrintAttributes(); + //printf("faces:%5d AREA distorsion:%lf\n",base_mesh.fn,ApproxAreaDistortion(final_mesh,base_mesh.fn)); + //printf("faces:%5d ANGLE distorsion:%lf\n",base_mesh.fn,ApproxAngleDistortion(final_mesh)); + + vcg::tri::UpdateBounding::Box(final_mesh); + + ///area perr vertex + for (unsigned int i=0;iV(1)->P()-f->V(0)->P())^(f->V(2)->P()-f->V(0)->P())).Norm())/(ScalarType)2.0; + /*AuxHPara[f->V(0)].area+=areaf/3.0; + AuxHPara[f->V(1)].area+=areaf/3.0; + AuxHPara[f->V(2)].area+=areaf/3.0;*/ + f->V(0)->area+=areaf/(ScalarType)3.0; + f->V(1)->area+=areaf/(ScalarType)3.0; + f->V(2)->area+=areaf/(ScalarType)3.0; + } + + return 0; + } + + void ExportMeshes(ParamMesh ¶_mesh,AbstractMesh &abs_mesh) + { + para_mesh.Clear(); + abs_mesh.Clear(); + + ///copy meshes + vcg::tri::Append::Mesh(abs_mesh,base_mesh); + vcg::tri::Append::Mesh(para_mesh,final_mesh); + + ///copy additional values + for (unsigned int i=0;i faceMap; + for (unsigned int i=0;i(&base_mesh.face[i],i)); + + ///then reassing with new mesh + for (unsigned int i=0;i::iterator cur = faceMap.find(final_mesh.vert[i].father); + assert(cur!= faceMap.end()); + CoordType bary=final_mesh.vert[i].Bary; + int index=(*cur).second; + para_mesh.vert[i].T().N()=index; +#ifdef _DEBUG + bool done=NormalizeBaryCoords(bary); + assert(done); +#else + NormalizeBaryCoords(bary); +#endif + para_mesh.vert[i].T().U()=bary.X(); + para_mesh.vert[i].T().V()=bary.Y(); + + } + } + + //int draw_mode; + + void PrintAttributes() + { + int done=(final_mesh.fn-base_mesh.fn); + int total=(final_mesh.fn-lower_limit); + ScalarType ratio=(ScalarType)done/total; + ratio=pow(ratio,3); + int percent=(int)(ratio*(ScalarType)100); + ScalarType areaD=ApproxAreaDistortion(final_mesh,base_mesh.fn); + ScalarType angleD=ApproxAngleDistortion(final_mesh); + char ret[200]; + sprintf(ret," GATHERING ABSTRACT DOMAIN faces:%5d AREA distorsion:%4f ; ANGLE distorsion:%4f ",base_mesh.fn,areaD,angleD); + (*cb)(percent,ret); + } + + void SetParameters(vcg::CallBackPos *_cb, + const int &_lower_limit=100, + const int &_interval=50, + StopMode _SMode=SM_Euristic, + const int &_accuracy=1) + { + lower_limit=_lower_limit; + interval=_interval; + accuracy=_accuracy; + SMode=_SMode; + ParaInfo::SM()=_SMode; + cb=_cb; + } + + void getValues(ScalarType &aggregate, + ScalarType &L2, + int &n_faces) + { + L2=ApproxL2Error(final_mesh); + ScalarType val0=ApproxAreaDistortion(final_mesh,base_mesh.fn); + ScalarType val1=ApproxAngleDistortion(final_mesh); + aggregate=geomAverage(val0+1.0,val1+1.0,3,1)-1; + n_faces=base_mesh.fn; + } + + IsoParametrizator() + { + ///parameters + SMode=SM_Euristic; + lower_limit=40; + interval=50; + accuracy=1; + } + +}; + +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/stat_remeshing.h b/src/meshlabplugins/filter_isoparametrization/stat_remeshing.h index 65faecb0f..9e2d76f8a 100644 --- a/src/meshlabplugins/filter_isoparametrization/stat_remeshing.h +++ b/src/meshlabplugins/filter_isoparametrization/stat_remeshing.h @@ -1,343 +1,343 @@ -#include -#include -#include -#include -#include -#include -#include - -#ifndef STAT_REMESHING -#define STAT_REMESHING - -#define PI 3.14159265 - - - -//return moltiplication of aspect ratio of faces of the mesh -///to see if add + normalize is better -template -typename MeshType::ScalarType MinimumAspectRatio(const MeshType &mesh) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - ScalarType res=1.f; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - ScalarType test=vcg::QualityRadii((*Fi).P(0),(*Fi).P(1),(*Fi).P(2)); - if (test -typename MeshType::ScalarType MinimumArea(const MeshType &mesh) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - ScalarType res=10000.f; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - ScalarType test=vcg::DoubleArea(*Fi)/2.0; - if (test -typename MeshType::ScalarType MaximumArea(const MeshType &mesh) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - ScalarType res=0.f; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - ScalarType test=vcg::DoubleArea(*Fi)/2.0; - if (test>res) - res=test; - } - return (res); -} - -//return moltiplication of aspect ratio of faces of the mesh -///to see if add + normalize is better -template -typename FaceType::ScalarType MinAngleFace(const FaceType &f) -{ - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::CoordType CoordType; - ScalarType res=360.0; - for (int i=0;i<3;i++) - { - CoordType v0=f.P((i+1)%3)-f.P(i); - CoordType v1=f.P((i+2)%3)-f.P(i); - v0.Normalize(); - v1.Normalize(); - ScalarType angle=acos(v0*v1)* 180.0 / PI; - if (angle -typename FaceType::ScalarType MaxAngleFace(const FaceType &f) -{ - typedef typename FaceType::ScalarType ScalarType; - typedef typename FaceType::CoordType CoordType; - ScalarType res=0; - for (int i=0;i<3;i++) - { - CoordType v0=f.P((i+1)%3)-f.P(i); - CoordType v1=f.P((i+2)%3)-f.P(i); - v0.Normalize(); - v1.Normalize(); - ScalarType angle=acos(v0*v1)* 180.0 / PI; - if (angle>res) - res=angle; - } - return (res); -} - -template -typename MeshType::ScalarType MinAngle(const MeshType &mesh) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - ScalarType res=360.0; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - ScalarType testAngle=MinAngleFace(*Fi); - if (testAngle -typename MeshType::ScalarType MaxAngle(const MeshType &mesh) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - ScalarType res=0; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - ScalarType testAngle=MaxAngleFace(*Fi); - if (testAngle>res) - res=testAngle; - } - return (res); -} - -template -void MaxMinEdge(const MeshType &mesh,typename MeshType::ScalarType &min, - typename MeshType::ScalarType &max) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - min=10000.0; - max=0.0; - typename MeshType::ConstFaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - if ((!(*Fi).IsD())) - { - - for (int i=0;i<3;i++) - { - typename MeshType::VertexType* v0=(*Fi).V(i); - typename MeshType::VertexType* v1=(*Fi).V((i+1)%3); - if (v0>v1) - { - ScalarType dist=(v0->P()-v1->P()).Norm(); - if (distmax) - max=dist; - } - } - } -} -////return moltiplication of aspect ratio of faces of the mesh -/////to see if add + normalize is better -//template -//ScalarType AverageMinAngle(const MeshType &mesh) -//{ -// ScalarType res=0; -// MeshType::ConstFaceIterator Fi; -// for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) -// if ((!(*Fi).IsD())) -// { -// ScalarType testAngle=MinAngleFace(*Fi); -// res+=testAngle; -// } -// return (res/((ScalarType)mesh.fn)); -//} - -template -void StatAspectRatio(MeshType &mesh, - typename MeshType::ScalarType &min, - typename MeshType::ScalarType &average, - typename MeshType::ScalarType &stand_dev) -{ - typedef typename MeshType::ScalarType ScalarType; - - vcg::Histogram HAspectRatio; - - ScalarType minRatio=MinimumAspectRatio(mesh); - ScalarType maxRatio=1.f; - HAspectRatio.SetRange(minRatio,maxRatio,500); - - - typename MeshType::FaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - HAspectRatio.Add(vcg::QualityRadii((*Fi).P(0),(*Fi).P(1),(*Fi).P(2))); - - average=HAspectRatio.Avg(); - stand_dev=HAspectRatio.StandardDeviation(); - min=minRatio; -} - -template -void StatArea(MeshType &mesh, - typename MeshType::ScalarType &min, - typename MeshType::ScalarType &max, - typename MeshType::ScalarType &average, - typename MeshType::ScalarType &stand_dev) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::CoordType CoordType; - - vcg::Histogram HArea; - - ScalarType minArea=MinimumArea(mesh); - ScalarType maxArea=MaximumArea(mesh); - HArea.SetRange(minArea,maxArea,500); - - - typename MeshType::FaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - { - CoordType p0=(*Fi).P0(0); - CoordType p1=(*Fi).P1(0); - CoordType p2=(*Fi).P2(0); - ScalarType area=((p1-p0)^(p2-p0)).Norm()/2.0; - HArea.Add(area); - } - - average=HArea.Avg(); - stand_dev=HArea.StandardDeviation(); - min=minArea; - max=maxArea; -} - -template -void StatAngle(MeshType &mesh, - typename MeshType::ScalarType &min, - typename MeshType::ScalarType &max, - typename MeshType::ScalarType &average, - typename MeshType::ScalarType &stand_dev) -{ - - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - vcg::Histogram HAngle; - - ScalarType minAngle=MinAngle(mesh); - ScalarType maxAngle=MaxAngle(mesh); - HAngle.SetRange(minAngle,maxAngle,500); - - - typename MeshType::FaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - HAngle.Add(MinAngleFace((*Fi))); - - average=HAngle.Avg(); - stand_dev=HAngle.StandardDeviation(); - min=minAngle; - max=maxAngle; -} - -template -void StatEdge(MeshType &mesh, - typename MeshType::ScalarType &min, - typename MeshType::ScalarType &max, - typename MeshType::ScalarType &average, - typename MeshType::ScalarType &stand_dev) -{ - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - - vcg::Histogram HEdge; - - ScalarType minEdge; - ScalarType maxEdge; - MaxMinEdge(mesh,minEdge,maxEdge); - HEdge.SetRange(minEdge,maxEdge,500); - - typedef typename MeshType::ScalarType ScalarType; - typename MeshType::FaceIterator Fi; - for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) - { - for (int i=0;i<3;i++) - { - VertexType* v0=(*Fi).V(i); - VertexType* v1=(*Fi).V((i+1)%3); - if ((v0>v1)||((*Fi).FFp(i)==&(*Fi))) - { - ScalarType dist=(v0->P()-v1->P()).Norm(); - HEdge.Add(dist); - } - } - } - - average=HEdge.Avg(); - stand_dev=HEdge.StandardDeviation(); - min=minEdge; - max=maxEdge; -} - -template -int NumRegular(MeshType &mesh) -{ - typedef typename MeshType::FaceType FaceType; - ///update topology - vcg::tri::UpdateTopology::VertexFace(mesh); - typename MeshType::VertexIterator Vi; - int irregular=0; - for (Vi=mesh.vert.begin();Vi!=mesh.vert.end();Vi++) - { - if ((!(*Vi).IsD())&&(!(*Vi).IsB())) - { - vcg::face::VFIterator VFI(&(*Vi)); - int num=0; - while (!(VFI.End())) - { - num++; - ++VFI; - } - if (num!=6) - irregular++; - } - } - return irregular; -} -#endif +#include +#include +#include +#include +#include +#include +#include + +#ifndef STAT_REMESHING +#define STAT_REMESHING + +#define PI 3.14159265 + + + +//return moltiplication of aspect ratio of faces of the mesh +///to see if add + normalize is better +template +typename MeshType::ScalarType MinimumAspectRatio(const MeshType &mesh) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + ScalarType res=1.f; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + ScalarType test=vcg::QualityRadii((*Fi).P(0),(*Fi).P(1),(*Fi).P(2)); + if (test +typename MeshType::ScalarType MinimumArea(const MeshType &mesh) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + ScalarType res=10000.f; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + ScalarType test=vcg::DoubleArea(*Fi)/2.0; + if (test +typename MeshType::ScalarType MaximumArea(const MeshType &mesh) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + ScalarType res=0.f; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + ScalarType test=vcg::DoubleArea(*Fi)/2.0; + if (test>res) + res=test; + } + return (res); +} + +//return moltiplication of aspect ratio of faces of the mesh +///to see if add + normalize is better +template +typename FaceType::ScalarType MinAngleFace(const FaceType &f) +{ + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::CoordType CoordType; + ScalarType res=360.0; + for (int i=0;i<3;i++) + { + CoordType v0=f.P((i+1)%3)-f.P(i); + CoordType v1=f.P((i+2)%3)-f.P(i); + v0.Normalize(); + v1.Normalize(); + ScalarType angle=acos(v0*v1)* 180.0 / PI; + if (angle +typename FaceType::ScalarType MaxAngleFace(const FaceType &f) +{ + typedef typename FaceType::ScalarType ScalarType; + typedef typename FaceType::CoordType CoordType; + ScalarType res=0; + for (int i=0;i<3;i++) + { + CoordType v0=f.P((i+1)%3)-f.P(i); + CoordType v1=f.P((i+2)%3)-f.P(i); + v0.Normalize(); + v1.Normalize(); + ScalarType angle=acos(v0*v1)* 180.0 / PI; + if (angle>res) + res=angle; + } + return (res); +} + +template +typename MeshType::ScalarType MinAngle(const MeshType &mesh) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + ScalarType res=360.0; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + ScalarType testAngle=MinAngleFace(*Fi); + if (testAngle +typename MeshType::ScalarType MaxAngle(const MeshType &mesh) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + ScalarType res=0; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + ScalarType testAngle=MaxAngleFace(*Fi); + if (testAngle>res) + res=testAngle; + } + return (res); +} + +template +void MaxMinEdge(const MeshType &mesh,typename MeshType::ScalarType &min, + typename MeshType::ScalarType &max) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + min=10000.0; + max=0.0; + typename MeshType::ConstFaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + if ((!(*Fi).IsD())) + { + + for (int i=0;i<3;i++) + { + typename MeshType::VertexType* v0=(*Fi).V(i); + typename MeshType::VertexType* v1=(*Fi).V((i+1)%3); + if (v0>v1) + { + ScalarType dist=(v0->P()-v1->P()).Norm(); + if (distmax) + max=dist; + } + } + } +} +////return moltiplication of aspect ratio of faces of the mesh +/////to see if add + normalize is better +//template +//ScalarType AverageMinAngle(const MeshType &mesh) +//{ +// ScalarType res=0; +// MeshType::ConstFaceIterator Fi; +// for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) +// if ((!(*Fi).IsD())) +// { +// ScalarType testAngle=MinAngleFace(*Fi); +// res+=testAngle; +// } +// return (res/((ScalarType)mesh.fn)); +//} + +template +void StatAspectRatio(MeshType &mesh, + typename MeshType::ScalarType &min, + typename MeshType::ScalarType &average, + typename MeshType::ScalarType &stand_dev) +{ + typedef typename MeshType::ScalarType ScalarType; + + vcg::Histogram HAspectRatio; + + ScalarType minRatio=MinimumAspectRatio(mesh); + ScalarType maxRatio=1.f; + HAspectRatio.SetRange(minRatio,maxRatio,500); + + + typename MeshType::FaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + HAspectRatio.Add(vcg::QualityRadii((*Fi).P(0),(*Fi).P(1),(*Fi).P(2))); + + average=HAspectRatio.Avg(); + stand_dev=HAspectRatio.StandardDeviation(); + min=minRatio; +} + +template +void StatArea(MeshType &mesh, + typename MeshType::ScalarType &min, + typename MeshType::ScalarType &max, + typename MeshType::ScalarType &average, + typename MeshType::ScalarType &stand_dev) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + + vcg::Histogram HArea; + + ScalarType minArea=MinimumArea(mesh); + ScalarType maxArea=MaximumArea(mesh); + HArea.SetRange(minArea,maxArea,500); + + + typename MeshType::FaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + { + CoordType p0=(*Fi).P0(0); + CoordType p1=(*Fi).P1(0); + CoordType p2=(*Fi).P2(0); + ScalarType area=((p1-p0)^(p2-p0)).Norm()/2.0; + HArea.Add(area); + } + + average=HArea.Avg(); + stand_dev=HArea.StandardDeviation(); + min=minArea; + max=maxArea; +} + +template +void StatAngle(MeshType &mesh, + typename MeshType::ScalarType &min, + typename MeshType::ScalarType &max, + typename MeshType::ScalarType &average, + typename MeshType::ScalarType &stand_dev) +{ + + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + vcg::Histogram HAngle; + + ScalarType minAngle=MinAngle(mesh); + ScalarType maxAngle=MaxAngle(mesh); + HAngle.SetRange(minAngle,maxAngle,500); + + + typename MeshType::FaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + HAngle.Add(MinAngleFace((*Fi))); + + average=HAngle.Avg(); + stand_dev=HAngle.StandardDeviation(); + min=minAngle; + max=maxAngle; +} + +template +void StatEdge(MeshType &mesh, + typename MeshType::ScalarType &min, + typename MeshType::ScalarType &max, + typename MeshType::ScalarType &average, + typename MeshType::ScalarType &stand_dev) +{ + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + + vcg::Histogram HEdge; + + ScalarType minEdge; + ScalarType maxEdge; + MaxMinEdge(mesh,minEdge,maxEdge); + HEdge.SetRange(minEdge,maxEdge,500); + + typedef typename MeshType::ScalarType ScalarType; + typename MeshType::FaceIterator Fi; + for (Fi=mesh.face.begin();Fi!=mesh.face.end();Fi++) + { + for (int i=0;i<3;i++) + { + VertexType* v0=(*Fi).V(i); + VertexType* v1=(*Fi).V((i+1)%3); + if ((v0>v1)||((*Fi).FFp(i)==&(*Fi))) + { + ScalarType dist=(v0->P()-v1->P()).Norm(); + HEdge.Add(dist); + } + } + } + + average=HEdge.Avg(); + stand_dev=HEdge.StandardDeviation(); + min=minEdge; + max=maxEdge; +} + +template +int NumRegular(MeshType &mesh) +{ + typedef typename MeshType::FaceType FaceType; + ///update topology + vcg::tri::UpdateTopology::VertexFace(mesh); + typename MeshType::VertexIterator Vi; + int irregular=0; + for (Vi=mesh.vert.begin();Vi!=mesh.vert.end();Vi++) + { + if ((!(*Vi).IsD())&&(!(*Vi).IsB())) + { + vcg::face::VFIterator VFI(&(*Vi)); + int num=0; + while (!(VFI.End())) + { + num++; + ++VFI; + } + if (num!=6) + irregular++; + } + } + return irregular; +} +#endif diff --git a/src/meshlabplugins/filter_isoparametrization/tangent_space.h b/src/meshlabplugins/filter_isoparametrization/tangent_space.h index e41ded393..62be560eb 100644 --- a/src/meshlabplugins/filter_isoparametrization/tangent_space.h +++ b/src/meshlabplugins/filter_isoparametrization/tangent_space.h @@ -1,498 +1,498 @@ -#ifndef _ISO_TANGENTSPACE -#define _ISO_TANGENTSPACE -#include "iso_parametrization.h" -#include -#include - -class TangentSpace{ - typedef IsoParametrization::CoordType CoordType; - typedef IsoParametrization::ScalarType ScalarType; - - - vcg::SimpleTempData > *ProjMatrix; - -public: - IsoParametrization *isoParam; - - - bool isoParamTheta(int i, vcg::Point2 p, vcg::Point3 &res) const{ - return isoParam->Theta(i,p,res); - } - - // - void Theta(int i, - const vcg::Point2 &UV, - CoordType &pos3D){ - isoParamTheta(i,UV,pos3D); - } - - bool Theta(const int &I, - const vcg::Point2 &alpha_beta, // alphaBeta - std::vector &face, - std::vector &baryVal) - { - int ret=isoParam->Theta(I,alpha_beta,face,baryVal); - return (ret!=-1); - } - - ///initialize the sampler - void Init(IsoParametrization *_isoParam,ScalarType radius=(ScalarType)0.1) - { - isoParam=_isoParam; - ProjMatrix = new vcg::SimpleTempData > (isoParam->ParaMesh()->vert); - - InitProjectionMatrix(radius); - vcg::tri::UpdateNormals::PerFaceNormalized(*isoParam->ParaMesh()); - vcg::tri::UpdateCurvature::PrincipalDirectionsNormalCycles(*isoParam->ParaMesh()); - } - - ///given an initial position in parametric space (I0,bary0) - ///and a 2D vector (vect) expressed in parametric space modify the final - ///position (I1,bary1) abd return true if everithing was ok, false otherwise - bool Sum(const int &I0,const vcg::Point2 &bary0, - const vcg::Point2 &vect, - int &I1,vcg::Point2 &bary1,int &domain) const - { - - - vcg::Point2 dest=bary0+vect; - //vect[0]*Xaxis + vect[1]*Yaxis; - ScalarType alpha=dest.X(); - ScalarType beta=dest.Y(); - ///point inside the face - if ((alpha>=0)&&(alpha<=1)&&(beta>=0)&&(beta<=1)&&((alpha+beta)<=1)) - { - bary1=dest; - I1=I0; - domain=0; - return true; - } - - ///control edges - int edge=-1; - if ((alpha<=1)&&(beta<=1)&&((alpha+beta)>=1)) - edge=0; - else - if ((alpha<=0)&&(beta<=1)&&((alpha+beta)>=0)) - edge=1; - else - if ((alpha<=1)&&(beta<=0)&&((alpha+beta)>=0)) - edge=2; - if (edge!=-1) - { - int DiamIndex=isoParam->GetDiamond(I0,edge); - vcg::Point2 UVDiam; - ///transform to diamond coordinates - isoParam->GE1(I0,dest,DiamIndex,UVDiam); - ///trasform back to I,alpha,beta - isoParam->inv_GE1(DiamIndex,UVDiam,I1,bary1); - domain=1; - return true; - } - int star=-1; - ScalarType gamma=(1-alpha-beta); - if ((alpha>beta)&&(alpha>gamma)) - star=0; - else - if ((beta>alpha)&&(beta>gamma)) - star=1; - else - star=2; - - ///get the index of star - int StarIndex=isoParam->GetStarIndex(I0,star); - vcg::Point2 UVHstar; - ///transform to UV - bool found=isoParam->GE0(I0,dest,StarIndex,UVHstar); - ///trasform back to I,alpha,beta - if (!found) - return false; - found=isoParam->inv_GE0(StarIndex,UVHstar,I1,bary1); - /*AbstractFace* f0=&isoParam->AbsMesh()->face[I0]; - AbstractFace* f1=&isoParam->AbsMesh()->face[I1]; - AbstractVertex *v0=f0->V(0); - AbstractVertex *v1=f0->V(1); - AbstractVertex *v2=f0->V(2); - AbstractVertex *v3=f1->V(0); - AbstractVertex *v4=f1->V(1); - AbstractVertex *v5=f1->V(2);*/ - domain=2; - return found; - } - - ///given two positions in parametric space (I0,bary0) and (I1,bary1) - ///modify the 2D vector (vect) and return true if everithing was ok, false otherwise - bool Sub(const int &I0,const vcg::Point2 &bary0, - const int &I1,const vcg::Point2 &bary1, - vcg::Point2 &vect,int &num) const - { - int IndexDomain; - num=isoParam->InterpolationSpace(I0,I1,IndexDomain); - ///is a face - if (num==0) - { - //printf("F"); - assert(I0==I1); - vect=bary0-bary1; - return true; - } - else - ///a diamond - if (num==1) - { - //printf("D"); - ///tranform in UV space - vcg::Point2 UVDiam; - isoParam->GE1(I1,bary1,IndexDomain,UVDiam); - ///then find bary coords wich respect to the first face - vcg::Point2 bary2; - isoParam->inv_GE1_fixedI(IndexDomain,UVDiam,I0,bary2); - vect=bary0-bary2; - return true; - } - else - ///a star - if (num==2) - { - //printf("S"); - ///tranform in UV space - vcg::Point2 UVStar; - isoParam->GE0(I1,bary1,IndexDomain,UVStar); - ///then find bary coords wich respect to the first face - vcg::Point2 bary2; - isoParam->inv_GE0_fixedI(IndexDomain,UVStar,I0,bary2); - vect=bary0-bary2; - - return true; - } - else - return false; - } - - bool TangentDir(const int &I,const vcg::Point2 &bary, - CoordType &XAxis,CoordType &YAxis,ScalarType radius=(ScalarType)0.5) const - { - ///3d position of origin - //CoordType origin; - //isoParam->Theta(I,bary,origin); - - // two axis in alpha-beta space that will be orthogonal in UV-Space - const ScalarType h=(ScalarType)2.0/sqrt((ScalarType)3.0); - vcg::Point2 XP=vcg::Point2(1,0); - vcg::Point2 YP=vcg::Point2(-0.5,h); - - XP*=radius; - YP*=radius; - vcg::Point2 XM=-XP; - vcg::Point2 YM=-YP; - //Yaxis.Normalize(); - - vcg::Point2 bary0,bary1,bary2,bary3; - int I0,I1,I2,I3; - CoordType X0,X1,Y0,Y1; - ///find paraCoords of four neighbors - int domain; - bool done=true; - done&=Sum(I,bary,XP,I0,bary0,domain); - done&=Sum(I,bary,XM,I1,bary1,domain); - done&=Sum(I,bary,YP,I2,bary2,domain); - done&=Sum(I,bary,YM,I3,bary3,domain); - if (!done) - return false; - - //if (I0!=I1 || I1!=I2 || I2!=I3) return false; - - ///get 3d position - isoParamTheta(I0,bary0,X0); - isoParamTheta(I1,bary1,X1); - isoParamTheta(I2,bary2,Y0); - isoParamTheta(I3,bary3,Y1); - - - ///average .. considering one is opposite respect to the other - XAxis=(X0-X1)/(ScalarType)2.0; - YAxis=(Y0-Y1)/(ScalarType)2.0; - ///final scaling - XAxis/=radius; - YAxis/=radius; - return true; - } - - void Test(int Sample=100,int Ite=100) - { - int max=isoParam->AbsMesh()->face.size(); - for (int I=0;I bary=vcg::Point2(alpha,beta); - assert((bary.X()>=0)&&(bary.X()<=1)); - assert((bary.Y()>=0)&&(bary.Y()<=1)); - assert((bary.X()+bary.Y()<=1)); - - for (int k=0;k vect=vcg::Point2(d0,d1); - vect.Normalize(); - ScalarType norm=(ScalarType)0.05;//((ScalarType)(rand()%1000))/(ScalarType)2000; - assert(norm<1); - vect*=norm; - int I1; - vcg::Point2 bary1; - vcg::Point2 vect1; - int domain0; - bool b1=Sum(I,bary,vect,I1,bary1,domain0); - assert(b1); - - assert((bary1.X()>=0)&&(bary1.X()<=1)); - assert((bary1.Y()>=0)&&(bary1.Y()<=1)); - if(!((bary1.X()+bary1.Y())<=1.00001)) - { - printf("\n SUM %.4f \n",bary1.X()+bary1.Y()); - assert(0); - } - assert(I10.001) - { - printf("\n DIFF %.4f domain SUM %d domain SUB %d \n",diff,domain0,domain); - //assert(0); - } - //assert(fabs(vect1.X()-vect.X())<0.0001); - //assert(fabs(vect1.Y()-vect.Y())<0.0001); - - } - } - } - } - } - } - - void InitProjectionMatrix(ScalarType radius=(ScalarType)0.1) - { - for (int i=0;iParaMesh()->vert.size();i++) - { - int I=isoParam->ParaMesh()->vert[i].T().N(); - vcg::Point2 bary=isoParam->ParaMesh()->vert[i].T().P(); - - CoordType origin; - isoParamTheta(I,bary,origin); - CoordType XAxis,YAxis; // tangent axis in 3D Object space - ///get tangent directions - - bool done=TangentDir(I,bary,XAxis,YAxis,(ScalarType)0.1); - if (!done) - { - (*ProjMatrix)[i].SetIdentity(); - continue; - } - - // must compute res2d such that: res2d.X() * XAxis + res2d.Y() * YAxis + dontCare * ZAxis = vect3d - CoordType ZAxis = -(XAxis^YAxis).Normalize()*XAxis.Norm(); - - (*ProjMatrix)[i].SetColumn(0,XAxis); - (*ProjMatrix)[i].SetColumn(1,YAxis); - (*ProjMatrix)[i].SetColumn(2,ZAxis); - vcg::Invert((*ProjMatrix)[i]); - } - } - - void GetCurvature(const int &I,const vcg::Point2 &alpha_beta, - CoordType &d1,CoordType &d2,ScalarType &k1,ScalarType &k2) - { - ParamFace* face=NULL; - CoordType baryVal; - isoParam->Theta(I,alpha_beta,face,baryVal); - ParamVertex *v0=face->V(0); - ParamVertex *v1=face->V(1); - ParamVertex *v2=face->V(2); - d1=v0->PD1()*baryVal.X()+v1->PD1()*baryVal.Y()+v2->PD1()*baryVal.Z(); - d2=v0->PD2()*baryVal.X()+v1->PD2()*baryVal.Y()+v2->PD2()*baryVal.Z(); - k1=v0->K1()*baryVal.X()+v1->K1()*baryVal.Y()+v2->K1()*baryVal.Z(); - k2=v0->K2()*baryVal.X()+v1->K2()*baryVal.Y()+v2->K2()*baryVal.Z(); - } - - void GetProjectionMatrix(const int &I,const vcg::Point2 &alpha_beta, - vcg::Matrix33 &projMatr) const - { - ParamFace* face=NULL; - CoordType baryVal; - int dom=isoParam->Theta(I,alpha_beta,face,baryVal); - if (dom==-1) - { - projMatr.SetIdentity(); - return; - } - ParamVertex *v0=face->V(0); - ParamVertex *v1=face->V(1); - ParamVertex *v2=face->V(2); - - projMatr=(*ProjMatrix)[v0]*baryVal.X(); - projMatr+=(*ProjMatrix)[v1]*baryVal.Y(); - projMatr+=(*ProjMatrix)[v2]*baryVal.Z(); - } - - - bool Project(const int &I,const vcg::Point2 &bary, - const CoordType &vect3d, // in object space - vcg::Point2 &res2d) const - { - vcg::Matrix33f m; - GetProjectionMatrix(I,bary,m); - - ScalarType deltaX=vect3d*m.GetRow(0); - ScalarType deltaY=vect3d*m.GetRow(1); - - // two axis in alpha-beta space that will be orthogonal in UV-Space - const ScalarType h=(ScalarType)2.0/sqrt((ScalarType)3.0); - vcg::Point2 XP=vcg::Point2(1,0); - vcg::Point2 YP=vcg::Point2(-0.5,h); - res2d = XP*deltaX + YP*deltaY; - //res2d=vcg::Point2(deltaX,deltaY); - - return true; - } - - // WEIGHTED INTERPOLATION OF POINTS IN TANGENT SPACE - /// weights MUST be normalized - bool Interpolate(const int &I0,const vcg::Point2 &alpha_beta0, - const int &I1,const vcg::Point2 &alpha_beta1, - ScalarType weight, - int &I_res, - vcg::Point2 &alpha_beta_res) - { - int IndexDomain; - int kind=isoParam->InterpolationSpace(I0,I1,IndexDomain); - if (kind==-1) - return false; - - vcg::Point2 transformed0,transformed1; - - ///interpolate in a face - if (kind==0) - { - isoParam->GE2(IndexDomain,alpha_beta0,transformed0); - isoParam->GE2(IndexDomain,alpha_beta1,transformed1); - } - else - ///interpolate in a diamond - if (kind==1) - { - isoParam->GE1(I0,alpha_beta0,IndexDomain,transformed0); - isoParam->GE1(I1,alpha_beta1,IndexDomain,transformed1); - } - else - { - isoParam->GE0(I0,alpha_beta0,IndexDomain,transformed0); - isoParam->GE0(I1,alpha_beta1,IndexDomain,transformed1); - } - - vcg::Point2 UV_interp=transformed0*weight+transformed1*(1.0-weight); - ///FINALLY...... - ///transform back to alpha,beta,I - if (kind==0) - { - isoParam->inv_GE2(IndexDomain,UV_interp,alpha_beta_res); - I_res=IndexDomain; - } - else - if (kind==1) - { - isoParam->inv_GE1(IndexDomain,UV_interp,I_res,alpha_beta_res); - } - else - isoParam->inv_GE0(IndexDomain,UV_interp,I_res,alpha_beta_res); - return true; - } - - ScalarType AbstractArea() - { - ScalarType Cnum=sqrt(3.0)/4.0; - return(isoParam->AbsMesh()->fn*Cnum); - } - - // WEIGHTED INTERPOLATION OF POINTS IN TANGENT SPACE - /// weights MUST be normalized - bool Interpolate(const std::vector &I, - const std::vector > &alpha_beta, - const std::vector &weights, - int &I_res, - vcg::Point2 &alpha_beta_res, - int *num=NULL) - { - int size; - if (num==NULL) - size=alpha_beta.size(); - else - size=*num; - - int IndexDomain; - int kind=isoParam->InterpolationSpace(I,IndexDomain,num); - if (kind==-1) - return false; - - std::vector > transformed; - transformed.resize(size); - - ///interpolate in a face - if (kind==0) - { - for (int i=0;iGE2(IndexDomain,alpha_beta[i],transformed[i]); - } - else - ///interpolate in a diamond - if (kind==1) - { - for (int i=0;iGE1(I[i],alpha_beta[i],IndexDomain,transformed[i]); - } - else - { - for (int i=0;iGE0(I[i],alpha_beta[i],IndexDomain,transformed[i]); - } - - /// do the interpolation - vcg::Point2 UV_interp=vcg::Point2(0,0); - for (int i=0;iinv_GE2(IndexDomain,UV_interp,alpha_beta_res); - I_res=IndexDomain; - } - else - if (kind==1) - { - isoParam->inv_GE1(IndexDomain,UV_interp,I_res,alpha_beta_res); - } - else - isoParam->inv_GE0(IndexDomain,UV_interp,I_res,alpha_beta_res); - return true; - } - -}; -#endif +#ifndef _ISO_TANGENTSPACE +#define _ISO_TANGENTSPACE +#include "iso_parametrization.h" +#include +#include + +class TangentSpace{ + typedef IsoParametrization::CoordType CoordType; + typedef IsoParametrization::ScalarType ScalarType; + + + vcg::SimpleTempData > *ProjMatrix; + +public: + IsoParametrization *isoParam; + + + bool isoParamTheta(int i, vcg::Point2 p, vcg::Point3 &res) const{ + return isoParam->Theta(i,p,res); + } + + // + void Theta(int i, + const vcg::Point2 &UV, + CoordType &pos3D){ + isoParamTheta(i,UV,pos3D); + } + + bool Theta(const int &I, + const vcg::Point2 &alpha_beta, // alphaBeta + std::vector &face, + std::vector &baryVal) + { + int ret=isoParam->Theta(I,alpha_beta,face,baryVal); + return (ret!=-1); + } + + ///initialize the sampler + void Init(IsoParametrization *_isoParam,ScalarType radius=(ScalarType)0.1) + { + isoParam=_isoParam; + ProjMatrix = new vcg::SimpleTempData > (isoParam->ParaMesh()->vert); + + InitProjectionMatrix(radius); + vcg::tri::UpdateNormals::PerFaceNormalized(*isoParam->ParaMesh()); + vcg::tri::UpdateCurvature::PrincipalDirectionsNormalCycles(*isoParam->ParaMesh()); + } + + ///given an initial position in parametric space (I0,bary0) + ///and a 2D vector (vect) expressed in parametric space modify the final + ///position (I1,bary1) abd return true if everithing was ok, false otherwise + bool Sum(const int &I0,const vcg::Point2 &bary0, + const vcg::Point2 &vect, + int &I1,vcg::Point2 &bary1,int &domain) const + { + + + vcg::Point2 dest=bary0+vect; + //vect[0]*Xaxis + vect[1]*Yaxis; + ScalarType alpha=dest.X(); + ScalarType beta=dest.Y(); + ///point inside the face + if ((alpha>=0)&&(alpha<=1)&&(beta>=0)&&(beta<=1)&&((alpha+beta)<=1)) + { + bary1=dest; + I1=I0; + domain=0; + return true; + } + + ///control edges + int edge=-1; + if ((alpha<=1)&&(beta<=1)&&((alpha+beta)>=1)) + edge=0; + else + if ((alpha<=0)&&(beta<=1)&&((alpha+beta)>=0)) + edge=1; + else + if ((alpha<=1)&&(beta<=0)&&((alpha+beta)>=0)) + edge=2; + if (edge!=-1) + { + int DiamIndex=isoParam->GetDiamond(I0,edge); + vcg::Point2 UVDiam; + ///transform to diamond coordinates + isoParam->GE1(I0,dest,DiamIndex,UVDiam); + ///trasform back to I,alpha,beta + isoParam->inv_GE1(DiamIndex,UVDiam,I1,bary1); + domain=1; + return true; + } + int star=-1; + ScalarType gamma=(1-alpha-beta); + if ((alpha>beta)&&(alpha>gamma)) + star=0; + else + if ((beta>alpha)&&(beta>gamma)) + star=1; + else + star=2; + + ///get the index of star + int StarIndex=isoParam->GetStarIndex(I0,star); + vcg::Point2 UVHstar; + ///transform to UV + bool found=isoParam->GE0(I0,dest,StarIndex,UVHstar); + ///trasform back to I,alpha,beta + if (!found) + return false; + found=isoParam->inv_GE0(StarIndex,UVHstar,I1,bary1); + /*AbstractFace* f0=&isoParam->AbsMesh()->face[I0]; + AbstractFace* f1=&isoParam->AbsMesh()->face[I1]; + AbstractVertex *v0=f0->V(0); + AbstractVertex *v1=f0->V(1); + AbstractVertex *v2=f0->V(2); + AbstractVertex *v3=f1->V(0); + AbstractVertex *v4=f1->V(1); + AbstractVertex *v5=f1->V(2);*/ + domain=2; + return found; + } + + ///given two positions in parametric space (I0,bary0) and (I1,bary1) + ///modify the 2D vector (vect) and return true if everithing was ok, false otherwise + bool Sub(const int &I0,const vcg::Point2 &bary0, + const int &I1,const vcg::Point2 &bary1, + vcg::Point2 &vect,int &num) const + { + int IndexDomain; + num=isoParam->InterpolationSpace(I0,I1,IndexDomain); + ///is a face + if (num==0) + { + //printf("F"); + assert(I0==I1); + vect=bary0-bary1; + return true; + } + else + ///a diamond + if (num==1) + { + //printf("D"); + ///tranform in UV space + vcg::Point2 UVDiam; + isoParam->GE1(I1,bary1,IndexDomain,UVDiam); + ///then find bary coords wich respect to the first face + vcg::Point2 bary2; + isoParam->inv_GE1_fixedI(IndexDomain,UVDiam,I0,bary2); + vect=bary0-bary2; + return true; + } + else + ///a star + if (num==2) + { + //printf("S"); + ///tranform in UV space + vcg::Point2 UVStar; + isoParam->GE0(I1,bary1,IndexDomain,UVStar); + ///then find bary coords wich respect to the first face + vcg::Point2 bary2; + isoParam->inv_GE0_fixedI(IndexDomain,UVStar,I0,bary2); + vect=bary0-bary2; + + return true; + } + else + return false; + } + + bool TangentDir(const int &I,const vcg::Point2 &bary, + CoordType &XAxis,CoordType &YAxis,ScalarType radius=(ScalarType)0.5) const + { + ///3d position of origin + //CoordType origin; + //isoParam->Theta(I,bary,origin); + + // two axis in alpha-beta space that will be orthogonal in UV-Space + const ScalarType h=(ScalarType)2.0/sqrt((ScalarType)3.0); + vcg::Point2 XP=vcg::Point2(1,0); + vcg::Point2 YP=vcg::Point2(-0.5,h); + + XP*=radius; + YP*=radius; + vcg::Point2 XM=-XP; + vcg::Point2 YM=-YP; + //Yaxis.Normalize(); + + vcg::Point2 bary0,bary1,bary2,bary3; + int I0,I1,I2,I3; + CoordType X0,X1,Y0,Y1; + ///find paraCoords of four neighbors + int domain; + bool done=true; + done&=Sum(I,bary,XP,I0,bary0,domain); + done&=Sum(I,bary,XM,I1,bary1,domain); + done&=Sum(I,bary,YP,I2,bary2,domain); + done&=Sum(I,bary,YM,I3,bary3,domain); + if (!done) + return false; + + //if (I0!=I1 || I1!=I2 || I2!=I3) return false; + + ///get 3d position + isoParamTheta(I0,bary0,X0); + isoParamTheta(I1,bary1,X1); + isoParamTheta(I2,bary2,Y0); + isoParamTheta(I3,bary3,Y1); + + + ///average .. considering one is opposite respect to the other + XAxis=(X0-X1)/(ScalarType)2.0; + YAxis=(Y0-Y1)/(ScalarType)2.0; + ///final scaling + XAxis/=radius; + YAxis/=radius; + return true; + } + + void Test(int Sample=100,int Ite=100) + { + int max=isoParam->AbsMesh()->face.size(); + for (int I=0;I bary=vcg::Point2(alpha,beta); + assert((bary.X()>=0)&&(bary.X()<=1)); + assert((bary.Y()>=0)&&(bary.Y()<=1)); + assert((bary.X()+bary.Y()<=1)); + + for (int k=0;k vect=vcg::Point2(d0,d1); + vect.Normalize(); + ScalarType norm=(ScalarType)0.05;//((ScalarType)(rand()%1000))/(ScalarType)2000; + assert(norm<1); + vect*=norm; + int I1; + vcg::Point2 bary1; + vcg::Point2 vect1; + int domain0; + bool b1=Sum(I,bary,vect,I1,bary1,domain0); + assert(b1); + + assert((bary1.X()>=0)&&(bary1.X()<=1)); + assert((bary1.Y()>=0)&&(bary1.Y()<=1)); + if(!((bary1.X()+bary1.Y())<=1.00001)) + { + printf("\n SUM %.4f \n",bary1.X()+bary1.Y()); + assert(0); + } + assert(I10.001) + { + printf("\n DIFF %.4f domain SUM %d domain SUB %d \n",diff,domain0,domain); + //assert(0); + } + //assert(fabs(vect1.X()-vect.X())<0.0001); + //assert(fabs(vect1.Y()-vect.Y())<0.0001); + + } + } + } + } + } + } + + void InitProjectionMatrix(ScalarType radius=(ScalarType)0.1) + { + for (int i=0;iParaMesh()->vert.size();i++) + { + int I=isoParam->ParaMesh()->vert[i].T().N(); + vcg::Point2 bary=isoParam->ParaMesh()->vert[i].T().P(); + + CoordType origin; + isoParamTheta(I,bary,origin); + CoordType XAxis,YAxis; // tangent axis in 3D Object space + ///get tangent directions + + bool done=TangentDir(I,bary,XAxis,YAxis,(ScalarType)0.1); + if (!done) + { + (*ProjMatrix)[i].SetIdentity(); + continue; + } + + // must compute res2d such that: res2d.X() * XAxis + res2d.Y() * YAxis + dontCare * ZAxis = vect3d + CoordType ZAxis = -(XAxis^YAxis).Normalize()*XAxis.Norm(); + + (*ProjMatrix)[i].SetColumn(0,XAxis); + (*ProjMatrix)[i].SetColumn(1,YAxis); + (*ProjMatrix)[i].SetColumn(2,ZAxis); + vcg::Invert((*ProjMatrix)[i]); + } + } + + void GetCurvature(const int &I,const vcg::Point2 &alpha_beta, + CoordType &d1,CoordType &d2,ScalarType &k1,ScalarType &k2) + { + ParamFace* face=NULL; + CoordType baryVal; + isoParam->Theta(I,alpha_beta,face,baryVal); + ParamVertex *v0=face->V(0); + ParamVertex *v1=face->V(1); + ParamVertex *v2=face->V(2); + d1=v0->PD1()*baryVal.X()+v1->PD1()*baryVal.Y()+v2->PD1()*baryVal.Z(); + d2=v0->PD2()*baryVal.X()+v1->PD2()*baryVal.Y()+v2->PD2()*baryVal.Z(); + k1=v0->K1()*baryVal.X()+v1->K1()*baryVal.Y()+v2->K1()*baryVal.Z(); + k2=v0->K2()*baryVal.X()+v1->K2()*baryVal.Y()+v2->K2()*baryVal.Z(); + } + + void GetProjectionMatrix(const int &I,const vcg::Point2 &alpha_beta, + vcg::Matrix33 &projMatr) const + { + ParamFace* face=NULL; + CoordType baryVal; + int dom=isoParam->Theta(I,alpha_beta,face,baryVal); + if (dom==-1) + { + projMatr.SetIdentity(); + return; + } + ParamVertex *v0=face->V(0); + ParamVertex *v1=face->V(1); + ParamVertex *v2=face->V(2); + + projMatr=(*ProjMatrix)[v0]*baryVal.X(); + projMatr+=(*ProjMatrix)[v1]*baryVal.Y(); + projMatr+=(*ProjMatrix)[v2]*baryVal.Z(); + } + + + bool Project(const int &I,const vcg::Point2 &bary, + const CoordType &vect3d, // in object space + vcg::Point2 &res2d) const + { + vcg::Matrix33f m; + GetProjectionMatrix(I,bary,m); + + ScalarType deltaX=vect3d*m.GetRow(0); + ScalarType deltaY=vect3d*m.GetRow(1); + + // two axis in alpha-beta space that will be orthogonal in UV-Space + const ScalarType h=(ScalarType)2.0/sqrt((ScalarType)3.0); + vcg::Point2 XP=vcg::Point2(1,0); + vcg::Point2 YP=vcg::Point2(-0.5,h); + res2d = XP*deltaX + YP*deltaY; + //res2d=vcg::Point2(deltaX,deltaY); + + return true; + } + + // WEIGHTED INTERPOLATION OF POINTS IN TANGENT SPACE + /// weights MUST be normalized + bool Interpolate(const int &I0,const vcg::Point2 &alpha_beta0, + const int &I1,const vcg::Point2 &alpha_beta1, + ScalarType weight, + int &I_res, + vcg::Point2 &alpha_beta_res) + { + int IndexDomain; + int kind=isoParam->InterpolationSpace(I0,I1,IndexDomain); + if (kind==-1) + return false; + + vcg::Point2 transformed0,transformed1; + + ///interpolate in a face + if (kind==0) + { + isoParam->GE2(IndexDomain,alpha_beta0,transformed0); + isoParam->GE2(IndexDomain,alpha_beta1,transformed1); + } + else + ///interpolate in a diamond + if (kind==1) + { + isoParam->GE1(I0,alpha_beta0,IndexDomain,transformed0); + isoParam->GE1(I1,alpha_beta1,IndexDomain,transformed1); + } + else + { + isoParam->GE0(I0,alpha_beta0,IndexDomain,transformed0); + isoParam->GE0(I1,alpha_beta1,IndexDomain,transformed1); + } + + vcg::Point2 UV_interp=transformed0*weight+transformed1*(1.0-weight); + ///FINALLY...... + ///transform back to alpha,beta,I + if (kind==0) + { + isoParam->inv_GE2(IndexDomain,UV_interp,alpha_beta_res); + I_res=IndexDomain; + } + else + if (kind==1) + { + isoParam->inv_GE1(IndexDomain,UV_interp,I_res,alpha_beta_res); + } + else + isoParam->inv_GE0(IndexDomain,UV_interp,I_res,alpha_beta_res); + return true; + } + + ScalarType AbstractArea() + { + ScalarType Cnum=sqrt(3.0)/4.0; + return(isoParam->AbsMesh()->fn*Cnum); + } + + // WEIGHTED INTERPOLATION OF POINTS IN TANGENT SPACE + /// weights MUST be normalized + bool Interpolate(const std::vector &I, + const std::vector > &alpha_beta, + const std::vector &weights, + int &I_res, + vcg::Point2 &alpha_beta_res, + int *num=NULL) + { + int size; + if (num==NULL) + size=alpha_beta.size(); + else + size=*num; + + int IndexDomain; + int kind=isoParam->InterpolationSpace(I,IndexDomain,num); + if (kind==-1) + return false; + + std::vector > transformed; + transformed.resize(size); + + ///interpolate in a face + if (kind==0) + { + for (int i=0;iGE2(IndexDomain,alpha_beta[i],transformed[i]); + } + else + ///interpolate in a diamond + if (kind==1) + { + for (int i=0;iGE1(I[i],alpha_beta[i],IndexDomain,transformed[i]); + } + else + { + for (int i=0;iGE0(I[i],alpha_beta[i],IndexDomain,transformed[i]); + } + + /// do the interpolation + vcg::Point2 UV_interp=vcg::Point2(0,0); + for (int i=0;iinv_GE2(IndexDomain,UV_interp,alpha_beta_res); + I_res=IndexDomain; + } + else + if (kind==1) + { + isoParam->inv_GE1(IndexDomain,UV_interp,I_res,alpha_beta_res); + } + else + isoParam->inv_GE0(IndexDomain,UV_interp,I_res,alpha_beta_res); + return true; + } + +}; +#endif diff --git a/src/meshlabplugins/filter_layer/filter_layer.cpp b/src/meshlabplugins/filter_layer/filter_layer.cpp index 62659408d..483092786 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.cpp +++ b/src/meshlabplugins/filter_layer/filter_layer.cpp @@ -29,8 +29,7 @@ #include "filter_layer.h" -#include -#include +#include diff --git a/src/meshlabplugins/filter_measure/filter_measure.cpp b/src/meshlabplugins/filter_measure/filter_measure.cpp index 14443b9ab..ecc53a046 100644 --- a/src/meshlabplugins/filter_measure/filter_measure.cpp +++ b/src/meshlabplugins/filter_measure/filter_measure.cpp @@ -26,15 +26,15 @@ #include #include #include -#include -#include -#include +#include +#include +#include -#include -#include +#include +#include #include -#include -#include +#include +#include #include "filter_measure.h" using namespace std; diff --git a/src/meshlabplugins/filter_meshing/filter_meshing.pro b/src/meshlabplugins/filter_meshing/filter_meshing.pro index 9fd260bac..a54393877 100644 --- a/src/meshlabplugins/filter_meshing/filter_meshing.pro +++ b/src/meshlabplugins/filter_meshing/filter_meshing.pro @@ -1,6 +1,6 @@ include (../../shared.pri) -HEADERS += $$VCGDIR/vcg/complex/trimesh/clean.h\ +HEADERS += $$VCGDIR/vcg/complex/algorithms/clean.h\ quadric_simp.h \ quadric_tex_simp.h \ meshfilter.h diff --git a/src/meshlabplugins/filter_meshing/meshfilter.cpp b/src/meshlabplugins/filter_meshing/meshfilter.cpp index 6518c18e4..8d0280533 100644 --- a/src/meshlabplugins/filter_meshing/meshfilter.cpp +++ b/src/meshlabplugins/filter_meshing/meshfilter.cpp @@ -21,17 +21,17 @@ ****************************************************************************/ #include "meshfilter.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include "quadric_tex_simp.h" diff --git a/src/meshlabplugins/filter_meshing/quadric_simp.cpp b/src/meshlabplugins/filter_meshing/quadric_simp.cpp index 3cedf7bfa..d371652e5 100644 --- a/src/meshlabplugins/filter_meshing/quadric_simp.cpp +++ b/src/meshlabplugins/filter_meshing/quadric_simp.cpp @@ -20,9 +20,6 @@ * * ****************************************************************************/ #include "meshfilter.h" -#include -#include -#include #include "quadric_simp.h" using namespace vcg; diff --git a/src/meshlabplugins/filter_meshing/quadric_simp.h b/src/meshlabplugins/filter_meshing/quadric_simp.h index be52898b2..4f3d0e6cd 100644 --- a/src/meshlabplugins/filter_meshing/quadric_simp.h +++ b/src/meshlabplugins/filter_meshing/quadric_simp.h @@ -55,11 +55,11 @@ Added remove non manifold and quadric simplification filter. #include #include "meshfilter.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace vcg { namespace tri { diff --git a/src/meshlabplugins/filter_meshing/quadric_tex_simp.h b/src/meshlabplugins/filter_meshing/quadric_tex_simp.h index 73f483ede..3534e207f 100644 --- a/src/meshlabplugins/filter_meshing/quadric_tex_simp.h +++ b/src/meshlabplugins/filter_meshing/quadric_tex_simp.h @@ -23,8 +23,8 @@ #ifndef __QUADRICTEXSIMP_H #define __QUADRICTEXSIMP_H -#include -#include +#include +#include #include #include "algebra5.h" #include "quadric5.h" diff --git a/src/meshlabplugins/filter_mls/mlsplugin.cpp b/src/meshlabplugins/filter_mls/mlsplugin.cpp index 668659919..04d9a971b 100644 --- a/src/meshlabplugins/filter_mls/mlsplugin.cpp +++ b/src/meshlabplugins/filter_mls/mlsplugin.cpp @@ -30,12 +30,12 @@ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "mlsmarchingcube.h" #include "mlsplugin.h" diff --git a/src/meshlabplugins/filter_mutualinfo/alignset.cpp b/src/meshlabplugins/filter_mutualinfo/alignset.cpp index a46a957d4..f5a7f1ff6 100644 --- a/src/meshlabplugins/filter_mutualinfo/alignset.cpp +++ b/src/meshlabplugins/filter_mutualinfo/alignset.cpp @@ -1,357 +1,357 @@ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - - -#include "alignset.h" - -#include -#include -//#include -#include -#include -#include - -#include "shutils.h" - -using namespace std; - -AlignSet::AlignSet(): mode(COMBINE), -target(NULL), render(NULL), -vbo(0), nbo(0), cbo(0), ibo(0), error(0){ - - box.SetNull(); - correspList = new QList(); - imageRatio=1; -} - -AlignSet::~AlignSet() { - if(target) delete []target; - if(render) delete []render; - delete correspList; -} - -void AlignSet::initializeGL() { - - programs[COLOR] = createShaders("varying vec4 color; void main() { gl_Position = ftransform(); color = gl_Color; }", - "varying vec4 color; void main() { gl_FragColor = color; }"); - programs[NORMALMAP] = createShaders("varying vec3 normal; void main() { normal = gl_NormalMatrix * gl_Normal; gl_Position = ftransform(); }", - "varying vec3 normal; void main() { " - "vec3 color = normalize(normal); color = color * 0.5 + 0.5; gl_FragColor = vec4(color, 1.0); }"); - programs[COMBINE] = createShaders("varying vec3 normal; varying vec4 color; void main() { " - "normal = gl_NormalMatrix * gl_Normal; gl_Position = ftransform(); color = gl_Color; }", - "varying vec3 normal; varying vec4 color; void main() { " - "vec3 ncolor = normalize(normal); ncolor = ncolor * 0.5 + 0.5; " - "float t = color.x*color.x; gl_FragColor = (1-t)*color + t*(vec4(ncolor, 1.0)); }"); - programs[SPECULAR] = createShaders("varying vec3 reflection; void main() { " - "vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 position = gl_ModelViewMatrix * gl_Vertex; " - "reflection = reflect(position.xyz, normal); gl_Position = ftransform(); }", - "varying vec3 reflection; varying vec4 color; void main() { " - "vec4 ncolor; ncolor.xyz = normalize(reflection); ncolor.w = 1.0; gl_FragColor = ncolor * 0.5 + 0.5; }"); - programs[SILHOUETTE] = createShaders("varying vec4 color; void main() { gl_Position = ftransform(); color = gl_Color; }", - "varying vec4 color; void main() { gl_FragColor = color; }"); - - programs[SPECAMB] = createShaders("varying vec3 reflection; varying vec4 color; void main() { " - "vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 position = gl_ModelViewMatrix * gl_Vertex; " - "reflection = reflect(position.xyz, normal); gl_Position = ftransform(); color = gl_Color; }", - "varying vec3 reflection; varying vec4 color; void main() { " - "vec3 ncolor = normalize(reflection); ncolor = ncolor * 0.5 + 0.5; " - "float t = color.x*color.x; gl_FragColor = (1-t)*color + t*(vec4(ncolor, 1.0)); }"); - - - // generate a new VBO and get the associated ID - glGenBuffersARB(1, &vbo); - glGenBuffersARB(1, &nbo); - glGenBuffersARB(1, &cbo); - glGenBuffersARB(1, &ibo); -} - -//resample image IF too big. -void AlignSet::resize(int max_side) { - int w = image->width(); - int h = image->height(); - if(image->isNull()) { - w = 1024; - h = 768; - } - - if(w > max_side) { - h = h*max_side/w; - w = max_side; - } - if(h > max_side) { - w = w*max_side/h; - h = max_side; - } - - wt=w; - ht=h; - - if(target) delete []target; - if(render) delete []render; - target = new unsigned char[w*h]; - render = new unsigned char[w*h]; - - - if(image->isNull()) return; - //resize image and store values into render - QImage im; - if(w != image->width() || h != image->height()) - im = image->scaled(w, h, Qt::IgnoreAspectRatio); //Qt::KeepAspectRatio); - else im = *image; - im.save("image.jpg"); - assert(w == im.width()); - assert(h == im.height()); - QColor color; - int offset = 0; - //equalize image - int histo[256]; - memset(histo, 0, 256*sizeof(int)); - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - color.setRgb(im.pixel(x, y)); - unsigned char c = (unsigned char)(color.red() * 0.3f + color.green() * 0.59f + color.blue() * 0.11f); - target[offset] = c; - histo[c]++; - offset++; - } - } -#ifdef RESCALE_HISTO - int cumulative[256]; - cumulative[0] = histo[0]; - for(int i = 1; i < 256; i++) - cumulative[i] = cumulative[i-1] + histo[i]; - - int min = 0; - int max = 255; - for(int i = 0; i < 256; i++) { - if(cumulative[i] > 20) break; - min = i; - } - - //invert cumulative.. - cumulative[255] = histo[255]; - for(int i = 254; i >= 0; i--) - cumulative[i] = cumulative[i+1] + histo[i]; - - for(int i = 255; i >= 0; i--) { - if(cumulative[i] > 20) break; - max = i; - } - assert(max > min); - //rescale between min and max (should use bresenham but I am lazy - unsigned char equa[256]; - for(int i = 0; i < 256; i++) { - if(i < min) equa[i] = 0; - if(i > max) equa[i] = 255; - equa[i] = (255*(i - min))/(max - min); - } - for(int i = 0; i < w*h; i++) - target[i] = equa[target[i]]; -#endif -} - -void AlignSet::renderScene(vcg::Shot &view, int component) { - QSize fbosize(wt,ht); - QGLFramebufferObjectFormat frmt; - frmt.setInternalTextureFormat(GL_RGBA); - frmt.setAttachment(QGLFramebufferObject::Depth); - QGLFramebufferObject fbo(fbosize,frmt); - - float _near, _far; - _near=0.1; - _far=10000; - - GlShot< vcg::Shot >::GetNearFarPlanes(view, mesh->bbox, _near, _far); - //assert(_near <= _far); - if(_near <= 0) _near = 0.1; - if(_far < _near) _far = 1000; - - -//GLenum err = glGetError(); - - //render to FBO - fbo.bind(); - - glViewport(0, 0, wt, ht); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GlShot< vcg::Shot >::SetView(shot, 0.5*_near, 2*_far); - -// err = glGetError(); - - bool use_colors = false; - bool use_normals = false; - int program = programs[mode]; //standard pipeline - switch(mode){ - case COLOR: - use_colors = true; - break; - case NORMALMAP: - case SPECULAR: - use_normals = true; - break; - case COMBINE: - case SPECAMB: - use_colors = true; - use_normals = true; - break; - case SILHOUETTE: - break; - default: assert(0); - } - glDisable(GL_LIGHTING); - //bind indices - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo); - - //bind vertices - glEnable(GL_COLOR_MATERIAL); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); - glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array - glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr - -// err = glGetError(); - - glUseProgram(program); - -// err = glGetError(); - - if(use_colors) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, cbo); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); - } - if(use_normals) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, nbo); - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, 0); - } - -// err = glGetError(); - - - int start = 0; - int tot = 30000; - if (mesh->fn>0) - { - while(start < mesh->fn) { - glDrawElements(GL_TRIANGLES, tot*3, GL_UNSIGNED_INT, (void *)(start*3*sizeof(int))); - start += tot; - if(start + tot > mesh->fn) - tot = mesh->fn - start; - } - } - else glDrawArrays(GL_POINTS, 0, mesh->vn); - - - - render = new unsigned char[wt*ht]; - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - switch(component) { - case 0: glReadPixels( 0, 0, wt, ht, GL_RED, GL_UNSIGNED_BYTE, render); break; - case 1: glReadPixels( 0, 0, wt, ht, GL_GREEN, GL_UNSIGNED_BYTE, render); break; - case 2: glReadPixels( 0, 0, wt, ht, GL_BLUE, GL_UNSIGNED_BYTE, render); break; - case 3: glReadPixels( 0, 0, wt, ht, GL_ALPHA, GL_UNSIGNED_BYTE, render); break; - case 4: break; - } - - //err = glGetError(); - - glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array - if(use_colors) glDisableClientState(GL_COLOR_ARRAY); - if(use_normals) glDisableClientState(GL_NORMAL_ARRAY); - - //err = glGetError(); - - // bind with 0, so, switch back to normal pointer operation - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - switch(mode) { - case SILHOUETTE: - case COLOR: - case COMBINE: - case NORMALMAP: glEnable(GL_LIGHTING); break; - default: break; - } - - // standard opengl pipeline is re-activated - glUseProgram(0); - - GlShot< vcg::Shot >::UnsetView(); - - glFinish(); - /*QImage l=fbo.toImage(); - l.save("rendering.jpg");*/ - fbo.release(); - -} - -void AlignSet::readRender(int component) { - QSize fbosize(wt,ht); - QGLFramebufferObjectFormat frmt; - frmt.setInternalTextureFormat(GL_RGBA); - frmt.setAttachment(QGLFramebufferObject::Depth); - QGLFramebufferObject fbo(fbosize,frmt); - - fbo.bind(); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - switch(component) { - case 0: glReadPixels( 0, 0, width(), height(), GL_RED, GL_UNSIGNED_BYTE, render); break; - case 1: glReadPixels( 0, 0, width(), height(), GL_GREEN, GL_UNSIGNED_BYTE, render); break; - case 2: glReadPixels( 0, 0, width(), height(), GL_BLUE, GL_UNSIGNED_BYTE, render); break; - case 3: glReadPixels( 0, 0, width(), height(), GL_ALPHA, GL_UNSIGNED_BYTE, render); break; - } - QImage l=fbo.toImage(); - l.save("puppo.jpg"); - fbo.release(); -} - -GLuint AlignSet::createShaderFromFiles(QString name) { - QString vert = "shaders/" + name + ".vert"; - QString frag = "shaders/" + name + ".frag"; - - const char *vs_src = ShaderUtils::importShaders(vert.toAscii().data()); - if(!vs_src) { - cerr << "Could not load shader: " << qPrintable(vert) << endl; - return 0; - } - - const char *fs_src = ShaderUtils::importShaders(frag.toAscii().data()); - if(!fs_src) { - cerr << "Could not load shader: " << qPrintable(frag) << endl; - return 0; - } - - return createShaders(vs_src, fs_src); -} - -GLuint AlignSet::createShaders(const char *vert, const char *frag) { - GLuint vs = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vs, 1, &vert, NULL); - ShaderUtils::compileShader(vs); - - GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fs, 1, &frag, NULL); - ShaderUtils::compileShader(fs); - - GLuint prog = glCreateProgram(); - glAttachShader(prog, vs); - glAttachShader(prog, fs); - - ShaderUtils::linkShaderProgram(prog); - return prog; -} - +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "alignset.h" + +#include +#include +//#include +#include +#include +#include + +#include "shutils.h" + +using namespace std; + +AlignSet::AlignSet(): mode(COMBINE), +target(NULL), render(NULL), +vbo(0), nbo(0), cbo(0), ibo(0), error(0){ + + box.SetNull(); + correspList = new QList(); + imageRatio=1; +} + +AlignSet::~AlignSet() { + if(target) delete []target; + if(render) delete []render; + delete correspList; +} + +void AlignSet::initializeGL() { + + programs[COLOR] = createShaders("varying vec4 color; void main() { gl_Position = ftransform(); color = gl_Color; }", + "varying vec4 color; void main() { gl_FragColor = color; }"); + programs[NORMALMAP] = createShaders("varying vec3 normal; void main() { normal = gl_NormalMatrix * gl_Normal; gl_Position = ftransform(); }", + "varying vec3 normal; void main() { " + "vec3 color = normalize(normal); color = color * 0.5 + 0.5; gl_FragColor = vec4(color, 1.0); }"); + programs[COMBINE] = createShaders("varying vec3 normal; varying vec4 color; void main() { " + "normal = gl_NormalMatrix * gl_Normal; gl_Position = ftransform(); color = gl_Color; }", + "varying vec3 normal; varying vec4 color; void main() { " + "vec3 ncolor = normalize(normal); ncolor = ncolor * 0.5 + 0.5; " + "float t = color.x*color.x; gl_FragColor = (1-t)*color + t*(vec4(ncolor, 1.0)); }"); + programs[SPECULAR] = createShaders("varying vec3 reflection; void main() { " + "vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 position = gl_ModelViewMatrix * gl_Vertex; " + "reflection = reflect(position.xyz, normal); gl_Position = ftransform(); }", + "varying vec3 reflection; varying vec4 color; void main() { " + "vec4 ncolor; ncolor.xyz = normalize(reflection); ncolor.w = 1.0; gl_FragColor = ncolor * 0.5 + 0.5; }"); + programs[SILHOUETTE] = createShaders("varying vec4 color; void main() { gl_Position = ftransform(); color = gl_Color; }", + "varying vec4 color; void main() { gl_FragColor = color; }"); + + programs[SPECAMB] = createShaders("varying vec3 reflection; varying vec4 color; void main() { " + "vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 position = gl_ModelViewMatrix * gl_Vertex; " + "reflection = reflect(position.xyz, normal); gl_Position = ftransform(); color = gl_Color; }", + "varying vec3 reflection; varying vec4 color; void main() { " + "vec3 ncolor = normalize(reflection); ncolor = ncolor * 0.5 + 0.5; " + "float t = color.x*color.x; gl_FragColor = (1-t)*color + t*(vec4(ncolor, 1.0)); }"); + + + // generate a new VBO and get the associated ID + glGenBuffersARB(1, &vbo); + glGenBuffersARB(1, &nbo); + glGenBuffersARB(1, &cbo); + glGenBuffersARB(1, &ibo); +} + +//resample image IF too big. +void AlignSet::resize(int max_side) { + int w = image->width(); + int h = image->height(); + if(image->isNull()) { + w = 1024; + h = 768; + } + + if(w > max_side) { + h = h*max_side/w; + w = max_side; + } + if(h > max_side) { + w = w*max_side/h; + h = max_side; + } + + wt=w; + ht=h; + + if(target) delete []target; + if(render) delete []render; + target = new unsigned char[w*h]; + render = new unsigned char[w*h]; + + + if(image->isNull()) return; + //resize image and store values into render + QImage im; + if(w != image->width() || h != image->height()) + im = image->scaled(w, h, Qt::IgnoreAspectRatio); //Qt::KeepAspectRatio); + else im = *image; + im.save("image.jpg"); + assert(w == im.width()); + assert(h == im.height()); + QColor color; + int offset = 0; + //equalize image + int histo[256]; + memset(histo, 0, 256*sizeof(int)); + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + color.setRgb(im.pixel(x, y)); + unsigned char c = (unsigned char)(color.red() * 0.3f + color.green() * 0.59f + color.blue() * 0.11f); + target[offset] = c; + histo[c]++; + offset++; + } + } +#ifdef RESCALE_HISTO + int cumulative[256]; + cumulative[0] = histo[0]; + for(int i = 1; i < 256; i++) + cumulative[i] = cumulative[i-1] + histo[i]; + + int min = 0; + int max = 255; + for(int i = 0; i < 256; i++) { + if(cumulative[i] > 20) break; + min = i; + } + + //invert cumulative.. + cumulative[255] = histo[255]; + for(int i = 254; i >= 0; i--) + cumulative[i] = cumulative[i+1] + histo[i]; + + for(int i = 255; i >= 0; i--) { + if(cumulative[i] > 20) break; + max = i; + } + assert(max > min); + //rescale between min and max (should use bresenham but I am lazy + unsigned char equa[256]; + for(int i = 0; i < 256; i++) { + if(i < min) equa[i] = 0; + if(i > max) equa[i] = 255; + equa[i] = (255*(i - min))/(max - min); + } + for(int i = 0; i < w*h; i++) + target[i] = equa[target[i]]; +#endif +} + +void AlignSet::renderScene(vcg::Shot &view, int component) { + QSize fbosize(wt,ht); + QGLFramebufferObjectFormat frmt; + frmt.setInternalTextureFormat(GL_RGBA); + frmt.setAttachment(QGLFramebufferObject::Depth); + QGLFramebufferObject fbo(fbosize,frmt); + + float _near, _far; + _near=0.1; + _far=10000; + + GlShot< vcg::Shot >::GetNearFarPlanes(view, mesh->bbox, _near, _far); + //assert(_near <= _far); + if(_near <= 0) _near = 0.1; + if(_far < _near) _far = 1000; + + +//GLenum err = glGetError(); + + //render to FBO + fbo.bind(); + + glViewport(0, 0, wt, ht); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GlShot< vcg::Shot >::SetView(shot, 0.5*_near, 2*_far); + +// err = glGetError(); + + bool use_colors = false; + bool use_normals = false; + int program = programs[mode]; //standard pipeline + switch(mode){ + case COLOR: + use_colors = true; + break; + case NORMALMAP: + case SPECULAR: + use_normals = true; + break; + case COMBINE: + case SPECAMB: + use_colors = true; + use_normals = true; + break; + case SILHOUETTE: + break; + default: assert(0); + } + glDisable(GL_LIGHTING); + //bind indices + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo); + + //bind vertices + glEnable(GL_COLOR_MATERIAL); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo); + glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array + glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr + +// err = glGetError(); + + glUseProgram(program); + +// err = glGetError(); + + if(use_colors) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, cbo); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); + } + if(use_normals) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, nbo); + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, 0); + } + +// err = glGetError(); + + + int start = 0; + int tot = 30000; + if (mesh->fn>0) + { + while(start < mesh->fn) { + glDrawElements(GL_TRIANGLES, tot*3, GL_UNSIGNED_INT, (void *)(start*3*sizeof(int))); + start += tot; + if(start + tot > mesh->fn) + tot = mesh->fn - start; + } + } + else glDrawArrays(GL_POINTS, 0, mesh->vn); + + + + render = new unsigned char[wt*ht]; + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + switch(component) { + case 0: glReadPixels( 0, 0, wt, ht, GL_RED, GL_UNSIGNED_BYTE, render); break; + case 1: glReadPixels( 0, 0, wt, ht, GL_GREEN, GL_UNSIGNED_BYTE, render); break; + case 2: glReadPixels( 0, 0, wt, ht, GL_BLUE, GL_UNSIGNED_BYTE, render); break; + case 3: glReadPixels( 0, 0, wt, ht, GL_ALPHA, GL_UNSIGNED_BYTE, render); break; + case 4: break; + } + + //err = glGetError(); + + glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array + if(use_colors) glDisableClientState(GL_COLOR_ARRAY); + if(use_normals) glDisableClientState(GL_NORMAL_ARRAY); + + //err = glGetError(); + + // bind with 0, so, switch back to normal pointer operation + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + + switch(mode) { + case SILHOUETTE: + case COLOR: + case COMBINE: + case NORMALMAP: glEnable(GL_LIGHTING); break; + default: break; + } + + // standard opengl pipeline is re-activated + glUseProgram(0); + + GlShot< vcg::Shot >::UnsetView(); + + glFinish(); + /*QImage l=fbo.toImage(); + l.save("rendering.jpg");*/ + fbo.release(); + +} + +void AlignSet::readRender(int component) { + QSize fbosize(wt,ht); + QGLFramebufferObjectFormat frmt; + frmt.setInternalTextureFormat(GL_RGBA); + frmt.setAttachment(QGLFramebufferObject::Depth); + QGLFramebufferObject fbo(fbosize,frmt); + + fbo.bind(); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + switch(component) { + case 0: glReadPixels( 0, 0, width(), height(), GL_RED, GL_UNSIGNED_BYTE, render); break; + case 1: glReadPixels( 0, 0, width(), height(), GL_GREEN, GL_UNSIGNED_BYTE, render); break; + case 2: glReadPixels( 0, 0, width(), height(), GL_BLUE, GL_UNSIGNED_BYTE, render); break; + case 3: glReadPixels( 0, 0, width(), height(), GL_ALPHA, GL_UNSIGNED_BYTE, render); break; + } + QImage l=fbo.toImage(); + l.save("puppo.jpg"); + fbo.release(); +} + +GLuint AlignSet::createShaderFromFiles(QString name) { + QString vert = "shaders/" + name + ".vert"; + QString frag = "shaders/" + name + ".frag"; + + const char *vs_src = ShaderUtils::importShaders(vert.toAscii().data()); + if(!vs_src) { + cerr << "Could not load shader: " << qPrintable(vert) << endl; + return 0; + } + + const char *fs_src = ShaderUtils::importShaders(frag.toAscii().data()); + if(!fs_src) { + cerr << "Could not load shader: " << qPrintable(frag) << endl; + return 0; + } + + return createShaders(vs_src, fs_src); +} + +GLuint AlignSet::createShaders(const char *vert, const char *frag) { + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &vert, NULL); + ShaderUtils::compileShader(vs); + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, &frag, NULL); + ShaderUtils::compileShader(fs); + + GLuint prog = glCreateProgram(); + glAttachShader(prog, vs); + glAttachShader(prog, fs); + + ShaderUtils::linkShaderProgram(prog); + return prog; +} + diff --git a/src/meshlabplugins/filter_perceptualmetric/filter_perceptualmetric.cpp b/src/meshlabplugins/filter_perceptualmetric/filter_perceptualmetric.cpp index 90dfc463b..714413087 100644 --- a/src/meshlabplugins/filter_perceptualmetric/filter_perceptualmetric.cpp +++ b/src/meshlabplugins/filter_perceptualmetric/filter_perceptualmetric.cpp @@ -1,224 +1,217 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ -/**************************************************************************** - History -$Log: filter_perceptualmetric.cpp,v $ -****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// filter interface -#include "filter_perceptualmetric.h" - -// perceptual metrics core -#include "perceptualmetrics.h" - -using namespace vcg; -using namespace std; - - -// Constructor usually performs only two simple tasks of filling the two lists -// - typeList: with all the possible id of the filtering actions -// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly - -FilterPerceptualMetric::FilterPerceptualMetric() -{ - typeList - << FP_ROUGHNESS_MULTISCALE - << FP_ROUGHNESS_SMOOTHING - << FP_STRAIN_ENERGY - ; - - foreach(FilterIDType tt , types()) - actionList << new QAction(filterName(tt), this); -} - -// ST() must return the very short string describing each filtering action -// (this string is used also to define the menu entry) - QString FilterPerceptualMetric::filterName(FilterIDType filterId) -{ - switch(filterId) - { - case FP_ROUGHNESS_MULTISCALE : return QString("Roughness-multiscale perceptual metric"); - case FP_ROUGHNESS_SMOOTHING : return QString("Roughness-smoothing perceptual metric"); - case FP_STRAIN_ENERGY : return QString("Energy Strain-based perceptual metric"); - - default : assert(0); return QString("unknown filter!!!!"); - } -} - -// Info() must return the longer string describing each filtering action -// (this string is used in the About plugin dialog) - QString FilterPerceptualMetric::filterInfo(FilterIDType filterId) -{ - switch(filterId) - { - case FP_ROUGHNESS_MULTISCALE : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on roughness measure, the roughness is evaluated at multiple-scale using dihedral angles."); - case FP_ROUGHNESS_SMOOTHING : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on roughness measure, the roughness is evaluated using a smoothed version of the 3D models."); - case FP_STRAIN_ENERGY : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on strain energy."); - - default : assert(0); return QString("unknown filter!!!!"); - } -} - int FilterPerceptualMetric::getRequirements(QAction *action) -{ - switch(ID(action)) - { - case FP_ROUGHNESS_MULTISCALE : return MeshModel::MM_VERTFACETOPO | MeshModel::MM_FACENORMAL; - case FP_ROUGHNESS_SMOOTHING : return MeshModel::MM_VERTFACETOPO; - case FP_STRAIN_ENERGY : return MeshModel::MM_VERTFACETOPO; - - default: assert(0); - } - - return 0; -} - -// This function define the needed parameters for each filter. Return true if the filter has some parameters -// it is called every time, so you can set the default value of parameters according to the mesh -// For each parameter you need to define, -// - the name of the parameter, -// - the string shown in the dialog -// - the default value -// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterPerceptualMetric::initParameterSet(QAction *action, MeshDocument & md, FilterParameterSet & parlst) -{ - switch(ID(action)) - { - case FP_ROUGHNESS_MULTISCALE : - { - MeshModel *refmesh = md.mm(); - foreach (refmesh, md.meshList) - if (refmesh != md.mm()) break; - - parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", - "The original mesh."); - parlst.addMesh("InputMesh", md.mm(), "Mesh", - "The mesh where the perceptual impairment of the processing is evaluated."); - } break; - - case FP_ROUGHNESS_SMOOTHING : - { - MeshModel *refmesh = md.mm(); - foreach (refmesh, md.meshList) - if (refmesh != md.mm()) break; - - parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", - "The original mesh."); - parlst.addMesh("InputMesh", md.mm(), "Mesh", - "The mesh where the perceptual impairment of the processing is evaluated."); - } break; - - case FP_STRAIN_ENERGY : - { - MeshModel *refmesh = md.mm(); - foreach (refmesh, md.meshList) - if (refmesh != md.mm()) break; - - parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", - "The original mesh."); - parlst.addMesh("InputMesh", md.mm(), "Mesh", - "The mesh where the perceptual impairment of the processing is evaluated."); - } break; - - default : assert(0); - } -} - -bool FilterPerceptualMetric::applyFilter(QAction *action, MeshDocument &md, FilterParameterSet & par, vcg::CallBackPos *cb) -{ - switch(ID(action)) - { - - case FP_ROUGHNESS_MULTISCALE : - { - MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh - MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh - - double globalimpact = PerceptualMetrics::roughnessMultiscale(mesh0->cm, mesh1->cm); - - Log(0,"This metric is not implemented yet!!"); - } - break; - - case FP_ROUGHNESS_SMOOTHING : - { - MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh - MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh - - double globalimpact = PerceptualMetrics::roughnessSmoothing(mesh0->cm, mesh1->cm); - - Log(0,"This metric is not implemented yet!!"); - } - break; - - case FP_STRAIN_ENERGY : - { - MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh - MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh - - double globalimpact = PerceptualMetrics::strainEnergy(mesh0->cm, mesh1->cm); - - Log(0,"Perceptual Distance: %f",globalimpact); - } - break; - - default : assert(0); - } - return true; -} - - MeshFilterInterface::FilterClass FilterPerceptualMetric::getClass(QAction *action) -{ - switch(ID(action)) - { - case FP_ROUGHNESS_MULTISCALE : return Quality; - case FP_ROUGHNESS_SMOOTHING : return Quality; - case FP_STRAIN_ENERGY : return Quality; - default: assert(0); - } - return FilterClass(0); -} - - -Q_EXPORT_PLUGIN(FilterPerceptualMetric) +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* 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. * +* * +****************************************************************************/ +/**************************************************************************** + History +$Log: filter_perceptualmetric.cpp,v $ +****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +// filter interface +#include "filter_perceptualmetric.h" + +// perceptual metrics core +#include "perceptualmetrics.h" + +using namespace vcg; +using namespace std; + + +// Constructor usually performs only two simple tasks of filling the two lists +// - typeList: with all the possible id of the filtering actions +// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly + +FilterPerceptualMetric::FilterPerceptualMetric() +{ + typeList + << FP_ROUGHNESS_MULTISCALE + << FP_ROUGHNESS_SMOOTHING + << FP_STRAIN_ENERGY + ; + + foreach(FilterIDType tt , types()) + actionList << new QAction(filterName(tt), this); +} + +// ST() must return the very short string describing each filtering action +// (this string is used also to define the menu entry) + QString FilterPerceptualMetric::filterName(FilterIDType filterId) +{ + switch(filterId) + { + case FP_ROUGHNESS_MULTISCALE : return QString("Roughness-multiscale perceptual metric"); + case FP_ROUGHNESS_SMOOTHING : return QString("Roughness-smoothing perceptual metric"); + case FP_STRAIN_ENERGY : return QString("Energy Strain-based perceptual metric"); + + default : assert(0); return QString("unknown filter!!!!"); + } +} + +// Info() must return the longer string describing each filtering action +// (this string is used in the About plugin dialog) + QString FilterPerceptualMetric::filterInfo(FilterIDType filterId) +{ + switch(filterId) + { + case FP_ROUGHNESS_MULTISCALE : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on roughness measure, the roughness is evaluated at multiple-scale using dihedral angles."); + case FP_ROUGHNESS_SMOOTHING : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on roughness measure, the roughness is evaluated using a smoothed version of the 3D models."); + case FP_STRAIN_ENERGY : return QString("Evaluate the perceptual difference between two given meshes; this perceptual metric is based on strain energy."); + + default : assert(0); return QString("unknown filter!!!!"); + } +} + int FilterPerceptualMetric::getRequirements(QAction *action) +{ + switch(ID(action)) + { + case FP_ROUGHNESS_MULTISCALE : return MeshModel::MM_VERTFACETOPO | MeshModel::MM_FACENORMAL; + case FP_ROUGHNESS_SMOOTHING : return MeshModel::MM_VERTFACETOPO; + case FP_STRAIN_ENERGY : return MeshModel::MM_VERTFACETOPO; + + default: assert(0); + } + + return 0; +} + +// This function define the needed parameters for each filter. Return true if the filter has some parameters +// it is called every time, so you can set the default value of parameters according to the mesh +// For each parameter you need to define, +// - the name of the parameter, +// - the string shown in the dialog +// - the default value +// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) +void FilterPerceptualMetric::initParameterSet(QAction *action, MeshDocument & md, FilterParameterSet & parlst) +{ + switch(ID(action)) + { + case FP_ROUGHNESS_MULTISCALE : + { + MeshModel *refmesh = md.mm(); + foreach (refmesh, md.meshList) + if (refmesh != md.mm()) break; + + parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", + "The original mesh."); + parlst.addMesh("InputMesh", md.mm(), "Mesh", + "The mesh where the perceptual impairment of the processing is evaluated."); + } break; + + case FP_ROUGHNESS_SMOOTHING : + { + MeshModel *refmesh = md.mm(); + foreach (refmesh, md.meshList) + if (refmesh != md.mm()) break; + + parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", + "The original mesh."); + parlst.addMesh("InputMesh", md.mm(), "Mesh", + "The mesh where the perceptual impairment of the processing is evaluated."); + } break; + + case FP_STRAIN_ENERGY : + { + MeshModel *refmesh = md.mm(); + foreach (refmesh, md.meshList) + if (refmesh != md.mm()) break; + + parlst.addMesh("ReferenceMesh", refmesh, "Reference Mesh", + "The original mesh."); + parlst.addMesh("InputMesh", md.mm(), "Mesh", + "The mesh where the perceptual impairment of the processing is evaluated."); + } break; + + default : assert(0); + } +} + +bool FilterPerceptualMetric::applyFilter(QAction *action, MeshDocument &md, FilterParameterSet & par, vcg::CallBackPos *cb) +{ + switch(ID(action)) + { + + case FP_ROUGHNESS_MULTISCALE : + { + MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh + MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh + + double globalimpact = PerceptualMetrics::roughnessMultiscale(mesh0->cm, mesh1->cm); + + Log(0,"This metric is not implemented yet!!"); + } + break; + + case FP_ROUGHNESS_SMOOTHING : + { + MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh + MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh + + double globalimpact = PerceptualMetrics::roughnessSmoothing(mesh0->cm, mesh1->cm); + + Log(0,"This metric is not implemented yet!!"); + } + break; + + case FP_STRAIN_ENERGY : + { + MeshModel* mesh0 = par.getMesh("ReferenceMesh"); // reference mesh + MeshModel* mesh1 = par.getMesh("InputMesh"); // the processed mesh + + double globalimpact = PerceptualMetrics::strainEnergy(mesh0->cm, mesh1->cm); + + Log(0,"Perceptual Distance: %f",globalimpact); + } + break; + + default : assert(0); + } + return true; +} + + MeshFilterInterface::FilterClass FilterPerceptualMetric::getClass(QAction *action) +{ + switch(ID(action)) + { + case FP_ROUGHNESS_MULTISCALE : return Quality; + case FP_ROUGHNESS_SMOOTHING : return Quality; + case FP_STRAIN_ENERGY : return Quality; + default: assert(0); + } + return FilterClass(0); +} + + +Q_EXPORT_PLUGIN(FilterPerceptualMetric) diff --git a/src/meshlabplugins/filter_perceptualmetric/perceptualmetrics.h b/src/meshlabplugins/filter_perceptualmetric/perceptualmetrics.h index fd392fefc..7d0e05ce1 100644 --- a/src/meshlabplugins/filter_perceptualmetric/perceptualmetrics.h +++ b/src/meshlabplugins/filter_perceptualmetric/perceptualmetrics.h @@ -1,242 +1,242 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ - -/**************************************************************************** - History -$Log: perceptualmetrics.h,v $ -****************************************************************************/ - -#ifndef PERCEPTUALMETRICS_H -#define PERCEPTUALMETRICS_H - -#include - -#include -#include - -template -class PerceptualMetrics -{ - -// definitions -public: - - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FaceContainer FaceContainer; - - -// private methods -private: - - static void planeProjection(double a, double b, double c, double d, - const CoordType &axis1, const CoordType &axis2, const CoordType & O, - const CoordType &p, double &xcoor, double &ycoor) - { - double u = p[0]; - double v = p[1]; - double w = p[2]; - - CoordType Pproj; - - double num = a*u + b*v + c*w + d; - - // den = a*a + b*b + c*c that is assumed one in this case (!) - Pproj[0] = u - a * num; // num/den - Pproj[1] = v - b * num; // num/den - Pproj[2] = w - c * num; // num/den - - Pproj -= O; - - xcoor = axis1 * Pproj; - ycoor = axis2 * Pproj; - } - - static void computingDisplacementFunctionCoefficients(FacePointer f0, FacePointer f1, - double & a1u, double & a2u, double & a3u, double & a1v, double & a2v, double & a3v, - double & area) - { - CoordType pD = f0->V(0)->P(); - CoordType pE = f0->V(1)->P(); - CoordType pF = f0->V(2)->P(); - - CoordType pDp = f1->V(0)->P(); - CoordType pEp = f1->V(1)->P(); - CoordType pFp = f1->V(2)->P(); - - CoordType axis1 = (pE-pD); - CoordType axis2 = (pF-pD); - CoordType N = axis1 ^ axis2; - - // axis adjustment - axis2 = N ^ axis1; - - axis1.Normalize(); - axis2.Normalize(); - N.Normalize(); - - double a = N[0]; - double b = N[1]; - double c = N[2]; - double d = -(a * pD[0] + b * pD[1] + c * pD[2]); - - // triangle in the local reference system - double xD,yD,xE,yE,xF,yF; - planeProjection(a,b,c,d, axis1, axis2, pD, pD, xD, yD); - planeProjection(a,b,c,d, axis1, axis2, pD, pE, xE, yE); - planeProjection(a,b,c,d, axis1, axis2, pD, pF, xF, yF); - - // triangle in the local reference system after deformations - double xDp,yDp,xEp,yEp,xFp,yFp; - planeProjection(a,b,c,d, axis1, axis2, pD, pDp, xDp, yDp); - planeProjection(a,b,c,d, axis1, axis2, pD, pEp, xEp, yEp); - planeProjection(a,b,c,d, axis1, axis2, pD, pFp, xFp, yFp); - - // deformation - double uD = xDp - xD; - double vD = yDp - yD; - - double uE = xEp - xE; - double vE = yEp - yE; - - double uF = xFp - xF; - double vF = yFp - yF; - - // parameterization - double AA = (yE-yF) * xD + (yF-yD) * xE + (yD-yE) * xF; // AA = 2A - double factor = 1.0 / (AA); - - a1u = factor * ((xE*yF - xF*yE)*uD + (xF*yD - xD*yF)*uE + (xD*yE - xE*yD)*uF); - a2u = factor * ((yE-yF)*uD + (yF-yD)*uE + (yD-yE)*uF); - a3u = factor * ((xF-xE)*uD + (xD-xF)*uE + (xE-xD)*uF); - - a1v = factor * ((xE*yF - xF*yE)*vD + (xF*yD - xD*yF)*vE + (xD*yE - xE*yD)*vF); - a2v = factor * ((yE-yF)*vD + (yF-yD)*vE + (yD-yE)*vF); - a3v = factor * ((xF-xE)*vD + (xD-xF)*vE + (xE-xD)*vF); - - area = 0.5 * AA; - } - -// public methods -public: - - static double roughnessMultiscale(MeshType & refmesh, MeshType & mesh) - { - //...TODO... - return 0.0; - } - - static double roughnessSmoothing(MeshType & refmesh, MeshType & mesh) - { - //...TODO... - return 0.0; - } - - static double strainEnergy(MeshType & refmesh, MeshType & mesh) - { - double epsilonx, epsilony, epsilonz; - double gammaxy, gammayz, gammazx; - double epsilonx_prime, epsilony_prime, epsilonz_prime; - double epsilon_ii_squared; - double epsilon_ij_prime_epsilon_ij_prime; - double Sdelta; // Area of each triangle - double ni = 0.0; // Poisson's ratio - double E = 1.0; // Young's modulus - double lambda; // Lame's first parameter - double G; - double Warea, Wdistortion, W; - double u,v; - double a1u,a2u,a3u; - double a1v,a2v,a3v; - double x,y; - double D; - - FacePointer f0; - FacePointer f1; - - W = 0.0; - for (int i = 0; i < refmesh.fn; i++) - { - f0 = &refmesh.face[i]; - f1 = &mesh.face[i]; - - // displacement function are: - // u = a1u + x a2u + y a3u - // v = a1v + x a2v + y a3v - computingDisplacementFunctionCoefficients(f0, f1, a1u, a2u, a3u, a1v, a2v, a3v, Sdelta); - - // epsilonx = du / dx - epsilonx = a2u; - - // epsilony = dv / dy - epsilony = a3v; - - // epsilonz - epsilonz = (ni / (ni - 1.0)) * (epsilonx + epsilony); - - // gammaxy = dv / dx + du / dy - gammaxy = a2v + a3u; - gammayz = 0.0; - gammazx = 0.0; - - // strain energy for a single triangle - /////////////////////////////////////////////////////////////////////////////////////// - - epsilonx_prime = epsilonx - (epsilonx + epsilony + epsilonz) / 3.0; - epsilony_prime = epsilony - (epsilonx + epsilony + epsilonz) / 3.0; - epsilonz_prime = epsilonz - (epsilonx + epsilony + epsilonz) / 3.0; - - epsilon_ii_squared = (epsilonx + epsilony + epsilonz) * (epsilonx + epsilony + epsilonz); - epsilon_ij_prime_epsilon_ij_prime = epsilonx_prime * epsilonx_prime + epsilony_prime * epsilony_prime + - epsilonz_prime * epsilonz_prime + 0.5 * (gammaxy*gammaxy + gammayz*gammayz + gammazx*gammazx); - - lambda = (E * ni) / ((1.0 + ni) * (1 - 2.0 * ni)); - G = E / (2.0 * (1.0 + ni)); - - Warea = 0.5 * (lambda + 0.666666666666 * G) * epsilon_ii_squared * Sdelta; - Wdistortion = G * epsilon_ij_prime_epsilon_ij_prime * Sdelta; - W += Warea + Wdistortion; - } - - // Average Strain Energy (ASE) - ////////////////////////////////////////////////////////////////////////// - - double area1 = vcg::tri::Stat::ComputeMeshArea(refmesh); - //double area2 = vcg::tri::Stat::ComputeMeshArea(mesh); - - // the area if the deformed mesh is considered the same of the original one, - // since the deformation is assumed to be small - - return W / (area1); - } - -}; - -#endif /* PERCEPTUALMETRICS_H */ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* 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. * +* * +****************************************************************************/ + +/**************************************************************************** + History +$Log: perceptualmetrics.h,v $ +****************************************************************************/ + +#ifndef PERCEPTUALMETRICS_H +#define PERCEPTUALMETRICS_H + +#include + +#include +#include + +template +class PerceptualMetrics +{ + +// definitions +public: + + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::FacePointer FacePointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FaceContainer FaceContainer; + + +// private methods +private: + + static void planeProjection(double a, double b, double c, double d, + const CoordType &axis1, const CoordType &axis2, const CoordType & O, + const CoordType &p, double &xcoor, double &ycoor) + { + double u = p[0]; + double v = p[1]; + double w = p[2]; + + CoordType Pproj; + + double num = a*u + b*v + c*w + d; + + // den = a*a + b*b + c*c that is assumed one in this case (!) + Pproj[0] = u - a * num; // num/den + Pproj[1] = v - b * num; // num/den + Pproj[2] = w - c * num; // num/den + + Pproj -= O; + + xcoor = axis1 * Pproj; + ycoor = axis2 * Pproj; + } + + static void computingDisplacementFunctionCoefficients(FacePointer f0, FacePointer f1, + double & a1u, double & a2u, double & a3u, double & a1v, double & a2v, double & a3v, + double & area) + { + CoordType pD = f0->V(0)->P(); + CoordType pE = f0->V(1)->P(); + CoordType pF = f0->V(2)->P(); + + CoordType pDp = f1->V(0)->P(); + CoordType pEp = f1->V(1)->P(); + CoordType pFp = f1->V(2)->P(); + + CoordType axis1 = (pE-pD); + CoordType axis2 = (pF-pD); + CoordType N = axis1 ^ axis2; + + // axis adjustment + axis2 = N ^ axis1; + + axis1.Normalize(); + axis2.Normalize(); + N.Normalize(); + + double a = N[0]; + double b = N[1]; + double c = N[2]; + double d = -(a * pD[0] + b * pD[1] + c * pD[2]); + + // triangle in the local reference system + double xD,yD,xE,yE,xF,yF; + planeProjection(a,b,c,d, axis1, axis2, pD, pD, xD, yD); + planeProjection(a,b,c,d, axis1, axis2, pD, pE, xE, yE); + planeProjection(a,b,c,d, axis1, axis2, pD, pF, xF, yF); + + // triangle in the local reference system after deformations + double xDp,yDp,xEp,yEp,xFp,yFp; + planeProjection(a,b,c,d, axis1, axis2, pD, pDp, xDp, yDp); + planeProjection(a,b,c,d, axis1, axis2, pD, pEp, xEp, yEp); + planeProjection(a,b,c,d, axis1, axis2, pD, pFp, xFp, yFp); + + // deformation + double uD = xDp - xD; + double vD = yDp - yD; + + double uE = xEp - xE; + double vE = yEp - yE; + + double uF = xFp - xF; + double vF = yFp - yF; + + // parameterization + double AA = (yE-yF) * xD + (yF-yD) * xE + (yD-yE) * xF; // AA = 2A + double factor = 1.0 / (AA); + + a1u = factor * ((xE*yF - xF*yE)*uD + (xF*yD - xD*yF)*uE + (xD*yE - xE*yD)*uF); + a2u = factor * ((yE-yF)*uD + (yF-yD)*uE + (yD-yE)*uF); + a3u = factor * ((xF-xE)*uD + (xD-xF)*uE + (xE-xD)*uF); + + a1v = factor * ((xE*yF - xF*yE)*vD + (xF*yD - xD*yF)*vE + (xD*yE - xE*yD)*vF); + a2v = factor * ((yE-yF)*vD + (yF-yD)*vE + (yD-yE)*vF); + a3v = factor * ((xF-xE)*vD + (xD-xF)*vE + (xE-xD)*vF); + + area = 0.5 * AA; + } + +// public methods +public: + + static double roughnessMultiscale(MeshType & refmesh, MeshType & mesh) + { + //...TODO... + return 0.0; + } + + static double roughnessSmoothing(MeshType & refmesh, MeshType & mesh) + { + //...TODO... + return 0.0; + } + + static double strainEnergy(MeshType & refmesh, MeshType & mesh) + { + double epsilonx, epsilony, epsilonz; + double gammaxy, gammayz, gammazx; + double epsilonx_prime, epsilony_prime, epsilonz_prime; + double epsilon_ii_squared; + double epsilon_ij_prime_epsilon_ij_prime; + double Sdelta; // Area of each triangle + double ni = 0.0; // Poisson's ratio + double E = 1.0; // Young's modulus + double lambda; // Lame's first parameter + double G; + double Warea, Wdistortion, W; + double u,v; + double a1u,a2u,a3u; + double a1v,a2v,a3v; + double x,y; + double D; + + FacePointer f0; + FacePointer f1; + + W = 0.0; + for (int i = 0; i < refmesh.fn; i++) + { + f0 = &refmesh.face[i]; + f1 = &mesh.face[i]; + + // displacement function are: + // u = a1u + x a2u + y a3u + // v = a1v + x a2v + y a3v + computingDisplacementFunctionCoefficients(f0, f1, a1u, a2u, a3u, a1v, a2v, a3v, Sdelta); + + // epsilonx = du / dx + epsilonx = a2u; + + // epsilony = dv / dy + epsilony = a3v; + + // epsilonz + epsilonz = (ni / (ni - 1.0)) * (epsilonx + epsilony); + + // gammaxy = dv / dx + du / dy + gammaxy = a2v + a3u; + gammayz = 0.0; + gammazx = 0.0; + + // strain energy for a single triangle + /////////////////////////////////////////////////////////////////////////////////////// + + epsilonx_prime = epsilonx - (epsilonx + epsilony + epsilonz) / 3.0; + epsilony_prime = epsilony - (epsilonx + epsilony + epsilonz) / 3.0; + epsilonz_prime = epsilonz - (epsilonx + epsilony + epsilonz) / 3.0; + + epsilon_ii_squared = (epsilonx + epsilony + epsilonz) * (epsilonx + epsilony + epsilonz); + epsilon_ij_prime_epsilon_ij_prime = epsilonx_prime * epsilonx_prime + epsilony_prime * epsilony_prime + + epsilonz_prime * epsilonz_prime + 0.5 * (gammaxy*gammaxy + gammayz*gammayz + gammazx*gammazx); + + lambda = (E * ni) / ((1.0 + ni) * (1 - 2.0 * ni)); + G = E / (2.0 * (1.0 + ni)); + + Warea = 0.5 * (lambda + 0.666666666666 * G) * epsilon_ii_squared * Sdelta; + Wdistortion = G * epsilon_ij_prime_epsilon_ij_prime * Sdelta; + W += Warea + Wdistortion; + } + + // Average Strain Energy (ASE) + ////////////////////////////////////////////////////////////////////////// + + double area1 = vcg::tri::Stat::ComputeMeshArea(refmesh); + //double area2 = vcg::tri::Stat::ComputeMeshArea(mesh); + + // the area if the deformed mesh is considered the same of the original one, + // since the deformation is assumed to be small + + return W / (area1); + } + +}; + +#endif /* PERCEPTUALMETRICS_H */