Moved delaunay mesh creation function from voronoi remesher to voronoi processing
Added better runtime info (by callback use)
This commit is contained in:
parent
d3b9aa83c1
commit
74c7b308ed
|
@ -82,6 +82,8 @@ struct VoronoiProcessingParameter
|
||||||
float collapseShortEdgePerc = 0.01f;
|
float collapseShortEdgePerc = 0.01f;
|
||||||
|
|
||||||
bool geodesicRelaxFlag= true;
|
bool geodesicRelaxFlag= true;
|
||||||
|
|
||||||
|
CallBackPos *lcb=DummyCallBackPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class MeshType, class DistanceFunctor = EuclideanDistance<MeshType> >
|
template <class MeshType, class DistanceFunctor = EuclideanDistance<MeshType> >
|
||||||
|
@ -97,7 +99,7 @@ class VoronoiProcessing
|
||||||
typedef typename MeshType::FaceType FaceType;
|
typedef typename MeshType::FaceType FaceType;
|
||||||
typedef typename MeshType::FaceContainer FaceContainer;
|
typedef typename MeshType::FaceContainer FaceContainer;
|
||||||
typedef typename tri::Geodesic<MeshType>::VertDist VertDist;
|
typedef typename tri::Geodesic<MeshType>::VertDist VertDist;
|
||||||
|
typedef typename face::Pos<FaceType> PosType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static math::MarsenneTwisterRNG &RandomGenerator()
|
static math::MarsenneTwisterRNG &RandomGenerator()
|
||||||
|
@ -1118,7 +1120,7 @@ static bool GeodesicRelax(MeshType &m, std::vector<VertexType *> &seedVec, std::
|
||||||
tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
|
tri::UpdateColor<MeshType>::PerVertexQualityRamp(m);
|
||||||
|
|
||||||
// Search the local maxima for each region and use them as new seeds
|
// Search the local maxima for each region and use them as new seeds
|
||||||
std::pair<float,VertexPointer> zz(0.0f,static_cast<VertexPointer>(NULL));
|
std::pair<float,VertexPointer> zz(0.0f,nullptr);
|
||||||
std::vector< std::pair<float,VertexPointer> > seedMaximaVec(m.vert.size(),zz);
|
std::vector< std::pair<float,VertexPointer> > seedMaximaVec(m.vert.size(),zz);
|
||||||
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
||||||
{
|
{
|
||||||
|
@ -1193,8 +1195,7 @@ static void MarkVertexVectorAsFixed(MeshType &m, std::vector<VertexType *> &vert
|
||||||
static int RestrictedVoronoiRelaxing(MeshType &m, std::vector<CoordType> &seedPosVec,
|
static int RestrictedVoronoiRelaxing(MeshType &m, std::vector<CoordType> &seedPosVec,
|
||||||
std::vector<bool> &fixedVec,
|
std::vector<bool> &fixedVec,
|
||||||
int relaxStep,
|
int relaxStep,
|
||||||
VoronoiProcessingParameter &vpp,
|
VoronoiProcessingParameter &vpp)
|
||||||
vcg::CallBackPos *cb=0)
|
|
||||||
{
|
{
|
||||||
PerVertexFloatHandle area = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m,"area");
|
PerVertexFloatHandle area = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m,"area");
|
||||||
|
|
||||||
|
@ -1213,7 +1214,7 @@ static int RestrictedVoronoiRelaxing(MeshType &m, std::vector<CoordType> &seedPo
|
||||||
ScalarType perturb = m.bbox.Diag()*vpp.seedPerturbationAmount;
|
ScalarType perturb = m.bbox.Diag()*vpp.seedPerturbationAmount;
|
||||||
for(i=0;i<relaxStep;++i)
|
for(i=0;i<relaxStep;++i)
|
||||||
{
|
{
|
||||||
if(cb) cb(i*100/relaxStep,"RestrictedVoronoiRelaxing ");
|
vpp.lcb(i*100/relaxStep,StrFormat("RestrictedVoronoiRelaxing %i on %i",i,relaxStep));
|
||||||
// Kdtree for the seeds must be rebuilt at each step;
|
// Kdtree for the seeds must be rebuilt at each step;
|
||||||
VectorConstDataWrapper<std::vector<CoordType> > vdw(seedPosVec);
|
VectorConstDataWrapper<std::vector<CoordType> > vdw(seedPosVec);
|
||||||
KdTree<ScalarType> seedTree(vdw);
|
KdTree<ScalarType> seedTree(vdw);
|
||||||
|
@ -1656,6 +1657,7 @@ static void PreprocessForVoronoi(MeshType &m, ScalarType radius,
|
||||||
|
|
||||||
for(int i=0;i<maxSubDiv;++i)
|
for(int i=0;i<maxSubDiv;++i)
|
||||||
{
|
{
|
||||||
|
vpp.lcb(0,StrFormat("Subdividing %i vn %i",i,m.vn));
|
||||||
bool ret = tri::Refine<MeshType, MidPointType >(m,mid,min(edgeLen*2.0f,radius/vpp.refinementRatio));
|
bool ret = tri::Refine<MeshType, MidPointType >(m,mid,min(edgeLen*2.0f,radius/vpp.refinementRatio));
|
||||||
if(!ret) break;
|
if(!ret) break;
|
||||||
}
|
}
|
||||||
|
@ -1788,6 +1790,145 @@ static void RelaxRefineTriangulationLaplacian(MeshType &m, MeshType &delaMesh, i
|
||||||
}
|
}
|
||||||
for(int i=origVertNum;i<delaMesh.vn;++i) delaMesh.vert[i].C()=Color4b::LightBlue;
|
for(int i=origVertNum;i<delaMesh.vn;++i) delaMesh.vert[i].C()=Color4b::LightBlue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ConvertDelaunayTriangulationExtendedToMesh(MeshType &m,
|
||||||
|
MeshType &outMesh,
|
||||||
|
std::vector<VertexType *> &seedVec)
|
||||||
|
{
|
||||||
|
RequirePerVertexAttribute(m ,"sources");
|
||||||
|
RequireCompactness(m);
|
||||||
|
RequireVFAdjacency(m);
|
||||||
|
|
||||||
|
auto sources = Allocator<MeshType>::template GetPerVertexAttribute<VertexPointer> (m,"sources");
|
||||||
|
|
||||||
|
outMesh.Clear();
|
||||||
|
UpdateTopology<MeshType>::FaceFace(m);
|
||||||
|
UpdateFlags<MeshType>::FaceBorderFromFF(m);
|
||||||
|
|
||||||
|
std::map<VertexPointer, int> seedMap; // It says if a given vertex of m is a seed (and its index in seedVec)
|
||||||
|
BuildSeedMap(m, seedVec, seedMap);
|
||||||
|
|
||||||
|
std::vector<FacePointer> 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<seedVec.size();++i)
|
||||||
|
{
|
||||||
|
Allocator<MeshType>::AddVertex(outMesh, seedVec[i]->P(), vcg::Color4b::White);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now just add one face for each inner corner
|
||||||
|
for(size_t i=0; i<innerCornerVec.size(); ++i)
|
||||||
|
{
|
||||||
|
VertexPointer s0 = sources[innerCornerVec[i]->V(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<MeshType>::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<MeshType>::VertexBorderFromFaceAdj(m);
|
||||||
|
UpdateFlags<MeshType>::VertexClearS(m);
|
||||||
|
UpdateFlags<MeshType>::VertexClearV(m);
|
||||||
|
|
||||||
|
std::vector<VertexPointer> 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<VertexPointer> 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<VertexPointer> v;
|
||||||
|
for (size_t i=0; i<edgeVoroVertices.size(); i++)
|
||||||
|
{
|
||||||
|
v.push_back(&outMesh.vert[seedMap[edgeVoroVertices[i]]]);
|
||||||
|
}
|
||||||
|
// also handles N>3 vertices holes
|
||||||
|
for (size_t i=0; i<edgeVoroVertices.size()-2; i++)
|
||||||
|
{
|
||||||
|
Allocator<MeshType>::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<MeshType>::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<MeshType>::AddFace(outMesh, v0,v1,v2);
|
||||||
|
// Allocator<MeshType>::AddFace(outMesh, v0,v2,v3);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
} while ((pos.V() != startBorderVertex));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Clean<MeshType>::RemoveUnreferencedVertex(outMesh);
|
||||||
|
Allocator<MeshType>::CompactVertexVector(outMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}; // end class VoronoiProcessing
|
}; // end class VoronoiProcessing
|
||||||
|
|
||||||
} // end namespace tri
|
} // end namespace tri
|
||||||
|
|
|
@ -45,11 +45,11 @@
|
||||||
|
|
||||||
|
|
||||||
//#define DEBUG_VORO 1
|
//#define DEBUG_VORO 1
|
||||||
//#include <QElapsedTimer>
|
|
||||||
|
|
||||||
#ifdef DEBUG_VORO
|
#ifdef DEBUG_VORO
|
||||||
#include <wrap/io_trimesh/export.h>
|
#include <wrap/io_trimesh/export.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QElapsedTimer>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace vcg {
|
namespace vcg {
|
||||||
|
@ -62,6 +62,7 @@ class VoroEdgeMeshAux
|
||||||
class EUsedTypes : public vcg::UsedTypes<vcg::Use<EmVertexType>::AsVertexType,
|
class EUsedTypes : public vcg::UsedTypes<vcg::Use<EmVertexType>::AsVertexType,
|
||||||
vcg::Use<EmEdgeType>::AsEdgeType> {};
|
vcg::Use<EmEdgeType>::AsEdgeType> {};
|
||||||
class EmVertexType : public vcg::Vertex<EUsedTypes
|
class EmVertexType : public vcg::Vertex<EUsedTypes
|
||||||
|
,vcg::vertex::Normal3d
|
||||||
, vcg::vertex::Coord3d
|
, vcg::vertex::Coord3d
|
||||||
, vcg::vertex::BitFlags
|
, vcg::vertex::BitFlags
|
||||||
, vcg::vertex::VEAdj> {};
|
, vcg::vertex::VEAdj> {};
|
||||||
|
@ -133,12 +134,12 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int VoroRelaxationStep = 40;
|
static const int VoroRelaxationStep = 10;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Remesh the main function that remeshes a mesh preserving creases.
|
/// \brief Remesh the main function that remeshes a mesh preserving creases.
|
||||||
/// \param original the mesh
|
/// \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 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)
|
/// \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
|
/// \return the remeshed mesh
|
||||||
|
@ -246,6 +247,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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).
|
/// \brief RemeshOneCC the function that remeshes a single connected component mesh preserving its boundary (consistently for eventually adjacent meshes).
|
||||||
|
@ -355,7 +357,9 @@ protected:
|
||||||
|
|
||||||
// refine to obtain a base mesh
|
// refine to obtain a base mesh
|
||||||
VoronoiProcessingParameter vpp;
|
VoronoiProcessingParameter vpp;
|
||||||
vpp.refinementRatio = 8.0f;
|
vpp.refinementRatio = 5.0f;
|
||||||
|
vpp.lcb = debugCallBack;
|
||||||
|
|
||||||
Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp);
|
Voronoi::PreprocessForVoronoi(baseMesh, samplingRadius, vpp);
|
||||||
|
|
||||||
// Poisson sampling preserving border
|
// Poisson sampling preserving border
|
||||||
|
@ -406,7 +410,7 @@ protected:
|
||||||
pp.preGenMesh = &poissonEdgeMesh;
|
pp.preGenMesh = &poissonEdgeMesh;
|
||||||
pp.preGenFlag = true;
|
pp.preGenFlag = true;
|
||||||
pp.bestSampleChoiceFlag = true;
|
pp.bestSampleChoiceFlag = true;
|
||||||
pp.bestSamplePoolSize = 100;
|
pp.bestSamplePoolSize = 10;
|
||||||
pp.randomSeed = 7;
|
pp.randomSeed = 7;
|
||||||
SurfaceFixSampler::PoissonDiskPruning(fix_sampler, montecarloMesh, samplingRadius, pp);
|
SurfaceFixSampler::PoissonDiskPruning(fix_sampler, montecarloMesh, samplingRadius, pp);
|
||||||
|
|
||||||
|
@ -461,7 +465,7 @@ protected:
|
||||||
// traditional
|
// traditional
|
||||||
// Voronoi::ConvertDelaunayTriangulationToMesh(baseMesh, *finalMeshPtr, seedVertexVec, false);
|
// Voronoi::ConvertDelaunayTriangulationToMesh(baseMesh, *finalMeshPtr, seedVertexVec, false);
|
||||||
// border-preserving
|
// border-preserving
|
||||||
ThisType::ConvertDelaunayTriangulationExtendedToMesh(baseMesh, *finalMeshPtr, seedVertexVec);
|
Voronoi::ConvertDelaunayTriangulationExtendedToMesh(baseMesh, *finalMeshPtr, seedVertexVec);
|
||||||
|
|
||||||
#ifdef DEBUG_VORO
|
#ifdef DEBUG_VORO
|
||||||
io::ExporterPLY<MeshType>::Save(*finalMeshPtr, QString("voroMesh_%1.ply").arg(idx).toStdString().c_str());
|
io::ExporterPLY<MeshType>::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<VertexType *> &seedVec)
|
|
||||||
{
|
|
||||||
typedef VoronoiProcessing<MeshType> Voronoi;
|
|
||||||
|
|
||||||
RequirePerVertexAttribute(m ,"sources");
|
|
||||||
RequireCompactness(m);
|
|
||||||
RequireVFAdjacency(m);
|
|
||||||
|
|
||||||
auto sources = Allocator<MeshType>::template GetPerVertexAttribute<VertexPointer> (m,"sources");
|
|
||||||
|
|
||||||
outMesh.Clear();
|
|
||||||
UpdateTopology<MeshType>::FaceFace(m);
|
|
||||||
UpdateFlags<MeshType>::FaceBorderFromFF(m);
|
|
||||||
|
|
||||||
std::map<VertexPointer, int> seedMap; // It says if a given vertex of m is a seed (and its index in seedVec)
|
|
||||||
Voronoi::BuildSeedMap(m, seedVec, seedMap);
|
|
||||||
|
|
||||||
std::vector<FacePointer> 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<seedVec.size();++i)
|
|
||||||
{
|
|
||||||
Allocator<MeshType>::AddVertex(outMesh, seedVec[i]->P(), vcg::Color4b::White);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now just add one face for each inner corner
|
|
||||||
std::vector<std::array<VertexPointer, 3> > toAdd;
|
|
||||||
for(size_t i=0; i<innerCornerVec.size(); ++i)
|
|
||||||
{
|
|
||||||
VertexPointer s0 = sources[innerCornerVec[i]->V(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<MeshType>::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<Mesh>::VertexBorderFromFaceAdj(m);
|
|
||||||
UpdateFlags<Mesh>::VertexClearS(m);
|
|
||||||
UpdateFlags<Mesh>::VertexClearV(m);
|
|
||||||
|
|
||||||
std::vector<VertexPointer> 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<VertexPointer> 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<VertexPointer> v;
|
|
||||||
for (size_t i=0; i<edgeVoroVertices.size(); i++)
|
|
||||||
{
|
|
||||||
v.push_back(&outMesh.vert[seedMap[edgeVoroVertices[i]]]);
|
|
||||||
}
|
|
||||||
// also handles N>3 vertices holes
|
|
||||||
for (size_t i=0; i<edgeVoroVertices.size()-2; i++)
|
|
||||||
{
|
|
||||||
Allocator<MeshType>::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<MeshType>::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<MeshType>::AddFace(outMesh, v0,v1,v2);
|
|
||||||
// Allocator<MeshType>::AddFace(outMesh, v0,v2,v3);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
} while ((pos.V() != startBorderVertex));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Clean<MeshType>::RemoveUnreferencedVertex(outMesh);
|
|
||||||
Allocator<MeshType>::CompactVertexVector(outMesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief The FixSampler class is used with poisson disk pruning to preserve selected vertices and
|
/// \brief The FixSampler class is used with poisson disk pruning to preserve selected vertices and
|
||||||
|
|
Loading…
Reference in New Issue