From e8866848429daf829cd2219fb660ca0b3ab2298f Mon Sep 17 00:00:00 2001 From: cignoni Date: Thu, 20 Oct 2011 22:26:46 +0000 Subject: [PATCH] moved voronoi_clustering here from meshlab... --- vcg/complex/algorithms/voronoi_clustering.h | 324 ++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 vcg/complex/algorithms/voronoi_clustering.h diff --git a/vcg/complex/algorithms/voronoi_clustering.h b/vcg/complex/algorithms/voronoi_clustering.h new file mode 100644 index 00000000..02b710c5 --- /dev/null +++ b/vcg/complex/algorithms/voronoi_clustering.h @@ -0,0 +1,324 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + + +#ifndef VORONOI_PROCESSING_H +#define VORONOI_PROCESSING_H + +//#include +#include +#include +namespace vcg +{ +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 + + + +template +class VoronoiProcessing +{ + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + 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: + + +// Given a vector of point3f it finds the closest vertices on the mesh. +static void SeedToVertexConversion(MeshType &m,std::vector &seedPVec,std::vector &seedVVec) +{ + typedef typename vcg::SpatialHashTable HashVertexGrid; + seedVVec.clear(); + + HashVertexGrid HG; + HG.Set(m.vert.begin(),m.vert.end()); + + const float dist_upper_bound=m.bbox.Diag()/10.0; + + typename std::vector::iterator pi; + for(pi=seedPVec.begin();pi!=seedPVec.end();++pi) + { + float dist; + VertexPointer vp; + vp=tri::GetClosestVertex(m, HG, *pi, dist_upper_bound, dist); + if(vp) + { + seedVVec.push_back(vp); + } + } +} + +typedef typename MeshType::template PerVertexAttributeHandle PerVertexPointerHandle; + +static void ComputePerVertexSources(MeshType &m, std::vector &seedVec) +{ + tri::Geo g; + VertexPointer farthest; + tri::Allocator::DeletePerVertexAttribute(m,"sources"); // delete any conflicting handle regardless of the type... + PerVertexPointerHandle sources = tri::Allocator:: template AddPerVertexAttribute (m,"sources"); + assert(tri::Allocator::IsValidHandle(m,sources)); + g.FarthestVertex(m,seedVec,farthest,std::numeric_limits::max(),&sources); +} + +static void VoronoiColoring(MeshType &m, std::vector &seedVec, bool frontierFlag=true) +{ + PerVertexPointerHandle sources = tri::Allocator:: template GetPerVertexAttribute (m,"sources"); + assert(tri::Allocator::IsValidHandle(m,sources)); + tri::Geo g; + VertexPointer farthest; + + if(frontierFlag) + { + std::pair zz(0,0); + std::vector< std::pair > regionArea(m.vert.size(),zz); + std::vector borderVec; + GetAreaAndFrontier(m, sources, regionArea, borderVec); + g.FarthestVertex(m,borderVec,farthest); + } + + tri::UpdateColor::VertexQualityRamp(m); +} + +// Given a seed, it selects all the faces such with at least one vertex sourced by the passed VertexPointer. +// Faces are selected more than once. +static void SelectRegion(MeshType &m, VertexPointer vp) +{ + PerVertexPointerHandle sources = tri::Allocator:: template GetPerVertexAttribute (m,"sources"); + assert(tri::Allocator::IsValidHandle(m,sources)); + tri::UpdateSelection::ClearFace(m); + tri::UpdateSelection::ClearVertex(m); + + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + if( sources[(*fi).V(0)] == vp || + sources[(*fi).V(1)] == vp || + sources[(*fi).V(2)] == vp) + fi->SetS(); + } + tri::UpdateSelection::VertexFromFaceLoose(m); + +} + +// find the vertexes of frontier faces +// and compute Area of all the regions +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); +} + +static void VoronoiRelaxing(MeshType &m, std::vector &seedVec, int relaxIter, int /*percentileClamping*/, vcg::CallBackPos *cb=0) +{ + for(int iter=0;iter g; + VertexPointer farthest; + // first run: find for each point what is the closest to one of the seeds. + typename MeshType::template PerVertexAttributeHandle sources; + sources = tri::Allocator:: template AddPerVertexAttribute (m,"sources"); + + g.FarthestVertex(m,seedVec,farthest,std::numeric_limits::max(),&sources); + + std::pair zz(0,0); + 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::VertexQualityRamp(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 = sources[vi] - &*m.vert.begin(); + 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::VertexQualityRamp(m); + for(size_t i=0;iC() = Color4b::Black; + + for(size_t i=0;iC() = Color4b::Gray; + + swap(newSeeds,seedVec); + + for(size_t i=0;iC() = Color4b::White; + + 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()) + + } + + // This function assumes that in the mOld mesh, for each vertex you have a quality that denotes the index of the cluster + // 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) +{ + std::set clusteredFace; + + FaceIterator fi; + for(fi=mOld.face.begin();fi!=mOld.face.end();++fi) + { + 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()))); + } + + tri::Allocator::AddVertices(mNew,seedVec.size()); + for(size_t i=0;i< seedVec.size();++i) + mNew.vert[i].ImportLocal(*(seedVec[i])); + + tri::Allocator::AddFaces(mNew,clusteredFace.size()); + std::set::iterator fsi; ; + + for(fi=mNew.face.begin(),fsi=clusteredFace.begin(); fsi!=clusteredFace.end();++fsi,++fi) + { + (*fi).V(0) = & mNew.vert[(int)(fsi->V(0)-1)]; + (*fi).V(1) = & mNew.vert[(int)(fsi->V(1)-1)]; + (*fi).V(2) = & mNew.vert[(int)(fsi->V(2)-1)]; + } +} + +}; + +} // end namespace tri +} // end namespace vcg +#endif