diff --git a/vcg/complex/algorithms/voronoi_processing.h b/vcg/complex/algorithms/voronoi_processing.h index 56ccdaf4..e3cf60ca 100644 --- a/vcg/complex/algorithms/voronoi_processing.h +++ b/vcg/complex/algorithms/voronoi_processing.h @@ -82,6 +82,8 @@ struct VoronoiProcessingParameter float collapseShortEdgePerc = 0.01f; bool geodesicRelaxFlag= true; + + CallBackPos *lcb=DummyCallBackPos; }; template > @@ -97,7 +99,7 @@ class VoronoiProcessing typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FaceContainer FaceContainer; typedef typename tri::Geodesic::VertDist VertDist; - + typedef typename face::Pos PosType; public: static math::MarsenneTwisterRNG &RandomGenerator() @@ -1118,7 +1120,7 @@ static bool GeodesicRelax(MeshType &m, std::vector &seedVec, std:: tri::UpdateColor::PerVertexQualityRamp(m); // Search the local maxima for each region and use them as new seeds - std::pair zz(0.0f,static_cast(NULL)); + std::pair zz(0.0f,nullptr); std::vector< std::pair > seedMaximaVec(m.vert.size(),zz); for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) { @@ -1193,8 +1195,7 @@ static void MarkVertexVectorAsFixed(MeshType &m, std::vector &vert static int RestrictedVoronoiRelaxing(MeshType &m, std::vector &seedPosVec, std::vector &fixedVec, int relaxStep, - VoronoiProcessingParameter &vpp, - vcg::CallBackPos *cb=0) + VoronoiProcessingParameter &vpp) { PerVertexFloatHandle area = tri::Allocator:: template GetPerVertexAttribute (m,"area"); @@ -1213,7 +1214,7 @@ static int RestrictedVoronoiRelaxing(MeshType &m, std::vector &seedPo ScalarType perturb = m.bbox.Diag()*vpp.seedPerturbationAmount; for(i=0;i > vdw(seedPosVec); KdTree seedTree(vdw); @@ -1656,6 +1657,7 @@ static void PreprocessForVoronoi(MeshType &m, ScalarType radius, for(int i=0;i(m,mid,min(edgeLen*2.0f,radius/vpp.refinementRatio)); if(!ret) break; } @@ -1788,6 +1790,145 @@ static void RelaxRefineTriangulationLaplacian(MeshType &m, MeshType &delaMesh, i } for(int i=origVertNum;i &seedVec) +{ + RequirePerVertexAttribute(m ,"sources"); + RequireCompactness(m); + RequireVFAdjacency(m); + + auto sources = Allocator::template GetPerVertexAttribute (m,"sources"); + + outMesh.Clear(); + UpdateTopology::FaceFace(m); + UpdateFlags::FaceBorderFromFF(m); + + std::map seedMap; // It says if a given vertex of m is a seed (and its index in seedVec) + BuildSeedMap(m, seedVec, seedMap); + + 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); + + // First add all the needed vertices: seeds and corners + + for(size_t i=0;i::AddVertex(outMesh, seedVec[i]->P(), vcg::Color4b::White); + } + + // Now just add one face for each inner corner + for(size_t i=0; iV(0)]; + VertexPointer s1 = sources[innerCornerVec[i]->V(1)]; + VertexPointer s2 = sources[innerCornerVec[i]->V(2)]; + assert ( (s0!=s1) && (s0!=s2) && (s1!=s2) ); + VertexPointer v0 = & outMesh.vert[seedMap[s0]]; + VertexPointer v1 = & outMesh.vert[seedMap[s1]]; + VertexPointer v2 = & outMesh.vert[seedMap[s2]]; + Allocator::AddFace(outMesh, v0, v1, v2); + } + + // Now loop around the borders and find the missing delaunay triangles + // select border seed vertices only and pick one + UpdateFlags::VertexBorderFromFaceAdj(m); + UpdateFlags::VertexClearS(m); + UpdateFlags::VertexClearV(m); + + std::vector borderSeeds; + for (auto & s : seedVec) + { + if (s->IsB()) + { + s->SetS(); + borderSeeds.emplace_back(s); + } + } + + for (VertexPointer startBorderVertex : borderSeeds) + { + if (startBorderVertex->IsV()) + { + continue; + } + + // unvisited border seed found + + // put the pos on the border + PosType pos(startBorderVertex->VFp(), startBorderVertex->VFi()); + do { + pos.NextE(); + } while (!pos.IsBorder() || (pos.VInd() != pos.E())); + + // check all border edges between each consecutive border seeds pair + do { + std::vector edgeVoroVertices(1, sources[pos.V()]); + // among all sources found + do { + pos.NextB(); + VertexPointer source = sources[pos.V()]; + if (edgeVoroVertices.empty() || edgeVoroVertices.back() != source) + { + edgeVoroVertices.push_back(source); + } + } while (!pos.V()->IsS()); + + pos.V()->SetV(); + +// assert(edgeVoroVertices.size() >= 2); + + + if (edgeVoroVertices.size() >= 3) + { + std::vector v; + for (size_t i=0; i3 vertices holes + for (size_t i=0; i::AddFace(outMesh, v[0],v[i+1],v[i+2]); + } +// if (edgeVoroVertices.size() > 3) +// { +// std::cout << "Weird case: " << edgeVoroVertices.size() << " voroseeds on one border" << std::endl; +// } + } +// // add face if 3 different voronoi regions are crossed by the edge +// if (edgeVoroVertices.size() == 3) +// { +// VertexPointer v0 = & outMesh.vert[seedMap[edgeVoroVertices[0]]]; +// VertexPointer v1 = & outMesh.vert[seedMap[edgeVoroVertices[1]]]; +// VertexPointer v2 = & outMesh.vert[seedMap[edgeVoroVertices[2]]]; +// Allocator::AddFace(outMesh, v0,v1,v2); +// } +// else +// { +// std::cout << "Weird case!! " << edgeVoroVertices.size() << " voroseeds on one border" << std::endl; +// if (edgeVoroVertices.size() == 4) +// { +// VertexPointer v0 = & outMesh.vert[seedMap[edgeVoroVertices[0]]]; +// VertexPointer v1 = & outMesh.vert[seedMap[edgeVoroVertices[1]]]; +// VertexPointer v2 = & outMesh.vert[seedMap[edgeVoroVertices[2]]]; +// VertexPointer v3 = & outMesh.vert[seedMap[edgeVoroVertices[3]]]; +// Allocator::AddFace(outMesh, v0,v1,v2); +// Allocator::AddFace(outMesh, v0,v2,v3); +// } +// } + + } while ((pos.V() != startBorderVertex)); + } + + + Clean::RemoveUnreferencedVertex(outMesh); + Allocator::CompactVertexVector(outMesh); +} + + }; // end class VoronoiProcessing } // end namespace tri diff --git a/vcg/complex/algorithms/voronoi_remesher.h b/vcg/complex/algorithms/voronoi_remesher.h index 3f206494..9d275f82 100644 --- a/vcg/complex/algorithms/voronoi_remesher.h +++ b/vcg/complex/algorithms/voronoi_remesher.h @@ -45,11 +45,11 @@ //#define DEBUG_VORO 1 -//#include #ifdef DEBUG_VORO #include #include +#include #endif namespace vcg { @@ -62,6 +62,7 @@ class VoroEdgeMeshAux class EUsedTypes : public vcg::UsedTypes::AsVertexType, vcg::Use::AsEdgeType> {}; class EmVertexType : public vcg::Vertex {}; @@ -133,12 +134,12 @@ protected: } public: - static const int VoroRelaxationStep = 40; + static const int VoroRelaxationStep = 10; /// /// \brief Remesh the main function that remeshes a mesh preserving creases. /// \param original the mesh - /// \param samplingRadius is the sampling ragius for remeshing + /// \param samplingRadius is the sampling radius for remeshing /// \param borderCreaseAngleDeg is the angle treshold for preserving corner points on the mesh boundary /// \param internalCreaseAngleDeg is the angle treshold for preserving creases on the mesh surface (if this value is < 0 it is set to borderCreaseAngleDeg) /// \return the remeshed mesh @@ -246,6 +247,7 @@ public: } protected: + static bool debugCallBack(const int pos, const char * str) { printf("Processing: %s \n",str); fflush(stdout); return true;} /// /// \brief RemeshOneCC the function that remeshes a single connected component mesh preserving its boundary (consistently for eventually adjacent meshes). @@ -266,7 +268,7 @@ protected: // timer.start(); (void)idx; - + RequireCompactness(original); RequirePerFaceFlags(original); @@ -355,7 +357,9 @@ protected: // refine to obtain a base mesh VoronoiProcessingParameter vpp; - vpp.refinementRatio = 8.0f; + vpp.refinementRatio = 5.0f; + vpp.lcb = debugCallBack; + Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp); // Poisson sampling preserving border @@ -406,7 +410,7 @@ protected: pp.preGenMesh = &poissonEdgeMesh; pp.preGenFlag = true; pp.bestSampleChoiceFlag = true; - pp.bestSamplePoolSize = 100; + pp.bestSamplePoolSize = 10; pp.randomSeed = 7; SurfaceFixSampler::PoissonDiskPruning(fix_sampler, montecarloMesh, samplingRadius, pp); @@ -461,7 +465,7 @@ protected: // traditional // Voronoi::ConvertDelaunayTriangulationToMesh(baseMesh, *finalMeshPtr, seedVertexVec, false); // border-preserving - ThisType::ConvertDelaunayTriangulationExtendedToMesh(baseMesh, *finalMeshPtr, seedVertexVec); + Voronoi::ConvertDelaunayTriangulationExtendedToMesh(baseMesh, *finalMeshPtr, seedVertexVec); #ifdef DEBUG_VORO io::ExporterPLY::Save(*finalMeshPtr, QString("voroMesh_%1.ply").arg(idx).toStdString().c_str()); @@ -623,145 +627,7 @@ protected: } } - static void ConvertDelaunayTriangulationExtendedToMesh(MeshType &m, - MeshType &outMesh, - std::vector &seedVec) - { - typedef VoronoiProcessing Voronoi; - - RequirePerVertexAttribute(m ,"sources"); - RequireCompactness(m); - RequireVFAdjacency(m); - - auto sources = Allocator::template GetPerVertexAttribute (m,"sources"); - - outMesh.Clear(); - UpdateTopology::FaceFace(m); - UpdateFlags::FaceBorderFromFF(m); - - std::map seedMap; // It says if a given vertex of m is a seed (and its index in seedVec) - Voronoi::BuildSeedMap(m, seedVec, seedMap); - - std::vector innerCornerVec, // Faces adjacent to three different regions - borderCornerVec; // Faces that are on the border and adjacent to at least two regions. - Voronoi::GetFaceCornerVec(m, sources, innerCornerVec, borderCornerVec); - - // First add all the needed vertices: seeds and corners - - for(size_t i=0;i::AddVertex(outMesh, seedVec[i]->P(), vcg::Color4b::White); - } - - // Now just add one face for each inner corner - std::vector > toAdd; - for(size_t i=0; iV(0)]; - VertexPointer s1 = sources[innerCornerVec[i]->V(1)]; - VertexPointer s2 = sources[innerCornerVec[i]->V(2)]; - assert ( (s0!=s1) && (s0!=s2) && (s1!=s2) ); - VertexPointer v0 = & outMesh.vert[seedMap[s0]]; - VertexPointer v1 = & outMesh.vert[seedMap[s1]]; - VertexPointer v2 = & outMesh.vert[seedMap[s2]]; - Allocator::AddFace(outMesh, v0, v1, v2); - } - - // Now loop around the borders and find the missing delaunay triangles - // select border seed vertices only and pick one - UpdateFlags::VertexBorderFromFaceAdj(m); - UpdateFlags::VertexClearS(m); - UpdateFlags::VertexClearV(m); - - std::vector borderSeeds; - for (auto & s : seedVec) - { - if (s->IsB()) - { - s->SetS(); - borderSeeds.emplace_back(s); - } - } - - for (VertexPointer startBorderVertex : borderSeeds) - { - if (startBorderVertex->IsV()) - { - continue; - } - - // unvisited border seed found - - // put the pos on the border - PosType pos(startBorderVertex->VFp(), startBorderVertex->VFi()); - do { - pos.NextE(); - } while (!pos.IsBorder() || (pos.VInd() != pos.E())); - - // check all border edges between each consecutive border seeds pair - do { - std::vector edgeVoroVertices(1, sources[pos.V()]); - // among all sources found - do { - pos.NextB(); - VertexPointer source = sources[pos.V()]; - if (edgeVoroVertices.empty() || edgeVoroVertices.back() != source) - { - edgeVoroVertices.push_back(source); - } - } while (!pos.V()->IsS()); - - pos.V()->SetV(); - -// assert(edgeVoroVertices.size() >= 2); - - - if (edgeVoroVertices.size() >= 3) - { - std::vector v; - for (size_t i=0; i3 vertices holes - for (size_t i=0; i::AddFace(outMesh, v[0],v[i+1],v[i+2]); - } -// if (edgeVoroVertices.size() > 3) -// { -// std::cout << "Weird case: " << edgeVoroVertices.size() << " voroseeds on one border" << std::endl; -// } - } -// // add face if 3 different voronoi regions are crossed by the edge -// if (edgeVoroVertices.size() == 3) -// { -// VertexPointer v0 = & outMesh.vert[seedMap[edgeVoroVertices[0]]]; -// VertexPointer v1 = & outMesh.vert[seedMap[edgeVoroVertices[1]]]; -// VertexPointer v2 = & outMesh.vert[seedMap[edgeVoroVertices[2]]]; -// Allocator::AddFace(outMesh, v0,v1,v2); -// } -// else -// { -// std::cout << "Weird case!! " << edgeVoroVertices.size() << " voroseeds on one border" << std::endl; -// if (edgeVoroVertices.size() == 4) -// { -// VertexPointer v0 = & outMesh.vert[seedMap[edgeVoroVertices[0]]]; -// VertexPointer v1 = & outMesh.vert[seedMap[edgeVoroVertices[1]]]; -// VertexPointer v2 = & outMesh.vert[seedMap[edgeVoroVertices[2]]]; -// VertexPointer v3 = & outMesh.vert[seedMap[edgeVoroVertices[3]]]; -// Allocator::AddFace(outMesh, v0,v1,v2); -// Allocator::AddFace(outMesh, v0,v2,v3); -// } -// } - - } while ((pos.V() != startBorderVertex)); - } - - - Clean::RemoveUnreferencedVertex(outMesh); - Allocator::CompactVertexVector(outMesh); - } + /// /// \brief The FixSampler class is used with poisson disk pruning to preserve selected vertices and