You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

167 lines
8.3 KiB

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2022 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef __VCGLIB_REFINE_DOOSABIN_H
#define __VCGLIB_REFINE_DOOSABIN_H
namespace vcg {
namespace tri {
/// \ingroup trimesh
/// \headerfile refine_doosabin.h vcg/complex/algorithms/refine_doosabin.h
/// \brief This class is used convert between polygonal meshes and triangular meshes
/**
This class contains two members that allow to build a triangular mesh from a polygonal mesh
and viceversa. In a trimesh, the generic polygons with n sides are codified represented by
tagging the internal edge of the face as 'faux' with the SetF.
*/
template <class PolyMeshType>
class DooSabin {
typedef typename PolyMeshType::FaceType FaceType;
typedef typename PolyMeshType::FacePointer FacePointer;
typedef typename PolyMeshType::FaceIterator FaceIterator;
typedef typename PolyMeshType::VertexIterator VertexIterator;
public:
static void Refine(PolyMeshType &baseIn, PolyMeshType &refinedOut, int iterationNum=1)
{
tri::RequirePolygonalMesh(baseIn);
tri::RequirePolygonalMesh(refinedOut);
tri::RequireFFAdjacency(baseIn);
// fprintf(stdout,"Refining starting \n");fflush(stdout);
PolyMeshType refined;
PolyMeshType base;
Append<PolyMeshType,PolyMeshType>::MeshCopy(base,baseIn);
for(int step = 0; step<iterationNum;++step)
{
refined.Clear();
// fprintf(stdout,"Refining iteration %i mesh has %i faces\n",step,base.FN() );fflush(stdout);
UpdateTopology<PolyMeshType>::FaceFace(base);
// tri::UpdateTopology<PolyMeshType>::VertexFace(base);
typedef typename PolyMeshType :: template PerVertexAttributeHandle<int> VertexIntHandleType;
typedef typename PolyMeshType :: template PerFaceAttributeHandle<int> FaceIntHandleType;
typedef typename PolyMeshType :: template PerVertexAttributeHandle<std::pair<FacePointer,int> > VertexPairHandleType;
// This handle stores for each vertex v the index of the face that I have added to the refined mesh
VertexIntHandleType FaceVertIndVH = vcg::tri::Allocator<PolyMeshType>:: template GetPerVertexAttribute<int>(base,"facevertInd");
// This handle stores for each face f the index of the first of the f.VN() vertexes that I have added for that face
FaceIntHandleType FaceVertBaseFH = vcg::tri::Allocator<PolyMeshType>:: template GetPerFaceAttribute<int>(base,"FaceVertBase");
// Computing the degree of each vertex and storing it in an attribute
VertexIntHandleType degreeVH = vcg::tri::Allocator<PolyMeshType>:: template GetPerVertexAttribute<int>(base,"degree");
VertexPairHandleType VFpH = vcg::tri::Allocator<PolyMeshType>:: template GetPerVertexAttribute<std::pair<FacePointer,int> >(base,"VFP");
for(auto vi=base.vert.begin();vi!=base.vert.end();vi++)
degreeVH[*vi]=0;
for(auto fi=base.face.begin();fi!=base.face.end();fi++)
{
for(int j=0;j<fi->VN();++j)
{
degreeVH[fi->V(j)]= degreeVH[fi->V(j)]+1;
VFpH[fi->V(j)] = std::make_pair(&*fi,j);
}
}
// This map indicates for each corner of each face of the base mesh,
// what is the index of the vertex I have created.
std::map<std::pair<int,int>,int> faceCornerToNewVertMap;
// First create a new face for each face of the base mesh
for(auto fi=base.face.begin();fi!=base.face.end();fi++)
{
Point3f b = PolyBarycenter(*fi);
auto newf = tri::Allocator<PolyMeshType>::AddFaces(refined,1);
newf->Alloc(fi->VN());
FaceVertBaseFH[fi]= refined.vert.size();
for(int j=0;j<fi->VN();++j)
{
auto newv = tri::Allocator<PolyMeshType>::AddVertex(refined,(fi->V(j)->P()+b)/2.0f);
newf->V(j)=&*newv;
faceCornerToNewVertMap[std::make_pair(tri::Index(base,*fi),j)] = tri::Index(refined,*newv);
}
}
// second loop creating a face for each vertex
for(auto vi=base.vert.begin();vi!=base.vert.end();vi++)
{
auto newf = tri::Allocator<PolyMeshType>::AddFaces(refined,1);
newf->Alloc(degreeVH[vi]);
FaceVertIndVH[tri::Index(refined, *newf)];
FacePointer curf = VFpH[&*vi].first;
int curi = VFpH[&*vi].second;
face::Pos<FaceType> startPos(curf,curi);
assert(curf->V(curi) == &*vi);
std::vector<face::Pos<FaceType> > starPosVec;
face::VFOrderedStarFF(startPos,starPosVec,false);
assert(starPosVec.size() == (size_t)degreeVH[vi]);
for(size_t i =0 ; i < starPosVec.size(); ++i)
{
int vind = starPosVec[i].VInd();
int fpind = tri::Index(base, starPosVec[i].F());
auto newvi = faceCornerToNewVertMap[std::make_pair(fpind,vind)];
newf->V(i) = &refined.vert[newvi];
}
}
// Third loop creating the faces on the edges
tri::UpdateFlags<PolyMeshType>::FaceClearV(base);
for(auto fi=base.face.begin();fi!=base.face.end();fi++)
{
fi->SetV();
for(int j=0;j<fi->VN();++j)
{
if(fi->FFp(j)->IsV())
{
auto newf = tri::Allocator<PolyMeshType>::AddFaces(refined,1);
int newvi;
newf->Alloc(4);
face::Pos<FaceType> startPos(&*fi,j);
newvi = faceCornerToNewVertMap[std::make_pair((int)(tri::Index(base, startPos.F())),startPos.VInd())];
newf->V(3) = &refined.vert[newvi];
startPos.FlipV();
newvi = faceCornerToNewVertMap[std::make_pair((int)(tri::Index(base, startPos.F())),startPos.VInd())];
newf->V(2) = &refined.vert[newvi];
startPos.FlipF();
newvi = faceCornerToNewVertMap[std::make_pair((int)(tri::Index(base, startPos.F())),startPos.VInd())];
newf->V(1) = &refined.vert[newvi];
startPos.FlipV();
newvi = faceCornerToNewVertMap[std::make_pair((int)(tri::Index(base, startPos.F())),startPos.VInd())];
newf->V(0) = &refined.vert[newvi];
}
}
}
Append<PolyMeshType,PolyMeshType>::MeshCopy(base,refined);
}
Append<PolyMeshType,PolyMeshType>::MeshCopy(refinedOut,refined);
} // end refine Function
}; // end DooSabin class
} // end namespace tri
} // end namespace vcg
#endif // __VCGLIB_REFINE_DOOSABIN_H