Slight change of the PoissonDiskPruning interface. Removed a useless parameter (the original surface mesh)
This commit is contained in:
parent
0f34456c92
commit
d61c5c24a1
|
@ -23,14 +23,14 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
||||||
The sampling Class has a set of static functions, that you can call to sample the surface of a mesh.
|
The sampling Class has a set of static functions, that you can call to sample the surface of a mesh.
|
||||||
Each function is templated on the mesh and on a Sampler object s.
|
Each function is templated on the mesh and on a Sampler object s.
|
||||||
Each function calls many time the sample object with the sampling point as parameter.
|
Each function calls many time the sample object with the sampling point as parameter.
|
||||||
|
|
||||||
Sampler Classes and Sampling algorithms are independent.
|
Sampler Classes and Sampling algorithms are independent.
|
||||||
Sampler classes exploits the sample that are generated with various algorithms.
|
Sampler classes exploits the sample that are generated with various algorithms.
|
||||||
For example, you can compute Hausdorff distance (that is a sampler) using various
|
For example, you can compute Hausdorff distance (that is a sampler) using various
|
||||||
sampling strategies (montecarlo, stratified etc).
|
sampling strategies (montecarlo, stratified etc).
|
||||||
|
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef __VCGLIB_POINT_SAMPLING
|
#ifndef __VCGLIB_POINT_SAMPLING
|
||||||
#define __VCGLIB_POINT_SAMPLING
|
#define __VCGLIB_POINT_SAMPLING
|
||||||
|
@ -50,15 +50,15 @@ namespace vcg
|
||||||
namespace tri
|
namespace tri
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Trivial Sampler, an example sampler object that show the required interface used by the sampling class.
|
/// Trivial Sampler, an example sampler object that show the required interface used by the sampling class.
|
||||||
/// Most of the sampling classes call the AddFace method with the face containing the sample and its barycentric coord.
|
/// Most of the sampling classes call the AddFace method with the face containing the sample and its barycentric coord.
|
||||||
/// Beside being an example of how to write a sampler it provides a simple way to use the various sampling classes.
|
/// Beside being an example of how to write a sampler it provides a simple way to use the various sampling classes.
|
||||||
// For example if you just want to get a vector with positions over the surface You have just to write
|
// For example if you just want to get a vector with positions over the surface You have just to write
|
||||||
//
|
//
|
||||||
// vector<Point3f> myVec;
|
// vector<Point3f> myVec;
|
||||||
// TrivialSampler<MyMesh> ts(myVec)
|
// TrivialSampler<MyMesh> ts(myVec)
|
||||||
// SurfaceSampling<MyMesh, TrivialSampler<MyMesh> >::Montecarlo(M, ts, SampleNum);
|
// SurfaceSampling<MyMesh, TrivialSampler<MyMesh> >::Montecarlo(M, ts, SampleNum);
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
template <class MeshType>
|
template <class MeshType>
|
||||||
|
@ -67,7 +67,7 @@ class TrivialSampler
|
||||||
public:
|
public:
|
||||||
typedef typename MeshType::CoordType CoordType;
|
typedef typename MeshType::CoordType CoordType;
|
||||||
typedef typename MeshType::VertexType VertexType;
|
typedef typename MeshType::VertexType VertexType;
|
||||||
typedef typename MeshType::FaceType FaceType;
|
typedef typename MeshType::FaceType FaceType;
|
||||||
|
|
||||||
TrivialSampler()
|
TrivialSampler()
|
||||||
{
|
{
|
||||||
|
@ -86,26 +86,26 @@ class TrivialSampler
|
||||||
{
|
{
|
||||||
if(vectorOwner) delete sampleVec;
|
if(vectorOwner) delete sampleVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<CoordType> *sampleVec;
|
std::vector<CoordType> *sampleVec;
|
||||||
bool vectorOwner;
|
bool vectorOwner;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void AddVert(const VertexType &p)
|
void AddVert(const VertexType &p)
|
||||||
{
|
{
|
||||||
sampleVec->push_back(p.cP());
|
sampleVec->push_back(p.cP());
|
||||||
}
|
}
|
||||||
void AddFace(const FaceType &f, const CoordType &p)
|
void AddFace(const FaceType &f, const CoordType &p)
|
||||||
{
|
{
|
||||||
sampleVec->push_back(f.cP(0)*p[0] + f.cP(1)*p[1] +f.cP(2)*p[2] );
|
sampleVec->push_back(f.cP(0)*p[0] + f.cP(1)*p[1] +f.cP(2)*p[2] );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTextureSample(const FaceType &, const CoordType &, const Point2i &, float )
|
void AddTextureSample(const FaceType &, const CoordType &, const Point2i &, float )
|
||||||
{
|
{
|
||||||
// Retrieve the color of the sample from the face f using the barycentric coord p
|
// Retrieve the color of the sample from the face f using the barycentric coord p
|
||||||
// and write that color in a texture image at position <tp[0], texHeight-tp[1]>
|
// and write that color in a texture image at position <tp[0], texHeight-tp[1]>
|
||||||
// if edgeDist is > 0 then the corrisponding point is affecting face color even if outside the face area (in texture space)
|
// if edgeDist is > 0 then the corrisponding point is affecting face color even if outside the face area (in texture space)
|
||||||
}
|
}
|
||||||
}; // end class TrivialSampler
|
}; // end class TrivialSampler
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class SurfaceSampling
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static math::MarsenneTwisterRNG &SamplingRandomGenerator()
|
static math::MarsenneTwisterRNG &SamplingRandomGenerator()
|
||||||
{
|
{
|
||||||
static math::MarsenneTwisterRNG rnd;
|
static math::MarsenneTwisterRNG rnd;
|
||||||
return rnd;
|
return rnd;
|
||||||
|
@ -147,7 +147,7 @@ static unsigned int RandomInt(unsigned int i)
|
||||||
// Returns a random number in the [0,1) real interval using the improved Marsenne-Twister method.
|
// Returns a random number in the [0,1) real interval using the improved Marsenne-Twister method.
|
||||||
static double RandomDouble01()
|
static double RandomDouble01()
|
||||||
{
|
{
|
||||||
return SamplingRandomGenerator().generate01();
|
return SamplingRandomGenerator().generate01();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Point3f RandomPoint3fBall01()
|
static Point3f RandomPoint3fBall01()
|
||||||
|
@ -288,28 +288,28 @@ static void AllVertex(MetroMesh & m, VertexSampler &ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample the vertices in a weighted way. Each vertex has a probability of being chosen
|
/// Sample the vertices in a weighted way. Each vertex has a probability of being chosen
|
||||||
/// that is proportional to its quality.
|
/// that is proportional to its quality.
|
||||||
/// It assumes that you are asking a number of vertices smaller than nv;
|
/// It assumes that you are asking a number of vertices smaller than nv;
|
||||||
/// Algorithm:
|
/// Algorithm:
|
||||||
/// 1) normalize quality so that sum q == 1;
|
/// 1) normalize quality so that sum q == 1;
|
||||||
/// 2) shuffle vertices.
|
/// 2) shuffle vertices.
|
||||||
/// 3) for each vertices choose it if rand > thr;
|
/// 3) for each vertices choose it if rand > thr;
|
||||||
|
|
||||||
static void VertexWeighted(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
static void VertexWeighted(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
{
|
{
|
||||||
ScalarType qSum = 0;
|
ScalarType qSum = 0;
|
||||||
VertexIterator vi;
|
VertexIterator vi;
|
||||||
for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
|
for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
|
||||||
if(!(*vi).IsD())
|
if(!(*vi).IsD())
|
||||||
qSum += (*vi).Q();
|
qSum += (*vi).Q();
|
||||||
|
|
||||||
ScalarType samplePerUnit = sampleNum/qSum;
|
ScalarType samplePerUnit = sampleNum/qSum;
|
||||||
ScalarType floatSampleNum =0;
|
ScalarType floatSampleNum =0;
|
||||||
std::vector<VertexPointer> vertVec;
|
std::vector<VertexPointer> vertVec;
|
||||||
FillAndShuffleVertexPointerVector(m,vertVec);
|
FillAndShuffleVertexPointerVector(m,vertVec);
|
||||||
|
|
||||||
std::vector<bool> vertUsed(m.vn,false);
|
std::vector<bool> vertUsed(m.vn,false);
|
||||||
|
|
||||||
int i=0; int cnt=0;
|
int i=0; int cnt=0;
|
||||||
while(cnt < sampleNum)
|
while(cnt < sampleNum)
|
||||||
{
|
{
|
||||||
|
@ -317,8 +317,8 @@ static void VertexWeighted(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
{
|
{
|
||||||
floatSampleNum += vertVec[i]->Q() * samplePerUnit;
|
floatSampleNum += vertVec[i]->Q() * samplePerUnit;
|
||||||
int vertSampleNum = (int) floatSampleNum;
|
int vertSampleNum = (int) floatSampleNum;
|
||||||
floatSampleNum -= (float) vertSampleNum;
|
floatSampleNum -= (float) vertSampleNum;
|
||||||
|
|
||||||
// for every sample p_i in T...
|
// for every sample p_i in T...
|
||||||
if(vertSampleNum > 1)
|
if(vertSampleNum > 1)
|
||||||
{
|
{
|
||||||
|
@ -327,66 +327,66 @@ static void VertexWeighted(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
vertUsed[i]=true;
|
vertUsed[i]=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = (i+1)%m.vn;
|
i = (i+1)%m.vn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample the vertices in a uniform way. Each vertex has a probability of being chosen
|
/// Sample the vertices in a uniform way. Each vertex has a probability of being chosen
|
||||||
/// that is proportional to the area it represent.
|
/// that is proportional to the area it represent.
|
||||||
static void VertexAreaUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
static void VertexAreaUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
{
|
{
|
||||||
VertexIterator vi;
|
VertexIterator vi;
|
||||||
for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
|
for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
|
||||||
if(!(*vi).IsD())
|
if(!(*vi).IsD())
|
||||||
(*vi).Q() = 0;
|
(*vi).Q() = 0;
|
||||||
|
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
|
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
ScalarType areaThird = DoubleArea(*fi)/6.0;
|
ScalarType areaThird = DoubleArea(*fi)/6.0;
|
||||||
(*fi).V(0)->Q()+=areaThird;
|
(*fi).V(0)->Q()+=areaThird;
|
||||||
(*fi).V(1)->Q()+=areaThird;
|
(*fi).V(1)->Q()+=areaThird;
|
||||||
(*fi).V(2)->Q()+=areaThird;
|
(*fi).V(2)->Q()+=areaThird;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexWeighted(m,ps,sampleNum);
|
VertexWeighted(m,ps,sampleNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FillAndShuffleFacePointerVector(MetroMesh & m, std::vector<FacePointer> &faceVec)
|
static void FillAndShuffleFacePointerVector(MetroMesh & m, std::vector<FacePointer> &faceVec)
|
||||||
{
|
{
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
||||||
if(!(*fi).IsD()) faceVec.push_back(&*fi);
|
if(!(*fi).IsD()) faceVec.push_back(&*fi);
|
||||||
|
|
||||||
assert((int)faceVec.size()==m.fn);
|
assert((int)faceVec.size()==m.fn);
|
||||||
|
|
||||||
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
||||||
std::random_shuffle(faceVec.begin(),faceVec.end(), p_myrandom);
|
std::random_shuffle(faceVec.begin(),faceVec.end(), p_myrandom);
|
||||||
}
|
}
|
||||||
static void FillAndShuffleVertexPointerVector(MetroMesh & m, std::vector<VertexPointer> &vertVec)
|
static void FillAndShuffleVertexPointerVector(MetroMesh & m, std::vector<VertexPointer> &vertVec)
|
||||||
{
|
{
|
||||||
VertexIterator vi;
|
VertexIterator vi;
|
||||||
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
||||||
if(!(*vi).IsD()) vertVec.push_back(&*vi);
|
if(!(*vi).IsD()) vertVec.push_back(&*vi);
|
||||||
|
|
||||||
assert((int)vertVec.size()==m.vn);
|
assert((int)vertVec.size()==m.vn);
|
||||||
|
|
||||||
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
||||||
std::random_shuffle(vertVec.begin(),vertVec.end(), p_myrandom);
|
std::random_shuffle(vertVec.begin(),vertVec.end(), p_myrandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample the vertices in a uniform way. Each vertex has the same probabiltiy of being chosen.
|
/// Sample the vertices in a uniform way. Each vertex has the same probabiltiy of being chosen.
|
||||||
static void VertexUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
static void VertexUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
{
|
{
|
||||||
if(sampleNum>=m.vn) {
|
if(sampleNum>=m.vn) {
|
||||||
AllVertex(m,ps);
|
AllVertex(m,ps);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VertexPointer> vertVec;
|
std::vector<VertexPointer> vertVec;
|
||||||
FillAndShuffleVertexPointerVector(m,vertVec);
|
FillAndShuffleVertexPointerVector(m,vertVec);
|
||||||
|
|
||||||
for(int i =0; i< sampleNum; ++i)
|
for(int i =0; i< sampleNum; ++i)
|
||||||
ps.AddVert(*vertVec[i]);
|
ps.AddVert(*vertVec[i]);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +397,7 @@ static void FaceUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
if(sampleNum>=m.fn) {
|
if(sampleNum>=m.fn) {
|
||||||
AllFace(m,ps);
|
AllFace(m,ps);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FacePointer> faceVec;
|
std::vector<FacePointer> faceVec;
|
||||||
FillAndShuffleFacePointerVector(m,faceVec);
|
FillAndShuffleFacePointerVector(m,faceVec);
|
||||||
|
@ -409,7 +409,7 @@ static void FaceUniform(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
static void AllFace(MetroMesh & m, VertexSampler &ps)
|
static void AllFace(MetroMesh & m, VertexSampler &ps)
|
||||||
{
|
{
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
ps.AddFace(*fi,Barycenter(*fi));
|
ps.AddFace(*fi,Barycenter(*fi));
|
||||||
|
@ -419,16 +419,16 @@ static void AllFace(MetroMesh & m, VertexSampler &ps)
|
||||||
|
|
||||||
static void AllEdge(MetroMesh & m, VertexSampler &ps)
|
static void AllEdge(MetroMesh & m, VertexSampler &ps)
|
||||||
{
|
{
|
||||||
// Edge sampling.
|
// Edge sampling.
|
||||||
typedef typename UpdateTopology<MetroMesh>::PEdge SimpleEdge;
|
typedef typename UpdateTopology<MetroMesh>::PEdge SimpleEdge;
|
||||||
std::vector< SimpleEdge > Edges;
|
std::vector< SimpleEdge > Edges;
|
||||||
typename std::vector< SimpleEdge >::iterator ei;
|
typename std::vector< SimpleEdge >::iterator ei;
|
||||||
UpdateTopology<MetroMesh>::FillUniqueEdgeVector(m,Edges);
|
UpdateTopology<MetroMesh>::FillUniqueEdgeVector(m,Edges);
|
||||||
|
|
||||||
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
||||||
{
|
{
|
||||||
Point3f interp(0,0,0);
|
Point3f interp(0,0,0);
|
||||||
interp[ (*ei).z ]=.5;
|
interp[ (*ei).z ]=.5;
|
||||||
interp[((*ei).z+1)%3]=.5;
|
interp[((*ei).z+1)%3]=.5;
|
||||||
ps.AddFace(*(*ei).f,interp);
|
ps.AddFace(*(*ei).f,interp);
|
||||||
}
|
}
|
||||||
|
@ -442,13 +442,13 @@ static void EdgeUniform(MetroMesh & m, VertexSampler &ps,int sampleNum, bool sam
|
||||||
{
|
{
|
||||||
typedef typename UpdateTopology<MetroMesh>::PEdge SimpleEdge;
|
typedef typename UpdateTopology<MetroMesh>::PEdge SimpleEdge;
|
||||||
std::vector< SimpleEdge > Edges;
|
std::vector< SimpleEdge > Edges;
|
||||||
UpdateTopology<MetroMesh>::FillUniqueEdgeVector(m,Edges,sampleFauxEdge);
|
UpdateTopology<MetroMesh>::FillUniqueEdgeVector(m,Edges,sampleFauxEdge);
|
||||||
// First loop compute total edge length;
|
// First loop compute total edge length;
|
||||||
float edgeSum=0;
|
float edgeSum=0;
|
||||||
typename std::vector< SimpleEdge >::iterator ei;
|
typename std::vector< SimpleEdge >::iterator ei;
|
||||||
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
||||||
edgeSum+=Distance((*ei).v[0]->P(),(*ei).v[1]->P());
|
edgeSum+=Distance((*ei).v[0]->P(),(*ei).v[1]->P());
|
||||||
|
|
||||||
float sampleLen = edgeSum/sampleNum;
|
float sampleLen = edgeSum/sampleNum;
|
||||||
float rest=0;
|
float rest=0;
|
||||||
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
|
||||||
|
@ -460,16 +460,16 @@ static void EdgeUniform(MetroMesh & m, VertexSampler &ps,int sampleNum, bool sam
|
||||||
for(int i=0;i<samplePerEdge;++i)
|
for(int i=0;i<samplePerEdge;++i)
|
||||||
{
|
{
|
||||||
Point3f interp(0,0,0);
|
Point3f interp(0,0,0);
|
||||||
interp[ (*ei).z ]=step*(i+1);
|
interp[ (*ei).z ]=step*(i+1);
|
||||||
interp[((*ei).z+1)%3]=1.0-step*(i+1);
|
interp[((*ei).z+1)%3]=1.0-step*(i+1);
|
||||||
ps.AddFace(*(*ei).f,interp);
|
ps.AddFace(*(*ei).f,interp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the barycentric coords of a random point over a single face,
|
// Generate the barycentric coords of a random point over a single face,
|
||||||
// with a uniform distribution over the triangle.
|
// with a uniform distribution over the triangle.
|
||||||
// It uses the parallelogram folding trick.
|
// It uses the parallelogram folding trick.
|
||||||
static CoordType RandomBarycentric()
|
static CoordType RandomBarycentric()
|
||||||
{
|
{
|
||||||
CoordType interp;
|
CoordType interp;
|
||||||
|
@ -480,7 +480,7 @@ static CoordType RandomBarycentric()
|
||||||
interp[1] = 1.0 - interp[1];
|
interp[1] = 1.0 - interp[1];
|
||||||
interp[2] = 1.0 - interp[2];
|
interp[2] = 1.0 - interp[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(interp[1] + interp[2] <= 1.0);
|
assert(interp[1] + interp[2] <= 1.0);
|
||||||
interp[0]=1.0-(interp[1] + interp[2]);
|
interp[0]=1.0-(interp[1] + interp[2]);
|
||||||
return interp;
|
return interp;
|
||||||
|
@ -500,19 +500,19 @@ static void StratifiedMontecarlo(MetroMesh & m, VertexSampler &ps,int sampleNum)
|
||||||
ScalarType samplePerAreaUnit = sampleNum/area;
|
ScalarType samplePerAreaUnit = sampleNum/area;
|
||||||
// Montecarlo sampling.
|
// Montecarlo sampling.
|
||||||
double floatSampleNum = 0.0;
|
double floatSampleNum = 0.0;
|
||||||
|
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
// compute # samples in the current face (taking into account of the remainders)
|
// compute # samples in the current face (taking into account of the remainders)
|
||||||
floatSampleNum += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
|
floatSampleNum += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
|
||||||
int faceSampleNum = (int) floatSampleNum;
|
int faceSampleNum = (int) floatSampleNum;
|
||||||
|
|
||||||
// for every sample p_i in T...
|
// for every sample p_i in T...
|
||||||
for(int i=0; i < faceSampleNum; i++)
|
for(int i=0; i < faceSampleNum; i++)
|
||||||
ps.AddFace(*fi,RandomBarycentric());
|
ps.AddFace(*fi,RandomBarycentric());
|
||||||
floatSampleNum -= (double) faceSampleNum;
|
floatSampleNum -= (double) faceSampleNum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +557,7 @@ static void Montecarlo(MetroMesh & m, VertexSampler &ps,int sampleNum)
|
||||||
{
|
{
|
||||||
typedef std::pair<ScalarType, FacePointer> IntervalType;
|
typedef std::pair<ScalarType, FacePointer> IntervalType;
|
||||||
std::vector< IntervalType > intervals (m.fn+1);
|
std::vector< IntervalType > intervals (m.fn+1);
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
int i=0;
|
int i=0;
|
||||||
intervals[i]=std::make_pair(0,FacePointer(0));
|
intervals[i]=std::make_pair(0,FacePointer(0));
|
||||||
// First loop: build a sequence of consecutive segments proportional to the triangle areas.
|
// First loop: build a sequence of consecutive segments proportional to the triangle areas.
|
||||||
|
@ -581,7 +581,7 @@ static void Montecarlo(MetroMesh & m, VertexSampler &ps,int sampleNum)
|
||||||
ps.AddFace( *(*it).second, RandomBarycentric() );
|
ps.AddFace( *(*it).second, RandomBarycentric() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ScalarType WeightedArea(FaceType f)
|
static ScalarType WeightedArea(FaceType f)
|
||||||
{
|
{
|
||||||
ScalarType averageQ = ( f.V(0)->Q() + f.V(1)->Q() + f.V(2)->Q() ) /3.0;
|
ScalarType averageQ = ( f.V(0)->Q() + f.V(1)->Q() + f.V(2)->Q() ) /3.0;
|
||||||
|
@ -589,38 +589,38 @@ static ScalarType WeightedArea(FaceType f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a sampling of the surface that is weighted by the quality
|
/// Compute a sampling of the surface that is weighted by the quality
|
||||||
/// the area of each face is multiplied by the average of the quality of the vertices.
|
/// the area of each face is multiplied by the average of the quality of the vertices.
|
||||||
/// So the a face with a zero quality on all its vertices is never sampled and a face with average quality 2 get twice the samples of a face with the same area but with an average quality of 1;
|
/// So the a face with a zero quality on all its vertices is never sampled and a face with average quality 2 get twice the samples of a face with the same area but with an average quality of 1;
|
||||||
static void WeightedMontecarlo(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
static void WeightedMontecarlo(MetroMesh & m, VertexSampler &ps, int sampleNum)
|
||||||
{
|
{
|
||||||
assert(tri::HasPerVertexQuality(m));
|
assert(tri::HasPerVertexQuality(m));
|
||||||
|
|
||||||
ScalarType weightedArea = 0;
|
ScalarType weightedArea = 0;
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
|
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
weightedArea += WeightedArea(*fi);
|
weightedArea += WeightedArea(*fi);
|
||||||
|
|
||||||
ScalarType samplePerAreaUnit = sampleNum/weightedArea;
|
ScalarType samplePerAreaUnit = sampleNum/weightedArea;
|
||||||
// Montecarlo sampling.
|
// Montecarlo sampling.
|
||||||
double floatSampleNum = 0.0;
|
double floatSampleNum = 0.0;
|
||||||
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
// compute # samples in the current face (taking into account of the remainders)
|
// compute # samples in the current face (taking into account of the remainders)
|
||||||
floatSampleNum += WeightedArea(*fi) * samplePerAreaUnit;
|
floatSampleNum += WeightedArea(*fi) * samplePerAreaUnit;
|
||||||
int faceSampleNum = (int) floatSampleNum;
|
int faceSampleNum = (int) floatSampleNum;
|
||||||
|
|
||||||
// for every sample p_i in T...
|
// for every sample p_i in T...
|
||||||
for(int i=0; i < faceSampleNum; i++)
|
for(int i=0; i < faceSampleNum; i++)
|
||||||
ps.AddFace(*fi,RandomBarycentric());
|
ps.AddFace(*fi,RandomBarycentric());
|
||||||
|
|
||||||
floatSampleNum -= (double) faceSampleNum;
|
floatSampleNum -= (double) faceSampleNum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Subdivision sampling of a single face.
|
// Subdivision sampling of a single face.
|
||||||
// return number of added samples
|
// return number of added samples
|
||||||
|
|
||||||
static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
|
static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
|
||||||
|
@ -630,7 +630,7 @@ static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const Coor
|
||||||
{
|
{
|
||||||
// ground case.
|
// ground case.
|
||||||
CoordType SamplePoint;
|
CoordType SamplePoint;
|
||||||
if(randSample)
|
if(randSample)
|
||||||
{
|
{
|
||||||
CoordType rb=RandomBarycentric();
|
CoordType rb=RandomBarycentric();
|
||||||
SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
|
SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
|
||||||
|
@ -640,12 +640,12 @@ static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const Coor
|
||||||
ps.AddFace(*fp,SamplePoint);
|
ps.AddFace(*fp,SamplePoint);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int s0 = sampleNum /2;
|
int s0 = sampleNum /2;
|
||||||
int s1 = sampleNum-s0;
|
int s1 = sampleNum-s0;
|
||||||
assert(s0>0);
|
assert(s0>0);
|
||||||
assert(s1>0);
|
assert(s1>0);
|
||||||
|
|
||||||
ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
|
ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
|
||||||
ScalarType w1 = 1.0-w0;
|
ScalarType w1 = 1.0-w0;
|
||||||
// compute the longest edge.
|
// compute the longest edge.
|
||||||
|
@ -659,7 +659,7 @@ static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const Coor
|
||||||
else
|
else
|
||||||
if(maxd12 > maxd20) res = 1;
|
if(maxd12 > maxd20) res = 1;
|
||||||
else res = 2;
|
else res = 2;
|
||||||
|
|
||||||
int faceSampleNum=0;
|
int faceSampleNum=0;
|
||||||
// break the input triangle along the midpoint of the longest edge.
|
// break the input triangle along the midpoint of the longest edge.
|
||||||
CoordType pp;
|
CoordType pp;
|
||||||
|
@ -685,7 +685,7 @@ static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const Coor
|
||||||
/// Compute a sampling of the surface where the points are regularly scattered over the face surface using a recursive longest-edge subdivision rule.
|
/// Compute a sampling of the surface where the points are regularly scattered over the face surface using a recursive longest-edge subdivision rule.
|
||||||
static void FaceSubdivision(MetroMesh & m, VertexSampler &ps,int sampleNum, bool randSample)
|
static void FaceSubdivision(MetroMesh & m, VertexSampler &ps,int sampleNum, bool randSample)
|
||||||
{
|
{
|
||||||
|
|
||||||
ScalarType area = Stat<MetroMesh>::ComputeMeshArea(m);
|
ScalarType area = Stat<MetroMesh>::ComputeMeshArea(m);
|
||||||
ScalarType samplePerAreaUnit = sampleNum/area;
|
ScalarType samplePerAreaUnit = sampleNum/area;
|
||||||
std::vector<FacePointer> faceVec;
|
std::vector<FacePointer> faceVec;
|
||||||
|
@ -693,20 +693,20 @@ static void FaceSubdivision(MetroMesh & m, VertexSampler &ps,int sampleNum, bool
|
||||||
vcg::tri::UpdateNormal<MetroMesh>::PerFaceNormalized(m);
|
vcg::tri::UpdateNormal<MetroMesh>::PerFaceNormalized(m);
|
||||||
double floatSampleNum = 0.0;
|
double floatSampleNum = 0.0;
|
||||||
int faceSampleNum;
|
int faceSampleNum;
|
||||||
// Subdivision sampling.
|
// Subdivision sampling.
|
||||||
typename std::vector<FacePointer>::iterator fi;
|
typename std::vector<FacePointer>::iterator fi;
|
||||||
for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
|
for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
|
||||||
{
|
{
|
||||||
const CoordType b0(1.0, 0.0, 0.0);
|
const CoordType b0(1.0, 0.0, 0.0);
|
||||||
const CoordType b1(0.0, 1.0, 0.0);
|
const CoordType b1(0.0, 1.0, 0.0);
|
||||||
const CoordType b2(0.0, 0.0, 1.0);
|
const CoordType b2(0.0, 0.0, 1.0);
|
||||||
// compute # samples in the current face.
|
// compute # samples in the current face.
|
||||||
floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
|
floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
|
||||||
faceSampleNum = (int) floatSampleNum;
|
faceSampleNum = (int) floatSampleNum;
|
||||||
if(faceSampleNum>0)
|
if(faceSampleNum>0)
|
||||||
faceSampleNum = SingleFaceSubdivision(faceSampleNum,b0,b1,b2,ps,*fi,randSample);
|
faceSampleNum = SingleFaceSubdivision(faceSampleNum,b0,b1,b2,ps,*fi,randSample);
|
||||||
floatSampleNum -= (double) faceSampleNum;
|
floatSampleNum -= (double) faceSampleNum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------
|
//---------
|
||||||
// Subdivision sampling of a single face.
|
// Subdivision sampling of a single face.
|
||||||
|
@ -802,44 +802,44 @@ static void FaceSubdivisionOld(MetroMesh & m, VertexSampler &ps,int sampleNum, b
|
||||||
|
|
||||||
// Similar Triangles sampling.
|
// Similar Triangles sampling.
|
||||||
// Skip vertex and edges
|
// Skip vertex and edges
|
||||||
// Sample per edges includes vertexes, so here we should expect n_samples_per_edge >=4
|
// Sample per edges includes vertexes, so here we should expect n_samples_per_edge >=4
|
||||||
|
|
||||||
static int SingleFaceSimilar(FacePointer fp, VertexSampler &ps, int n_samples_per_edge)
|
static int SingleFaceSimilar(FacePointer fp, VertexSampler &ps, int n_samples_per_edge)
|
||||||
{
|
{
|
||||||
int n_samples=0;
|
int n_samples=0;
|
||||||
int i, j;
|
int i, j;
|
||||||
float segmentNum=n_samples_per_edge -1 ;
|
float segmentNum=n_samples_per_edge -1 ;
|
||||||
float segmentLen = 1.0/segmentNum;
|
float segmentLen = 1.0/segmentNum;
|
||||||
// face sampling.
|
// face sampling.
|
||||||
for(i=1; i < n_samples_per_edge-1; i++)
|
for(i=1; i < n_samples_per_edge-1; i++)
|
||||||
for(j=1; j < n_samples_per_edge-1-i; j++)
|
for(j=1; j < n_samples_per_edge-1-i; j++)
|
||||||
{
|
{
|
||||||
//AddSample( v0 + (V1*(double)i + V2*(double)j) );
|
//AddSample( v0 + (V1*(double)i + V2*(double)j) );
|
||||||
CoordType sampleBary(i*segmentLen,j*segmentLen, 1.0 - (i*segmentLen+j*segmentLen) ) ;
|
CoordType sampleBary(i*segmentLen,j*segmentLen, 1.0 - (i*segmentLen+j*segmentLen) ) ;
|
||||||
n_samples++;
|
n_samples++;
|
||||||
ps.AddFace(*fp,sampleBary);
|
ps.AddFace(*fp,sampleBary);
|
||||||
}
|
}
|
||||||
return n_samples;
|
return n_samples;
|
||||||
}
|
}
|
||||||
static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_samples_per_edge, bool randomFlag)
|
static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_samples_per_edge, bool randomFlag)
|
||||||
{
|
{
|
||||||
int n_samples=0;
|
int n_samples=0;
|
||||||
float i, j;
|
float i, j;
|
||||||
float segmentNum=n_samples_per_edge -1 ;
|
float segmentNum=n_samples_per_edge -1 ;
|
||||||
float segmentLen = 1.0/segmentNum;
|
float segmentLen = 1.0/segmentNum;
|
||||||
// face sampling.
|
// face sampling.
|
||||||
for(i=0; i < n_samples_per_edge-1; i++)
|
for(i=0; i < n_samples_per_edge-1; i++)
|
||||||
for(j=0; j < n_samples_per_edge-1-i; j++)
|
for(j=0; j < n_samples_per_edge-1-i; j++)
|
||||||
{
|
{
|
||||||
//AddSample( v0 + (V1*(double)i + V2*(double)j) );
|
//AddSample( v0 + (V1*(double)i + V2*(double)j) );
|
||||||
CoordType V0((i+0)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+0)*segmentLen) ) ;
|
CoordType V0((i+0)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+0)*segmentLen) ) ;
|
||||||
CoordType V1((i+1)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+0)*segmentLen) ) ;
|
CoordType V1((i+1)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+0)*segmentLen) ) ;
|
||||||
CoordType V2((i+0)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+1)*segmentLen) ) ;
|
CoordType V2((i+0)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+1)*segmentLen) ) ;
|
||||||
n_samples++;
|
n_samples++;
|
||||||
if(randomFlag) {
|
if(randomFlag) {
|
||||||
CoordType rb=RandomBarycentric();
|
CoordType rb=RandomBarycentric();
|
||||||
ps.AddFace(*fp, V0*rb[0]+V1*rb[1]+V2*rb[2]);
|
ps.AddFace(*fp, V0*rb[0]+V1*rb[1]+V2*rb[2]);
|
||||||
} else ps.AddFace(*fp,(V0+V1+V2)/3.0);
|
} else ps.AddFace(*fp,(V0+V1+V2)/3.0);
|
||||||
|
|
||||||
if( j < n_samples_per_edge-i-2 )
|
if( j < n_samples_per_edge-i-2 )
|
||||||
{
|
{
|
||||||
|
@ -848,47 +848,47 @@ static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_sample
|
||||||
if(randomFlag) {
|
if(randomFlag) {
|
||||||
CoordType rb=RandomBarycentric();
|
CoordType rb=RandomBarycentric();
|
||||||
ps.AddFace(*fp, V3*rb[0]+V1*rb[1]+V2*rb[2]);
|
ps.AddFace(*fp, V3*rb[0]+V1*rb[1]+V2*rb[2]);
|
||||||
} else ps.AddFace(*fp,(V3+V1+V2)/3.0);
|
} else ps.AddFace(*fp,(V3+V1+V2)/3.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n_samples;
|
return n_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar sampling
|
// Similar sampling
|
||||||
// Each triangle is subdivided into similar triangles following a generalization of the classical 1-to-4 splitting rule of triangles.
|
// Each triangle is subdivided into similar triangles following a generalization of the classical 1-to-4 splitting rule of triangles.
|
||||||
// According to the level of subdivision <k> you get 1, 4 , 9, 16 , <k^2> triangles.
|
// According to the level of subdivision <k> you get 1, 4 , 9, 16 , <k^2> triangles.
|
||||||
// Depending on the kind of the sampling strategies we can have two different approach to choosing the sample points.
|
// Depending on the kind of the sampling strategies we can have two different approach to choosing the sample points.
|
||||||
// 1) you have already sampled both edges and vertices
|
// 1) you have already sampled both edges and vertices
|
||||||
// 2) you are not going to take samples on edges and vertices.
|
// 2) you are not going to take samples on edges and vertices.
|
||||||
//
|
//
|
||||||
// In the first case you have to consider only internal vertices of the subdivided triangles (to avoid multiple sampling of edges and vertices).
|
// In the first case you have to consider only internal vertices of the subdivided triangles (to avoid multiple sampling of edges and vertices).
|
||||||
// Therefore the number of internal points is ((k-3)*(k-2))/2. where k is the number of points on an edge (vertex included)
|
// Therefore the number of internal points is ((k-3)*(k-2))/2. where k is the number of points on an edge (vertex included)
|
||||||
// E.g. for k=4 you get 3 segments on each edges and the original triangle is subdivided
|
// E.g. for k=4 you get 3 segments on each edges and the original triangle is subdivided
|
||||||
// into 9 smaller triangles and you get (1*2)/2 == 1 only a single internal point.
|
// into 9 smaller triangles and you get (1*2)/2 == 1 only a single internal point.
|
||||||
// So if you want N samples in a triangle you have to solve k^2 -5k +6 - 2N = 0
|
// So if you want N samples in a triangle you have to solve k^2 -5k +6 - 2N = 0
|
||||||
// from which you get:
|
// from which you get:
|
||||||
//
|
//
|
||||||
// 5 + sqrt( 1 + 8N )
|
// 5 + sqrt( 1 + 8N )
|
||||||
// k = -------------------
|
// k = -------------------
|
||||||
// 2
|
// 2
|
||||||
//
|
//
|
||||||
// In the second case if you are not interested to skip the sampling on edges and vertices you have to consider as sample number the number of triangles.
|
// In the second case if you are not interested to skip the sampling on edges and vertices you have to consider as sample number the number of triangles.
|
||||||
// So if you want N samples in a triangle, the number <k> of points on an edge (vertex included) should be simply:
|
// So if you want N samples in a triangle, the number <k> of points on an edge (vertex included) should be simply:
|
||||||
// k = 1 + sqrt(N)
|
// k = 1 + sqrt(N)
|
||||||
// examples:
|
// examples:
|
||||||
// N = 4 -> k = 3
|
// N = 4 -> k = 3
|
||||||
// N = 9 -> k = 4
|
// N = 9 -> k = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//template <class MetroMesh>
|
//template <class MetroMesh>
|
||||||
//void Sampling<MetroMesh>::SimilarFaceSampling()
|
//void Sampling<MetroMesh>::SimilarFaceSampling()
|
||||||
static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dualFlag, bool randomFlag)
|
static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dualFlag, bool randomFlag)
|
||||||
{
|
{
|
||||||
ScalarType area = Stat<MetroMesh>::ComputeMeshArea(m);
|
ScalarType area = Stat<MetroMesh>::ComputeMeshArea(m);
|
||||||
ScalarType samplePerAreaUnit = sampleNum/area;
|
ScalarType samplePerAreaUnit = sampleNum/area;
|
||||||
|
|
||||||
// Similar Triangles sampling.
|
// Similar Triangles sampling.
|
||||||
int n_samples_per_edge;
|
int n_samples_per_edge;
|
||||||
double n_samples_decimal = 0.0;
|
double n_samples_decimal = 0.0;
|
||||||
FaceIterator fi;
|
FaceIterator fi;
|
||||||
|
@ -901,14 +901,14 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
if(n_samples>0)
|
if(n_samples>0)
|
||||||
{
|
{
|
||||||
// face sampling.
|
// face sampling.
|
||||||
if(dualFlag)
|
if(dualFlag)
|
||||||
{
|
{
|
||||||
n_samples_per_edge = (int)((sqrt(1.0+8.0*(double)n_samples) +5.0)/2.0); // original for non dual case
|
n_samples_per_edge = (int)((sqrt(1.0+8.0*(double)n_samples) +5.0)/2.0); // original for non dual case
|
||||||
n_samples = SingleFaceSimilar(&*fi,ps, n_samples_per_edge);
|
n_samples = SingleFaceSimilar(&*fi,ps, n_samples_per_edge);
|
||||||
} else {
|
} else {
|
||||||
n_samples_per_edge = (int)(sqrt((double)n_samples) +1.0);
|
n_samples_per_edge = (int)(sqrt((double)n_samples) +1.0);
|
||||||
n_samples = SingleFaceSimilarDual(&*fi,ps, n_samples_per_edge,randomFlag);
|
n_samples = SingleFaceSimilarDual(&*fi,ps, n_samples_per_edge,randomFlag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n_samples_decimal -= (double) n_samples;
|
n_samples_decimal -= (double) n_samples;
|
||||||
}
|
}
|
||||||
|
@ -916,7 +916,7 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
|
|
||||||
|
|
||||||
// Rasterization fuction
|
// Rasterization fuction
|
||||||
// Take a triangle
|
// Take a triangle
|
||||||
// T deve essere una classe funzionale che ha l'operatore ()
|
// T deve essere una classe funzionale che ha l'operatore ()
|
||||||
// con due parametri x,y di tipo S esempio:
|
// con due parametri x,y di tipo S esempio:
|
||||||
// class Foo { public void operator()(int x, int y ) { ??? } };
|
// class Foo { public void operator()(int x, int y ) { ??? } };
|
||||||
|
@ -933,16 +933,16 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
typedef typename MetroMesh::ScalarType S;
|
typedef typename MetroMesh::ScalarType S;
|
||||||
// Calcolo bounding box
|
// Calcolo bounding box
|
||||||
Box2i bbox;
|
Box2i bbox;
|
||||||
Box2<S> bboxf;
|
Box2<S> bboxf;
|
||||||
bboxf.Add(v0);
|
bboxf.Add(v0);
|
||||||
bboxf.Add(v1);
|
bboxf.Add(v1);
|
||||||
bboxf.Add(v2);
|
bboxf.Add(v2);
|
||||||
|
|
||||||
bbox.min[0] = floor(bboxf.min[0]);
|
bbox.min[0] = floor(bboxf.min[0]);
|
||||||
bbox.min[1] = floor(bboxf.min[1]);
|
bbox.min[1] = floor(bboxf.min[1]);
|
||||||
bbox.max[0] = ceil(bboxf.max[0]);
|
bbox.max[0] = ceil(bboxf.max[0]);
|
||||||
bbox.max[1] = ceil(bboxf.max[1]);
|
bbox.max[1] = ceil(bboxf.max[1]);
|
||||||
|
|
||||||
// Calcolo versori degli spigoli
|
// Calcolo versori degli spigoli
|
||||||
Point2<S> d10 = v1 - v0;
|
Point2<S> d10 = v1 - v0;
|
||||||
Point2<S> d21 = v2 - v1;
|
Point2<S> d21 = v2 - v1;
|
||||||
|
@ -974,7 +974,7 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
edgeLength[0] = borderEdges[0].Length();
|
edgeLength[0] = borderEdges[0].Length();
|
||||||
edgeMask |= 1;
|
edgeMask |= 1;
|
||||||
}
|
}
|
||||||
if (f.IsB(1)) {
|
if (f.IsB(1)) {
|
||||||
borderEdges[1] = Segment2<S>(v1, v2);
|
borderEdges[1] = Segment2<S>(v1, v2);
|
||||||
edgeLength[1] = borderEdges[1].Length();
|
edgeLength[1] = borderEdges[1].Length();
|
||||||
edgeMask |= 2;
|
edgeMask |= 2;
|
||||||
|
@ -991,7 +991,7 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
for(int x=bbox.min[0]-1;x<=bbox.max[0]+1;++x)
|
for(int x=bbox.min[0]-1;x<=bbox.max[0]+1;++x)
|
||||||
{
|
{
|
||||||
bool in = false;
|
bool in = false;
|
||||||
S n[3] = { b0-db0-dn0, b1-db1-dn1, b2-db2-dn2};
|
S n[3] = { b0-db0-dn0, b1-db1-dn1, b2-db2-dn2};
|
||||||
for(int y=bbox.min[1]-1;y<=bbox.max[1]+1;++y)
|
for(int y=bbox.min[1]-1;y<=bbox.max[1]+1;++y)
|
||||||
{
|
{
|
||||||
if( ((n[0]>=0 && n[1]>=0 && n[2]>=0) || (n[0]<=0 && n[1]<=0 && n[2]<=0)) && (de != 0))
|
if( ((n[0]>=0 && n[1]>=0 && n[2]>=0) || (n[0]<=0 && n[1]<=0 && n[2]<=0)) && (de != 0))
|
||||||
|
@ -1013,10 +1013,10 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
// find the closest point (on some edge) that lies on the 2x2 squared neighborhood of the considered point
|
// find the closest point (on some edge) that lies on the 2x2 squared neighborhood of the considered point
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
if (edgeMask & (1 << i))
|
if (edgeMask & (1 << i))
|
||||||
{
|
{
|
||||||
Point2<S> close;
|
Point2<S> close;
|
||||||
S dst;
|
S dst;
|
||||||
if ( ((!flipped) && (n[i]<0)) ||
|
if ( ((!flipped) && (n[i]<0)) ||
|
||||||
( flipped && (n[i]>0)) )
|
( flipped && (n[i]>0)) )
|
||||||
{
|
{
|
||||||
|
@ -1030,7 +1030,7 @@ static void FaceSimilar(MetroMesh & m, VertexSampler &ps,int sampleNum, bool dua
|
||||||
closeEdge = i;
|
closeEdge = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closeEdge >= 0)
|
if (closeEdge >= 0)
|
||||||
|
@ -1094,11 +1094,11 @@ static bool checkPoissonDisk(SampleSHT & sht, const Point3<ScalarType> & p, Scal
|
||||||
GridGetInBox(sht, mv, bb, closests);
|
GridGetInBox(sht, mv, bb, closests);
|
||||||
|
|
||||||
ScalarType r2 = radius*radius;
|
ScalarType r2 = radius*radius;
|
||||||
for(int i=0; i<closests.size(); ++i)
|
for(int i=0; i<closests.size(); ++i)
|
||||||
if(SquaredDistance(p,closests[i]->cP()) < r2)
|
if(SquaredDistance(p,closests[i]->cP()) < r2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PoissonDiskParam
|
struct PoissonDiskParam
|
||||||
|
@ -1141,15 +1141,15 @@ struct PoissonDiskParam
|
||||||
static ScalarType ComputePoissonDiskRadius(MetroMesh &origMesh, int sampleNum)
|
static ScalarType ComputePoissonDiskRadius(MetroMesh &origMesh, int sampleNum)
|
||||||
{
|
{
|
||||||
ScalarType meshArea = Stat<MetroMesh>::ComputeMeshArea(origMesh);
|
ScalarType meshArea = Stat<MetroMesh>::ComputeMeshArea(origMesh);
|
||||||
// Manage approximately the PointCloud Case, use the half a area of the bbox.
|
// Manage approximately the PointCloud Case, use the half a area of the bbox.
|
||||||
// TODO: If you had the radius a much better approximation could be done.
|
// TODO: If you had the radius a much better approximation could be done.
|
||||||
if(meshArea ==0)
|
if(meshArea ==0)
|
||||||
{
|
{
|
||||||
meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
|
meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
|
||||||
origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
|
origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
|
||||||
origMesh.bbox.DimY()*origMesh.bbox.DimZ());
|
origMesh.bbox.DimY()*origMesh.bbox.DimZ());
|
||||||
}
|
}
|
||||||
ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
|
ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
|
||||||
return diskRadius;
|
return diskRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1175,7 +1175,7 @@ static void ComputePoissonSampleRadii(MetroMesh &sampleMesh, ScalarType diskRadi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trivial approach that puts all the samples in a UG and removes all the ones that surely do not fit the
|
// Trivial approach that puts all the samples in a UG and removes all the ones that surely do not fit the
|
||||||
static void PoissonDiskPruning(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &montecarloMesh,
|
static void PoissonDiskPruning(VertexSampler &ps, MetroMesh &montecarloMesh,
|
||||||
ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
|
ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
|
||||||
{
|
{
|
||||||
// spatial index of montecarlo samples - used to choose a new sample to insert
|
// spatial index of montecarlo samples - used to choose a new sample to insert
|
||||||
|
@ -1187,7 +1187,8 @@ static void PoissonDiskPruning(MetroMesh &origMesh, VertexSampler &ps, MetroMesh
|
||||||
int t0 = clock();
|
int t0 = clock();
|
||||||
|
|
||||||
// inflating
|
// inflating
|
||||||
BoxType bb=origMesh.bbox;
|
BoxType bb=montecarloMesh.bbox;
|
||||||
|
assert(!bb.IsNull());
|
||||||
bb.Offset(cellsize);
|
bb.Offset(cellsize);
|
||||||
|
|
||||||
int sizeX = std::max(1.0f,bb.DimX() / cellsize);
|
int sizeX = std::max(1.0f,bb.DimX() / cellsize);
|
||||||
|
@ -1255,7 +1256,7 @@ static void PoissonDiskPruning(MetroMesh &origMesh, VertexSampler &ps, MetroMesh
|
||||||
*
|
*
|
||||||
* This algorithm is an adaptation of the algorithm of White et al. :
|
* This algorithm is an adaptation of the algorithm of White et al. :
|
||||||
*
|
*
|
||||||
* "Poisson Disk Point Set by Hierarchical Dart Throwing"
|
* "Poisson Disk Point Set by Hierarchical Dart Throwing"
|
||||||
* K. B. White, D. Cline, P. K. Egbert,
|
* K. B. White, D. Cline, P. K. Egbert,
|
||||||
* IEEE Symposium on Interactive Ray Tracing, 2007,
|
* IEEE Symposium on Interactive Ray Tracing, 2007,
|
||||||
* 10-12 Sept. 2007, pp. 129-132.
|
* 10-12 Sept. 2007, pp. 129-132.
|
||||||
|
@ -1263,12 +1264,12 @@ static void PoissonDiskPruning(MetroMesh &origMesh, VertexSampler &ps, MetroMesh
|
||||||
static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
|
static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
|
||||||
{
|
{
|
||||||
// int t0=clock();
|
// int t0=clock();
|
||||||
// spatial index of montecarlo samples - used to choose a new sample to insert
|
// spatial index of montecarlo samples - used to choose a new sample to insert
|
||||||
MontecarloSHT montecarloSHTVec[5];
|
MontecarloSHT montecarloSHTVec[5];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// initialize spatial hash table for searching
|
// initialize spatial hash table for searching
|
||||||
// radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
|
// radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
|
||||||
// This radius implies that when we pick a sample in a cell all that cell will not be touched again.
|
// This radius implies that when we pick a sample in a cell all that cell will not be touched again.
|
||||||
ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
|
ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
|
||||||
|
@ -1280,7 +1281,7 @@ static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &monte
|
||||||
int sizeX = std::max(1.0f,bb.DimX() / cellsize);
|
int sizeX = std::max(1.0f,bb.DimX() / cellsize);
|
||||||
int sizeY = std::max(1.0f,bb.DimY() / cellsize);
|
int sizeY = std::max(1.0f,bb.DimY() / cellsize);
|
||||||
int sizeZ = std::max(1.0f,bb.DimZ() / cellsize);
|
int sizeZ = std::max(1.0f,bb.DimZ() / cellsize);
|
||||||
Point3i gridsize(sizeX, sizeY, sizeZ);
|
Point3i gridsize(sizeX, sizeY, sizeZ);
|
||||||
|
|
||||||
// spatial hash table of the generated samples - used to check the radius constrain
|
// spatial hash table of the generated samples - used to check the radius constrain
|
||||||
SampleSHT checkSHT;
|
SampleSHT checkSHT;
|
||||||
|
@ -1298,7 +1299,7 @@ static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &monte
|
||||||
//
|
//
|
||||||
|
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
||||||
// initialize spatial hash to index pre-generated samples
|
// initialize spatial hash to index pre-generated samples
|
||||||
montecarloSHTVec[0].InitEmpty(bb, gridsize);
|
montecarloSHTVec[0].InitEmpty(bb, gridsize);
|
||||||
// create active cell list
|
// create active cell list
|
||||||
|
@ -1307,12 +1308,12 @@ static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &monte
|
||||||
montecarloSHTVec[0].UpdateAllocatedCells();
|
montecarloSHTVec[0].UpdateAllocatedCells();
|
||||||
|
|
||||||
// if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii.
|
// if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii.
|
||||||
if(pp.adaptiveRadiusFlag)
|
if(pp.adaptiveRadiusFlag)
|
||||||
ComputePoissonSampleRadii(montecarloMesh, diskRadius, pp.radiusVariance, pp.invertQuality);
|
ComputePoissonSampleRadii(montecarloMesh, diskRadius, pp.radiusVariance, pp.invertQuality);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
MontecarloSHT &montecarloSHT = montecarloSHTVec[level];
|
MontecarloSHT &montecarloSHT = montecarloSHTVec[level];
|
||||||
|
|
||||||
if(level>0)
|
if(level>0)
|
||||||
{// initialize spatial hash with the remaining points
|
{// initialize spatial hash with the remaining points
|
||||||
|
@ -1322,29 +1323,29 @@ static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &monte
|
||||||
montecarloSHT.Add((*hi).second);
|
montecarloSHT.Add((*hi).second);
|
||||||
montecarloSHT.UpdateAllocatedCells();
|
montecarloSHT.UpdateAllocatedCells();
|
||||||
}
|
}
|
||||||
// shuffle active cells
|
// shuffle active cells
|
||||||
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
unsigned int (*p_myrandom)(unsigned int) = RandomInt;
|
||||||
std::random_shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), p_myrandom);
|
std::random_shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), p_myrandom);
|
||||||
|
|
||||||
// generate a sample inside C by choosing one of the contained pre-generated samples
|
// generate a sample inside C by choosing one of the contained pre-generated samples
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
int removedCnt=montecarloSHT.hash_table.size();
|
int removedCnt=montecarloSHT.hash_table.size();
|
||||||
int addedCnt=checkSHT.hash_table.size();
|
int addedCnt=checkSHT.hash_table.size();
|
||||||
for (int i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
|
for (int i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
|
||||||
{
|
{
|
||||||
for(int j=0;j<4;j++)
|
for(int j=0;j<4;j++)
|
||||||
{
|
{
|
||||||
if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
|
if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
|
||||||
|
|
||||||
// generate a sample chosen from the pre-generated one
|
// generate a sample chosen from the pre-generated one
|
||||||
typename MontecarloSHT::HashIterator hi = montecarloSHT.hash_table.find(montecarloSHT.AllocatedCells[i]);
|
typename MontecarloSHT::HashIterator hi = montecarloSHT.hash_table.find(montecarloSHT.AllocatedCells[i]);
|
||||||
|
|
||||||
if(hi==montecarloSHT.hash_table.end()) {break;}
|
if(hi==montecarloSHT.hash_table.end()) {break;}
|
||||||
VertexPointer sp = (*hi).second;
|
VertexPointer sp = (*hi).second;
|
||||||
// vr spans between 3.0*r and r / 4.0 according to vertex quality
|
// vr spans between 3.0*r and r / 4.0 according to vertex quality
|
||||||
ScalarType sampleRadius = diskRadius;
|
ScalarType sampleRadius = diskRadius;
|
||||||
if(pp.adaptiveRadiusFlag) sampleRadius = sp->Q();
|
if(pp.adaptiveRadiusFlag) sampleRadius = sp->Q();
|
||||||
if (checkPoissonDisk(checkSHT, sp->cP(), sampleRadius))
|
if (checkPoissonDisk(checkSHT, sp->cP(), sampleRadius))
|
||||||
{
|
{
|
||||||
ps.AddVert(*sp);
|
ps.AddVert(*sp);
|
||||||
montecarloSHT.RemoveCell(sp);
|
montecarloSHT.RemoveCell(sp);
|
||||||
|
@ -1354,17 +1355,17 @@ static void PoissonDisk(MetroMesh &origMesh, VertexSampler &ps, MetroMesh &monte
|
||||||
else
|
else
|
||||||
montecarloSHT.RemovePunctual(sp);
|
montecarloSHT.RemovePunctual(sp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addedCnt = checkSHT.hash_table.size()-addedCnt;
|
addedCnt = checkSHT.hash_table.size()-addedCnt;
|
||||||
removedCnt = removedCnt-montecarloSHT.hash_table.size();
|
removedCnt = removedCnt-montecarloSHT.hash_table.size();
|
||||||
|
|
||||||
// proceed to the next level of subdivision
|
// proceed to the next level of subdivision
|
||||||
// increase grid resolution
|
// increase grid resolution
|
||||||
gridsize *= 2;
|
gridsize *= 2;
|
||||||
|
|
||||||
//
|
//
|
||||||
level++;
|
level++;
|
||||||
} while(level < 5);
|
} while(level < 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
//template <class MetroMesh>
|
//template <class MetroMesh>
|
||||||
|
@ -1386,12 +1387,12 @@ static void Texture(MetroMesh & m, VertexSampler &ps, int textureWidth, int text
|
||||||
|
|
||||||
printf("Similar Triangles face sampling\n");
|
printf("Similar Triangles face sampling\n");
|
||||||
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
for(fi=m.face.begin(); fi != m.face.end(); fi++)
|
||||||
if (!fi->IsD())
|
if (!fi->IsD())
|
||||||
{
|
{
|
||||||
Point2f ti[3];
|
Point2f ti[3];
|
||||||
for(int i=0;i<3;++i)
|
for(int i=0;i<3;++i)
|
||||||
ti[i]=Point2f((*fi).WT(i).U() * textureWidth - 0.5, (*fi).WT(i).V() * textureHeight - 0.5);
|
ti[i]=Point2f((*fi).WT(i).U() * textureWidth - 0.5, (*fi).WT(i).V() * textureHeight - 0.5);
|
||||||
// - 0.5 constants are used to obtain correct texture mapping
|
// - 0.5 constants are used to obtain correct texture mapping
|
||||||
|
|
||||||
SingleFaceRaster(*fi, ps, ti[0],ti[1],ti[2], correctSafePointsBaryCoords);
|
SingleFaceRaster(*fi, ps, ti[0],ti[1],ti[2], correctSafePointsBaryCoords);
|
||||||
}
|
}
|
||||||
|
@ -1412,13 +1413,13 @@ static void RegularRecursiveOffset(MetroMesh & m, std::vector<Point3f> &pvec, Sc
|
||||||
{
|
{
|
||||||
Box3<ScalarType> bb=m.bbox;
|
Box3<ScalarType> bb=m.bbox;
|
||||||
bb.Offset(offset*2.0);
|
bb.Offset(offset*2.0);
|
||||||
|
|
||||||
RRParam rrp;
|
RRParam rrp;
|
||||||
|
|
||||||
rrp.markerFunctor.SetMesh(&m);
|
rrp.markerFunctor.SetMesh(&m);
|
||||||
|
|
||||||
rrp.gM.Set(m.face.begin(),m.face.end(),bb);
|
rrp.gM.Set(m.face.begin(),m.face.end(),bb);
|
||||||
|
|
||||||
|
|
||||||
rrp.offset=offset;
|
rrp.offset=offset;
|
||||||
rrp.minDiag=minDiag;
|
rrp.minDiag=minDiag;
|
||||||
|
@ -1428,9 +1429,9 @@ static void RegularRecursiveOffset(MetroMesh & m, std::vector<Point3f> &pvec, Sc
|
||||||
static void SubdivideAndSample(MetroMesh & m, std::vector<Point3f> &pvec, const Box3<ScalarType> bb, RRParam &rrp, float curDiag)
|
static void SubdivideAndSample(MetroMesh & m, std::vector<Point3f> &pvec, const Box3<ScalarType> bb, RRParam &rrp, float curDiag)
|
||||||
{
|
{
|
||||||
Point3f startPt = bb.Center();
|
Point3f startPt = bb.Center();
|
||||||
|
|
||||||
ScalarType dist;
|
ScalarType dist;
|
||||||
// Compute mesh point nearest to bb center
|
// Compute mesh point nearest to bb center
|
||||||
FaceType *nearestF=0;
|
FaceType *nearestF=0;
|
||||||
float dist_upper_bound = curDiag+rrp.offset;
|
float dist_upper_bound = curDiag+rrp.offset;
|
||||||
Point3f closestPt;
|
Point3f closestPt;
|
||||||
|
@ -1438,32 +1439,32 @@ static void SubdivideAndSample(MetroMesh & m, std::vector<Point3f> &pvec, const
|
||||||
dist=dist_upper_bound;
|
dist=dist_upper_bound;
|
||||||
nearestF = rrp.gM.GetClosest(PDistFunct,rrp.markerFunctor,startPt,dist_upper_bound,dist,closestPt);
|
nearestF = rrp.gM.GetClosest(PDistFunct,rrp.markerFunctor,startPt,dist_upper_bound,dist,closestPt);
|
||||||
curDiag /=2;
|
curDiag /=2;
|
||||||
if(dist < dist_upper_bound)
|
if(dist < dist_upper_bound)
|
||||||
{
|
{
|
||||||
if(curDiag/3 < rrp.minDiag) //store points only for the last level of recursion (?)
|
if(curDiag/3 < rrp.minDiag) //store points only for the last level of recursion (?)
|
||||||
{
|
{
|
||||||
if(rrp.offset==0)
|
if(rrp.offset==0)
|
||||||
pvec.push_back(closestPt);
|
pvec.push_back(closestPt);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(dist>rrp.offset) // points below the offset threshold cannot be displaced at the right offset distance, we can only make points nearer.
|
if(dist>rrp.offset) // points below the offset threshold cannot be displaced at the right offset distance, we can only make points nearer.
|
||||||
{
|
{
|
||||||
Point3f delta = startPt-closestPt;
|
Point3f delta = startPt-closestPt;
|
||||||
pvec.push_back(closestPt+delta*(rrp.offset/dist));
|
pvec.push_back(closestPt+delta*(rrp.offset/dist));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(curDiag < rrp.minDiag) return;
|
if(curDiag < rrp.minDiag) return;
|
||||||
Point3f hs = (bb.max-bb.min)/2;
|
Point3f hs = (bb.max-bb.min)/2;
|
||||||
for(int i=0;i<2;i++)
|
for(int i=0;i<2;i++)
|
||||||
for(int j=0;j<2;j++)
|
for(int j=0;j<2;j++)
|
||||||
for(int k=0;k<2;k++)
|
for(int k=0;k<2;k++)
|
||||||
SubdivideAndSample(m,pvec,
|
SubdivideAndSample(m,pvec,
|
||||||
Box3f(Point3f( bb.min[0]+i*hs[0], bb.min[1]+j*hs[1], bb.min[2]+k*hs[2]),
|
Box3f(Point3f( bb.min[0]+i*hs[0], bb.min[1]+j*hs[1], bb.min[2]+k*hs[2]),
|
||||||
Point3f(startPt[0]+i*hs[0],startPt[1]+j*hs[1],startPt[2]+k*hs[2])),rrp,curDiag);
|
Point3f(startPt[0]+i*hs[0],startPt[1]+j*hs[1],startPt[2]+k*hs[2])),rrp,curDiag);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}; // end class
|
}; // end class
|
||||||
|
|
||||||
|
|
||||||
|
@ -1522,4 +1523,4 @@ void PoissonSampling(MeshType &m, // the mesh that has to be sampled
|
||||||
} // end namespace vcg
|
} // end namespace vcg
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue