/**************************************************************************** * 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 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::MeshCopy(base,baseIn); for(int step = 0; step::FaceFace(base); // tri::UpdateTopology::VertexFace(base); typedef typename PolyMeshType :: template PerVertexAttributeHandle VertexIntHandleType; typedef typename PolyMeshType :: template PerFaceAttributeHandle FaceIntHandleType; typedef typename PolyMeshType :: template PerVertexAttributeHandle > 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:: template GetPerVertexAttribute(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:: template GetPerFaceAttribute(base,"FaceVertBase"); // Computing the degree of each vertex and storing it in an attribute VertexIntHandleType degreeVH = vcg::tri::Allocator:: template GetPerVertexAttribute(base,"degree"); VertexPairHandleType VFpH = vcg::tri::Allocator:: template GetPerVertexAttribute >(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;jVN();++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,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::AddFaces(refined,1); newf->Alloc(fi->VN()); FaceVertBaseFH[fi]= refined.vert.size(); for(int j=0;jVN();++j) { auto newv = tri::Allocator::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::AddFaces(refined,1); newf->Alloc(degreeVH[vi]); FaceVertIndVH[tri::Index(refined, *newf)]; FacePointer curf = VFpH[&*vi].first; int curi = VFpH[&*vi].second; face::Pos startPos(curf,curi); assert(curf->V(curi) == &*vi); std::vector > 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::FaceClearV(base); for(auto fi=base.face.begin();fi!=base.face.end();fi++) { fi->SetV(); for(int j=0;jVN();++j) { if(fi->FFp(j)->IsV()) { auto newf = tri::Allocator::AddFaces(refined,1); int newvi; newf->Alloc(4); face::Pos 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::MeshCopy(base,refined); } Append::MeshCopy(refinedOut,refined); } // end refine Function }; // end DooSabin class } // end namespace tri } // end namespace vcg #endif // __VCGLIB_REFINE_DOOSABIN_H