From 3963786487e73b61bf27c851f07c5e71c7caa47f Mon Sep 17 00:00:00 2001 From: cignoni Date: Tue, 6 May 2014 23:13:22 +0000 Subject: [PATCH] Complete rewrote of the function that convert a mesh with a set of seeds and geodesic distances computed from them into a voronoi diagram mesh. Now works also in strange cases (like almost degenerate regions) --- vcg/complex/algorithms/voronoi_processing.h | 162 ++++++++++++++++---- 1 file changed, 136 insertions(+), 26 deletions(-) diff --git a/vcg/complex/algorithms/voronoi_processing.h b/vcg/complex/algorithms/voronoi_processing.h index eef71f23..8c0057f8 100644 --- a/vcg/complex/algorithms/voronoi_processing.h +++ b/vcg/complex/algorithms/voronoi_processing.h @@ -24,10 +24,11 @@ #ifndef VORONOI_PROCESSING_H #define VORONOI_PROCESSING_H -#include -#include -#include +#include +#include +#include #include +#include namespace vcg @@ -35,26 +36,6 @@ namespace vcg namespace tri { -template -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 - - struct VoronoiProcessingParameter { enum { @@ -411,6 +392,132 @@ static VertexPointer CommonSourceBetweenBorderCorner(FacePointer f0, FacePointer return 0; } + +static void ConvertVoronoiDiagramToMesh(MeshType &m, + MeshType &outMesh, MeshType &outPoly, + std::vector &seedVec, + VoronoiProcessingParameter &vpp ) +{ + tri::RequirePerVertexAttribute(m,"sources"); + PerVertexPointerHandle sources = tri::Allocator:: template GetPerVertexAttribute (m,"sources"); + outMesh.Clear(); + outPoly.Clear(); + tri::UpdateTopology::FaceFace(m); + tri::UpdateFlags::FaceBorderFromFF(m); + + std::vector innerCornerVec, // Faces adjacent to three different regions + borderCornerVec; // Faces that are on the border and adjacent to at least two regions. + GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec); + + // For each seed collect all the vertices and build + for(int i=0;i::AddVertex(outMesh,seedVec[i]->P(),Color4b::DarkGray); + + for(int i=0;i pt; + for(int j=0;jV(qq)] == curSeed) + { + pt.push_back(Barycenter(*innerCornerVec[j])); + break; + } + for(int j=0;jV(qq)] == curSeed) + { + pt.push_back(Barycenter(*borderCornerVec[j])); + break; + } + Plane3f pl; + pt.push_back(curSeed->P()); + FitPlaneToPointSet(pt,pl); + pt.pop_back(); + Point3f nZ = pl.Direction(); + Point3f nX = (pt[0]-curSeed->P()).Normalize(); + Point3f nY = (nX^nZ).Normalize(); + vector > angleVec(pt.size()); + for(int j=0;jP()).Normalize(); + float angle = 180.0f+math::ToDeg(atan2(p*nY,p*nX)); + angleVec[j] = make_pair(angle,j); + } + std::sort(angleVec.begin(),angleVec.end()); + // Now build another piece of mesh. + int curRegionStart=outMesh.vert.size(); + + + for(int j=0;j::AddVertex(outMesh,pt[angleVec[j].second],Color4b::LightGray); + + for(int j=0;j::AddFace(outMesh, + &outMesh.vert[i ], + &outMesh.vert[curRegionStart + j ], + &outMesh.vert[curRegionStart + ((j+1)%pt.size())]); + outMesh.face.back().SetF(0); + outMesh.face.back().SetF(2); + } + } // end for each seed. + tri::Clean::RemoveDuplicateVertex(outMesh); + tri::UpdateTopology::FaceFace(outMesh); + + // last loop to remove faux edges bit that are now on the boundary. + for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) + for(int i=0;i<3;++i) + if(face::IsBorder(*fi,i) && fi->IsF(i)) fi->ClearF(i); + + std::vector< typename tri::UpdateTopology::PEdge> EdgeVec; + + // ******************* star to tri conversion ********* + // If requested the voronoi regions are converted from a star arragned polygon + // with vertex on the seed to a simple triangulated polygon by mean of a simple edge collapse + if(vpp.triangulateRegion) + { + tri::UpdateFlags::FaceBorderFromFF(outMesh); + tri::UpdateFlags::VertexBorderFromFace(outMesh); + for(FaceIterator fi=outMesh.face.begin();fi!=outMesh.face.end();++fi) if(!fi->IsD()) + { + for(int i=0;i<3;++i) + { + bool b0 = fi->V0(i)->IsB(); + bool b1 = fi->V1(i)->IsB(); + if( ((b0 && b1) || (fi->IsF(i) && !b0) ) && + tri::Index(outMesh,fi->V(i))V(i))]->IsS()) + if(face::FFLinkCondition(*fi, i)) + { + face::FFEdgeCollapse(outMesh, *fi,i); + break; + } + } + } + } + } + + // Now a plain conversion of the non faux edges into a polygonal mesh + tri::UpdateTopology::FillUniqueEdgeVector(outMesh,EdgeVec,false); + tri::UpdateTopology::AllocateEdge(outMesh); + for(size_t i=0;i::AddVertex(outPoly,outMesh.vert[i].P()); + for(size_t i=0;i::AddEdge(outPoly,&(outPoly.vert[e0]),&(outPoly.vert[e1])); + } + +} + /// \brief Build a mesh of voronoi diagram from the given seeds /// /// This function assumes that you have just run a geodesic like algorithm over your mesh using @@ -421,7 +528,7 @@ static VertexPointer CommonSourceBetweenBorderCorner(FacePointer f0, FacePointer /// tri::Geodesic::Compute(m, seedVec, df, std::numeric_limits::max(),0,&sources); /// -static void ConvertVoronoiDiagramToMesh(MeshType &m, +static void ConvertVoronoiDiagramToMeshOld(MeshType &m, MeshType &outMesh, MeshType &outPoly, std::vector &seedVec, VoronoiProcessingParameter &vpp ) @@ -939,7 +1046,9 @@ static bool QuadricRelax(MeshType &m, std::vector &seedVec, } } - tri::UpdateColor::PerVertexQualityRamp(m); + if(vpp.colorStrategy==VoronoiProcessingParameter::DistanceFromBorder) + tri::UpdateColor::PerVertexQualityRamp(m); + // tri::io::ExporterPLY::Save(m,"last.ply",tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY ); bool seedChanged=false; // update the seedvector with the new maxima (For the vertex not fixed) @@ -981,7 +1090,8 @@ static bool GeodesicRelax(MeshType &m, std::vector &seedVec, std:: std::vector::VertDist> biasedFrontierVec; BuildBiasedSeedVec(m,df,seedVec,frontierVec,biasedFrontierVec,vpp); tri::Geodesic::Visit(m,biasedFrontierVec,df); - tri::UpdateColor::PerVertexQualityRamp(m); + if(vpp.colorStrategy == VoronoiProcessingParameter::DistanceFromSeed) + tri::UpdateColor::PerVertexQualityRamp(m); // tri::io::ExporterPLY::Save(m,"last.ply",tri::io::Mask::IOM_VERTCOLOR + tri::io::Mask::IOM_VERTQUALITY ); if(vpp.colorStrategy == VoronoiProcessingParameter::DistanceFromBorder)