From 4b29ec5ef6cd50849138ad1a9fbf9c4f3459a467 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 25 Jan 2017 17:25:26 +0100 Subject: [PATCH] first release version of polygonal algorithms methods --- .gitignore | 25 +- vcg/complex/algorithms/polygonal_algorithms.h | 957 ++++++++++++++++++ 2 files changed, 981 insertions(+), 1 deletion(-) create mode 100644 vcg/complex/algorithms/polygonal_algorithms.h diff --git a/.gitignore b/.gitignore index caf98bf3..a624d444 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,27 @@ release/ /docs/Doxygen/html/ # Intermediate Files -*.bc \ No newline at end of file +*.bc +apps/sample/polygonmesh_dual/polygonmesh_base + +*.stash + +apps/sample/polygonmesh_dual/dual_dual.obj + +apps/sample/polygonmesh_dual/dual.obj + +apps/sample/polygonmesh_dual/Makefile + +apps/sample/polygonmesh_dual/plylib.o + +*.o + +*.ply + +*.obj + +apps/sample/polygonmesh_optimize/polygonmesh_base + +apps/sample/polygonmesh_optimize/Makefile + +vcg/complex/algorithms/polygonal_algorithmsOLD.h diff --git a/vcg/complex/algorithms/polygonal_algorithms.h b/vcg/complex/algorithms/polygonal_algorithms.h new file mode 100644 index 00000000..d25fd400 --- /dev/null +++ b/vcg/complex/algorithms/polygonal_algorithms.h @@ -0,0 +1,957 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004-2016 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +#ifndef __VCGLIB_POLY_MESH_ALGORITHM +#define __VCGLIB_POLY_MESH_ALGORITHM + +#include +#include +#include +#include +#include +#include +#include + +//define a temporary triangle mesh type +class TempFace; +class TempVertex; + +struct TempUsedTypes: public vcg::UsedTypes::AsVertexType, + vcg::Use::AsFaceType>{}; + +class TempVertex:public vcg::Vertex +{}; + +class TempFace:public vcg::Face +{}; + + +class TempMesh: public vcg::tri::TriMesh< std::vector,std::vector > +{}; + +namespace vcg{ + +/*! +\ingroup PolyMeshType + +\headerfile color.h vcg/complex/algorithms/polygonal_algorithms.h + +\brief processing and optimization of generic polygonal meshes. + +This class is used to performs varisous kind of geometric optimization on generic polygonal mesh such as flattengin or imptove the shape of polygons. +*/ + +template +class PolygonalAlgorithm +{ + typedef typename PolyMeshType::FaceType FaceType; + typedef typename PolyMeshType::VertexType VertexType; + typedef typename PolyMeshType::CoordType CoordType; + typedef typename PolyMeshType::ScalarType ScalarType; + + + static bool CollapseBorderSmallEdgesStep(PolyMeshType &poly_m, + const ScalarType edge_limit) + { + bool collapsed=false; + + //update topology + vcg::tri::UpdateTopology::FaceFace(poly_m); + + //update border vertices + //UpdateBorderVertexFromPFFAdj(poly_m); + vcg::tri::UpdateFlags::VertexBorderFromFaceAdj(poly_m); + + //get border edges + std::vector > IsBorder; + BorderEdgeFromPFFAdj(poly_m,IsBorder); + + //deselect all vertices + vcg::tri::UpdateFlags::VertexClearS(poly_m); + + //this set how to remap the vertices after deletion + std::map VertexRemap; + + //go over all faces and check the ones needed to be deleted + for (size_t i=0;iIsB(); + bool IsBV1=v1->IsB(); + + //in these cases is not possible to collapse + if ((!IsBV0)&&(!IsBV1))continue; + if ((!IsBorder[i][j])&&(IsBV0)&&(IsBV1))continue; + if (v0->IsS())continue; + if (v1->IsS())continue; + + assert((IsBV0)||(IsBV1)); + CoordType pos0=v0->P(); + CoordType pos1=v1->P(); + ScalarType currL=(pos0-pos1).Norm(); + if (currL>edge_limit)continue; + + //then collapse the point + CoordType InterpPos; + if ((IsBV0)&&(!IsBV1))InterpPos=pos0; + if ((!IsBV0)&&(IsBV1))InterpPos=pos1; + if ((IsBV0)&&(IsBV1))InterpPos=(pos0+pos1)/2.0; + + //put on the same position + v0->P()=InterpPos; + v1->P()=InterpPos; + + //select the the two vertices + v0->SetS(); + v1->SetS(); + + //set the remap + VertexRemap[v1]=v0; + + collapsed=true; + } + } + + //then remap vertices + for (size_t i=0;i FaceV; + for (int j=0;j &AvVert) + { + //cumulate step + AvVert.clear(); + AvVert.resize(poly_m.vert.size(),CoordType(0,0,0)); + std::vector AvSum(poly_m.vert.size(),0); + for (size_t i=0;iP(); + //cumulate over other positions + ScalarType W=vcg::PolyArea(poly_m.face[i]); + //assert(W!=0); + for (size_t k=0;k<(size_t)poly_m.face[i].VN();k++) + { + if (k==j)continue; + int IndexV=vcg::tri::Index(poly_m,poly_m.face[i].V(k)); + AvVert[IndexV]+=currP*W; + AvSum[IndexV]+=W; + } + } + + //average step + for (size_t i=0;i PlF; + PlF=PolyFittingPlane(F); + if ((PlF.Direction()*F.N())<0) + F.N()=-PlF.Direction(); + else + F.N()=PlF.Direction(); + } + +public: + +// static void GetFaceNormals(FaceType &F, +// std::vector &Norms) +// { +// Norms.clear(); +// if (F.VN()<=2) return; +// for (int i=0;i &IsBorder) +// { +// IsBorder.resize(F.VN(),false); +// for (int j=0;j > &IsBorder) +// { +// IsBorder.resize(poly_m.face.size()); +// for (size_t i=0;i > IsBorderE; +// BorderEdgeFromPFFAdj(poly_m,IsBorderE); + +// //then update per vertex +// vcg::tri::UpdateFlags::VertexClearB(poly_m); +// for (size_t i=0;iSetB(); +// poly_m.face[i].V1(j)->SetB(); +// } +// } +// } + +// //METTERE IN QUALITY -> update quality +// static void PerVertexValence(PolyMeshType &poly_m, +// std::vector &Valence) +// { +// Valence.resize(poly_m.vert.size(),0); +// for (size_t i=0;i::PerFaceQualityRamp(poly_m); +// } + +// static void ColorScatterByQuality(PolyMeshType &poly_m) +// { +// //get the max of quality +// ScalarType MaxQ=0; +// for (size_t i=0;imaxV; +// for (size_t i=0;itestMax)val=testMax; +// if (!to_swap) +// poly_m.face[i].C()=vcg::Color4b::ColorRamp(testMin,testMax,poly_m.face[i].Q()); +// else +// poly_m.face[i].C()=vcg::Color4b::ColorRamp(testMax,testMin,poly_m.face[i].Q()); + +// } +// } + +// //DELETE +// static void ColorUniformly(PolyMeshType &poly_m, +// vcg::Color4b col=vcg::Color4b(200,200,200,255)) +// { +// vcg::tri::UpdateColor::PerFaceConstant(poly_m,col); +// } + + /*! \brief given a face this function returns the template positions as in "Statics Aware Grid Shells" + */ + static void GetRotatedTemplatePos(FaceType &f, + std::vector &TemplatePos) + { + vcg::GetPolyTemplatePos(f,TemplatePos,true); + + CoordType NormT=Normal(TemplatePos); + //get the normal of vertices + CoordType AVN(0,0,0); + CoordType Origin(0,0,0); + for (int j=0;jN(); + + for (size_t j=0;j Rot=vcg::RotationMatrix(NormT,AVN); + + //apply transformation + for (size_t j=0;j avgPos(poly_m.vert.size(),CoordType(0,0,0)); + std::vector weightSum(poly_m.vert.size(),0); + //then compute the templated positions + for (size_t i=0;i TemplatePos; + GetRotatedTemplatePos(poly_m.face[i],TemplatePos); + //then cumulate the position per vertex + ScalarType val=vcg::PolyArea(poly_m.face[i]); + if (val<(AvgArea*0.00001)) + val=(AvgArea*0.00001); + ScalarType W=1.0/val;//poly_m.face[i].Q(); + //ScalarType W=1; + + for (size_t j=0;j AvVert; + LaplacianPos(poly_m,AvVert); + //then update the position + for (size_t i=0;i1)alpha=1; + // if (isnan(alpha))alpha=1; + CoordType newP=avgPos[i]/weightSum[i]; + newP=newP*(1-alpha)+AvVert[i]*alpha; + if ((fixB)&&(poly_m.vert[i].IsB()))continue; + if ((fixIrr)&&(poly_m.vert[i].IsS()))continue; + poly_m.vert[i].P()=poly_m.vert[i].P()*Damp+ + newP*(1-Damp); + } + } + } + + /*! \brief This function smooth the borders of the polygonal mesh and reproject back to the triangolar one + * except the vertices that are considered as corner wrt the angleDeg threshold + */ + template + static void LaplacianReprojectBorder(PolyMeshType &poly_m, + TriMeshType &tri_mesh, + int nstep=100, + ScalarType Damp=0.5, + ScalarType angleDeg=100) + { + typedef typename TriMeshType::FaceType FaceType; + + //first select corners + vcg::tri::UpdateFlags::VertexClearS(poly_m); + + //update topology + vcg::tri::UpdateTopology::FaceFace(poly_m); + + //update border vertices + vcg::tri::UpdateFlags::VertexBorderFromFaceAdj(poly_m); + + //select corner vertices on the border + ScalarType angleRad=angleDeg * M_PI / 180; + vcg::tri::UpdateFlags::SelectVertexCornerBorder(poly_m,angleRad); + + for (int s=0;s AvVert; + LaplacianPos(poly_m,AvVert); + + for (size_t i=0;i::max(); + CoordType closPos; + for (size_t j=0;j Seg(P0,P1); + ScalarType testD; + CoordType closTest; + vcg::SegmentPointDistance(Seg,testPos,closTest,testD); + if (testD>minD)continue; + minD=testD; + closPos=closTest; + } + poly_m.vert[i].P()=closPos; + } + } + } + + /*! \brief This function smooth the borders of the polygonal mesh and reproject back to its border + */ + static void LaplacianReprojectBorder(PolyMeshType &poly_m, + int nstep=100, + ScalarType Damp=0.5) + { + //transform into triangular + TempMesh GuideSurf; + vcg::tri::PolygonSupport::ImportFromPolyMesh(GuideSurf,poly_m); + vcg::tri::UpdateBounding::Box(GuideSurf); + vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(GuideSurf); + vcg::tri::UpdateTopology::FaceFace(GuideSurf); + vcg::tri::UpdateFlags::FaceBorderFromFF(GuideSurf); + + LaplacianReprojectBorder(poly_m,GuideSurf,nstep,Damp); + } + + /*! \brief This function performs the reprojection of the polygonal mesh onto a triangular one passed as input parameter + */ + template + static void LaplacianReproject(PolyMeshType &poly_m, + TriMeshType &tri_mesh, + bool fixIrr=false, + int nstep=100, + ScalarType Damp=0.5) + { + typedef typename TriMeshType::FaceType FaceType; + typedef vcg::GridStaticPtr TriMeshGrid; + TriMeshGrid grid; + + //initialize the grid + grid.Set(tri_mesh.face.begin(),tri_mesh.face.end()); + + ScalarType MaxD=tri_mesh.bbox.Diag(); + + if (fixIrr) + poly_m.NumIrregular(true); + for (int s=0;s AvVert; + LaplacianPos(poly_m,AvVert); + + for (size_t i=0;i + static void SmoothReprojectPCA(PolyMeshType &poly_m, + TriMeshType &tri_mesh, + int relaxStep=100, + bool fixIrr=false, + ScalarType Damp=0.5) + { + vcg::tri::UpdateTopology::FaceFace(poly_m); + + //UpdateBorderVertexFromPFFAdj(poly_m); + vcg::tri::UpdateFlags::VertexBorderFromFaceAdj(poly_m); + + typedef typename TriMeshType::FaceType FaceType; + typedef vcg::GridStaticPtr TriMeshGrid; + TriMeshGrid grid; + + //initialize the grid + grid.Set(tri_mesh.face.begin(),tri_mesh.face.end()); + + ScalarType MaxD=tri_mesh.bbox.Diag(); + + // //update quality as area + // for (size_t i=0;i::ImportFromPolyMesh(GuideSurf,poly_m); + vcg::tri::UpdateBounding::Box(GuideSurf); + vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(GuideSurf); + vcg::tri::UpdateTopology::FaceFace(GuideSurf); + vcg::tri::UpdateFlags::FaceBorderFromFF(GuideSurf); + + //optimize it + vcg::PolygonalAlgorithm::SmoothReprojectPCA(poly_m,GuideSurf,relaxStep,fixIrr,Damp); + } + + /*! \brief This function return average edge size + */ + static ScalarType AverageEdge(PolyMeshType &poly_m) + { + ScalarType AvL=0; + size_t numE=0; + for (size_t i=0;iP(); + CoordType pos1=poly_m.face[i].V((j+1)%NumV)->P(); + AvL+=(pos0-pos1).Norm(); + numE++; + } + } + AvL/=numE; + return AvL; + } + + + /*! \brief This function remove valence 2 faces from the mesh + */ + static void RemoveValence2Faces(PolyMeshType &poly_m) + { + for (size_t i=0;i=3)continue; + vcg::tri::Allocator::DeleteFace(poly_m,poly_m.face[i]); + } + + //then remove unreferenced vertices + vcg::tri::Clean::RemoveUnreferencedVertex(poly_m); + vcg::tri::Allocator::CompactEveryVector(poly_m); + + } + + /*! \brief This function remove valence 2 vertices on the border by considering the degree threshold + * bacause there could be eventually some corner that should be preserved + */ + static void RemoveValence2BorderVertices(PolyMeshType &poly_m, + ScalarType corner_degree=25) + { + //update topology + vcg::tri::UpdateTopology::FaceFace(poly_m); + + //update border vertices + //UpdateBorderVertexFromPFFAdj(poly_m); + vcg::tri::UpdateFlags::VertexBorderFromFaceAdj(poly_m); + + vcg::tri::UpdateFlags::VertexClearS(poly_m); + + //select corners + for (size_t i=0;iIsB())||(!v1->IsB())||(!v2->IsB()))continue; + CoordType dir0=(v0->P()-v1->P()); + CoordType dir1=(v2->P()-v1->P()); + dir0.Normalize(); + dir1.Normalize(); + ScalarType testDot=(dir0*dir1); + if (testDot>(-cos(corner_degree* (M_PI / 180.0)))) + v1->SetS(); + } + } + + typename PolyMeshType::template PerVertexAttributeHandle valenceVertH = + vcg::tri::Allocator:: template GetPerVertexAttribute (poly_m); + + //initialize to zero + for (size_t i=0;i FaceV; + for (size_t j=0;jIsD()); + if ((!v->IsS()) && (v->IsB()) && (valenceVertH[v]==1)) continue; + FaceV.push_back(v); + } + + //then deallocate face + if (FaceV.size()==NumV)continue; + + //otherwise deallocate and set new vertices + poly_m.face[i].Dealloc(); + poly_m.face[i].Alloc(FaceV.size()); + for (size_t j=0;j::RemoveUnreferencedVertex(poly_m); + vcg::tri::Allocator::CompactEveryVector(poly_m); + + vcg::tri::Allocator::DeletePerVertexAttribute(poly_m,valenceVertH); + } + + /*! \brief This function collapse small edges which are on the boundary of the mesh + * this is sometimes useful to remove small edges coming out from a quadrangulation which is not + * aligned to boundaries + */ + static void CollapseBorderSmallEdges(PolyMeshType &poly_m,const ScalarType perc_average=0.3) + { + //compute the average edge + ScalarType AvEdge=AverageEdge(poly_m); + ScalarType minLimit=AvEdge*perc_average; + + while(CollapseBorderSmallEdgesStep(poly_m,minLimit)){}; + + RemoveValence2Faces(poly_m); + + RemoveValence2BorderVertices(poly_m); + } + + /*! \brief This function use a local global approach to flatten polygonal faces + * the approach is similar to "Shape-Up: Shaping Discrete Geometry with Projections" + */ + static ScalarType FlattenFaces(PolyMeshType &poly_m, size_t steps=100,bool OnlySFaces=false) + { + ScalarType MaxDispl=0; + for (size_t s=0;s > VertPos(poly_m.vert.size()); + + for (size_t i=0;i FacePos; + for (int j=0;jIsD()); + FacePos.push_back(v->P()); + } + + //then fit the plane + vcg::Plane3 FitPl; + vcg::FitPlaneToPointSet(FacePos,FitPl); + + //project each point onto fitting plane + for (int j=0;jP()); + VertPos[IndexV].push_back(ProjP); + } + } + + for (size_t i=0;i