From 42da29417b9996ae136998b7c19701d33eb1e81e Mon Sep 17 00:00:00 2001 From: cignoni Date: Fri, 5 Jul 2013 14:46:48 +0000 Subject: [PATCH] cleaned up a bit the interface and formatting of the code of the voronoiclustering alg --- vcg/complex/algorithms/voronoi_clustering.h | 343 ++++++++++---------- 1 file changed, 171 insertions(+), 172 deletions(-) diff --git a/vcg/complex/algorithms/voronoi_clustering.h b/vcg/complex/algorithms/voronoi_clustering.h index de639162..cfe68769 100644 --- a/vcg/complex/algorithms/voronoi_clustering.h +++ b/vcg/complex/algorithms/voronoi_clustering.h @@ -8,7 +8,7 @@ * \ * * All rights reserved. * * * -* This program is free software; you can redistribute it and/or modify * +* 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. * @@ -21,11 +21,9 @@ * * ****************************************************************************/ - #ifndef VORONOI_PROCESSING_H #define VORONOI_PROCESSING_H -//#include #include #include namespace vcg @@ -35,41 +33,38 @@ namespace tri template class ClusteringSampler - { - public: - typedef typename MeshType::VertexType VertexType; - - ClusteringSampler() - { - sampleVec=0; - } - ClusteringSampler(std::vector *_vec) - { - sampleVec = _vec; - } - std::vector *sampleVec; - - void AddVert(const VertexType &p) - { - sampleVec->push_back((VertexType *)(&p)); - } - }; // end class ClusteringSampler +{ +public: + typedef typename MeshType::VertexType VertexType; + + ClusteringSampler(std::vector &_vec): sampleVec(_vec) + { + sampleVec = _vec; + } + + std::vector &sampleVec; + + void AddVert(const VertexType &p) + { + sampleVec.push_back((VertexType *)(&p)); + } +}; // end class ClusteringSampler template class VoronoiProcessing { - typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::CoordType CoordType; typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexPointer VertexPointer; 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; - public: + public: // Given a vector of point3f it finds the closest vertices on the mesh. @@ -118,18 +113,18 @@ static void VoronoiColoring(MeshType &m, std::vector &seedVec, boo tri::Geodesic g; VertexPointer farthest; - if(frontierFlag) - { - //static_cast(NULL) has been introduced just to avoid an error in the MSVS2010's compiler confusing pointer with int. You could use nullptr to avoid it, but it's not supported by all compilers. - //The error should have been removed from MSVS2012 - std::pair zz(0.0f,static_cast(NULL)); - std::vector< std::pair > regionArea(m.vert.size(),zz); - std::vector borderVec; - GetAreaAndFrontier(m, sources, regionArea, borderVec); - tri::Geodesic::Compute(m,borderVec); - } + if(frontierFlag) + { + //static_cast(NULL) has been introduced just to avoid an error in the MSVS2010's compiler confusing pointer with int. You could use nullptr to avoid it, but it's not supported by all compilers. + //The error should have been removed from MSVS2012 + std::pair zz(0.0f,static_cast(NULL)); + std::vector< std::pair > regionArea(m.vert.size(),zz); + std::vector borderVec; + GetAreaAndFrontier(m, sources, regionArea, borderVec); + tri::Geodesic::Compute(m,borderVec); + } - tri::UpdateColor::PerVertexQualityRamp(m); + tri::UpdateColor::PerVertexQualityRamp(m); } // It associates the faces with a given vertex according to the vertex associations @@ -242,153 +237,157 @@ static void GetAreaAndFrontier(MeshType &m, PerVertexPointerHandle &sources, std::vector< std::pair > ®ionArea, std::vector &borderVec) { - tri::UpdateFlags::VertexClearV(m); - for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) - { - if( sources[(*fi).V(0)] != sources[(*fi).V(1)] || - sources[(*fi).V(0)] != sources[(*fi).V(2)] ) - { - for(int i=0;i<3;++i) - { - (*fi).V(i)->SetV(); - (*fi).V(i)->C() = Color4b::Black; - } - } - else // the face belongs to a single region; accumulate area; - { - if(sources[(*fi).V(0)] != 0) - { - int seedIndex = sources[(*fi).V(0)] - &*m.vert.begin(); - regionArea[seedIndex].first+=DoubleArea(*fi); - regionArea[seedIndex].second=sources[(*fi).V(0)]; - } - } - } - - // Collect the frontier vertexes - borderVec.clear(); - for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) - if((*vi).IsV()) borderVec.push_back(&*vi); + tri::UpdateFlags::VertexClearV(m); + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + if( sources[(*fi).V(0)] != sources[(*fi).V(1)] || + sources[(*fi).V(0)] != sources[(*fi).V(2)] ) + { + for(int i=0;i<3;++i) + { + (*fi).V(i)->SetV(); + (*fi).V(i)->C() = Color4b::Black; + } + } + else // the face belongs to a single region; accumulate area; + { + if(sources[(*fi).V(0)] != 0) + { + int seedIndex = sources[(*fi).V(0)] - &*m.vert.begin(); + regionArea[seedIndex].first+=DoubleArea(*fi); + regionArea[seedIndex].second=sources[(*fi).V(0)]; + } + } + } + + // Collect the frontier vertexes + borderVec.clear(); + for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) + if((*vi).IsV()) borderVec.push_back(&*vi); } static void VoronoiRelaxing(MeshType &m, std::vector &seedVec, int relaxIter, int /*percentileClamping*/, vcg::CallBackPos *cb=0) -{ - for(int iter=0;iter sources; - sources = tri::Allocator:: template AddPerVertexAttribute (m,"sources"); - - tri::Geodesic::Compute(m,seedVec,std::numeric_limits::max(),0,&sources); +{ + tri::RequireVFAdjacency(m); - // Delete all the (hopefully) small regions that have not been reached by the seeds; - tri::UpdateFlags::VertexClearV(m); - for(int i=0;i sources; + sources = tri::Allocator:: template AddPerVertexAttribute (m,"sources"); - for(FaceIterator fi=m.face.begin(); fi!=m.face.end();++fi) - if(fi->V(0)->IsV() || fi->V(1)->IsV() || fi->V(2)->IsV() ) - { - face::VFDetach(*fi); - tri::Allocator::DeleteFace(m,*fi); - } - qDebug("Deleted faces not reached: %i -> %i",int(m.face.size()),m.fn); - tri::Clean::RemoveUnreferencedVertex(m); - tri::Allocator::CompactFaceVector(m); - tri::Allocator::CompactVertexVector(m); + for(int iter=0;iter(NULL) has been introduced just to avoid an error in the MSVS2010's compiler confusing pointer with int. You could use nullptr to avoid it, but it's not supported by all compilers. - //The error should have been removed from MSVS2012 - std::pair zz(0.0f,static_cast(NULL)); - std::vector< std::pair > regionArea(m.vert.size(),zz); - std::vector borderVec; + tri::Geodesic::Compute(m,seedVec,std::numeric_limits::max(),0,&sources); - GetAreaAndFrontier(m, sources, regionArea, borderVec); - - // Smaller area region are discarded - Distribution H; + // Delete all the (hopefully) small regions that have not been reached by the seeds; + tri::UpdateFlags::VertexClearV(m); + for(int i=0;iV(0)->IsV() || fi->V(1)->IsV() || fi->V(2)->IsV() ) + { + face::VFDetach(*fi); + tri::Allocator::DeleteFace(m,*fi); + } + // qDebug("Deleted faces not reached: %i -> %i",int(m.face.size()),m.fn); + tri::Clean::RemoveUnreferencedVertex(m); + tri::Allocator::CompactFaceVector(m); + tri::Allocator::CompactVertexVector(m); + + //static_cast(NULL) has been introduced just to avoid an error in the MSVS2010's compiler confusing pointer with int. You could use nullptr to avoid it, but it's not supported by all compilers. + //The error should have been removed from MSVS2012 + std::pair zz(0.0f,static_cast(NULL)); + std::vector< std::pair > regionArea(m.vert.size(),zz); + std::vector borderVec; + + GetAreaAndFrontier(m, sources, regionArea, borderVec); + + // Smaller area region are discarded + Distribution H; for(size_t i=0;i::Compute(m,borderVec); - tri::UpdateColor::PerVertexQualityRamp(m); + if(regionArea[i].second) H.Add(regionArea[i].first); - // Search the local maxima for each region and use them as new seeds - std::vector< std::pair > seedMaxima(m.vert.size(),zz); - for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) - { - int seedIndex = tri::Index(m,sources[vi]); - if(seedMaxima[seedIndex].first < (*vi).Q()) - { - seedMaxima[seedIndex].first=(*vi).Q(); - seedMaxima[seedIndex].second=&*vi; - } - } - std::vector newSeeds; + float areaThreshold; + if(iter==0) areaThreshold = H.Percentile(.1f); + else areaThreshold = H.Percentile(.001f); + //qDebug("We have found %i regions range (%f %f), avg area is %f, Variance is %f 10perc is %f",(int)seedVec.size(),H.Min(),H.Max(),H.Avg(),H.StandardDeviation(),areaThreshold); + + if(cb) cb(iter*100/relaxIter,"Voronoi Lloyd Relaxation: Searching New Seeds"); + + tri::Geodesic::Compute(m,borderVec); + tri::UpdateColor::PerVertexQualityRamp(m); + + // Search the local maxima for each region and use them as new seeds + std::vector< std::pair > seedMaxima(m.vert.size(),zz); + for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) + { + int seedIndex = tri::Index(m,sources[vi]); + if(seedMaxima[seedIndex].first < (*vi).Q()) + { + seedMaxima[seedIndex].first=(*vi).Q(); + seedMaxima[seedIndex].second=&*vi; + } + } + std::vector newSeeds; for(size_t i=0;iC() = Color4b::Gray; - if(regionArea[i].first >= areaThreshold) - newSeeds.push_back(seedMaxima[i].second); - } - - tri::UpdateColor::PerVertexQualityRamp(m); + if(seedMaxima[i].second) + { + seedMaxima[i].second->C() = Color4b::Gray; + if(regionArea[i].first >= areaThreshold) + newSeeds.push_back(seedMaxima[i].second); + } + + tri::UpdateColor::PerVertexQualityRamp(m); for(size_t i=0;iC() = Color4b::Black; - + seedVec[i]->C() = Color4b::Black; + for(size_t i=0;iC() = Color4b::Gray; - - swap(newSeeds,seedVec); - + borderVec[i]->C() = Color4b::Gray; + + swap(newSeeds,seedVec); + for(size_t i=0;iC() = Color4b::White; + seedVec[i]->C() = Color4b::White; + } + tri::Allocator::DeletePerVertexAttribute (m,"sources"); - tri::Allocator::DeletePerVertexAttribute (m,"sources"); - - } } -// Base vertex voronoi coloring algorithm. -// it assumes VF adjacency. No attempt of computing real geodesic distnace is done. Just a BFS visit starting from the seeds. -static void TopologicalVertexColoring(MeshType &m, std::vector &seedVec) -{ - std::queue VQ; - - tri::UpdateQuality::VertexConstant(m,0); - - for(size_t i=0;iQ()=i+1; - } - - while(!VQ.empty()) - { - VertexPointer vp = VQ.front(); - VQ.pop(); - - std::vector vertStar; - vcg::face::VVStarVF(vp,vertStar); - for(typename std::vector::iterator vv = vertStar.begin();vv!=vertStar.end();++vv) - { - if((*vv)->Q()==0) - { - (*vv)->Q()=vp->Q(); - VQ.push(*vv); - } - } - } // end while(!VQ.empty()) - } + +// Base vertex voronoi coloring algorithm. +// it assumes VF adjacency. No attempt of computing real geodesic distnace is done. Just a BFS visit starting from the seeds. +static void TopologicalVertexColoring(MeshType &m, std::vector &seedVec) +{ + std::queue VQ; + + tri::UpdateQuality::VertexConstant(m,0); + + for(size_t i=0;iQ()=i+1; + } + + while(!VQ.empty()) + { + VertexPointer vp = VQ.front(); + VQ.pop(); + + std::vector vertStar; + vcg::face::VVStarVF(vp,vertStar); + for(typename std::vector::iterator vv = vertStar.begin();vv!=vertStar.end();++vv) + { + if((*vv)->Q()==0) + { + (*vv)->Q()=vp->Q(); + VQ.push(*vv); + } + } + } // end while(!VQ.empty()) + +} // Drastic Simplification algorithm. // Similar in philosopy to the classic grid clustering but using a voronoi partition instead of the regular grid. @@ -397,22 +396,22 @@ static void TopologicalVertexColoring(MeshType &m, std::vector &se // mNew is created by collasping onto a single vertex all the vertices that lies in the same cluster. // Non degenerate triangles are preserved. -static void VoronoiClustering(MeshType &mOld, MeshType &mNew, std::vector &seedVec) +static void VoronoiClustering(MeshType &mOld, MeshType &mNew, std::vector &seedVec) { std::set clusteredFace; FaceIterator fi; for(fi=mOld.face.begin();fi!=mOld.face.end();++fi) { - if( (fi->V(0)->Q() != fi->V(1)->Q() ) && + if( (fi->V(0)->Q() != fi->V(1)->Q() ) && (fi->V(0)->Q() != fi->V(2)->Q() ) && (fi->V(1)->Q() != fi->V(2)->Q() ) ) - clusteredFace.insert( Point3i(int(fi->V(0)->Q()), int(fi->V(1)->Q()), int(fi->V(2)->Q()))); - } + clusteredFace.insert( Point3i(int(fi->V(0)->Q()), int(fi->V(1)->Q()), int(fi->V(2)->Q()))); + } tri::Allocator::AddVertices(mNew,seedVec.size()); for(size_t i=0;i< seedVec.size();++i) - mNew.vert[i].ImportLocal(*(seedVec[i])); + mNew.vert[i].ImportData(*(seedVec[i])); tri::Allocator::AddFaces(mNew,clusteredFace.size()); std::set::iterator fsi; ;