VCG Library
Loading...
Searching...
No Matches
point_sampling.h
1/****************************************************************************
2* VCGLib o o *
3* Visual and Computer Graphics Library o o *
4* _ O _ *
5* Copyright(C) 2004-2016 \/)\/ *
6* Visual Computing Lab /\/| *
7* ISTI - Italian National Research Council | *
8* \ *
9* All rights reserved. *
10* *
11* This program is free software; you can redistribute it and/or modify *
12* it under the terms of the GNU General Public License as published by *
13* the Free Software Foundation; either version 2 of the License, or *
14* (at your option) any later version. *
15* *
16* This program is distributed in the hope that it will be useful, *
17* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20* for more details. *
21* *
22****************************************************************************/
23/****************************************************************************
24
25The sampling Class has a set of static functions, that you can call to sample the surface of a mesh.
26Each function is templated on the mesh and on a Sampler object s.
27Each function calls many time the sample object with the sampling point as parameter.
28
29Sampler Classes and Sampling algorithms are independent.
30Sampler classes exploits the sample that are generated with various algorithms.
31For example, you can compute Hausdorff distance (that is a sampler) using various
32sampling strategies (montecarlo, stratified etc).
33
34****************************************************************************/
35#ifndef __VCGLIB_POINT_SAMPLING
36#define __VCGLIB_POINT_SAMPLING
37
38#include <random>
39
40#include <vcg/math/random_generator.h>
41#include <vcg/complex/algorithms/closest.h>
42#include <vcg/space/index/spatial_hashing.h>
43#include <vcg/complex/algorithms/hole.h>
44#include <vcg/complex/algorithms/stat.h>
45#include <vcg/complex/algorithms/create/platonic.h>
46#include <vcg/complex/algorithms/update/normal.h>
47#include <vcg/complex/algorithms/update/bounding.h>
48#include <vcg/space/segment2.h>
49#include <vcg/space/index/grid_static_ptr.h>
50
51namespace vcg
52{
53namespace tri
54{
57
70template <class MeshType>
72{
73public:
74 typedef typename MeshType::ScalarType ScalarType;
75 typedef typename MeshType::CoordType CoordType;
76 typedef typename MeshType::VertexType VertexType;
77 typedef typename MeshType::EdgeType EdgeType;
78 typedef typename MeshType::FaceType FaceType;
79
80 void reset()
81 {
82 sampleVec->clear();
83 }
84
86 {
87 sampleVec = new std::vector<CoordType>();
88 vectorOwner=true;
89 }
90
91 TrivialSampler(std::vector<CoordType> &Vec)
92 {
93 sampleVec = &Vec;
94 vectorOwner=false;
95 reset();
96 }
97
99 {
100 if(vectorOwner) delete sampleVec;
101 }
102
103private:
104 std::vector<CoordType> *sampleVec;
105 bool vectorOwner;
106public:
107
108 std::vector<CoordType> &SampleVec()
109 {
110 return *sampleVec;
111 }
112
113 void AddVert(const VertexType &p)
114 {
115 sampleVec->push_back(p.cP());
116 }
117 void AddEdge(const EdgeType& e, ScalarType u ) // u==0 -> v(0) u==1 -> v(1);
118 {
119 sampleVec->push_back(e.cV(0)->cP()*(1.0-u)+e.cV(1)->cP()*u);
120 }
121
122 void AddFace(const FaceType &f, const CoordType &p)
123 {
124 sampleVec->push_back(f.cP(0)*p[0] + f.cP(1)*p[1] +f.cP(2)*p[2] );
125 }
126
127 void AddTextureSample(const FaceType &, const CoordType &, const Point2i &, float )
128 {
129 // Retrieve the color of the sample from the face f using the barycentric coord p
130 // and write that color in a texture image at position <tp[0], texHeight-tp[1]>
131 // if edgeDist is > 0 then the corrisponding point is affecting face color even if outside the face area (in texture space)
132 }
133}; // end class TrivialSampler
134
135template <class MeshType>
137{
138public:
139 typedef typename MeshType::ScalarType ScalarType;
140 typedef typename MeshType::CoordType CoordType;
141 typedef typename MeshType::VertexType VertexType;
142 typedef typename MeshType::EdgeType EdgeType;
143 typedef typename MeshType::FaceType FaceType;
144
147
148 void reset()
149 {
150 sampleVec.clear();
151 }
152
153public:
154 std::vector<VertexType *> sampleVec;
155
156 void AddVert(VertexType &p)
157 {
158 sampleVec.push_back(&p);
159 }
160
161 void AddEdge(const EdgeType& e, ScalarType u ) // u==0 -> v(0) u==1 -> v(1);
162 {
163 if( u < 0.5 )
164 sampleVec.push_back(e.cV(0));
165 else
166 sampleVec.push_back(e.cV(1));
167 }
168
169 // This sampler should be used only for getting vertex pointers. Meaningless in other case.
170 void AddFace(const FaceType &, const CoordType &) { assert(0); }
171 void AddTextureSample(const FaceType &, const CoordType &, const Point2i &, float ) { assert(0); }
172}; // end class TrivialSampler
173
174
175template <class MeshType>
177{
178public:
179 typedef typename MeshType::VertexType VertexType;
180 typedef typename MeshType::FaceType FaceType;
181 typedef typename MeshType::EdgeType EdgeType;
182 typedef typename MeshType::CoordType CoordType;
183 typedef typename MeshType::ScalarType ScalarType;
184
185 MeshSampler(MeshType &_m):m(_m){
186 perFaceNormal = false;
187 }
188 MeshType &m;
189
190 bool perFaceNormal; // default false; if true the sample normal is the face normal, otherwise it is interpolated
191
192 void reset()
193 {
194 m.Clear();
195 }
196
197 void AddVert(const VertexType &p)
198 {
200 m.vert.back().ImportData(p);
201 }
202
203 void AddEdge(const EdgeType& e, ScalarType u ) // u==0 -> v(0) u==1 -> v(1);
204 {
206 m.vert.back().P() = e.cV(0)->cP()*(1.0-u)+e.cV(1)->cP()*u;
207 m.vert.back().N() = e.cV(0)->cN()*(1.0-u)+e.cV(1)->cN()*u;
208 }
209
210 void AddFace(const FaceType &f, CoordType p)
211 {
213 m.vert.back().P() = f.cP(0)*p[0] + f.cP(1)*p[1] +f.cP(2)*p[2];
214 if(perFaceNormal) m.vert.back().N() = f.cN();
215 else m.vert.back().N() = f.cV(0)->N()*p[0] + f.cV(1)->N()*p[1] + f.cV(2)->N()*p[2];
216 if(tri::HasPerVertexQuality(m) )
217 m.vert.back().Q() = f.cV(0)->Q()*p[0] + f.cV(1)->Q()*p[1] + f.cV(2)->Q()*p[2];
218 }
219}; // end class MeshSampler
220
221
222
223/* This sampler is used to perform compute the Hausdorff measuring.
224 * It keep internally the spatial indexing structure used to find the closest point
225 * and the partial integration results needed to compute the average and rms error values.
226 * Averaged values assume that the samples are equi-distributed (e.g. a good unbiased montecarlo sampling of the surface).
227 */
228template <class MeshType>
230{
231 typedef typename MeshType::FaceType FaceType;
232 typedef typename MeshType::VertexType VertexType;
233 typedef typename MeshType::CoordType CoordType;
234 typedef typename MeshType::ScalarType ScalarType;
235 typedef GridStaticPtr<FaceType, ScalarType > MetroMeshFaceGrid;
236 typedef GridStaticPtr<VertexType, ScalarType > MetroMeshVertexGrid;
237
238public:
239
240 HausdorffSampler(MeshType* _m, MeshType* _sampleMesh=0, MeshType* _closestMesh=0 ) :markerFunctor(_m)
241 {
242 m=_m;
243 init(_sampleMesh,_closestMesh);
244 }
245
246 MeshType *m;
247 MeshType *samplePtMesh;
248 MeshType *closestPtMesh;
249
250 MetroMeshVertexGrid unifGridVert;
251 MetroMeshFaceGrid unifGridFace;
252
253 // Parameters
254 double min_dist;
255 double max_dist;
256 double mean_dist;
257 double RMS_dist;
258 double volume;
259 double area_S1;
260 Histogramf hist;
261 // globals parameters driving the samples.
262 int n_total_samples;
263 int n_samples;
264 bool useVertexSampling;
265 ScalarType dist_upper_bound; // samples that have a distance beyond this threshold distance are not considered.
266 typedef typename tri::FaceTmark<MeshType> MarkerFace;
267 MarkerFace markerFunctor;
268
269
270 float getMeanDist() const { return mean_dist / n_total_samples; }
271 float getMinDist() const { return min_dist ; }
272 float getMaxDist() const { return max_dist ; }
273 float getRMSDist() const { return sqrt(RMS_dist / n_total_samples); }
274
275 void init(MeshType* _sampleMesh=0, MeshType* _closestMesh=0 )
276 {
277 samplePtMesh =_sampleMesh;
278 closestPtMesh = _closestMesh;
279 if(m)
280 {
282 if(m->fn==0) useVertexSampling = true;
283 else useVertexSampling = false;
284
285 if(useVertexSampling) unifGridVert.Set(m->vert.begin(),m->vert.end());
286 else unifGridFace.Set(m->face.begin(),m->face.end());
287 markerFunctor.SetMesh(m);
288 hist.SetRange(0.0, m->bbox.Diag()/100.0, 100);
289 }
290 min_dist = std::numeric_limits<double>::max();
291 max_dist = 0;
292 mean_dist =0;
293 RMS_dist = 0;
294 n_total_samples = 0;
295 }
296
297 void AddFace(const FaceType &f, CoordType interp)
298 {
299 CoordType startPt = f.cP(0)*interp[0] + f.cP(1)*interp[1] +f.cP(2)*interp[2]; // point to be sampled
300 CoordType startN = f.cV(0)->cN()*interp[0] + f.cV(1)->cN()*interp[1] +f.cV(2)->cN()*interp[2]; // Normal of the interpolated point
301 AddSample(startPt,startN); // point to be sampled);
302 }
303
304 void AddVert(VertexType &p)
305 {
306 p.Q()=AddSample(p.cP(),p.cN());
307 }
308
309
310 float AddSample(const CoordType &startPt,const CoordType &startN)
311 {
312 // the results
313 CoordType closestPt;
314 ScalarType dist = dist_upper_bound;
315
316 // compute distance between startPt and the mesh S2
317 FaceType *nearestF=0;
318 VertexType *nearestV=0;
319 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
320 dist=dist_upper_bound;
321 if(useVertexSampling)
322 nearestV = tri::GetClosestVertex<MeshType,MetroMeshVertexGrid>(*m,unifGridVert,startPt,dist_upper_bound,dist);
323 else
324 nearestF = unifGridFace.GetClosest(PDistFunct,markerFunctor,startPt,dist_upper_bound,dist,closestPt);
325
326 // update distance measures
327 if(dist == dist_upper_bound)
328 return dist;
329
330 if(dist > max_dist) max_dist = dist; // L_inf
331 if(dist < min_dist) min_dist = dist; // L_inf
332
333 mean_dist += dist; // L_1
334 RMS_dist += dist*dist; // L_2
335 n_total_samples++;
336
337 hist.Add((float)fabs(dist));
338 if(samplePtMesh)
339 {
341 samplePtMesh->vert.back().P() = startPt;
342 samplePtMesh->vert.back().Q() = dist;
343 samplePtMesh->vert.back().N() = startN;
344 }
345 if(closestPtMesh)
346 {
348 closestPtMesh->vert.back().P() = closestPt;
349 closestPtMesh->vert.back().Q() = dist;
350 closestPtMesh->vert.back().N() = startN;
351 }
352 return dist;
353 }
354}; // end class HausdorffSampler
355
356
357
358/* This sampler is used to transfer the detail of a mesh onto another one.
359 * It keep internally the spatial indexing structure used to find the closest point
360 */
361template <class MeshType>
363{
364 typedef typename MeshType::FaceType FaceType;
365 typedef typename MeshType::VertexType VertexType;
366 typedef typename MeshType::CoordType CoordType;
367 typedef typename MeshType::ScalarType ScalarType;
368 typedef GridStaticPtr<FaceType, ScalarType > MetroMeshGrid;
369 typedef GridStaticPtr<VertexType, ScalarType > VertexMeshGrid;
370
371public:
372
373 RedetailSampler():m(0) {}
374
375 MeshType *m;
376 CallBackPos *cb;
377 int sampleNum; // the expected number of samples. Used only for the callback
378 int sampleCnt;
379 MetroMeshGrid unifGridFace;
380 VertexMeshGrid unifGridVert;
381 bool useVertexSampling;
382
383 // Parameters
384 typedef tri::FaceTmark<MeshType> MarkerFace;
385 MarkerFace markerFunctor;
386
387 bool coordFlag;
388 bool colorFlag;
389 bool normalFlag;
390 bool qualityFlag;
391 bool selectionFlag;
392 bool storeDistanceAsQualityFlag;
393 float dist_upper_bound;
394 void init(MeshType *_m, CallBackPos *_cb=0, int targetSz=0)
395 {
396 coordFlag=false;
397 colorFlag=false;
398 qualityFlag=false;
399 selectionFlag=false;
400 storeDistanceAsQualityFlag=false;
401 m=_m;
403 if(m->fn==0) useVertexSampling = true;
404 else useVertexSampling = false;
405
406 if(useVertexSampling) unifGridVert.Set(m->vert.begin(),m->vert.end());
407 else unifGridFace.Set(m->face.begin(),m->face.end());
408 markerFunctor.SetMesh(m);
409 // sampleNum and sampleCnt are used only for the progress callback.
410 cb=_cb;
411 sampleNum = targetSz;
412 sampleCnt = 0;
413 }
414
415 // this function is called for each vertex of the target mesh.
416 // and retrieve the closest point on the source mesh.
417 void AddVert(VertexType &p)
418 {
419 assert(m);
420 // the results
421 CoordType closestPt, normf, bestq, ip;
422 ScalarType dist = dist_upper_bound;
423 const CoordType &startPt= p.cP();
424 // compute distance between startPt and the mesh S2
425 if(useVertexSampling)
426 {
427 VertexType *nearestV=0;
428 nearestV = tri::GetClosestVertex<MeshType,VertexMeshGrid>(*m,unifGridVert,startPt,dist_upper_bound,dist); //(PDistFunct,markerFunctor,startPt,dist_upper_bound,dist,closestPt);
429 if(cb) cb(sampleCnt++*100/sampleNum,"Resampling Vertex attributes");
430 if(storeDistanceAsQualityFlag) p.Q() = dist;
431 if(dist == dist_upper_bound) return ;
432
433 if(coordFlag) p.P()=nearestV->P();
434 if(colorFlag) p.C() = nearestV->C();
435 if(normalFlag) p.N() = nearestV->N();
436 if(qualityFlag) p.Q()= nearestV->Q();
437 if(selectionFlag) if(nearestV->IsS()) p.SetS();
438 }
439 else
440 {
441 FaceType *nearestF=0;
442 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
443 dist=dist_upper_bound;
444 if(cb) cb(sampleCnt++*100/sampleNum,"Resampling Vertex attributes");
445 nearestF = unifGridFace.GetClosest(PDistFunct,markerFunctor,startPt,dist_upper_bound,dist,closestPt);
446 if(dist == dist_upper_bound) return ;
447
448 CoordType interp;
449 InterpolationParameters(*nearestF,(*nearestF).cN(),closestPt, interp);
450 interp[2]=1.0-interp[1]-interp[0];
451
452 if(coordFlag) p.P()=closestPt;
453 if(colorFlag) p.C().lerp(nearestF->V(0)->C(),nearestF->V(1)->C(),nearestF->V(2)->C(),interp);
454 if(normalFlag) p.N() = nearestF->V(0)->N()*interp[0] + nearestF->V(1)->N()*interp[1] + nearestF->V(2)->N()*interp[2];
455 if(qualityFlag) p.Q()= nearestF->V(0)->Q()*interp[0] + nearestF->V(1)->Q()*interp[1] + nearestF->V(2)->Q()*interp[2];
456 if(selectionFlag) if(nearestF->IsS()) p.SetS();
457 }
458 }
459}; // end class RedetailSampler
460
461
462
463
474template <class MeshType, class VertexSampler = TrivialSampler< MeshType> >
476{
477 typedef typename MeshType::CoordType CoordType;
478 typedef typename MeshType::BoxType BoxType;
479 typedef typename MeshType::ScalarType ScalarType;
480 typedef typename MeshType::VertexType VertexType;
481 typedef typename MeshType::VertexPointer VertexPointer;
482 typedef typename MeshType::VertexIterator VertexIterator;
483 typedef typename MeshType::EdgeType EdgeType;
484 typedef typename MeshType::EdgeIterator EdgeIterator;
485 typedef typename MeshType::FaceType FaceType;
486 typedef typename MeshType::FacePointer FacePointer;
487 typedef typename MeshType::FaceIterator FaceIterator;
488 typedef typename MeshType::FaceContainer FaceContainer;
489
490 typedef typename vcg::SpatialHashTable<FaceType, ScalarType> MeshSHT;
491 typedef typename vcg::SpatialHashTable<FaceType, ScalarType>::CellIterator MeshSHTIterator;
492 typedef typename vcg::SpatialHashTable<VertexType, ScalarType> MontecarloSHT;
493 typedef typename vcg::SpatialHashTable<VertexType, ScalarType>::CellIterator MontecarloSHTIterator;
494 typedef typename vcg::SpatialHashTable<VertexType, ScalarType> SampleSHT;
495 typedef typename vcg::SpatialHashTable<VertexType, ScalarType>::CellIterator SampleSHTIterator;
496
497 typedef typename MeshType::template PerVertexAttributeHandle<float> PerVertexFloatAttribute;
498
499public:
500
501static math::MarsenneTwisterRNG &SamplingRandomGenerator()
502{
503 static math::MarsenneTwisterRNG rnd;
504 return rnd;
505}
506
507// Returns an integer random number in the [0,i-1] interval using the improve Marsenne-Twister method.
508// this functor is needed for passing it to the std functions.
509static unsigned int RandomInt(unsigned int i)
510{
511 return (SamplingRandomGenerator().generate(i));
512}
513
514// A UniformRandomBitGenerator over the shared sampling generator, for std::shuffle and
515// friends.
516//
517// It used to take an upper bound and return generate(bound), i.e. values in [0,bound),
518// while still advertising the full 32 bit range through min()/max() -- a broken
519// UniformRandomBitGenerator. In practice std::shuffle survived it, because every caller
520// passed the container size and the range shuffle asks for is bounded by that same size;
521// measured over 4000 permutations of a 642 vertex mesh the result was still uniform.
522// It is fixed anyway: the guarantee a generator makes about its own range should not
523// depend on a coincidence between two call sites, and a different standard library is
524// free to compose several calls into a wider value, where the missing high bits would
525// matter. The old one-argument constructor is kept, ignoring its argument, so existing
526// callers still compile.
527//
528// Note that this changes which random numbers each caller consumes, so a given seed no
529// longer selects the same subset it did before.
531{
532public:
533 typedef unsigned int result_type;
535 explicit MarsenneTwisterURBG(result_type /*unused_bound*/) {}
536 static constexpr result_type min() {return 0;}
537 static constexpr result_type max() {return std::numeric_limits<result_type>::max();}
538 result_type operator()() {return SamplingRandomGenerator().generate();}
539};
540
541// Returns a random number in the [0,1) real interval using the improved Marsenne-Twister method.
542static double RandomDouble01()
543{
544 return SamplingRandomGenerator().generate01();
545}
546
547#define FAK_LEN 1024
548static double LnFac(int n) {
549 // Tabled log factorial function. gives natural logarithm of n!
550
551 // define constants
552 static const double // coefficients in Stirling approximation
553 C0 = 0.918938533204672722, // ln(sqrt(2*pi))
554 C1 = 1./12.,
555 C3 = -1./360.;
556 // C5 = 1./1260., // use r^5 term if FAK_LEN < 50
557 // C7 = -1./1680.; // use r^7 term if FAK_LEN < 20
558 // static variables
559 static double fac_table[FAK_LEN]; // table of ln(n!):
560 static bool initialized = false; // remember if fac_table has been initialized
561
562
563 if (n < FAK_LEN) {
564 if (n <= 1) {
565 if (n < 0) assert(0);//("Parameter negative in LnFac function");
566 return 0;
567 }
568 if (!initialized) { // first time. Must initialize table
569 // make table of ln(n!)
570 double sum = fac_table[0] = 0.;
571 for (int i=1; i<FAK_LEN; i++) {
572 sum += log(double(i));
573 fac_table[i] = sum;
574 }
575 initialized = true;
576 }
577 return fac_table[n];
578 }
579 // not found in table. use Stirling approximation
580 double n1, r;
581 n1 = n; r = 1. / n1;
582 return (n1 + 0.5)*log(n1) - n1 + C0 + r*(C1 + r*r*C3);
583}
584
585static int PoissonRatioUniforms(double L) {
586 /*
587
588 This subfunction generates a integer with the poisson
589 distribution using the ratio-of-uniforms rejection method (PRUAt).
590 This approach is STABLE even for large L (e.g. it does not suffer from the overflow limit of the classical Knuth implementation)
591 Execution time does not depend on L, except that it matters whether
592 is within the range where ln(n!) is tabulated.
593
594 Reference:
595
596 E. Stadlober
597 "The ratio of uniforms approach for generating discrete random variates".
598 Journal of Computational and Applied Mathematics,
599 vol. 31, no. 1, 1990, pp. 181-189.
600
601 Partially adapted/inspired from some subfunctions of the Agner Fog stocc library ( www.agner.org/random )
602 Same licensing scheme.
603
604 */
605 // constants
606
607 const double SHAT1 = 2.943035529371538573; // 8/e
608 const double SHAT2 = 0.8989161620588987408; // 3-sqrt(12/e)
609 double u; // uniform random
610 double lf; // ln(f(x))
611 double x; // real sample
612 int k; // integer sample
613
614 double pois_a = L + 0.5; // hat center
615 int mode = (int)L; // mode
616 double pois_g = log(L);
617 double pois_f0 = mode * pois_g - LnFac(mode); // value at mode
618 double pois_h = sqrt(SHAT1 * (L+0.5)) + SHAT2; // hat width
619 double pois_bound = (int)(pois_a + 6.0 * pois_h); // safety-bound
620
621 while(1) {
622 u = RandomDouble01();
623 if (u == 0) continue; // avoid division by 0
624 x = pois_a + pois_h * (RandomDouble01() - 0.5) / u;
625 if (x < 0 || x >= pois_bound) continue; // reject if outside valid range
626 k = (int)(x);
627 lf = k * pois_g - LnFac(k) - pois_f0;
628 if (lf >= u * (4.0 - u) - 3.0) break; // quick acceptance
629 if (u * (u - lf) > 1.0) continue; // quick rejection
630 if (2.0 * log(u) <= lf) break; // final acceptance
631 }
632 return k;
633}
634
635
647static int Poisson(double lambda)
648{
649 if(lambda>50) return PoissonRatioUniforms(lambda);
650 double L = exp(-lambda);
651 int k =0;
652 double p = 1.0;
653 do
654 {
655 k = k+1;
656 p = p*RandomDouble01();
657 } while (p>L);
658
659 return k -1;
660}
661
662
663static void AllVertex(MeshType & m, VertexSampler &ps)
664{
665 AllVertex(m, ps, false);
666}
667
668static void AllVertex(MeshType & m, VertexSampler &ps, bool onlySelected)
669{
670 VertexIterator vi;
671 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
672 if(!(*vi).IsD())
673 if ((!onlySelected) || ((*vi).IsS()))
674 {
675 ps.AddVert(*vi);
676 }
677}
678
686
687static void VertexWeighted(MeshType & m, VertexSampler &ps, int sampleNum)
688{
689 ScalarType qSum = 0;
690 VertexIterator vi;
691 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
692 if(!(*vi).IsD())
693 qSum += (*vi).Q();
694
695 ScalarType samplePerUnit = sampleNum/qSum;
696 ScalarType floatSampleNum =0;
697 std::vector<VertexPointer> vertVec;
698 FillAndShuffleVertexPointerVector(m,vertVec);
699
700 std::vector<bool> vertUsed(m.vn,false);
701
702 int i=0; int cnt=0;
703 while(cnt < sampleNum)
704 {
705 if(vertUsed[i])
706 {
707 floatSampleNum += vertVec[i]->Q() * samplePerUnit;
708 int vertSampleNum = (int) floatSampleNum;
709 floatSampleNum -= (float) vertSampleNum;
710
711 // for every sample p_i in T...
712 if(vertSampleNum > 1)
713 {
714 ps.AddVert(*vertVec[i]);
715 cnt++;
716 vertUsed[i]=true;
717 }
718 }
719 i = (i+1)%m.vn;
720 }
721}
722
725static void VertexAreaUniform(MeshType & m, VertexSampler &ps, int sampleNum)
726{
727 VertexIterator vi;
728 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
729 if(!(*vi).IsD())
730 (*vi).Q() = 0;
731
732 FaceIterator fi;
733 for(fi = m.face.begin(); fi != m.face.end(); ++fi)
734 if(!(*fi).IsD())
735 {
736 ScalarType areaThird = DoubleArea(*fi)/6.0;
737 (*fi).V(0)->Q()+=areaThird;
738 (*fi).V(1)->Q()+=areaThird;
739 (*fi).V(2)->Q()+=areaThird;
740 }
741
742 VertexWeighted(m,ps,sampleNum);
743}
744
745static void FillAndShuffleFacePointerVector(MeshType & m, std::vector<FacePointer> &faceVec)
746{
747 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
748 if(!(*fi).IsD()) faceVec.push_back(&*fi);
749
750 assert((int)faceVec.size()==m.fn);
751
752 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
753 //std::random_device rd;
754 //std::mt19937 g(rd());
755 MarsenneTwisterURBG g;
756 std::shuffle(faceVec.begin(),faceVec.end(), g);
757}
758static void FillAndShuffleVertexPointerVector(MeshType & m, std::vector<VertexPointer> &vertVec)
759{
760 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
761 if(!(*vi).IsD()) vertVec.push_back(&*vi);
762
763 assert((int)vertVec.size()==m.vn);
764
765 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
766 //std::random_device rd;
767 //std::mt19937 g(rd());
768 MarsenneTwisterURBG g;
769 std::shuffle(vertVec.begin(),vertVec.end(), g);
770}
771
773static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum, bool onlySelected)
774{
775 if (sampleNum >= m.vn) {
776 AllVertex(m, ps, onlySelected);
777 return;
778 }
779
780 std::vector<VertexPointer> vertVec;
781 FillAndShuffleVertexPointerVector(m, vertVec);
782
783 int added = 0;
784 for (int i = 0; ((i < m.vn) && (added < sampleNum)); ++i)
785 if (!(*vertVec[i]).IsD())
786 if ((!onlySelected) || (*vertVec[i]).IsS())
787 {
788 ps.AddVert(*vertVec[i]);
789 added++;
790 }
791
792}
793
794
795static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum)
796{
797 VertexUniform(m, ps, sampleNum, false);
798}
799
800
808{
809 Floor = 0,
810 Round,
811 Ceil,
812};
813
829
830static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, EdgeSamplingRoundingStrategy strategy = Floor)
831{
832 tri::RequireEEAdjacency(m);
833 tri::RequireCompactness(m);
834 tri::RequirePerEdgeFlags(m);
835 tri::RequirePerVertexFlags(m);
838 tri::MeshAssert<MeshType>::EEOneManifold(m);
839
840 for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei)
841 {
842 if (!ei->IsV())
843 {
844 edge::Pos<EdgeType> ep(&*ei,0);
845 edge::Pos<EdgeType> startep = ep;
846 do // first loop to search a boundary component or check if it is a ring
847 {
848 ep.NextE();
849 if (ep.IsBorder())
850 break;
851 } while (startep != ep);
852
853 if (!ep.IsBorder()) // ******************** Circular Ring ********************
854 {
855 assert(ep == startep);
856
857 // to keep the uniform resampling order-independent:
858 // 1) start from the 'lowest' point...
859 edge::Pos<EdgeType> altEp = ep;
860 altEp.NextE();
861 while (altEp != startep) {
862 if (altEp.V()->cP() < ep.V()->cP())
863 {
864 ep = altEp;
865 }
866 altEp.NextE();
867 }
868
869 // 2) ... with consistent direction
870 const auto dir0 = ep.VFlip()->cP() - ep.V()->cP();
871 ep.FlipE();
872 const auto dir1 = ep.VFlip()->cP() - ep.V()->cP();
873 if (dir0 < dir1)
874 ep.FlipE();
875 }
876 else // ******************** NOT Circular Ring ********************
877 {
878 // to keep the uniform resampling order-independent
879 // start from the border with 'lowest' point
880 edge::Pos<EdgeType> altEp = ep;
881 do {
882 altEp.NextE();
883 } while (!altEp.IsBorder());
884
885 if (altEp.V()->cP() < ep.V()->cP())
886 {
887 ep = altEp;
888 }
889 }
890
891 ScalarType totalLen = 0;
892 ep.FlipV();
893 // second loop to compute the length of the chain marking visited all the edges
894 do
895 {
896 ep.E()->SetV();
897 totalLen += Distance(ep.V()->cP(), ep.VFlip()->cP());
898 ep.NextE();
899 } while (!ep.E()->IsV() && !ep.IsBorder());
900 if (ep.IsBorder() && !ep.E()->IsV())
901 {
902 ep.E()->SetV();
903 totalLen += Distance(ep.V()->cP(), ep.VFlip()->cP());
904 }
905
906 VertexPointer startVertex = ep.V();
907
908 // Third loop: actually performs the sampling by walking on the edge chain
909 int sampleNum = -1;
910 {
911 double div = double(totalLen) / radius;
912 switch (strategy) {
913 case Round: sampleNum = int(round(div)); break;
914 case Ceil: sampleNum = int( ceil(div)); break;
915 default: sampleNum = int(floor(div)); break;
916 };
917 }
918 assert(sampleNum >= 0);
919
920 ScalarType sampleDist = totalLen / sampleNum; // the steplen we use for sampling
921
922 // printf("Found a chain with len %f: we will place %i samples every %f (original radius : %f)\n", totalLen, sampleNum, sampleDist, radius);
923
924 ScalarType curLen = 0;
925 int sampleCnt = 1;
926 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 0.0 : 1.0); // First Sample always at the start of the chain
927
928 do {
929 ep.NextE();
930 assert(ep.E()->IsV());
931 ScalarType edgeLen = Distance(ep.VFlip()->cP(), ep.V()->cP());
932 ScalarType d0 = curLen;
933 ScalarType d1 = d0 + edgeLen;
934
935 while (d1 > sampleCnt * sampleDist && sampleCnt < sampleNum)
936 {
937 ScalarType off = (sampleCnt * sampleDist - d0) / edgeLen;
938// printf("edgeLen %f off %f samplecnt %i\n", edgeLen, off, sampleCnt);
939 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 1.0 - off : off);
940 sampleCnt++;
941 }
942 curLen += edgeLen;
943 } while(!ep.IsBorder() && ep.V() != startVertex);
944
945 if(ep.V() != startVertex) // if we are not in a loop we add the last vertex
946 {
947 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 0.0 : 1.0);
948 }
949 }
950 }
951}
952
953
959static void VertexBorderCorner(MeshType & m, VertexSampler &ps, ScalarType angleRad)
960{
962 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
963 {
964 if(vi->IsS()) ps.AddVert(*vi);
965 }
966}
967
973static void VertexBorder(MeshType & m, VertexSampler &ps)
974{
975 VertexBorderCorner(m,ps,std::numeric_limits<ScalarType>::max());
976}
977
984static void VertexCrease(MeshType & m, VertexSampler &ps)
985{
986 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
987 std::vector< SimpleEdge > Edges;
988 typename std::vector< SimpleEdge >::iterator ei;
990
991 typename MeshType::template PerVertexAttributeHandle <int> hv = tri::Allocator<MeshType>:: template GetPerVertexAttribute<int> (m);
992
993 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
994 {
995 hv[ei->v[0]]++;
996 hv[ei->v[1]]++;
997 }
998
999 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
1000 {
1001 if(hv[vi]>2)
1002 ps.AddVert(*vi);
1003 }
1004}
1005
1006
1007// AddFace() takes the sample's *barycentric* coordinates inside the face, not a
1008// position: the sampler reconstructs the point as v0*b[0]+v1*b[1]+v2*b[2]. Passing
1009// Barycenter(f), which is a world-space point, made every sample land on an arbitrary
1010// linear combination of the corners -- on a unit sphere, radii from 0.10 to 1.72
1011// instead of ~0.996. The face centroid in barycentric coordinates is simply (1/3,1/3,1/3).
1012static inline CoordType CentroidBarycentricCoord()
1013{
1014 return CoordType(ScalarType(1.0/3.0), ScalarType(1.0/3.0), ScalarType(1.0/3.0));
1015}
1016
1017static void FaceUniform(MeshType & m, VertexSampler &ps, int sampleNum)
1018{
1019 if(sampleNum>=m.fn) {
1020 AllFace(m,ps);
1021 return;
1022 }
1023
1024 std::vector<FacePointer> faceVec;
1025 FillAndShuffleFacePointerVector(m,faceVec);
1026
1027 for(int i =0; i< sampleNum; ++i)
1028 ps.AddFace(*faceVec[i],CentroidBarycentricCoord());
1029}
1030
1031static void AllFace(MeshType & m, VertexSampler &ps)
1032{
1033 FaceIterator fi;
1034 for(fi=m.face.begin();fi!=m.face.end();++fi)
1035 if(!(*fi).IsD())
1036 {
1037 ps.AddFace(*fi,CentroidBarycentricCoord());
1038 }
1039}
1040
1041
1042static void AllEdge(MeshType & m, VertexSampler &ps)
1043{
1044 // Edge sampling.
1045 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1046 std::vector< SimpleEdge > Edges;
1047 typename std::vector< SimpleEdge >::iterator ei;
1048 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges);
1049
1050 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1051 ps.AddFace(*(*ei).f,ei->EdgeBarycentricToFaceBarycentric(0.5));
1052}
1053
1054// Regular Uniform Edge sampling
1055// Each edge is subdivided in a number of pieces proprtional to its length
1056// Samples are chosen without touching the vertices.
1057
1058static void EdgeUniform(MeshType & m, VertexSampler &ps,int sampleNum, bool sampleFauxEdge=true)
1059{
1060 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1061
1062 std::vector< SimpleEdge > Edges;
1063 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges,sampleFauxEdge);
1064 // First loop compute total edge length;
1065 float edgeSum=0;
1066 typename std::vector< SimpleEdge >::iterator ei;
1067 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1068 edgeSum+=Distance((*ei).v[0]->P(),(*ei).v[1]->P());
1069
1070 float sampleLen = edgeSum/sampleNum;
1071 float rest=0;
1072 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1073 {
1074 float len = Distance((*ei).v[0]->P(),(*ei).v[1]->P());
1075 float samplePerEdge = floor((len+rest)/sampleLen);
1076 rest = (len+rest) - samplePerEdge * sampleLen;
1077 float step = 1.0/(samplePerEdge+1);
1078 for(int i=0;i<samplePerEdge;++i)
1079 {
1080 CoordType interp(0,0,0);
1081 interp[ (*ei).z ]=step*(i+1);
1082 interp[((*ei).z+1)%3]=1.0-step*(i+1);
1083 ps.AddFace(*(*ei).f,interp);
1084 }
1085 }
1086}
1087
1088// Generate the barycentric coords of a random point over a single face,
1089// with a uniform distribution over the triangle.
1090// It uses the parallelogram folding trick.
1091static CoordType RandomBarycentric()
1092{
1093 return math::GenerateBarycentricUniform<ScalarType>(SamplingRandomGenerator());
1094}
1095
1096// Given a triangle return a random point over it
1097static CoordType RandomPointInTriangle(const FaceType &f)
1098{
1099 CoordType u = RandomBarycentric();
1100 return f.cP(0)*u[0] + f.cP(1)*u[1] + f.cP(2)*u[2];
1101}
1102
1103static void StratifiedMontecarlo(MeshType & m, VertexSampler &ps,int sampleNum)
1104{
1105 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1106 ScalarType samplePerAreaUnit = sampleNum/area;
1107 // Montecarlo sampling.
1108 double floatSampleNum = 0.0;
1109
1110 FaceIterator fi;
1111 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1112 if(!(*fi).IsD())
1113 {
1114 // compute # samples in the current face (taking into account of the remainders)
1115 floatSampleNum += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
1116 int faceSampleNum = (int) floatSampleNum;
1117
1118 // for every sample p_i in T...
1119 for(int i=0; i < faceSampleNum; i++)
1120 ps.AddFace(*fi,RandomBarycentric());
1121 floatSampleNum -= (double) faceSampleNum;
1122 }
1123}
1124
1139static void MontecarloPoisson(MeshType & m, VertexSampler &ps,int sampleNum)
1140{
1141 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1142 ScalarType samplePerAreaUnit = sampleNum/area;
1143
1144 FaceIterator fi;
1145 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1146 if(!(*fi).IsD())
1147 {
1148 float areaT=DoubleArea(*fi) * 0.5f;
1149 int faceSampleNum = Poisson(areaT*samplePerAreaUnit);
1150
1151 // for every sample p_i in T...
1152 for(int i=0; i < faceSampleNum; i++)
1153 ps.AddFace(*fi,RandomBarycentric());
1154// SampleNum -= (double) faceSampleNum;
1155 }
1156}
1157
1158
1165static void EdgeMontecarlo(MeshType & m, VertexSampler &ps, int sampleNum, bool sampleAllEdges)
1166{
1167 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1168 std::vector< SimpleEdge > Edges;
1169 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges,sampleAllEdges);
1170
1171 assert(!Edges.empty());
1172
1173 typedef std::pair<ScalarType, SimpleEdge*> IntervalType;
1174 std::vector< IntervalType > intervals (Edges.size()+1);
1175 int i=0;
1176 intervals[i]=std::make_pair(0,(SimpleEdge*)(0));
1177 // First loop: build a sequence of consecutive segments proportional to the edge lenghts.
1178 typename std::vector< SimpleEdge >::iterator ei;
1179 for(ei=Edges.begin(); ei != Edges.end(); ei++)
1180 {
1181 intervals[i+1]=std::make_pair(intervals[i].first+Distance((*ei).v[0]->P(),(*ei).v[1]->P()), &*ei);
1182 ++i;
1183 }
1184
1185 // Second Loop get a point on the line 0...Sum(edgeLen) to pick a point;
1186 ScalarType edgeSum = intervals.back().first;
1187 for(i=0;i<sampleNum;++i)
1188 {
1189 ScalarType val = edgeSum * RandomDouble01();
1190 // lower_bound returns the furthermost iterator i in [first, last) such that, for every iterator j in [first, i), *j < value.
1191 // E.g. An iterator pointing to the first element "not less than" val, or end() if every element is less than val.
1192 typename std::vector<IntervalType>::iterator it = lower_bound(intervals.begin(),intervals.end(),std::make_pair(val,(SimpleEdge*)(0)) );
1193 assert(it != intervals.end() && it != intervals.begin());
1194 assert( ( (*(it-1)).first < val ) && ((*(it)).first >= val) );
1195 SimpleEdge * ep=(*it).second;
1196 ps.AddFace( *(ep->f), ep->EdgeBarycentricToFaceBarycentric(RandomDouble01()) );
1197 }
1198}
1199
1206static void Montecarlo(MeshType & m, VertexSampler &ps,int sampleNum)
1207{
1208 typedef std::pair<ScalarType, FacePointer> IntervalType;
1209 std::vector< IntervalType > intervals (m.fn+1);
1210 FaceIterator fi;
1211 int i=0;
1212 intervals[i]=std::make_pair(0,FacePointer(0));
1213 // First loop: build a sequence of consecutive segments proportional to the triangle areas.
1214 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1215 if(!(*fi).IsD())
1216 {
1217 intervals[i+1]=std::make_pair(intervals[i].first+0.5*DoubleArea(*fi), &*fi);
1218 ++i;
1219 }
1220 ScalarType meshArea = intervals.back().first;
1221 for(i=0;i<sampleNum;++i)
1222 {
1223 ScalarType val = meshArea * RandomDouble01();
1224 // lower_bound returns the furthermost iterator i in [first, last) such that, for every iterator j in [first, i), *j < value.
1225 // E.g. An iterator pointing to the first element "not less than" val, or end() if every element is less than val.
1226 typename std::vector<IntervalType>::iterator it = lower_bound(intervals.begin(),intervals.end(),std::make_pair(val,FacePointer(0)) );
1227 assert(it != intervals.end());
1228 assert(it != intervals.begin());
1229 assert( (*(it-1)).first <val );
1230 assert( (*(it)).first >= val);
1231 ps.AddFace( *(*it).second, RandomBarycentric() );
1232 }
1233}
1234
1235static ScalarType WeightedArea(FaceType &f, PerVertexFloatAttribute &wH)
1236{
1237 ScalarType averageQ = ( wH[f.V(0)] + wH[f.V(1)] + wH[f.V(2)] )/3.0;
1238 return averageQ*averageQ*DoubleArea(f)/2.0;
1239}
1240
1249static void WeightedMontecarlo(MeshType & m, VertexSampler &ps,int sampleNum, float variance)
1250{
1251 tri::RequirePerVertexQuality(m);
1252 tri::RequireCompactness(m);
1253 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m,"radius");
1254 InitRadiusHandleFromQuality(m, rH, 1.0, variance, true);
1255
1256 ScalarType weightedArea = 0;
1257 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
1258 weightedArea += WeightedArea(*fi,rH);
1259
1260 ScalarType samplePerAreaUnit = sampleNum/weightedArea;
1261 // Montecarlo sampling.
1262 double floatSampleNum = 0.0;
1263 for(FaceIterator fi=m.face.begin(); fi != m.face.end(); fi++)
1264 {
1265 // compute # samples in the current face (taking into account of the remainders)
1266 floatSampleNum += WeightedArea(*fi,rH) * samplePerAreaUnit;
1267 int faceSampleNum = (int) floatSampleNum;
1268
1269 // for every sample p_i in T...
1270 for(int i=0; i < faceSampleNum; i++)
1271 ps.AddFace(*fi,RandomBarycentric());
1272
1273 floatSampleNum -= (double) faceSampleNum;
1274 }
1275}
1276
1277
1278// Subdivision sampling of a single face.
1279// return number of added samples
1280
1281static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
1282{
1283 // recursive face subdivision.
1284 if(sampleNum == 1)
1285 {
1286 // ground case.
1287 CoordType SamplePoint;
1288 if(randSample)
1289 {
1290 CoordType rb=RandomBarycentric();
1291 SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
1292 }
1293 else SamplePoint=((v0+v1+v2)*(1.0f/3.0f));
1294
1295 ps.AddFace(*fp,SamplePoint);
1296 return 1;
1297 }
1298
1299 int s0 = sampleNum /2;
1300 int s1 = sampleNum-s0;
1301 assert(s0>0);
1302 assert(s1>0);
1303
1304 ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
1305 ScalarType w1 = 1.0-w0;
1306 // compute the longest edge.
1307 ScalarType maxd01 = SquaredDistance(v0,v1);
1308 ScalarType maxd12 = SquaredDistance(v1,v2);
1309 ScalarType maxd20 = SquaredDistance(v2,v0);
1310 int res;
1311 if(maxd01 > maxd12)
1312 if(maxd01 > maxd20) res = 0;
1313 else res = 2;
1314 else
1315 if(maxd12 > maxd20) res = 1;
1316 else res = 2;
1317
1318 int faceSampleNum=0;
1319 // break the input triangle along the midpoint of the longest edge.
1320 CoordType pp;
1321 switch(res)
1322 {
1323 case 0 : pp = v0*w0 + v1*w1;
1324 faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample);
1325 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1326 break;
1327 case 1 : pp = v1*w0 + v2*w1;
1328 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1329 faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample);
1330 break;
1331 case 2 : pp = v0*w0 + v2*w1;
1332 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1333 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1334 break;
1335 }
1336 return faceSampleNum;
1337}
1338
1339
1341static void FaceSubdivision(MeshType & m, VertexSampler &ps,int sampleNum, bool randSample)
1342{
1343
1344 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1345 ScalarType samplePerAreaUnit = sampleNum/area;
1346 std::vector<FacePointer> faceVec;
1347 FillAndShuffleFacePointerVector(m,faceVec);
1349 double floatSampleNum = 0.0;
1350 int faceSampleNum;
1351 // Subdivision sampling.
1352 typename std::vector<FacePointer>::iterator fi;
1353 for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
1354 {
1355 const CoordType b0(1.0, 0.0, 0.0);
1356 const CoordType b1(0.0, 1.0, 0.0);
1357 const CoordType b2(0.0, 0.0, 1.0);
1358 // compute # samples in the current face.
1359 floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
1360 faceSampleNum = (int) floatSampleNum;
1361 if(faceSampleNum>0)
1362 faceSampleNum = SingleFaceSubdivision(faceSampleNum,b0,b1,b2,ps,*fi,randSample);
1363 floatSampleNum -= (double) faceSampleNum;
1364 }
1365}
1366//---------
1367// Subdivision sampling of a single face.
1368// return number of added samples
1369
1370static int SingleFaceSubdivisionOld(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
1371{
1372 // recursive face subdivision.
1373 if(sampleNum == 1)
1374 {
1375 // ground case.
1376 CoordType SamplePoint;
1377 if(randSample)
1378 {
1379 CoordType rb=RandomBarycentric();
1380 SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
1381 }
1382 else SamplePoint=((v0+v1+v2)*(1.0f/3.0f));
1383
1384 CoordType SampleBary;
1385 InterpolationParameters(*fp,SamplePoint,SampleBary);
1386 ps.AddFace(*fp,SampleBary);
1387 return 1;
1388 }
1389
1390 int s0 = sampleNum /2;
1391 int s1 = sampleNum-s0;
1392 assert(s0>0);
1393 assert(s1>0);
1394
1395 ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
1396 ScalarType w1 = 1.0-w0;
1397 // compute the longest edge.
1398 ScalarType maxd01 = SquaredDistance(v0,v1);
1399 ScalarType maxd12 = SquaredDistance(v1,v2);
1400 ScalarType maxd20 = SquaredDistance(v2,v0);
1401 int res;
1402 if(maxd01 > maxd12)
1403 if(maxd01 > maxd20) res = 0;
1404 else res = 2;
1405 else
1406 if(maxd12 > maxd20) res = 1;
1407 else res = 2;
1408
1409 int faceSampleNum=0;
1410 // break the input triangle along the midpoint of the longest edge.
1411 CoordType pp;
1412 switch(res)
1413 {
1414 case 0 : pp = v0*w0 + v1*w1;
1415 faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample);
1416 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1417 break;
1418 case 1 : pp = v1*w0 + v2*w1;
1419 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1420 faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample);
1421 break;
1422 case 2 : pp = v0*w0 + v2*w1;
1423 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1424 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1425 break;
1426 }
1427 return faceSampleNum;
1428}
1429
1430
1432static void FaceSubdivisionOld(MeshType & m, VertexSampler &ps,int sampleNum, bool randSample)
1433{
1434
1435 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1436 ScalarType samplePerAreaUnit = sampleNum/area;
1437 std::vector<FacePointer> faceVec;
1438 FillAndShuffleFacePointerVector(m,faceVec);
1440 double floatSampleNum = 0.0;
1441 int faceSampleNum;
1442 // Subdivision sampling.
1443 typename std::vector<FacePointer>::iterator fi;
1444 for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
1445 {
1446 // compute # samples in the current face.
1447 floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
1448 faceSampleNum = (int) floatSampleNum;
1449 if(faceSampleNum>0)
1450 faceSampleNum = SingleFaceSubdivision(faceSampleNum,(**fi).V(0)->cP(), (**fi).V(1)->cP(), (**fi).V(2)->cP(),ps,*fi,randSample);
1451 floatSampleNum -= (double) faceSampleNum;
1452 }
1453}
1454
1455
1456//---------
1457
1458// Similar Triangles sampling.
1459// Skip vertex and edges
1460// Sample per edges includes vertexes, so here we should expect n_samples_per_edge >=4
1461
1462static int SingleFaceSimilar(FacePointer fp, VertexSampler &ps, int n_samples_per_edge)
1463{
1464 int n_samples=0;
1465 int i, j;
1466 float segmentNum=n_samples_per_edge -1 ;
1467 float segmentLen = 1.0/segmentNum;
1468 // face sampling.
1469 for(i=1; i < n_samples_per_edge-1; i++)
1470 for(j=1; j < n_samples_per_edge-1-i; j++)
1471 {
1472 //AddSample( v0 + (V1*(double)i + V2*(double)j) );
1473 CoordType sampleBary(i*segmentLen,j*segmentLen, 1.0 - (i*segmentLen+j*segmentLen) ) ;
1474 n_samples++;
1475 ps.AddFace(*fp,sampleBary);
1476 }
1477 return n_samples;
1478}
1479static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_samples_per_edge, bool randomFlag)
1480{
1481 int n_samples=0;
1482 float i, j;
1483 float segmentNum=n_samples_per_edge -1 ;
1484 float segmentLen = 1.0/segmentNum;
1485 // face sampling.
1486 for(i=0; i < n_samples_per_edge-1; i++)
1487 for(j=0; j < n_samples_per_edge-1-i; j++)
1488 {
1489 //AddSample( v0 + (V1*(double)i + V2*(double)j) );
1490 CoordType V0((i+0)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+0)*segmentLen) ) ;
1491 CoordType V1((i+1)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+0)*segmentLen) ) ;
1492 CoordType V2((i+0)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+1)*segmentLen) ) ;
1493 n_samples++;
1494 if(randomFlag) {
1495 CoordType rb=RandomBarycentric();
1496 ps.AddFace(*fp, V0*rb[0]+V1*rb[1]+V2*rb[2]);
1497 } else ps.AddFace(*fp,(V0+V1+V2)/3.0);
1498
1499 if( j < n_samples_per_edge-i-2 )
1500 {
1501 CoordType V3((i+1)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+1)*segmentLen) ) ;
1502 n_samples++;
1503 if(randomFlag) {
1504 CoordType rb=RandomBarycentric();
1505 ps.AddFace(*fp, V3*rb[0]+V1*rb[1]+V2*rb[2]);
1506 } else ps.AddFace(*fp,(V3+V1+V2)/3.0);
1507 }
1508 }
1509 return n_samples;
1510}
1511
1512// Similar sampling
1513// Each triangle is subdivided into similar triangles following a generalization of the classical 1-to-4 splitting rule of triangles.
1514// According to the level of subdivision <k> you get 1, 4 , 9, 16 , <k^2> triangles.
1515// Depending on the kind of the sampling strategies we can have two different approach to choosing the sample points.
1516// 1) you have already sampled both edges and vertices
1517// 2) you are not going to take samples on edges and vertices.
1518//
1519// In the first case you have to consider only internal vertices of the subdivided triangles (to avoid multiple sampling of edges and vertices).
1520// Therefore the number of internal points is ((k-3)*(k-2))/2. where k is the number of points on an edge (vertex included)
1521// E.g. for k=4 you get 3 segments on each edges and the original triangle is subdivided
1522// into 9 smaller triangles and you get (1*2)/2 == 1 only a single internal point.
1523// So if you want N samples in a triangle you have to solve k^2 -5k +6 - 2N = 0
1524// from which you get:
1525//
1526// 5 + sqrt( 1 + 8N )
1527// k = -------------------
1528// 2
1529//
1530// 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.
1531// So if you want N samples in a triangle, the number <k> of points on an edge (vertex included) should be simply:
1532// k = 1 + sqrt(N)
1533// examples:
1534// N = 4 -> k = 3
1535// N = 9 -> k = 4
1536
1537
1538
1539//template <class MeshType>
1540//void Sampling<MeshType>::SimilarFaceSampling()
1541static void FaceSimilar(MeshType & m, VertexSampler &ps,int sampleNum, bool dualFlag, bool randomFlag)
1542{
1543 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1544 ScalarType samplePerAreaUnit = sampleNum/area;
1545
1546 // Similar Triangles sampling.
1547 int n_samples_per_edge;
1548 double n_samples_decimal = 0.0;
1549 FaceIterator fi;
1550
1551 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1552 {
1553 // compute # samples in the current face.
1554 n_samples_decimal += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
1555 int n_samples = (int) n_samples_decimal;
1556 if(n_samples>0)
1557 {
1558 // face sampling.
1559 if(dualFlag)
1560 {
1561 n_samples_per_edge = (int)((sqrt(1.0+8.0*(double)n_samples) +5.0)/2.0); // original for non dual case
1562 n_samples = SingleFaceSimilar(&*fi,ps, n_samples_per_edge);
1563 } else {
1564 n_samples_per_edge = (int)(sqrt((double)n_samples) +1.0);
1565 n_samples = SingleFaceSimilarDual(&*fi,ps, n_samples_per_edge,randomFlag);
1566 }
1567 }
1568 n_samples_decimal -= (double) n_samples;
1569 }
1570}
1571
1572
1573 // Rasterization fuction
1574 // Take a triangle
1575 // T deve essere una classe funzionale che ha l'operatore ()
1576 // con due parametri x,y di tipo S esempio:
1577 // class Foo { public void operator()(int x, int y ) { ??? } };
1578
1579// This function does rasterization with a safety buffer area, thus accounting some points actually outside triangle area
1580// The safety area samples are generated according to face flag BORDER which should be true for texture space border edges
1581// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge).
1582 static void SingleFaceRaster(typename MeshType::FaceType &f, VertexSampler &ps,
1583 const Point2<typename MeshType::ScalarType> & v0,
1584 const Point2<typename MeshType::ScalarType> & v1,
1585 const Point2<typename MeshType::ScalarType> & v2,
1586 bool correctSafePointsBaryCoords=true)
1587 {
1588 typedef typename MeshType::ScalarType S;
1589 // Calcolo bounding box
1590 Box2i bbox;
1591 Box2<S> bboxf;
1592 bboxf.Add(v0);
1593 bboxf.Add(v1);
1594 bboxf.Add(v2);
1595
1596 bbox.min[0] = floor(bboxf.min[0]);
1597 bbox.min[1] = floor(bboxf.min[1]);
1598 bbox.max[0] = ceil(bboxf.max[0]);
1599 bbox.max[1] = ceil(bboxf.max[1]);
1600
1601 // Calcolo versori degli spigoli
1602 Point2<S> d10 = v1 - v0;
1603 Point2<S> d21 = v2 - v1;
1604 Point2<S> d02 = v0 - v2;
1605
1606 // Preparazione prodotti scalari
1607 S b0 = (bbox.min[0]-v0[0])*d10[1] - (bbox.min[1]-v0[1])*d10[0];
1608 S b1 = (bbox.min[0]-v1[0])*d21[1] - (bbox.min[1]-v1[1])*d21[0];
1609 S b2 = (bbox.min[0]-v2[0])*d02[1] - (bbox.min[1]-v2[1])*d02[0];
1610 // Preparazione degli steps
1611 S db0 = d10[1];
1612 S db1 = d21[1];
1613 S db2 = d02[1];
1614 // Preparazione segni
1615 S dn0 = -d10[0];
1616 S dn1 = -d21[0];
1617 S dn2 = -d02[0];
1618
1619 //Calculating orientation
1620 bool flipped = !(d02 * vcg::Point2<S>(-d10[1], d10[0]) >= 0);
1621
1622 // Calculating border edges
1623 Segment2<S> borderEdges[3];
1624 S edgeLength[3];
1625 unsigned char edgeMask = 0;
1626
1627 if (f.IsB(0)) {
1628 borderEdges[0] = Segment2<S>(v0, v1);
1629 edgeLength[0] = borderEdges[0].Length();
1630 edgeMask |= 1;
1631 }
1632 if (f.IsB(1)) {
1633 borderEdges[1] = Segment2<S>(v1, v2);
1634 edgeLength[1] = borderEdges[1].Length();
1635 edgeMask |= 2;
1636 }
1637 if (f.IsB(2)) {
1638 borderEdges[2] = Segment2<S>(v2, v0);
1639 edgeLength[2] = borderEdges[2].Length();
1640 edgeMask |= 4;
1641 }
1642
1643 // Rasterizzazione
1644 double de = v0[0]*v1[1]-v0[0]*v2[1]-v1[0]*v0[1]+v1[0]*v2[1]-v2[0]*v1[1]+v2[0]*v0[1];
1645
1646 for(int x=bbox.min[0]-1;x<=bbox.max[0]+1;++x)
1647 {
1648 bool in = false;
1649 S n[3] = { b0-db0-dn0, b1-db1-dn1, b2-db2-dn2};
1650 for(int y=bbox.min[1]-1;y<=bbox.max[1]+1;++y)
1651 {
1652 if( ((n[0]>=0 && n[1]>=0 && n[2]>=0) || (n[0]<=0 && n[1]<=0 && n[2]<=0)) && (de != 0))
1653 {
1654 typename MeshType::CoordType baryCoord;
1655 baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de;
1656 baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de;
1657 baryCoord[2] = 1-baryCoord[0]-baryCoord[1];
1658
1659 ps.AddTextureSample(f, baryCoord, Point2i(x,y), 0);
1660 in = true;
1661 } else {
1662 // Check whether a pixel outside (on a border edge side) triangle affects color inside it
1663 Point2<S> px(x, y);
1664 Point2<S> closePoint;
1665 int closeEdge = -1;
1666 S minDst = FLT_MAX;
1667
1668 // find the closest point (on some edge) that lies on the 2x2 squared neighborhood of the considered point
1669 for (int i=0; i<3; ++i)
1670 {
1671 if (edgeMask & (1 << i))
1672 {
1673 Point2<S> close;
1674 S dst;
1675 if ( ((!flipped) && (n[i]<0)) ||
1676 ( flipped && (n[i]>0)) )
1677 {
1678 dst = ((close = ClosestPoint(borderEdges[i], px)) - px).Norm();
1679 if(dst < minDst &&
1680 close.X() > px.X()-1 && close.X() < px.X()+1 &&
1681 close.Y() > px.Y()-1 && close.Y() < px.Y()+1)
1682 {
1683 minDst = dst;
1684 closePoint = close;
1685 closeEdge = i;
1686 }
1687 }
1688 }
1689 }
1690
1691 if (closeEdge >= 0)
1692 {
1693 typename MeshType::CoordType baryCoord;
1694 if (correctSafePointsBaryCoords)
1695 {
1696 // Add x,y sample with closePoint barycentric coords (on edge)
1697 baryCoord[closeEdge] = (closePoint - borderEdges[closeEdge].P1()).Norm()/edgeLength[closeEdge];
1698 baryCoord[(closeEdge+1)%3] = 1 - baryCoord[closeEdge];
1699 baryCoord[(closeEdge+2)%3] = 0;
1700 } else {
1701 // Add x,y sample with his own barycentric coords (off edge)
1702 baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de;
1703 baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de;
1704 baryCoord[2] = 1-baryCoord[0]-baryCoord[1];
1705 }
1706 ps.AddTextureSample(f, baryCoord, Point2i(x,y), minDst);
1707 in = true;
1708 }
1709 }
1710 n[0] += dn0;
1711 n[1] += dn1;
1712 n[2] += dn2;
1713 }
1714 b0 += db0;
1715 b1 += db1;
1716 b2 += db2;
1717 }
1718}
1719
1720// check the radius constrain
1721static bool checkPoissonDisk(SampleSHT & sht, const Point3<ScalarType> & p, ScalarType radius)
1722{
1723 // get the samples closest to the given one
1724 std::vector<VertexType*> closests;
1725 typedef EmptyTMark<MeshType> MarkerVert;
1726 static MarkerVert mv;
1727
1728 Box3f bb(p-Point3f(radius,radius,radius),p+Point3f(radius,radius,radius));
1729 GridGetInBox(sht, mv, bb, closests);
1730
1731 ScalarType r2 = radius*radius;
1732 for(int i=0; i<closests.size(); ++i)
1733 if(SquaredDistance(p,closests[i]->cP()) < r2)
1734 return false;
1735
1736 return true;
1737}
1738
1740{
1742 {
1743 adaptiveRadiusFlag = false;
1744 bestSampleChoiceFlag = true;
1745 bestSamplePoolSize = 10;
1746 radiusVariance =1;
1747 MAXLEVELS = 5;
1748 invertQuality = false;
1749 preGenFlag = false;
1750 preGenMesh = NULL;
1751 geodesicDistanceFlag = false;
1752 randomSeed = 0;
1753 }
1754
1755 struct Stat
1756 {
1757 int montecarloTime;
1758 int gridTime;
1759 int pruneTime;
1760 int totalTime;
1761 Point3i gridSize;
1762 int gridCellNum;
1763 size_t sampleNum;
1764 int montecarloSampleNum;
1765 };
1766
1767 bool geodesicDistanceFlag;
1768 bool bestSampleChoiceFlag; // In poisson disk pruning when we choose a sample in a cell, we choose the sample that remove the minimal number of other samples. This previlege the "on boundary" samples.
1769 int bestSamplePoolSize;
1770 bool adaptiveRadiusFlag;
1771 float radiusVariance;
1772 bool invertQuality;
1773 bool preGenFlag; // when generating a poisson distribution, you can initialize the set of computed points with
1774 // ALL the vertices of another mesh. Useful for building progressive//prioritize refinements.
1775 MeshType *preGenMesh; // There are two ways of passing the pregen vertexes to the pruning, 1) is with a mesh pointer
1776 // 2) with a per vertex attribute.
1777 int MAXLEVELS;
1778 int randomSeed;
1779
1780 Stat pds;
1781};
1782
1783
1784// generate Poisson-disk sample using a set of pre-generated samples (with the Montecarlo algorithm)
1785// It always return a point.
1786static VertexPointer getSampleFromCell(Point3i &cell, MontecarloSHT & samplepool)
1787{
1788 MontecarloSHTIterator cellBegin, cellEnd;
1789 samplepool.Grid(cell, cellBegin, cellEnd);
1790 return *cellBegin;
1791}
1792
1793// Given a cell of the grid it search the point that remove the minimum number of other samples
1794// it linearly scan all the points of a cell.
1795
1796static VertexPointer getBestPrecomputedMontecarloSample(Point3i &cell, MontecarloSHT & samplepool, ScalarType diskRadius, const PoissonDiskParam &pp)
1797{
1798 MontecarloSHTIterator cellBegin,cellEnd;
1799 samplepool.Grid(cell, cellBegin, cellEnd);
1800 VertexPointer bestSample=0;
1801 int minRemoveCnt = std::numeric_limits<int>::max();
1802 std::vector<typename MontecarloSHT::HashIterator> inSphVec;
1803 int i=0;
1804 for(MontecarloSHTIterator ci=cellBegin; ci!=cellEnd && i<pp.bestSamplePoolSize; ++ci,i++)
1805 {
1806 VertexPointer sp = *ci;
1807 if(pp.adaptiveRadiusFlag) diskRadius = sp->Q();
1808 int curRemoveCnt = samplepool.CountInSphere(sp->cP(),diskRadius,inSphVec);
1809 if(curRemoveCnt < minRemoveCnt)
1810 {
1811 bestSample = sp;
1812 minRemoveCnt = curRemoveCnt;
1813 }
1814 }
1815 return bestSample;
1816}
1817
1820static ScalarType ComputePoissonDiskRadius(MeshType &origMesh, int sampleNum)
1821{
1822 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
1823 // Manage approximately the PointCloud Case, use the half a area of the bbox.
1824 // TODO: If you had the radius a much better approximation could be done.
1825 if(meshArea ==0)
1826 {
1827 meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
1828 origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
1829 origMesh.bbox.DimY()*origMesh.bbox.DimZ());
1830 }
1831 ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
1832 return diskRadius;
1833}
1834
1835static int ComputePoissonSampleNum(MeshType &origMesh, ScalarType diskRadius)
1836{
1837 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
1838 int sampleNum = meshArea / (diskRadius*diskRadius *M_PI *0.7) ; // 0.7 is a density factor
1839 return sampleNum;
1840}
1841
1848
1849static void InitRadiusHandleFromQuality(MeshType &sampleMesh, PerVertexFloatAttribute &rH, ScalarType diskRadius, ScalarType radiusVariance, bool invert)
1850{
1851 std::pair<float,float> minmax = tri::Stat<MeshType>::ComputePerVertexQualityMinMax( sampleMesh);
1852 float minRad = diskRadius ;
1853 float maxRad = diskRadius * radiusVariance;
1854 float deltaQ = minmax.second-minmax.first;
1855 float deltaRad = maxRad-minRad;
1856 for (VertexIterator vi = sampleMesh.vert.begin(); vi != sampleMesh.vert.end(); vi++)
1857 {
1858 rH[*vi] = minRad + deltaRad*((invert ? minmax.second - (*vi).Q() : (*vi).Q() - minmax.first )/deltaQ);
1859 }
1860}
1861
1862// initialize spatial hash table for searching
1863// radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
1864// This radius implies that when we pick a sample in a cell all that cell probably will not be touched again.
1865// Howvever we must ensure that we do not put too many vertices inside each hash cell
1866
1867static void InitSpatialHashTable(MeshType &montecarloMesh, MontecarloSHT &montecarloSHT, ScalarType diskRadius,
1868 struct PoissonDiskParam pp=PoissonDiskParam())
1869{
1870 ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
1871 float occupancyRatio=0;
1872 do
1873 {
1874 // inflating
1875 BoxType bb=montecarloMesh.bbox;
1876 assert(!bb.IsNull());
1877 bb.Offset(cellsize);
1878
1879 int sizeX = std::max(1,int(bb.DimX() / cellsize));
1880 int sizeY = std::max(1,int(bb.DimY() / cellsize));
1881 int sizeZ = std::max(1,int(bb.DimZ() / cellsize));
1882 Point3i gridsize(sizeX, sizeY, sizeZ);
1883
1884 montecarloSHT.InitEmpty(bb, gridsize);
1885
1886 for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++)
1887 if(!(*vi).IsD())
1888 {
1889 montecarloSHT.Add(&(*vi));
1890 }
1891
1892 montecarloSHT.UpdateAllocatedCells();
1893 pp.pds.gridSize = gridsize;
1894 pp.pds.gridCellNum = (int)montecarloSHT.AllocatedCells.size();
1895 cellsize/=2.0f;
1896 occupancyRatio = float(montecarloMesh.vn) / float(montecarloSHT.AllocatedCells.size());
1897 // qDebug(" %i / %i = %6.3f", montecarloMesh.vn , montecarloSHT.AllocatedCells.size(),occupancyRatio);
1898 }
1899 while( occupancyRatio> 100);
1900}
1901
1902static void PoissonDiskPruningByNumber(VertexSampler &ps, MeshType &m,
1903 size_t sampleNum, ScalarType &diskRadius,
1904 PoissonDiskParam &pp,
1905 float tolerance=0.04,
1906 int maxIter=20)
1907
1908{
1909 size_t sampleNumMin = int(float(sampleNum)*(1.0f-tolerance));
1910 size_t sampleNumMax = int(float(sampleNum)*(1.0f+tolerance));
1911 float RangeMinRad = m.bbox.Diag()/50.0;
1912 float RangeMaxRad = m.bbox.Diag()/50.0;
1913 size_t RangeMinRadNum;
1914 size_t RangeMaxRadNum;
1915 // Note RangeMinRad < RangeMaxRad
1916 // but RangeMinRadNum > sampleNum > RangeMaxRadNum
1917 do {
1918 ps.reset();
1919 RangeMinRad/=2.0f;
1920 PoissonDiskPruning(ps, m ,RangeMinRad,pp);
1921 RangeMinRadNum = pp.pds.sampleNum;
1922// qDebug("PoissonDiskPruning Iteratin Min (%6.3f:%5i) instead of %i",RangeMinRad,RangeMinRadNum,sampleNum);
1923 } while(RangeMinRadNum < sampleNum); // if the number of sample is still smaller you have to make radius larger.
1924
1925 do {
1926 ps.reset();
1927 RangeMaxRad*=2.0f;
1928 PoissonDiskPruning(ps, m ,RangeMaxRad,pp);
1929 RangeMaxRadNum = pp.pds.sampleNum;
1930// qDebug("PoissonDiskPruning Iteratin Max (%6.3f:%5i) instead of %i",RangeMaxRad,RangeMaxRadNum,sampleNum);
1931 } while(RangeMaxRadNum > sampleNum);
1932
1933
1934 float curRadius=RangeMaxRad;
1935 int iterCnt=0;
1936 while(iterCnt<maxIter &&
1937 (pp.pds.sampleNum < sampleNumMin || pp.pds.sampleNum > sampleNumMax) )
1938 {
1939 iterCnt++;
1940 ps.reset();
1941 curRadius=(RangeMaxRad+RangeMinRad)/2.0f;
1942 PoissonDiskPruning(ps, m ,curRadius,pp);
1943// qDebug("PoissonDiskPruning Iteratin (%6.3f:%5lu %6.3f:%5lu) Cur Radius %f -> %lu sample instead of %lu",RangeMinRad,RangeMinRadNum,RangeMaxRad,RangeMaxRadNum,curRadius,pp.pds.sampleNum,sampleNum);
1944 if(pp.pds.sampleNum > sampleNum){
1945 RangeMinRad = curRadius;
1946 RangeMinRadNum = pp.pds.sampleNum;
1947 }
1948 if(pp.pds.sampleNum < sampleNum){
1949 RangeMaxRad = curRadius;
1950 RangeMaxRadNum = pp.pds.sampleNum;
1951 }
1952 }
1953 diskRadius = curRadius;
1954}
1955
1956
1966static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh,
1967 ScalarType diskRadius, PoissonDiskParam &pp)
1968{
1969 tri::RequireCompactness(montecarloMesh);
1970 if(pp.randomSeed) SamplingRandomGenerator().initialize(pp.randomSeed);
1971 if(pp.adaptiveRadiusFlag)
1972 tri::RequirePerVertexQuality(montecarloMesh);
1973 int t0 = clock();
1974 // spatial index of montecarlo samples - used to choose a new sample to insert
1975 MontecarloSHT montecarloSHT;
1976 InitSpatialHashTable(montecarloMesh,montecarloSHT,diskRadius,pp);
1977
1978 // if we are doing variable density sampling we have to prepare the handle that keeps the the random samples expected radii.
1979 // At this point we just assume that there is the quality values as sampled from the base mesh
1980 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (montecarloMesh,"radius");
1981 if(pp.adaptiveRadiusFlag)
1982 InitRadiusHandleFromQuality(montecarloMesh, rH, diskRadius, pp.radiusVariance, pp.invertQuality);
1983
1984 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
1985// std::random_device rd;
1986// std::mt19937 g(rd());
1987// std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
1989 std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
1990 int t1 = clock();
1991 pp.pds.montecarloSampleNum = montecarloMesh.vn;
1992 pp.pds.sampleNum =0;
1993 int removedCnt=0;
1994 // Initial pass for pruning the Hashed grid with the an eventual pre initialized set of samples
1995 if(pp.preGenFlag)
1996 {
1997 if(pp.preGenMesh==0)
1998 {
1999 typename MeshType::template PerVertexAttributeHandle<bool> fixed;
2000 fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (montecarloMesh,"fixed");
2001 for(VertexIterator vi=montecarloMesh.vert.begin();vi!=montecarloMesh.vert.end();++vi)
2002 if(fixed[*vi]) {
2003 pp.pds.sampleNum++;
2004 ps.AddVert(*vi);
2005 removedCnt += montecarloSHT.RemoveInSphere(vi->cP(),diskRadius);
2006 }
2007 }
2008 else
2009 {
2010 for(VertexIterator vi =pp.preGenMesh->vert.begin(); vi!=pp.preGenMesh->vert.end();++vi)
2011 {
2012 ps.AddVert(*vi);
2013 pp.pds.sampleNum++;
2014 removedCnt += montecarloSHT.RemoveInSphere(vi->cP(),diskRadius);
2015 }
2016 }
2017 montecarloSHT.UpdateAllocatedCells();
2018 }
2019 vertex::ApproximateGeodesicDistanceFunctor<VertexType> GDF;
2020 while(!montecarloSHT.AllocatedCells.empty())
2021 {
2022 removedCnt=0;
2023 for (size_t i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
2024 {
2025 if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
2026 ScalarType currentRadius =diskRadius;
2027 VertexPointer sp;
2028 if(pp.bestSampleChoiceFlag)
2029 sp = getBestPrecomputedMontecarloSample(montecarloSHT.AllocatedCells[i], montecarloSHT, diskRadius, pp);
2030 else
2031 sp = getSampleFromCell(montecarloSHT.AllocatedCells[i], montecarloSHT);
2032
2033 if(pp.adaptiveRadiusFlag)
2034 currentRadius = rH[sp];
2035
2036 ps.AddVert(*sp);
2037 pp.pds.sampleNum++;
2038 if(pp.geodesicDistanceFlag) removedCnt += montecarloSHT.RemoveInSphereNormal(sp->cP(),sp->cN(),GDF,currentRadius);
2039 else removedCnt += montecarloSHT.RemoveInSphere(sp->cP(),currentRadius);
2040 }
2041 montecarloSHT.UpdateAllocatedCells();
2042 }
2043 int t2 = clock();
2044 pp.pds.gridTime = t1-t0;
2045 pp.pds.pruneTime = t2-t1;
2046}
2047
2058static void HierarchicalPoissonDisk(MeshType &origMesh, VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
2059{
2060// int t0=clock();
2061 // spatial index of montecarlo samples - used to choose a new sample to insert
2062 MontecarloSHT montecarloSHTVec[5];
2063
2064
2065
2066 // initialize spatial hash table for searching
2067 // radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
2068 // This radius implies that when we pick a sample in a cell all that cell will not be touched again.
2069 ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
2070
2071 // inflating
2072 BoxType bb=origMesh.bbox;
2073 bb.Offset(cellsize);
2074
2075 int sizeX = std::max(1.0f,bb.DimX() / cellsize);
2076 int sizeY = std::max(1.0f,bb.DimY() / cellsize);
2077 int sizeZ = std::max(1.0f,bb.DimZ() / cellsize);
2078 Point3i gridsize(sizeX, sizeY, sizeZ);
2079
2080 // spatial hash table of the generated samples - used to check the radius constrain
2081 SampleSHT checkSHT;
2082 checkSHT.InitEmpty(bb, gridsize);
2083
2084
2085 // sampling algorithm
2086 // ------------------
2087 //
2088 // - generate millions of samples using montecarlo algorithm
2089 // - extract a cell (C) from the active cell list (with probability proportional to cell's volume)
2090 // - generate a sample inside C by choosing one of the contained pre-generated samples
2091 // - if the sample violates the radius constrain discard it, and add the cell to the cells-to-subdivide list
2092 // - iterate until the active cell list is empty or a pre-defined number of subdivisions is reached
2093 //
2094
2095 int level = 0;
2096
2097 // initialize spatial hash to index pre-generated samples
2098 montecarloSHTVec[0].InitEmpty(bb, gridsize);
2099 // create active cell list
2100 for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++)
2101 montecarloSHTVec[0].Add(&(*vi));
2102 montecarloSHTVec[0].UpdateAllocatedCells();
2103
2104 // if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii.
2105 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (montecarloMesh,"radius");
2106 if(pp.adaptiveRadiusFlag)
2107 InitRadiusHandleFromQuality(montecarloMesh, rH, diskRadius, pp.radiusVariance, pp.invertQuality);
2108
2109 do
2110 {
2111 MontecarloSHT &montecarloSHT = montecarloSHTVec[level];
2112
2113 if(level>0)
2114 {// initialize spatial hash with the remaining points
2115 montecarloSHT.InitEmpty(bb, gridsize);
2116 // create active cell list
2117 for (typename MontecarloSHT::HashIterator hi = montecarloSHTVec[level-1].hash_table.begin(); hi != montecarloSHTVec[level-1].hash_table.end(); hi++)
2118 montecarloSHT.Add((*hi).second);
2119 montecarloSHT.UpdateAllocatedCells();
2120 }
2121 // shuffle active cells
2122 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
2123 std::random_device rd;
2124// std::mt19937 g(rd());
2125// std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
2127 std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
2128
2129 // generate a sample inside C by choosing one of the contained pre-generated samples
2131 int removedCnt=montecarloSHT.hash_table.size();
2132 int addedCnt=checkSHT.hash_table.size();
2133 for (int i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
2134 {
2135 for(int j=0;j<4;j++)
2136 {
2137 if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
2138
2139 // generate a sample chosen from the pre-generated one
2140 typename MontecarloSHT::HashIterator hi = montecarloSHT.hash_table.find(montecarloSHT.AllocatedCells[i]);
2141
2142 if(hi==montecarloSHT.hash_table.end()) {break;}
2143 VertexPointer sp = (*hi).second;
2144 // vr spans between 3.0*r and r / 4.0 according to vertex quality
2145 ScalarType sampleRadius = diskRadius;
2146 if(pp.adaptiveRadiusFlag) sampleRadius = rH[sp];
2147 if (checkPoissonDisk(checkSHT, sp->cP(), sampleRadius))
2148 {
2149 ps.AddVert(*sp);
2150 montecarloSHT.RemoveCell(sp);
2151 checkSHT.Add(sp);
2152 break;
2153 }
2154 else
2155 montecarloSHT.RemovePunctual(sp);
2156 }
2157 }
2158 addedCnt = checkSHT.hash_table.size()-addedCnt;
2159 removedCnt = removedCnt-montecarloSHT.hash_table.size();
2160
2161 // proceed to the next level of subdivision
2162 // increase grid resolution
2163 gridsize *= 2;
2164
2165 //
2166 level++;
2167 } while(level < 5);
2168}
2169
2170//template <class MeshType>
2171//void Sampling<MeshType>::SimilarFaceSampling()
2172
2173// This function also generates samples outside faces if those affects faces in texture space.
2174// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge)
2175// otherwise obtained samples will map to barycentric coord actually outside face
2176//
2177// If you don't need to get those extra points clear faces Border Flags
2178// vcg::tri::UpdateFlags<Mesh>::FaceClearB(m);
2179//
2180// Else make sure to update border flags from texture space FFadj
2181// vcg::tri::UpdateTopology<Mesh>::FaceFaceFromTexCoord(m);
2182// vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m);
2183static void Texture(MeshType & m, VertexSampler &ps, int textureWidth, int textureHeight, bool correctSafePointsBaryCoords=true)
2184{
2185typedef Point2<ScalarType> Point2x;
2186 //printf("Similar Triangles face sampling\n");
2187 for(FaceIterator fi=m.face.begin(); fi != m.face.end(); fi++)
2188 if (!fi->IsD())
2189 {
2190 Point2x ti[3];
2191 for(int i=0;i<3;++i)
2192 ti[i]=Point2x((*fi).WT(i).U() * textureWidth - 0.5, (*fi).WT(i).V() * textureHeight - 0.5);
2193 // - 0.5 constants are used to obtain correct texture mapping
2194
2195 SingleFaceRaster(*fi, ps, ti[0],ti[1],ti[2], correctSafePointsBaryCoords);
2196 }
2197}
2198
2199typedef GridStaticPtr<FaceType, ScalarType > TriMeshGrid;
2200
2202{
2203public:
2204float offset;
2205float minDiag;
2206tri::FaceTmark<MeshType> markerFunctor;
2207TriMeshGrid gM;
2208};
2209
2210static void RegularRecursiveOffset(MeshType & m, std::vector<CoordType> &pvec, ScalarType offset, float minDiag)
2211{
2212 Box3<ScalarType> bb=m.bbox;
2213 bb.Offset(offset*2.0);
2214
2215 RRParam rrp;
2216
2217 rrp.markerFunctor.SetMesh(&m);
2218
2219 rrp.gM.Set(m.face.begin(),m.face.end(),bb);
2220
2221
2222 rrp.offset=offset;
2223 rrp.minDiag=minDiag;
2224 SubdivideAndSample(m, pvec, bb, rrp, bb.Diag());
2225}
2226
2227static void SubdivideAndSample(MeshType & m, std::vector<CoordType> &pvec, const Box3<ScalarType> bb, RRParam &rrp, float curDiag)
2228{
2229 CoordType startPt = bb.Center();
2230
2231 ScalarType dist;
2232 // Compute mesh point nearest to bb center
2233 FaceType *nearestF=0;
2234 ScalarType dist_upper_bound = curDiag+rrp.offset;
2235 CoordType closestPt;
2236 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
2237 dist=dist_upper_bound;
2238 nearestF = rrp.gM.GetClosest(PDistFunct,rrp.markerFunctor,startPt,dist_upper_bound,dist,closestPt);
2239 curDiag /=2;
2240 if(dist < dist_upper_bound)
2241 {
2242 if(curDiag/3 < rrp.minDiag) //store points only for the last level of recursion (?)
2243 {
2244 if(rrp.offset==0)
2245 pvec.push_back(closestPt);
2246 else
2247 {
2248 if(dist>rrp.offset) // points below the offset threshold cannot be displaced at the right offset distance, we can only make points nearer.
2249 {
2250 CoordType delta = startPt-closestPt;
2251 pvec.push_back(closestPt+delta*(rrp.offset/dist));
2252 }
2253 }
2254 }
2255 if(curDiag < rrp.minDiag) return;
2256 CoordType hs = (bb.max-bb.min)/2;
2257 for(int i=0;i<2;i++)
2258 for(int j=0;j<2;j++)
2259 for(int k=0;k<2;k++)
2260 SubdivideAndSample(m, pvec,
2261 BoxType(CoordType( bb.min[0]+i*hs[0], bb.min[1]+j*hs[1], bb.min[2]+k*hs[2]),
2262 CoordType(startPt[0]+i*hs[0], startPt[1]+j*hs[1], startPt[2]+k*hs[2]) ),
2263 rrp,curDiag
2264 );
2265
2266 }
2267}
2268}; // end sampling class
2269
2270template <class MeshType>
2271typename MeshType::ScalarType ComputePoissonDiskRadius(MeshType &origMesh, int sampleNum)
2272{
2273 typedef typename MeshType::ScalarType ScalarType;
2274 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
2275 // Manage approximately the PointCloud Case, use the half a area of the bbox.
2276 // TODO: If you had the radius a much better approximation could be done.
2277 if(meshArea ==0)
2278 {
2279 meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
2280 origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
2281 origMesh.bbox.DimY()*origMesh.bbox.DimZ());
2282 }
2283 ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
2284 return diskRadius;
2285}
2286
2287
2288
2289template <class MeshType>
2290void MontecarloSampling(MeshType &m, // the mesh that has to be sampled
2291 MeshType &mm, // the mesh that will contain the samples
2292 int sampleNum) // the desired number sample, if zero you must set the radius to the wanted value
2293{
2294 typedef tri::MeshSampler<MeshType> BaseSampler;
2295 MeshSampler<MeshType> mcSampler(&mm);
2297}
2298
2299
2300template <class MeshType>
2301void MontecarloSampling(MeshType &m, // the mesh that has to be sampled
2302 std::vector<Point3f> &montercarloSamples, // the vector that will contain the set of points
2303 int sampleNum) // the desired number sample, if zero you must set the radius to the wanted value
2304{
2305 typedef tri::TrivialSampler<MeshType> BaseSampler;
2306 BaseSampler mcSampler(montercarloSamples);
2308}
2309
2310// Yet another simpler wrapper for the generation of a poisson disk distribution over a mesh.
2311//
2312template <class MeshType>
2313void PoissonSampling(MeshType &m, // the mesh that has to be sampled
2314 std::vector<typename MeshType::CoordType> &poissonSamples, // the vector that will contain the set of points
2315 int sampleNum, // the desired number sample, if zero you must set the radius to the wanted value
2316 typename MeshType::ScalarType &radius, // the Poisson Disk Radius (used if sampleNum==0, setted if sampleNum!=0)
2317 typename MeshType::ScalarType radiusVariance=1,
2318 typename MeshType::ScalarType PruningByNumberTolerance=0.04f,
2319 unsigned int randSeed=0)
2320
2321{
2322 typedef tri::TrivialSampler<MeshType> BaseSampler;
2323 typedef tri::MeshSampler<MeshType> MontecarloSampler;
2324
2325 typename tri::SurfaceSampling<MeshType, BaseSampler>::PoissonDiskParam pp;
2326 int t0=clock();
2327
2328// if(sampleNum>0) radius = tri::SurfaceSampling<MeshType,BaseSampler>::ComputePoissonDiskRadius(m,sampleNum);
2329 if(radius>0 && sampleNum==0) sampleNum = tri::SurfaceSampling<MeshType,BaseSampler>::ComputePoissonSampleNum(m,radius);
2330
2331 pp.pds.sampleNum = sampleNum;
2332 pp.randomSeed = randSeed;
2333 poissonSamples.clear();
2334// std::vector<Point3f> MontecarloSamples;
2335 MeshType MontecarloMesh;
2336
2337 // First step build the sampling
2338 MontecarloSampler mcSampler(MontecarloMesh);
2339 BaseSampler pdSampler(poissonSamples);
2340
2341 if(randSeed) tri::SurfaceSampling<MeshType,MontecarloSampler>::SamplingRandomGenerator().initialize(randSeed);
2342 tri::SurfaceSampling<MeshType,MontecarloSampler>::Montecarlo(m, mcSampler, std::max(10000,sampleNum*40));
2343 tri::UpdateBounding<MeshType>::Box(MontecarloMesh);
2344// tri::Build(MontecarloMesh, MontecarloSamples);
2345 int t1=clock();
2346 pp.pds.montecarloTime = t1-t0;
2347
2348 if(radiusVariance !=1)
2349 {
2350 pp.adaptiveRadiusFlag=true;
2351 pp.radiusVariance=radiusVariance;
2352 }
2353 if(sampleNum==0) tri::SurfaceSampling<MeshType,BaseSampler>::PoissonDiskPruning(pdSampler, MontecarloMesh, radius,pp);
2354 else tri::SurfaceSampling<MeshType,BaseSampler>::PoissonDiskPruningByNumber(pdSampler, MontecarloMesh, sampleNum, radius,pp,PruningByNumberTolerance);
2355 int t2=clock();
2356 pp.pds.totalTime = t2-t0;
2357}
2358
2362//
2363template <class MeshType>
2364void PoissonPruning(MeshType &m, // the mesh that has to be pruned
2365 std::vector<typename MeshType::VertexPointer> &poissonSamples, // the vector that will contain the chosen set of points
2366 float radius, unsigned int randSeed=0)
2367{
2368 typedef tri::TrivialPointerSampler<MeshType> BaseSampler;
2370 pp.randomSeed = randSeed;
2371
2373 BaseSampler pdSampler;
2375 poissonSamples = pdSampler.sampleVec;
2376}
2377
2378
2384template <class MeshType>
2385void PoissonPruning(MeshType &m, // the mesh that has to be pruned
2386 std::vector<typename MeshType::CoordType> &poissonSamples, // the vector that will contain the chosen set of points
2387 float radius, unsigned int randSeed=0)
2388{
2389 std::vector<typename MeshType::VertexPointer> poissonSamplesVP;
2390 PoissonPruning(m,poissonSamplesVP,radius,randSeed);
2391 poissonSamples.resize(poissonSamplesVP.size());
2392 for(size_t i=0;i<poissonSamplesVP.size();++i)
2393 poissonSamples[i]=poissonSamplesVP[i]->P();
2394}
2395
2396
2397
2403template <class MeshType>
2404void PoissonPruningExact(MeshType &m,
2405 std::vector<typename MeshType::VertexPointer> &poissonSamples,
2406 typename MeshType::ScalarType & radius,
2407 int sampleNum,
2408 float tolerance=0.04,
2409 int maxIter=20,
2410 unsigned int randSeed=0)
2411{
2412 size_t sampleNumMin = int(float(sampleNum)*(1.0f-tolerance)); // the expected values range.
2413 size_t sampleNumMax = int(float(sampleNum)*(1.0f+tolerance)); // e.g. any sampling in [sampleNumMin, sampleNumMax] is OK
2414 float RangeMinRad = m.bbox.Diag()/10.0f;
2415 float RangeMaxRad = m.bbox.Diag()/10.0f;
2416 size_t RangeMinSampleNum;
2417 size_t RangeMaxSampleNum;
2418 std::vector<typename MeshType::VertexPointer> poissonSamplesTmp;
2419
2420 do
2421 {
2422 RangeMinRad/=2.0f;
2423 PoissonPruning(m,poissonSamplesTmp,RangeMinRad,randSeed);
2424 RangeMinSampleNum = poissonSamplesTmp.size();
2425 } while(RangeMinSampleNum < sampleNumMin);
2426
2427 do
2428 {
2429 RangeMaxRad*=2.0f;
2430 PoissonPruning(m,poissonSamplesTmp,RangeMaxRad,randSeed);
2431 RangeMaxSampleNum = poissonSamplesTmp.size();
2432 } while(RangeMaxSampleNum > sampleNumMax);
2433
2434 float curRadius;
2435 int iterCnt=0;
2436 while(iterCnt<maxIter &&
2437 (poissonSamplesTmp.size() < sampleNumMin || poissonSamplesTmp.size() > sampleNumMax) )
2438 {
2439 curRadius=(RangeMaxRad+RangeMinRad)/2.0f;
2440 PoissonPruning(m,poissonSamplesTmp,curRadius,randSeed);
2441 //qDebug("(%6.3f:%5i %6.3f:%5i) Cur Radius %f -> %i sample instead of %i",RangeMinRad,RangeMinSampleNum,RangeMaxRad,RangeMaxSampleNum,curRadius,poissonSamplesTmp.size(),sampleNum);
2442 if(poissonSamplesTmp.size() > size_t(sampleNum))
2443 RangeMinRad = curRadius;
2444 if(poissonSamplesTmp.size() < size_t(sampleNum))
2445 RangeMaxRad = curRadius;
2446 }
2447
2448 swap(poissonSamples,poissonSamplesTmp);
2449 radius = curRadius;
2450}
2451} // end namespace tri
2452} // end namespace vcg
2453
2454#endif
2455
Definition: box3.h:42
Point3< BoxScalarType > max
max coordinate point
Definition: box3.h:51
Point3< BoxScalarType > Center() const
Return the center of the box.
Definition: box3.h:250
void Offset(const BoxScalarType s)
Definition: box3.h:75
Point3< BoxScalarType > min
min coordinate point
Definition: box3.h:49
BoxScalarType Diag() const
Return the lenght of the diagonal of the box .
Definition: box3.h:240
Class to safely add and delete elements in a mesh.
Definition: allocate.h:97
static VertexIterator AddVertices(MeshType &m, size_t n, PointerUpdater< VertexPointer > &pu)
Add n vertices to the mesh. Function to add n vertices to the mesh. The elements are added always to ...
Definition: allocate.h:189
Definition: point_sampling.h:230
double volume
from the wikipedia defintion RMS DIST is sqrt(Sum(distances^2)/n), here we store Sum(distances^2)
Definition: point_sampling.h:258
MeshType * closestPtMesh
the mesh containing the sample points
Definition: point_sampling.h:248
MeshType * samplePtMesh
the mesh for which we search the closest points.
Definition: point_sampling.h:247
MetroMeshVertexGrid unifGridVert
the mesh containing the corresponding closest points that have been found
Definition: point_sampling.h:250
Definition: point_sampling.h:177
Definition: point_sampling.h:363
CallBackPos * cb
the source mesh for which we search the closest points (e.g. the mesh from which we take colors etc).
Definition: point_sampling.h:376
Definition: point_sampling.h:531
Definition: point_sampling.h:2202
Main Class of the Sampling framework.
Definition: point_sampling.h:476
static void Montecarlo(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:1206
static void HierarchicalPoissonDisk(MeshType &origMesh, VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
Definition: point_sampling.h:2058
static void VertexAreaUniform(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:725
static void VertexWeighted(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:687
static void VertexCrease(MeshType &m, VertexSampler &ps)
Definition: point_sampling.h:984
static void VertexUniform(MeshType &m, VertexSampler &ps, int sampleNum, bool onlySelected)
Sample the vertices in a uniform way. Each vertex has the same probabiltiy of being chosen.
Definition: point_sampling.h:773
static void FaceSubdivision(MeshType &m, VertexSampler &ps, int sampleNum, bool randSample)
Compute a sampling of the surface where the points are regularly scattered over the face surface usin...
Definition: point_sampling.h:1341
static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, PoissonDiskParam &pp)
Definition: point_sampling.h:1966
static ScalarType ComputePoissonDiskRadius(MeshType &origMesh, int sampleNum)
Estimate the radius r that you should give to get a certain number of samples in a Poissson Disk Dist...
Definition: point_sampling.h:1820
EdgeSamplingRoundingStrategy
The EdgeSamplingStrategy enum determines the sampling strategy for edge meshes. Given a sampling radi...
Definition: point_sampling.h:808
static void VertexBorder(MeshType &m, VertexSampler &ps)
Sample all the border vertices.
Definition: point_sampling.h:973
static void VertexBorderCorner(MeshType &m, VertexSampler &ps, ScalarType angleRad)
Sample all the border corner vertices.
Definition: point_sampling.h:959
static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, EdgeSamplingRoundingStrategy strategy=Floor)
Definition: point_sampling.h:830
static void FaceSubdivisionOld(MeshType &m, VertexSampler &ps, int sampleNum, bool randSample)
Compute a sampling of the surface where the points are regularly scattered over the face surface usin...
Definition: point_sampling.h:1432
static int Poisson(double lambda)
Definition: point_sampling.h:647
static void MontecarloPoisson(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:1139
static void WeightedMontecarlo(MeshType &m, VertexSampler &ps, int sampleNum, float variance)
Definition: point_sampling.h:1249
static void InitRadiusHandleFromQuality(MeshType &sampleMesh, PerVertexFloatAttribute &rH, ScalarType diskRadius, ScalarType radiusVariance, bool invert)
Definition: point_sampling.h:1849
static void EdgeMontecarlo(MeshType &m, VertexSampler &ps, int sampleNum, bool sampleAllEdges)
Definition: point_sampling.h:1165
Definition: point_sampling.h:137
A basic sampler class that show the required interface used by the SurfaceSampling class.
Definition: point_sampling.h:72
static void Box(ComputeMeshType &m)
Calculates the bounding box of the given mesh m.
Definition: bounding.h:45
Management, updating and computation of per-vertex and per-face flags (like border flags).
Definition: flag.h:44
static void PerFaceNormalized(ComputeMeshType &m)
Equivalent to PerFace() and NormalizePerFace()
Definition: normal.h:276
static size_t VertexCornerBorder(MeshType &m, ScalarType angleRad, bool preserveSelection=false)
Select the border vertices that form a corner along the border with an angle that is below a certain ...
Definition: selection.h:656
Auxiliary data structure for computing face face adjacency information.
Definition: topology.h:149
Generation of per-vertex and per-face topological information.
Definition: topology.h:43
void PoissonPruningExact(MeshType &m, std::vector< typename MeshType::VertexPointer > &poissonSamples, typename MeshType::ScalarType &radius, int sampleNum, float tolerance=0.04, int maxIter=20, unsigned int randSeed=0)
Very simple wrapping for the Exact Poisson Disk Pruning.
Definition: point_sampling.h:2404
void PoissonPruning(MeshType &m, std::vector< typename MeshType::VertexPointer > &poissonSamples, float radius, unsigned int randSeed=0)
Low level wrapper for Poisson Disk Pruning.
Definition: point_sampling.h:2364
Definition: color4.h:30
Definition: point_sampling.h:1756
Definition: point_sampling.h:1740