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
515{
516public:
517 typedef unsigned int result_type;
518 MarsenneTwisterURBG(result_type max){_max = max;}
519 static constexpr result_type min() {return 0;}
520 static constexpr result_type max() {return std::numeric_limits<result_type>::max();}
521 result_type operator()() {return SamplingRandomGenerator().generate(_max);}
522private:
523 result_type _max;
524};
525
526// Returns a random number in the [0,1) real interval using the improved Marsenne-Twister method.
527static double RandomDouble01()
528{
529 return SamplingRandomGenerator().generate01();
530}
531
532#define FAK_LEN 1024
533static double LnFac(int n) {
534 // Tabled log factorial function. gives natural logarithm of n!
535
536 // define constants
537 static const double // coefficients in Stirling approximation
538 C0 = 0.918938533204672722, // ln(sqrt(2*pi))
539 C1 = 1./12.,
540 C3 = -1./360.;
541 // C5 = 1./1260., // use r^5 term if FAK_LEN < 50
542 // C7 = -1./1680.; // use r^7 term if FAK_LEN < 20
543 // static variables
544 static double fac_table[FAK_LEN]; // table of ln(n!):
545 static bool initialized = false; // remember if fac_table has been initialized
546
547
548 if (n < FAK_LEN) {
549 if (n <= 1) {
550 if (n < 0) assert(0);//("Parameter negative in LnFac function");
551 return 0;
552 }
553 if (!initialized) { // first time. Must initialize table
554 // make table of ln(n!)
555 double sum = fac_table[0] = 0.;
556 for (int i=1; i<FAK_LEN; i++) {
557 sum += log(double(i));
558 fac_table[i] = sum;
559 }
560 initialized = true;
561 }
562 return fac_table[n];
563 }
564 // not found in table. use Stirling approximation
565 double n1, r;
566 n1 = n; r = 1. / n1;
567 return (n1 + 0.5)*log(n1) - n1 + C0 + r*(C1 + r*r*C3);
568}
569
570static int PoissonRatioUniforms(double L) {
571 /*
572
573 This subfunction generates a integer with the poisson
574 distribution using the ratio-of-uniforms rejection method (PRUAt).
575 This approach is STABLE even for large L (e.g. it does not suffer from the overflow limit of the classical Knuth implementation)
576 Execution time does not depend on L, except that it matters whether
577 is within the range where ln(n!) is tabulated.
578
579 Reference:
580
581 E. Stadlober
582 "The ratio of uniforms approach for generating discrete random variates".
583 Journal of Computational and Applied Mathematics,
584 vol. 31, no. 1, 1990, pp. 181-189.
585
586 Partially adapted/inspired from some subfunctions of the Agner Fog stocc library ( www.agner.org/random )
587 Same licensing scheme.
588
589 */
590 // constants
591
592 const double SHAT1 = 2.943035529371538573; // 8/e
593 const double SHAT2 = 0.8989161620588987408; // 3-sqrt(12/e)
594 double u; // uniform random
595 double lf; // ln(f(x))
596 double x; // real sample
597 int k; // integer sample
598
599 double pois_a = L + 0.5; // hat center
600 int mode = (int)L; // mode
601 double pois_g = log(L);
602 double pois_f0 = mode * pois_g - LnFac(mode); // value at mode
603 double pois_h = sqrt(SHAT1 * (L+0.5)) + SHAT2; // hat width
604 double pois_bound = (int)(pois_a + 6.0 * pois_h); // safety-bound
605
606 while(1) {
607 u = RandomDouble01();
608 if (u == 0) continue; // avoid division by 0
609 x = pois_a + pois_h * (RandomDouble01() - 0.5) / u;
610 if (x < 0 || x >= pois_bound) continue; // reject if outside valid range
611 k = (int)(x);
612 lf = k * pois_g - LnFac(k) - pois_f0;
613 if (lf >= u * (4.0 - u) - 3.0) break; // quick acceptance
614 if (u * (u - lf) > 1.0) continue; // quick rejection
615 if (2.0 * log(u) <= lf) break; // final acceptance
616 }
617 return k;
618}
619
620
632static int Poisson(double lambda)
633{
634 if(lambda>50) return PoissonRatioUniforms(lambda);
635 double L = exp(-lambda);
636 int k =0;
637 double p = 1.0;
638 do
639 {
640 k = k+1;
641 p = p*RandomDouble01();
642 } while (p>L);
643
644 return k -1;
645}
646
647
648static void AllVertex(MeshType & m, VertexSampler &ps)
649{
650 AllVertex(m, ps, false);
651}
652
653static void AllVertex(MeshType & m, VertexSampler &ps, bool onlySelected)
654{
655 VertexIterator vi;
656 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
657 if(!(*vi).IsD())
658 if ((!onlySelected) || ((*vi).IsS()))
659 {
660 ps.AddVert(*vi);
661 }
662}
663
671
672static void VertexWeighted(MeshType & m, VertexSampler &ps, int sampleNum)
673{
674 ScalarType qSum = 0;
675 VertexIterator vi;
676 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
677 if(!(*vi).IsD())
678 qSum += (*vi).Q();
679
680 ScalarType samplePerUnit = sampleNum/qSum;
681 ScalarType floatSampleNum =0;
682 std::vector<VertexPointer> vertVec;
683 FillAndShuffleVertexPointerVector(m,vertVec);
684
685 std::vector<bool> vertUsed(m.vn,false);
686
687 int i=0; int cnt=0;
688 while(cnt < sampleNum)
689 {
690 if(vertUsed[i])
691 {
692 floatSampleNum += vertVec[i]->Q() * samplePerUnit;
693 int vertSampleNum = (int) floatSampleNum;
694 floatSampleNum -= (float) vertSampleNum;
695
696 // for every sample p_i in T...
697 if(vertSampleNum > 1)
698 {
699 ps.AddVert(*vertVec[i]);
700 cnt++;
701 vertUsed[i]=true;
702 }
703 }
704 i = (i+1)%m.vn;
705 }
706}
707
710static void VertexAreaUniform(MeshType & m, VertexSampler &ps, int sampleNum)
711{
712 VertexIterator vi;
713 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
714 if(!(*vi).IsD())
715 (*vi).Q() = 0;
716
717 FaceIterator fi;
718 for(fi = m.face.begin(); fi != m.face.end(); ++fi)
719 if(!(*fi).IsD())
720 {
721 ScalarType areaThird = DoubleArea(*fi)/6.0;
722 (*fi).V(0)->Q()+=areaThird;
723 (*fi).V(1)->Q()+=areaThird;
724 (*fi).V(2)->Q()+=areaThird;
725 }
726
727 VertexWeighted(m,ps,sampleNum);
728}
729
730static void FillAndShuffleFacePointerVector(MeshType & m, std::vector<FacePointer> &faceVec)
731{
732 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
733 if(!(*fi).IsD()) faceVec.push_back(&*fi);
734
735 assert((int)faceVec.size()==m.fn);
736
737 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
738 //std::random_device rd;
739 //std::mt19937 g(rd());
740 MarsenneTwisterURBG g(faceVec.size());
741 std::shuffle(faceVec.begin(),faceVec.end(), g);
742}
743static void FillAndShuffleVertexPointerVector(MeshType & m, std::vector<VertexPointer> &vertVec)
744{
745 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
746 if(!(*vi).IsD()) vertVec.push_back(&*vi);
747
748 assert((int)vertVec.size()==m.vn);
749
750 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
751 //std::random_device rd;
752 //std::mt19937 g(rd());
753 MarsenneTwisterURBG g(vertVec.size());
754 std::shuffle(vertVec.begin(),vertVec.end(), g);
755}
756
758static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum, bool onlySelected)
759{
760 if (sampleNum >= m.vn) {
761 AllVertex(m, ps, onlySelected);
762 return;
763 }
764
765 std::vector<VertexPointer> vertVec;
766 FillAndShuffleVertexPointerVector(m, vertVec);
767
768 int added = 0;
769 for (int i = 0; ((i < m.vn) && (added < sampleNum)); ++i)
770 if (!(*vertVec[i]).IsD())
771 if ((!onlySelected) || (*vertVec[i]).IsS())
772 {
773 ps.AddVert(*vertVec[i]);
774 added++;
775 }
776
777}
778
779
780static void VertexUniform(MeshType & m, VertexSampler &ps, int sampleNum)
781{
782 VertexUniform(m, ps, sampleNum, false);
783}
784
785
793{
794 Floor = 0,
795 Round,
796 Ceil,
797};
798
814
815static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, EdgeSamplingRoundingStrategy strategy = Floor)
816{
817 tri::RequireEEAdjacency(m);
818 tri::RequireCompactness(m);
819 tri::RequirePerEdgeFlags(m);
820 tri::RequirePerVertexFlags(m);
823 tri::MeshAssert<MeshType>::EEOneManifold(m);
824
825 for (EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei)
826 {
827 if (!ei->IsV())
828 {
829 edge::Pos<EdgeType> ep(&*ei,0);
830 edge::Pos<EdgeType> startep = ep;
831 do // first loop to search a boundary component or check if it is a ring
832 {
833 ep.NextE();
834 if (ep.IsBorder())
835 break;
836 } while (startep != ep);
837
838 if (!ep.IsBorder()) // ******************** Circular Ring ********************
839 {
840 assert(ep == startep);
841
842 // to keep the uniform resampling order-independent:
843 // 1) start from the 'lowest' point...
844 edge::Pos<EdgeType> altEp = ep;
845 altEp.NextE();
846 while (altEp != startep) {
847 if (altEp.V()->cP() < ep.V()->cP())
848 {
849 ep = altEp;
850 }
851 altEp.NextE();
852 }
853
854 // 2) ... with consistent direction
855 const auto dir0 = ep.VFlip()->cP() - ep.V()->cP();
856 ep.FlipE();
857 const auto dir1 = ep.VFlip()->cP() - ep.V()->cP();
858 if (dir0 < dir1)
859 ep.FlipE();
860 }
861 else // ******************** NOT Circular Ring ********************
862 {
863 // to keep the uniform resampling order-independent
864 // start from the border with 'lowest' point
865 edge::Pos<EdgeType> altEp = ep;
866 do {
867 altEp.NextE();
868 } while (!altEp.IsBorder());
869
870 if (altEp.V()->cP() < ep.V()->cP())
871 {
872 ep = altEp;
873 }
874 }
875
876 ScalarType totalLen = 0;
877 ep.FlipV();
878 // second loop to compute the length of the chain marking visited all the edges
879 do
880 {
881 ep.E()->SetV();
882 totalLen += Distance(ep.V()->cP(), ep.VFlip()->cP());
883 ep.NextE();
884 } while (!ep.E()->IsV() && !ep.IsBorder());
885 if (ep.IsBorder() && !ep.E()->IsV())
886 {
887 ep.E()->SetV();
888 totalLen += Distance(ep.V()->cP(), ep.VFlip()->cP());
889 }
890
891 VertexPointer startVertex = ep.V();
892
893 // Third loop: actually performs the sampling by walking on the edge chain
894 int sampleNum = -1;
895 {
896 double div = double(totalLen) / radius;
897 switch (strategy) {
898 case Round: sampleNum = int(round(div)); break;
899 case Ceil: sampleNum = int( ceil(div)); break;
900 default: sampleNum = int(floor(div)); break;
901 };
902 }
903 assert(sampleNum >= 0);
904
905 ScalarType sampleDist = totalLen / sampleNum; // the steplen we use for sampling
906
907 // printf("Found a chain with len %f: we will place %i samples every %f (original radius : %f)\n", totalLen, sampleNum, sampleDist, radius);
908
909 ScalarType curLen = 0;
910 int sampleCnt = 1;
911 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 0.0 : 1.0); // First Sample always at the start of the chain
912
913 do {
914 ep.NextE();
915 assert(ep.E()->IsV());
916 ScalarType edgeLen = Distance(ep.VFlip()->cP(), ep.V()->cP());
917 ScalarType d0 = curLen;
918 ScalarType d1 = d0 + edgeLen;
919
920 while (d1 > sampleCnt * sampleDist && sampleCnt < sampleNum)
921 {
922 ScalarType off = (sampleCnt * sampleDist - d0) / edgeLen;
923// printf("edgeLen %f off %f samplecnt %i\n", edgeLen, off, sampleCnt);
924 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 1.0 - off : off);
925 sampleCnt++;
926 }
927 curLen += edgeLen;
928 } while(!ep.IsBorder() && ep.V() != startVertex);
929
930 if(ep.V() != startVertex) // if we are not in a loop we add the last vertex
931 {
932 ps.AddEdge(*(ep.E()), ep.VInd() == 0 ? 0.0 : 1.0);
933 }
934 }
935 }
936}
937
938
944static void VertexBorderCorner(MeshType & m, VertexSampler &ps, ScalarType angleRad)
945{
947 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
948 {
949 if(vi->IsS()) ps.AddVert(*vi);
950 }
951}
952
958static void VertexBorder(MeshType & m, VertexSampler &ps)
959{
960 VertexBorderCorner(m,ps,std::numeric_limits<ScalarType>::max());
961}
962
969static void VertexCrease(MeshType & m, VertexSampler &ps)
970{
971 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
972 std::vector< SimpleEdge > Edges;
973 typename std::vector< SimpleEdge >::iterator ei;
975
976 typename MeshType::template PerVertexAttributeHandle <int> hv = tri::Allocator<MeshType>:: template GetPerVertexAttribute<int> (m);
977
978 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
979 {
980 hv[ei->v[0]]++;
981 hv[ei->v[1]]++;
982 }
983
984 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
985 {
986 if(hv[vi]>2)
987 ps.AddVert(*vi);
988 }
989}
990
991
992static void FaceUniform(MeshType & m, VertexSampler &ps, int sampleNum)
993{
994 if(sampleNum>=m.fn) {
995 AllFace(m,ps);
996 return;
997 }
998
999 std::vector<FacePointer> faceVec;
1000 FillAndShuffleFacePointerVector(m,faceVec);
1001
1002 for(int i =0; i< sampleNum; ++i)
1003 ps.AddFace(*faceVec[i],Barycenter(*faceVec[i]));
1004}
1005
1006static void AllFace(MeshType & m, VertexSampler &ps)
1007{
1008 FaceIterator fi;
1009 for(fi=m.face.begin();fi!=m.face.end();++fi)
1010 if(!(*fi).IsD())
1011 {
1012 ps.AddFace(*fi,Barycenter(*fi));
1013 }
1014}
1015
1016
1017static void AllEdge(MeshType & m, VertexSampler &ps)
1018{
1019 // Edge sampling.
1020 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1021 std::vector< SimpleEdge > Edges;
1022 typename std::vector< SimpleEdge >::iterator ei;
1023 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges);
1024
1025 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1026 ps.AddFace(*(*ei).f,ei->EdgeBarycentricToFaceBarycentric(0.5));
1027}
1028
1029// Regular Uniform Edge sampling
1030// Each edge is subdivided in a number of pieces proprtional to its length
1031// Samples are chosen without touching the vertices.
1032
1033static void EdgeUniform(MeshType & m, VertexSampler &ps,int sampleNum, bool sampleFauxEdge=true)
1034{
1035 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1036
1037 std::vector< SimpleEdge > Edges;
1038 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges,sampleFauxEdge);
1039 // First loop compute total edge length;
1040 float edgeSum=0;
1041 typename std::vector< SimpleEdge >::iterator ei;
1042 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1043 edgeSum+=Distance((*ei).v[0]->P(),(*ei).v[1]->P());
1044
1045 float sampleLen = edgeSum/sampleNum;
1046 float rest=0;
1047 for(ei=Edges.begin(); ei!=Edges.end(); ++ei)
1048 {
1049 float len = Distance((*ei).v[0]->P(),(*ei).v[1]->P());
1050 float samplePerEdge = floor((len+rest)/sampleLen);
1051 rest = (len+rest) - samplePerEdge * sampleLen;
1052 float step = 1.0/(samplePerEdge+1);
1053 for(int i=0;i<samplePerEdge;++i)
1054 {
1055 CoordType interp(0,0,0);
1056 interp[ (*ei).z ]=step*(i+1);
1057 interp[((*ei).z+1)%3]=1.0-step*(i+1);
1058 ps.AddFace(*(*ei).f,interp);
1059 }
1060 }
1061}
1062
1063// Generate the barycentric coords of a random point over a single face,
1064// with a uniform distribution over the triangle.
1065// It uses the parallelogram folding trick.
1066static CoordType RandomBarycentric()
1067{
1068 return math::GenerateBarycentricUniform<ScalarType>(SamplingRandomGenerator());
1069}
1070
1071// Given a triangle return a random point over it
1072static CoordType RandomPointInTriangle(const FaceType &f)
1073{
1074 CoordType u = RandomBarycentric();
1075 return f.cP(0)*u[0] + f.cP(1)*u[1] + f.cP(2)*u[2];
1076}
1077
1078static void StratifiedMontecarlo(MeshType & m, VertexSampler &ps,int sampleNum)
1079{
1080 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1081 ScalarType samplePerAreaUnit = sampleNum/area;
1082 // Montecarlo sampling.
1083 double floatSampleNum = 0.0;
1084
1085 FaceIterator fi;
1086 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1087 if(!(*fi).IsD())
1088 {
1089 // compute # samples in the current face (taking into account of the remainders)
1090 floatSampleNum += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
1091 int faceSampleNum = (int) floatSampleNum;
1092
1093 // for every sample p_i in T...
1094 for(int i=0; i < faceSampleNum; i++)
1095 ps.AddFace(*fi,RandomBarycentric());
1096 floatSampleNum -= (double) faceSampleNum;
1097 }
1098}
1099
1114static void MontecarloPoisson(MeshType & m, VertexSampler &ps,int sampleNum)
1115{
1116 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1117 ScalarType samplePerAreaUnit = sampleNum/area;
1118
1119 FaceIterator fi;
1120 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1121 if(!(*fi).IsD())
1122 {
1123 float areaT=DoubleArea(*fi) * 0.5f;
1124 int faceSampleNum = Poisson(areaT*samplePerAreaUnit);
1125
1126 // for every sample p_i in T...
1127 for(int i=0; i < faceSampleNum; i++)
1128 ps.AddFace(*fi,RandomBarycentric());
1129// SampleNum -= (double) faceSampleNum;
1130 }
1131}
1132
1133
1140static void EdgeMontecarlo(MeshType & m, VertexSampler &ps, int sampleNum, bool sampleAllEdges)
1141{
1142 typedef typename UpdateTopology<MeshType>::PEdge SimpleEdge;
1143 std::vector< SimpleEdge > Edges;
1144 UpdateTopology<MeshType>::FillUniqueEdgeVector(m,Edges,sampleAllEdges);
1145
1146 assert(!Edges.empty());
1147
1148 typedef std::pair<ScalarType, SimpleEdge*> IntervalType;
1149 std::vector< IntervalType > intervals (Edges.size()+1);
1150 int i=0;
1151 intervals[i]=std::make_pair(0,(SimpleEdge*)(0));
1152 // First loop: build a sequence of consecutive segments proportional to the edge lenghts.
1153 typename std::vector< SimpleEdge >::iterator ei;
1154 for(ei=Edges.begin(); ei != Edges.end(); ei++)
1155 {
1156 intervals[i+1]=std::make_pair(intervals[i].first+Distance((*ei).v[0]->P(),(*ei).v[1]->P()), &*ei);
1157 ++i;
1158 }
1159
1160 // Second Loop get a point on the line 0...Sum(edgeLen) to pick a point;
1161 ScalarType edgeSum = intervals.back().first;
1162 for(i=0;i<sampleNum;++i)
1163 {
1164 ScalarType val = edgeSum * RandomDouble01();
1165 // lower_bound returns the furthermost iterator i in [first, last) such that, for every iterator j in [first, i), *j < value.
1166 // E.g. An iterator pointing to the first element "not less than" val, or end() if every element is less than val.
1167 typename std::vector<IntervalType>::iterator it = lower_bound(intervals.begin(),intervals.end(),std::make_pair(val,(SimpleEdge*)(0)) );
1168 assert(it != intervals.end() && it != intervals.begin());
1169 assert( ( (*(it-1)).first < val ) && ((*(it)).first >= val) );
1170 SimpleEdge * ep=(*it).second;
1171 ps.AddFace( *(ep->f), ep->EdgeBarycentricToFaceBarycentric(RandomDouble01()) );
1172 }
1173}
1174
1181static void Montecarlo(MeshType & m, VertexSampler &ps,int sampleNum)
1182{
1183 typedef std::pair<ScalarType, FacePointer> IntervalType;
1184 std::vector< IntervalType > intervals (m.fn+1);
1185 FaceIterator fi;
1186 int i=0;
1187 intervals[i]=std::make_pair(0,FacePointer(0));
1188 // First loop: build a sequence of consecutive segments proportional to the triangle areas.
1189 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1190 if(!(*fi).IsD())
1191 {
1192 intervals[i+1]=std::make_pair(intervals[i].first+0.5*DoubleArea(*fi), &*fi);
1193 ++i;
1194 }
1195 ScalarType meshArea = intervals.back().first;
1196 for(i=0;i<sampleNum;++i)
1197 {
1198 ScalarType val = meshArea * RandomDouble01();
1199 // lower_bound returns the furthermost iterator i in [first, last) such that, for every iterator j in [first, i), *j < value.
1200 // E.g. An iterator pointing to the first element "not less than" val, or end() if every element is less than val.
1201 typename std::vector<IntervalType>::iterator it = lower_bound(intervals.begin(),intervals.end(),std::make_pair(val,FacePointer(0)) );
1202 assert(it != intervals.end());
1203 assert(it != intervals.begin());
1204 assert( (*(it-1)).first <val );
1205 assert( (*(it)).first >= val);
1206 ps.AddFace( *(*it).second, RandomBarycentric() );
1207 }
1208}
1209
1210static ScalarType WeightedArea(FaceType &f, PerVertexFloatAttribute &wH)
1211{
1212 ScalarType averageQ = ( wH[f.V(0)] + wH[f.V(1)] + wH[f.V(2)] )/3.0;
1213 return averageQ*averageQ*DoubleArea(f)/2.0;
1214}
1215
1224static void WeightedMontecarlo(MeshType & m, VertexSampler &ps,int sampleNum, float variance)
1225{
1226 tri::RequirePerVertexQuality(m);
1227 tri::RequireCompactness(m);
1228 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (m,"radius");
1229 InitRadiusHandleFromQuality(m, rH, 1.0, variance, true);
1230
1231 ScalarType weightedArea = 0;
1232 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
1233 weightedArea += WeightedArea(*fi,rH);
1234
1235 ScalarType samplePerAreaUnit = sampleNum/weightedArea;
1236 // Montecarlo sampling.
1237 double floatSampleNum = 0.0;
1238 for(FaceIterator fi=m.face.begin(); fi != m.face.end(); fi++)
1239 {
1240 // compute # samples in the current face (taking into account of the remainders)
1241 floatSampleNum += WeightedArea(*fi,rH) * samplePerAreaUnit;
1242 int faceSampleNum = (int) floatSampleNum;
1243
1244 // for every sample p_i in T...
1245 for(int i=0; i < faceSampleNum; i++)
1246 ps.AddFace(*fi,RandomBarycentric());
1247
1248 floatSampleNum -= (double) faceSampleNum;
1249 }
1250}
1251
1252
1253// Subdivision sampling of a single face.
1254// return number of added samples
1255
1256static int SingleFaceSubdivision(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
1257{
1258 // recursive face subdivision.
1259 if(sampleNum == 1)
1260 {
1261 // ground case.
1262 CoordType SamplePoint;
1263 if(randSample)
1264 {
1265 CoordType rb=RandomBarycentric();
1266 SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
1267 }
1268 else SamplePoint=((v0+v1+v2)*(1.0f/3.0f));
1269
1270 ps.AddFace(*fp,SamplePoint);
1271 return 1;
1272 }
1273
1274 int s0 = sampleNum /2;
1275 int s1 = sampleNum-s0;
1276 assert(s0>0);
1277 assert(s1>0);
1278
1279 ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
1280 ScalarType w1 = 1.0-w0;
1281 // compute the longest edge.
1282 ScalarType maxd01 = SquaredDistance(v0,v1);
1283 ScalarType maxd12 = SquaredDistance(v1,v2);
1284 ScalarType maxd20 = SquaredDistance(v2,v0);
1285 int res;
1286 if(maxd01 > maxd12)
1287 if(maxd01 > maxd20) res = 0;
1288 else res = 2;
1289 else
1290 if(maxd12 > maxd20) res = 1;
1291 else res = 2;
1292
1293 int faceSampleNum=0;
1294 // break the input triangle along the midpoint of the longest edge.
1295 CoordType pp;
1296 switch(res)
1297 {
1298 case 0 : pp = v0*w0 + v1*w1;
1299 faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample);
1300 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1301 break;
1302 case 1 : pp = v1*w0 + v2*w1;
1303 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1304 faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample);
1305 break;
1306 case 2 : pp = v0*w0 + v2*w1;
1307 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1308 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1309 break;
1310 }
1311 return faceSampleNum;
1312}
1313
1314
1316static void FaceSubdivision(MeshType & m, VertexSampler &ps,int sampleNum, bool randSample)
1317{
1318
1319 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1320 ScalarType samplePerAreaUnit = sampleNum/area;
1321 std::vector<FacePointer> faceVec;
1322 FillAndShuffleFacePointerVector(m,faceVec);
1324 double floatSampleNum = 0.0;
1325 int faceSampleNum;
1326 // Subdivision sampling.
1327 typename std::vector<FacePointer>::iterator fi;
1328 for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
1329 {
1330 const CoordType b0(1.0, 0.0, 0.0);
1331 const CoordType b1(0.0, 1.0, 0.0);
1332 const CoordType b2(0.0, 0.0, 1.0);
1333 // compute # samples in the current face.
1334 floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
1335 faceSampleNum = (int) floatSampleNum;
1336 if(faceSampleNum>0)
1337 faceSampleNum = SingleFaceSubdivision(faceSampleNum,b0,b1,b2,ps,*fi,randSample);
1338 floatSampleNum -= (double) faceSampleNum;
1339 }
1340}
1341//---------
1342// Subdivision sampling of a single face.
1343// return number of added samples
1344
1345static int SingleFaceSubdivisionOld(int sampleNum, const CoordType & v0, const CoordType & v1, const CoordType & v2, VertexSampler &ps, FacePointer fp, bool randSample)
1346{
1347 // recursive face subdivision.
1348 if(sampleNum == 1)
1349 {
1350 // ground case.
1351 CoordType SamplePoint;
1352 if(randSample)
1353 {
1354 CoordType rb=RandomBarycentric();
1355 SamplePoint=v0*rb[0]+v1*rb[1]+v2*rb[2];
1356 }
1357 else SamplePoint=((v0+v1+v2)*(1.0f/3.0f));
1358
1359 CoordType SampleBary;
1360 InterpolationParameters(*fp,SamplePoint,SampleBary);
1361 ps.AddFace(*fp,SampleBary);
1362 return 1;
1363 }
1364
1365 int s0 = sampleNum /2;
1366 int s1 = sampleNum-s0;
1367 assert(s0>0);
1368 assert(s1>0);
1369
1370 ScalarType w0 = ScalarType(s1)/ScalarType(sampleNum);
1371 ScalarType w1 = 1.0-w0;
1372 // compute the longest edge.
1373 ScalarType maxd01 = SquaredDistance(v0,v1);
1374 ScalarType maxd12 = SquaredDistance(v1,v2);
1375 ScalarType maxd20 = SquaredDistance(v2,v0);
1376 int res;
1377 if(maxd01 > maxd12)
1378 if(maxd01 > maxd20) res = 0;
1379 else res = 2;
1380 else
1381 if(maxd12 > maxd20) res = 1;
1382 else res = 2;
1383
1384 int faceSampleNum=0;
1385 // break the input triangle along the midpoint of the longest edge.
1386 CoordType pp;
1387 switch(res)
1388 {
1389 case 0 : pp = v0*w0 + v1*w1;
1390 faceSampleNum+=SingleFaceSubdivision(s0,v0,pp,v2,ps,fp,randSample);
1391 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1392 break;
1393 case 1 : pp = v1*w0 + v2*w1;
1394 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1395 faceSampleNum+=SingleFaceSubdivision(s1,v0,pp,v2,ps,fp,randSample);
1396 break;
1397 case 2 : pp = v0*w0 + v2*w1;
1398 faceSampleNum+=SingleFaceSubdivision(s0,v0,v1,pp,ps,fp,randSample);
1399 faceSampleNum+=SingleFaceSubdivision(s1,pp,v1,v2,ps,fp,randSample);
1400 break;
1401 }
1402 return faceSampleNum;
1403}
1404
1405
1407static void FaceSubdivisionOld(MeshType & m, VertexSampler &ps,int sampleNum, bool randSample)
1408{
1409
1410 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1411 ScalarType samplePerAreaUnit = sampleNum/area;
1412 std::vector<FacePointer> faceVec;
1413 FillAndShuffleFacePointerVector(m,faceVec);
1415 double floatSampleNum = 0.0;
1416 int faceSampleNum;
1417 // Subdivision sampling.
1418 typename std::vector<FacePointer>::iterator fi;
1419 for(fi=faceVec.begin(); fi!=faceVec.end(); fi++)
1420 {
1421 // compute # samples in the current face.
1422 floatSampleNum += 0.5*DoubleArea(**fi) * samplePerAreaUnit;
1423 faceSampleNum = (int) floatSampleNum;
1424 if(faceSampleNum>0)
1425 faceSampleNum = SingleFaceSubdivision(faceSampleNum,(**fi).V(0)->cP(), (**fi).V(1)->cP(), (**fi).V(2)->cP(),ps,*fi,randSample);
1426 floatSampleNum -= (double) faceSampleNum;
1427 }
1428}
1429
1430
1431//---------
1432
1433// Similar Triangles sampling.
1434// Skip vertex and edges
1435// Sample per edges includes vertexes, so here we should expect n_samples_per_edge >=4
1436
1437static int SingleFaceSimilar(FacePointer fp, VertexSampler &ps, int n_samples_per_edge)
1438{
1439 int n_samples=0;
1440 int i, j;
1441 float segmentNum=n_samples_per_edge -1 ;
1442 float segmentLen = 1.0/segmentNum;
1443 // face sampling.
1444 for(i=1; i < n_samples_per_edge-1; i++)
1445 for(j=1; j < n_samples_per_edge-1-i; j++)
1446 {
1447 //AddSample( v0 + (V1*(double)i + V2*(double)j) );
1448 CoordType sampleBary(i*segmentLen,j*segmentLen, 1.0 - (i*segmentLen+j*segmentLen) ) ;
1449 n_samples++;
1450 ps.AddFace(*fp,sampleBary);
1451 }
1452 return n_samples;
1453}
1454static int SingleFaceSimilarDual(FacePointer fp, VertexSampler &ps, int n_samples_per_edge, bool randomFlag)
1455{
1456 int n_samples=0;
1457 float i, j;
1458 float segmentNum=n_samples_per_edge -1 ;
1459 float segmentLen = 1.0/segmentNum;
1460 // face sampling.
1461 for(i=0; i < n_samples_per_edge-1; i++)
1462 for(j=0; j < n_samples_per_edge-1-i; j++)
1463 {
1464 //AddSample( v0 + (V1*(double)i + V2*(double)j) );
1465 CoordType V0((i+0)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+0)*segmentLen) ) ;
1466 CoordType V1((i+1)*segmentLen,(j+0)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+0)*segmentLen) ) ;
1467 CoordType V2((i+0)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+0)*segmentLen+(j+1)*segmentLen) ) ;
1468 n_samples++;
1469 if(randomFlag) {
1470 CoordType rb=RandomBarycentric();
1471 ps.AddFace(*fp, V0*rb[0]+V1*rb[1]+V2*rb[2]);
1472 } else ps.AddFace(*fp,(V0+V1+V2)/3.0);
1473
1474 if( j < n_samples_per_edge-i-2 )
1475 {
1476 CoordType V3((i+1)*segmentLen,(j+1)*segmentLen, 1.0 - ((i+1)*segmentLen+(j+1)*segmentLen) ) ;
1477 n_samples++;
1478 if(randomFlag) {
1479 CoordType rb=RandomBarycentric();
1480 ps.AddFace(*fp, V3*rb[0]+V1*rb[1]+V2*rb[2]);
1481 } else ps.AddFace(*fp,(V3+V1+V2)/3.0);
1482 }
1483 }
1484 return n_samples;
1485}
1486
1487// Similar sampling
1488// Each triangle is subdivided into similar triangles following a generalization of the classical 1-to-4 splitting rule of triangles.
1489// According to the level of subdivision <k> you get 1, 4 , 9, 16 , <k^2> triangles.
1490// Depending on the kind of the sampling strategies we can have two different approach to choosing the sample points.
1491// 1) you have already sampled both edges and vertices
1492// 2) you are not going to take samples on edges and vertices.
1493//
1494// In the first case you have to consider only internal vertices of the subdivided triangles (to avoid multiple sampling of edges and vertices).
1495// Therefore the number of internal points is ((k-3)*(k-2))/2. where k is the number of points on an edge (vertex included)
1496// E.g. for k=4 you get 3 segments on each edges and the original triangle is subdivided
1497// into 9 smaller triangles and you get (1*2)/2 == 1 only a single internal point.
1498// So if you want N samples in a triangle you have to solve k^2 -5k +6 - 2N = 0
1499// from which you get:
1500//
1501// 5 + sqrt( 1 + 8N )
1502// k = -------------------
1503// 2
1504//
1505// 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.
1506// So if you want N samples in a triangle, the number <k> of points on an edge (vertex included) should be simply:
1507// k = 1 + sqrt(N)
1508// examples:
1509// N = 4 -> k = 3
1510// N = 9 -> k = 4
1511
1512
1513
1514//template <class MeshType>
1515//void Sampling<MeshType>::SimilarFaceSampling()
1516static void FaceSimilar(MeshType & m, VertexSampler &ps,int sampleNum, bool dualFlag, bool randomFlag)
1517{
1518 ScalarType area = Stat<MeshType>::ComputeMeshArea(m);
1519 ScalarType samplePerAreaUnit = sampleNum/area;
1520
1521 // Similar Triangles sampling.
1522 int n_samples_per_edge;
1523 double n_samples_decimal = 0.0;
1524 FaceIterator fi;
1525
1526 for(fi=m.face.begin(); fi != m.face.end(); fi++)
1527 {
1528 // compute # samples in the current face.
1529 n_samples_decimal += 0.5*DoubleArea(*fi) * samplePerAreaUnit;
1530 int n_samples = (int) n_samples_decimal;
1531 if(n_samples>0)
1532 {
1533 // face sampling.
1534 if(dualFlag)
1535 {
1536 n_samples_per_edge = (int)((sqrt(1.0+8.0*(double)n_samples) +5.0)/2.0); // original for non dual case
1537 n_samples = SingleFaceSimilar(&*fi,ps, n_samples_per_edge);
1538 } else {
1539 n_samples_per_edge = (int)(sqrt((double)n_samples) +1.0);
1540 n_samples = SingleFaceSimilarDual(&*fi,ps, n_samples_per_edge,randomFlag);
1541 }
1542 }
1543 n_samples_decimal -= (double) n_samples;
1544 }
1545}
1546
1547
1548 // Rasterization fuction
1549 // Take a triangle
1550 // T deve essere una classe funzionale che ha l'operatore ()
1551 // con due parametri x,y di tipo S esempio:
1552 // class Foo { public void operator()(int x, int y ) { ??? } };
1553
1554// This function does rasterization with a safety buffer area, thus accounting some points actually outside triangle area
1555// The safety area samples are generated according to face flag BORDER which should be true for texture space border edges
1556// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge).
1557 static void SingleFaceRaster(typename MeshType::FaceType &f, VertexSampler &ps,
1558 const Point2<typename MeshType::ScalarType> & v0,
1559 const Point2<typename MeshType::ScalarType> & v1,
1560 const Point2<typename MeshType::ScalarType> & v2,
1561 bool correctSafePointsBaryCoords=true)
1562 {
1563 typedef typename MeshType::ScalarType S;
1564 // Calcolo bounding box
1565 Box2i bbox;
1566 Box2<S> bboxf;
1567 bboxf.Add(v0);
1568 bboxf.Add(v1);
1569 bboxf.Add(v2);
1570
1571 bbox.min[0] = floor(bboxf.min[0]);
1572 bbox.min[1] = floor(bboxf.min[1]);
1573 bbox.max[0] = ceil(bboxf.max[0]);
1574 bbox.max[1] = ceil(bboxf.max[1]);
1575
1576 // Calcolo versori degli spigoli
1577 Point2<S> d10 = v1 - v0;
1578 Point2<S> d21 = v2 - v1;
1579 Point2<S> d02 = v0 - v2;
1580
1581 // Preparazione prodotti scalari
1582 S b0 = (bbox.min[0]-v0[0])*d10[1] - (bbox.min[1]-v0[1])*d10[0];
1583 S b1 = (bbox.min[0]-v1[0])*d21[1] - (bbox.min[1]-v1[1])*d21[0];
1584 S b2 = (bbox.min[0]-v2[0])*d02[1] - (bbox.min[1]-v2[1])*d02[0];
1585 // Preparazione degli steps
1586 S db0 = d10[1];
1587 S db1 = d21[1];
1588 S db2 = d02[1];
1589 // Preparazione segni
1590 S dn0 = -d10[0];
1591 S dn1 = -d21[0];
1592 S dn2 = -d02[0];
1593
1594 //Calculating orientation
1595 bool flipped = !(d02 * vcg::Point2<S>(-d10[1], d10[0]) >= 0);
1596
1597 // Calculating border edges
1598 Segment2<S> borderEdges[3];
1599 S edgeLength[3];
1600 unsigned char edgeMask = 0;
1601
1602 if (f.IsB(0)) {
1603 borderEdges[0] = Segment2<S>(v0, v1);
1604 edgeLength[0] = borderEdges[0].Length();
1605 edgeMask |= 1;
1606 }
1607 if (f.IsB(1)) {
1608 borderEdges[1] = Segment2<S>(v1, v2);
1609 edgeLength[1] = borderEdges[1].Length();
1610 edgeMask |= 2;
1611 }
1612 if (f.IsB(2)) {
1613 borderEdges[2] = Segment2<S>(v2, v0);
1614 edgeLength[2] = borderEdges[2].Length();
1615 edgeMask |= 4;
1616 }
1617
1618 // Rasterizzazione
1619 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];
1620
1621 for(int x=bbox.min[0]-1;x<=bbox.max[0]+1;++x)
1622 {
1623 bool in = false;
1624 S n[3] = { b0-db0-dn0, b1-db1-dn1, b2-db2-dn2};
1625 for(int y=bbox.min[1]-1;y<=bbox.max[1]+1;++y)
1626 {
1627 if( ((n[0]>=0 && n[1]>=0 && n[2]>=0) || (n[0]<=0 && n[1]<=0 && n[2]<=0)) && (de != 0))
1628 {
1629 typename MeshType::CoordType baryCoord;
1630 baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de;
1631 baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de;
1632 baryCoord[2] = 1-baryCoord[0]-baryCoord[1];
1633
1634 ps.AddTextureSample(f, baryCoord, Point2i(x,y), 0);
1635 in = true;
1636 } else {
1637 // Check whether a pixel outside (on a border edge side) triangle affects color inside it
1638 Point2<S> px(x, y);
1639 Point2<S> closePoint;
1640 int closeEdge = -1;
1641 S minDst = FLT_MAX;
1642
1643 // find the closest point (on some edge) that lies on the 2x2 squared neighborhood of the considered point
1644 for (int i=0; i<3; ++i)
1645 {
1646 if (edgeMask & (1 << i))
1647 {
1648 Point2<S> close;
1649 S dst;
1650 if ( ((!flipped) && (n[i]<0)) ||
1651 ( flipped && (n[i]>0)) )
1652 {
1653 dst = ((close = ClosestPoint(borderEdges[i], px)) - px).Norm();
1654 if(dst < minDst &&
1655 close.X() > px.X()-1 && close.X() < px.X()+1 &&
1656 close.Y() > px.Y()-1 && close.Y() < px.Y()+1)
1657 {
1658 minDst = dst;
1659 closePoint = close;
1660 closeEdge = i;
1661 }
1662 }
1663 }
1664 }
1665
1666 if (closeEdge >= 0)
1667 {
1668 typename MeshType::CoordType baryCoord;
1669 if (correctSafePointsBaryCoords)
1670 {
1671 // Add x,y sample with closePoint barycentric coords (on edge)
1672 baryCoord[closeEdge] = (closePoint - borderEdges[closeEdge].P1()).Norm()/edgeLength[closeEdge];
1673 baryCoord[(closeEdge+1)%3] = 1 - baryCoord[closeEdge];
1674 baryCoord[(closeEdge+2)%3] = 0;
1675 } else {
1676 // Add x,y sample with his own barycentric coords (off edge)
1677 baryCoord[0] = double(-y*v1[0]+v2[0]*y+v1[1]*x-v2[0]*v1[1]+v1[0]*v2[1]-x*v2[1])/de;
1678 baryCoord[1] = -double( x*v0[1]-x*v2[1]-v0[0]*y+v0[0]*v2[1]-v2[0]*v0[1]+v2[0]*y)/de;
1679 baryCoord[2] = 1-baryCoord[0]-baryCoord[1];
1680 }
1681 ps.AddTextureSample(f, baryCoord, Point2i(x,y), minDst);
1682 in = true;
1683 }
1684 }
1685 n[0] += dn0;
1686 n[1] += dn1;
1687 n[2] += dn2;
1688 }
1689 b0 += db0;
1690 b1 += db1;
1691 b2 += db2;
1692 }
1693}
1694
1695// check the radius constrain
1696static bool checkPoissonDisk(SampleSHT & sht, const Point3<ScalarType> & p, ScalarType radius)
1697{
1698 // get the samples closest to the given one
1699 std::vector<VertexType*> closests;
1700 typedef EmptyTMark<MeshType> MarkerVert;
1701 static MarkerVert mv;
1702
1703 Box3f bb(p-Point3f(radius,radius,radius),p+Point3f(radius,radius,radius));
1704 GridGetInBox(sht, mv, bb, closests);
1705
1706 ScalarType r2 = radius*radius;
1707 for(int i=0; i<closests.size(); ++i)
1708 if(SquaredDistance(p,closests[i]->cP()) < r2)
1709 return false;
1710
1711 return true;
1712}
1713
1715{
1717 {
1718 adaptiveRadiusFlag = false;
1719 bestSampleChoiceFlag = true;
1720 bestSamplePoolSize = 10;
1721 radiusVariance =1;
1722 MAXLEVELS = 5;
1723 invertQuality = false;
1724 preGenFlag = false;
1725 preGenMesh = NULL;
1726 geodesicDistanceFlag = false;
1727 randomSeed = 0;
1728 }
1729
1730 struct Stat
1731 {
1732 int montecarloTime;
1733 int gridTime;
1734 int pruneTime;
1735 int totalTime;
1736 Point3i gridSize;
1737 int gridCellNum;
1738 size_t sampleNum;
1739 int montecarloSampleNum;
1740 };
1741
1742 bool geodesicDistanceFlag;
1743 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.
1744 int bestSamplePoolSize;
1745 bool adaptiveRadiusFlag;
1746 float radiusVariance;
1747 bool invertQuality;
1748 bool preGenFlag; // when generating a poisson distribution, you can initialize the set of computed points with
1749 // ALL the vertices of another mesh. Useful for building progressive//prioritize refinements.
1750 MeshType *preGenMesh; // There are two ways of passing the pregen vertexes to the pruning, 1) is with a mesh pointer
1751 // 2) with a per vertex attribute.
1752 int MAXLEVELS;
1753 int randomSeed;
1754
1755 Stat pds;
1756};
1757
1758
1759// generate Poisson-disk sample using a set of pre-generated samples (with the Montecarlo algorithm)
1760// It always return a point.
1761static VertexPointer getSampleFromCell(Point3i &cell, MontecarloSHT & samplepool)
1762{
1763 MontecarloSHTIterator cellBegin, cellEnd;
1764 samplepool.Grid(cell, cellBegin, cellEnd);
1765 return *cellBegin;
1766}
1767
1768// Given a cell of the grid it search the point that remove the minimum number of other samples
1769// it linearly scan all the points of a cell.
1770
1771static VertexPointer getBestPrecomputedMontecarloSample(Point3i &cell, MontecarloSHT & samplepool, ScalarType diskRadius, const PoissonDiskParam &pp)
1772{
1773 MontecarloSHTIterator cellBegin,cellEnd;
1774 samplepool.Grid(cell, cellBegin, cellEnd);
1775 VertexPointer bestSample=0;
1776 int minRemoveCnt = std::numeric_limits<int>::max();
1777 std::vector<typename MontecarloSHT::HashIterator> inSphVec;
1778 int i=0;
1779 for(MontecarloSHTIterator ci=cellBegin; ci!=cellEnd && i<pp.bestSamplePoolSize; ++ci,i++)
1780 {
1781 VertexPointer sp = *ci;
1782 if(pp.adaptiveRadiusFlag) diskRadius = sp->Q();
1783 int curRemoveCnt = samplepool.CountInSphere(sp->cP(),diskRadius,inSphVec);
1784 if(curRemoveCnt < minRemoveCnt)
1785 {
1786 bestSample = sp;
1787 minRemoveCnt = curRemoveCnt;
1788 }
1789 }
1790 return bestSample;
1791}
1792
1795static ScalarType ComputePoissonDiskRadius(MeshType &origMesh, int sampleNum)
1796{
1797 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
1798 // Manage approximately the PointCloud Case, use the half a area of the bbox.
1799 // TODO: If you had the radius a much better approximation could be done.
1800 if(meshArea ==0)
1801 {
1802 meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
1803 origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
1804 origMesh.bbox.DimY()*origMesh.bbox.DimZ());
1805 }
1806 ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
1807 return diskRadius;
1808}
1809
1810static int ComputePoissonSampleNum(MeshType &origMesh, ScalarType diskRadius)
1811{
1812 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
1813 int sampleNum = meshArea / (diskRadius*diskRadius *M_PI *0.7) ; // 0.7 is a density factor
1814 return sampleNum;
1815}
1816
1823
1824static void InitRadiusHandleFromQuality(MeshType &sampleMesh, PerVertexFloatAttribute &rH, ScalarType diskRadius, ScalarType radiusVariance, bool invert)
1825{
1826 std::pair<float,float> minmax = tri::Stat<MeshType>::ComputePerVertexQualityMinMax( sampleMesh);
1827 float minRad = diskRadius ;
1828 float maxRad = diskRadius * radiusVariance;
1829 float deltaQ = minmax.second-minmax.first;
1830 float deltaRad = maxRad-minRad;
1831 for (VertexIterator vi = sampleMesh.vert.begin(); vi != sampleMesh.vert.end(); vi++)
1832 {
1833 rH[*vi] = minRad + deltaRad*((invert ? minmax.second - (*vi).Q() : (*vi).Q() - minmax.first )/deltaQ);
1834 }
1835}
1836
1837// initialize spatial hash table for searching
1838// radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
1839// This radius implies that when we pick a sample in a cell all that cell probably will not be touched again.
1840// Howvever we must ensure that we do not put too many vertices inside each hash cell
1841
1842static void InitSpatialHashTable(MeshType &montecarloMesh, MontecarloSHT &montecarloSHT, ScalarType diskRadius,
1843 struct PoissonDiskParam pp=PoissonDiskParam())
1844{
1845 ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
1846 float occupancyRatio=0;
1847 do
1848 {
1849 // inflating
1850 BoxType bb=montecarloMesh.bbox;
1851 assert(!bb.IsNull());
1852 bb.Offset(cellsize);
1853
1854 int sizeX = std::max(1,int(bb.DimX() / cellsize));
1855 int sizeY = std::max(1,int(bb.DimY() / cellsize));
1856 int sizeZ = std::max(1,int(bb.DimZ() / cellsize));
1857 Point3i gridsize(sizeX, sizeY, sizeZ);
1858
1859 montecarloSHT.InitEmpty(bb, gridsize);
1860
1861 for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++)
1862 if(!(*vi).IsD())
1863 {
1864 montecarloSHT.Add(&(*vi));
1865 }
1866
1867 montecarloSHT.UpdateAllocatedCells();
1868 pp.pds.gridSize = gridsize;
1869 pp.pds.gridCellNum = (int)montecarloSHT.AllocatedCells.size();
1870 cellsize/=2.0f;
1871 occupancyRatio = float(montecarloMesh.vn) / float(montecarloSHT.AllocatedCells.size());
1872 // qDebug(" %i / %i = %6.3f", montecarloMesh.vn , montecarloSHT.AllocatedCells.size(),occupancyRatio);
1873 }
1874 while( occupancyRatio> 100);
1875}
1876
1877static void PoissonDiskPruningByNumber(VertexSampler &ps, MeshType &m,
1878 size_t sampleNum, ScalarType &diskRadius,
1879 PoissonDiskParam &pp,
1880 float tolerance=0.04,
1881 int maxIter=20)
1882
1883{
1884 size_t sampleNumMin = int(float(sampleNum)*(1.0f-tolerance));
1885 size_t sampleNumMax = int(float(sampleNum)*(1.0f+tolerance));
1886 float RangeMinRad = m.bbox.Diag()/50.0;
1887 float RangeMaxRad = m.bbox.Diag()/50.0;
1888 size_t RangeMinRadNum;
1889 size_t RangeMaxRadNum;
1890 // Note RangeMinRad < RangeMaxRad
1891 // but RangeMinRadNum > sampleNum > RangeMaxRadNum
1892 do {
1893 ps.reset();
1894 RangeMinRad/=2.0f;
1895 PoissonDiskPruning(ps, m ,RangeMinRad,pp);
1896 RangeMinRadNum = pp.pds.sampleNum;
1897// qDebug("PoissonDiskPruning Iteratin Min (%6.3f:%5i) instead of %i",RangeMinRad,RangeMinRadNum,sampleNum);
1898 } while(RangeMinRadNum < sampleNum); // if the number of sample is still smaller you have to make radius larger.
1899
1900 do {
1901 ps.reset();
1902 RangeMaxRad*=2.0f;
1903 PoissonDiskPruning(ps, m ,RangeMaxRad,pp);
1904 RangeMaxRadNum = pp.pds.sampleNum;
1905// qDebug("PoissonDiskPruning Iteratin Max (%6.3f:%5i) instead of %i",RangeMaxRad,RangeMaxRadNum,sampleNum);
1906 } while(RangeMaxRadNum > sampleNum);
1907
1908
1909 float curRadius=RangeMaxRad;
1910 int iterCnt=0;
1911 while(iterCnt<maxIter &&
1912 (pp.pds.sampleNum < sampleNumMin || pp.pds.sampleNum > sampleNumMax) )
1913 {
1914 iterCnt++;
1915 ps.reset();
1916 curRadius=(RangeMaxRad+RangeMinRad)/2.0f;
1917 PoissonDiskPruning(ps, m ,curRadius,pp);
1918// 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);
1919 if(pp.pds.sampleNum > sampleNum){
1920 RangeMinRad = curRadius;
1921 RangeMinRadNum = pp.pds.sampleNum;
1922 }
1923 if(pp.pds.sampleNum < sampleNum){
1924 RangeMaxRad = curRadius;
1925 RangeMaxRadNum = pp.pds.sampleNum;
1926 }
1927 }
1928 diskRadius = curRadius;
1929}
1930
1931
1941static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh,
1942 ScalarType diskRadius, PoissonDiskParam &pp)
1943{
1944 tri::RequireCompactness(montecarloMesh);
1945 if(pp.randomSeed) SamplingRandomGenerator().initialize(pp.randomSeed);
1946 if(pp.adaptiveRadiusFlag)
1947 tri::RequirePerVertexQuality(montecarloMesh);
1948 int t0 = clock();
1949 // spatial index of montecarlo samples - used to choose a new sample to insert
1950 MontecarloSHT montecarloSHT;
1951 InitSpatialHashTable(montecarloMesh,montecarloSHT,diskRadius,pp);
1952
1953 // if we are doing variable density sampling we have to prepare the handle that keeps the the random samples expected radii.
1954 // At this point we just assume that there is the quality values as sampled from the base mesh
1955 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (montecarloMesh,"radius");
1956 if(pp.adaptiveRadiusFlag)
1957 InitRadiusHandleFromQuality(montecarloMesh, rH, diskRadius, pp.radiusVariance, pp.invertQuality);
1958
1959 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
1960// std::random_device rd;
1961// std::mt19937 g(rd());
1962// std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
1963 MarsenneTwisterURBG g(montecarloSHT.AllocatedCells.size());
1964 std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
1965 int t1 = clock();
1966 pp.pds.montecarloSampleNum = montecarloMesh.vn;
1967 pp.pds.sampleNum =0;
1968 int removedCnt=0;
1969 // Initial pass for pruning the Hashed grid with the an eventual pre initialized set of samples
1970 if(pp.preGenFlag)
1971 {
1972 if(pp.preGenMesh==0)
1973 {
1974 typename MeshType::template PerVertexAttributeHandle<bool> fixed;
1975 fixed = tri::Allocator<MeshType>:: template GetPerVertexAttribute<bool> (montecarloMesh,"fixed");
1976 for(VertexIterator vi=montecarloMesh.vert.begin();vi!=montecarloMesh.vert.end();++vi)
1977 if(fixed[*vi]) {
1978 pp.pds.sampleNum++;
1979 ps.AddVert(*vi);
1980 removedCnt += montecarloSHT.RemoveInSphere(vi->cP(),diskRadius);
1981 }
1982 }
1983 else
1984 {
1985 for(VertexIterator vi =pp.preGenMesh->vert.begin(); vi!=pp.preGenMesh->vert.end();++vi)
1986 {
1987 ps.AddVert(*vi);
1988 pp.pds.sampleNum++;
1989 removedCnt += montecarloSHT.RemoveInSphere(vi->cP(),diskRadius);
1990 }
1991 }
1992 montecarloSHT.UpdateAllocatedCells();
1993 }
1994 vertex::ApproximateGeodesicDistanceFunctor<VertexType> GDF;
1995 while(!montecarloSHT.AllocatedCells.empty())
1996 {
1997 removedCnt=0;
1998 for (size_t i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
1999 {
2000 if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
2001 ScalarType currentRadius =diskRadius;
2002 VertexPointer sp;
2003 if(pp.bestSampleChoiceFlag)
2004 sp = getBestPrecomputedMontecarloSample(montecarloSHT.AllocatedCells[i], montecarloSHT, diskRadius, pp);
2005 else
2006 sp = getSampleFromCell(montecarloSHT.AllocatedCells[i], montecarloSHT);
2007
2008 if(pp.adaptiveRadiusFlag)
2009 currentRadius = rH[sp];
2010
2011 ps.AddVert(*sp);
2012 pp.pds.sampleNum++;
2013 if(pp.geodesicDistanceFlag) removedCnt += montecarloSHT.RemoveInSphereNormal(sp->cP(),sp->cN(),GDF,currentRadius);
2014 else removedCnt += montecarloSHT.RemoveInSphere(sp->cP(),currentRadius);
2015 }
2016 montecarloSHT.UpdateAllocatedCells();
2017 }
2018 int t2 = clock();
2019 pp.pds.gridTime = t1-t0;
2020 pp.pds.pruneTime = t2-t1;
2021}
2022
2033static void HierarchicalPoissonDisk(MeshType &origMesh, VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
2034{
2035// int t0=clock();
2036 // spatial index of montecarlo samples - used to choose a new sample to insert
2037 MontecarloSHT montecarloSHTVec[5];
2038
2039
2040
2041 // initialize spatial hash table for searching
2042 // radius is the radius of empty disk centered over the samples (e.g. twice of the empty space disk)
2043 // This radius implies that when we pick a sample in a cell all that cell will not be touched again.
2044 ScalarType cellsize = 2.0f* diskRadius / sqrt(3.0);
2045
2046 // inflating
2047 BoxType bb=origMesh.bbox;
2048 bb.Offset(cellsize);
2049
2050 int sizeX = std::max(1.0f,bb.DimX() / cellsize);
2051 int sizeY = std::max(1.0f,bb.DimY() / cellsize);
2052 int sizeZ = std::max(1.0f,bb.DimZ() / cellsize);
2053 Point3i gridsize(sizeX, sizeY, sizeZ);
2054
2055 // spatial hash table of the generated samples - used to check the radius constrain
2056 SampleSHT checkSHT;
2057 checkSHT.InitEmpty(bb, gridsize);
2058
2059
2060 // sampling algorithm
2061 // ------------------
2062 //
2063 // - generate millions of samples using montecarlo algorithm
2064 // - extract a cell (C) from the active cell list (with probability proportional to cell's volume)
2065 // - generate a sample inside C by choosing one of the contained pre-generated samples
2066 // - if the sample violates the radius constrain discard it, and add the cell to the cells-to-subdivide list
2067 // - iterate until the active cell list is empty or a pre-defined number of subdivisions is reached
2068 //
2069
2070 int level = 0;
2071
2072 // initialize spatial hash to index pre-generated samples
2073 montecarloSHTVec[0].InitEmpty(bb, gridsize);
2074 // create active cell list
2075 for (VertexIterator vi = montecarloMesh.vert.begin(); vi != montecarloMesh.vert.end(); vi++)
2076 montecarloSHTVec[0].Add(&(*vi));
2077 montecarloSHTVec[0].UpdateAllocatedCells();
2078
2079 // if we are doing variable density sampling we have to prepare the random samples quality with the correct expected radii.
2080 PerVertexFloatAttribute rH = tri::Allocator<MeshType>:: template GetPerVertexAttribute<float> (montecarloMesh,"radius");
2081 if(pp.adaptiveRadiusFlag)
2082 InitRadiusHandleFromQuality(montecarloMesh, rH, diskRadius, pp.radiusVariance, pp.invertQuality);
2083
2084 do
2085 {
2086 MontecarloSHT &montecarloSHT = montecarloSHTVec[level];
2087
2088 if(level>0)
2089 {// initialize spatial hash with the remaining points
2090 montecarloSHT.InitEmpty(bb, gridsize);
2091 // create active cell list
2092 for (typename MontecarloSHT::HashIterator hi = montecarloSHTVec[level-1].hash_table.begin(); hi != montecarloSHTVec[level-1].hash_table.end(); hi++)
2093 montecarloSHT.Add((*hi).second);
2094 montecarloSHT.UpdateAllocatedCells();
2095 }
2096 // shuffle active cells
2097 //unsigned int (*p_myrandom)(unsigned int) = RandomInt;
2098 std::random_device rd;
2099// std::mt19937 g(rd());
2100// std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
2101 MarsenneTwisterURBG g(montecarloSHT.AllocatedCells.size());
2102 std::shuffle(montecarloSHT.AllocatedCells.begin(),montecarloSHT.AllocatedCells.end(), g);
2103
2104 // generate a sample inside C by choosing one of the contained pre-generated samples
2106 int removedCnt=montecarloSHT.hash_table.size();
2107 int addedCnt=checkSHT.hash_table.size();
2108 for (int i = 0; i < montecarloSHT.AllocatedCells.size(); i++)
2109 {
2110 for(int j=0;j<4;j++)
2111 {
2112 if( montecarloSHT.EmptyCell(montecarloSHT.AllocatedCells[i]) ) continue;
2113
2114 // generate a sample chosen from the pre-generated one
2115 typename MontecarloSHT::HashIterator hi = montecarloSHT.hash_table.find(montecarloSHT.AllocatedCells[i]);
2116
2117 if(hi==montecarloSHT.hash_table.end()) {break;}
2118 VertexPointer sp = (*hi).second;
2119 // vr spans between 3.0*r and r / 4.0 according to vertex quality
2120 ScalarType sampleRadius = diskRadius;
2121 if(pp.adaptiveRadiusFlag) sampleRadius = rH[sp];
2122 if (checkPoissonDisk(checkSHT, sp->cP(), sampleRadius))
2123 {
2124 ps.AddVert(*sp);
2125 montecarloSHT.RemoveCell(sp);
2126 checkSHT.Add(sp);
2127 break;
2128 }
2129 else
2130 montecarloSHT.RemovePunctual(sp);
2131 }
2132 }
2133 addedCnt = checkSHT.hash_table.size()-addedCnt;
2134 removedCnt = removedCnt-montecarloSHT.hash_table.size();
2135
2136 // proceed to the next level of subdivision
2137 // increase grid resolution
2138 gridsize *= 2;
2139
2140 //
2141 level++;
2142 } while(level < 5);
2143}
2144
2145//template <class MeshType>
2146//void Sampling<MeshType>::SimilarFaceSampling()
2147
2148// This function also generates samples outside faces if those affects faces in texture space.
2149// Use correctSafePointsBaryCoords = true to map safety texels to closest point barycentric coords (on edge)
2150// otherwise obtained samples will map to barycentric coord actually outside face
2151//
2152// If you don't need to get those extra points clear faces Border Flags
2153// vcg::tri::UpdateFlags<Mesh>::FaceClearB(m);
2154//
2155// Else make sure to update border flags from texture space FFadj
2156// vcg::tri::UpdateTopology<Mesh>::FaceFaceFromTexCoord(m);
2157// vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m);
2158static void Texture(MeshType & m, VertexSampler &ps, int textureWidth, int textureHeight, bool correctSafePointsBaryCoords=true)
2159{
2160typedef Point2<ScalarType> Point2x;
2161 //printf("Similar Triangles face sampling\n");
2162 for(FaceIterator fi=m.face.begin(); fi != m.face.end(); fi++)
2163 if (!fi->IsD())
2164 {
2165 Point2x ti[3];
2166 for(int i=0;i<3;++i)
2167 ti[i]=Point2x((*fi).WT(i).U() * textureWidth - 0.5, (*fi).WT(i).V() * textureHeight - 0.5);
2168 // - 0.5 constants are used to obtain correct texture mapping
2169
2170 SingleFaceRaster(*fi, ps, ti[0],ti[1],ti[2], correctSafePointsBaryCoords);
2171 }
2172}
2173
2174typedef GridStaticPtr<FaceType, ScalarType > TriMeshGrid;
2175
2177{
2178public:
2179float offset;
2180float minDiag;
2181tri::FaceTmark<MeshType> markerFunctor;
2182TriMeshGrid gM;
2183};
2184
2185static void RegularRecursiveOffset(MeshType & m, std::vector<CoordType> &pvec, ScalarType offset, float minDiag)
2186{
2187 Box3<ScalarType> bb=m.bbox;
2188 bb.Offset(offset*2.0);
2189
2190 RRParam rrp;
2191
2192 rrp.markerFunctor.SetMesh(&m);
2193
2194 rrp.gM.Set(m.face.begin(),m.face.end(),bb);
2195
2196
2197 rrp.offset=offset;
2198 rrp.minDiag=minDiag;
2199 SubdivideAndSample(m, pvec, bb, rrp, bb.Diag());
2200}
2201
2202static void SubdivideAndSample(MeshType & m, std::vector<CoordType> &pvec, const Box3<ScalarType> bb, RRParam &rrp, float curDiag)
2203{
2204 CoordType startPt = bb.Center();
2205
2206 ScalarType dist;
2207 // Compute mesh point nearest to bb center
2208 FaceType *nearestF=0;
2209 ScalarType dist_upper_bound = curDiag+rrp.offset;
2210 CoordType closestPt;
2211 vcg::face::PointDistanceBaseFunctor<ScalarType> PDistFunct;
2212 dist=dist_upper_bound;
2213 nearestF = rrp.gM.GetClosest(PDistFunct,rrp.markerFunctor,startPt,dist_upper_bound,dist,closestPt);
2214 curDiag /=2;
2215 if(dist < dist_upper_bound)
2216 {
2217 if(curDiag/3 < rrp.minDiag) //store points only for the last level of recursion (?)
2218 {
2219 if(rrp.offset==0)
2220 pvec.push_back(closestPt);
2221 else
2222 {
2223 if(dist>rrp.offset) // points below the offset threshold cannot be displaced at the right offset distance, we can only make points nearer.
2224 {
2225 CoordType delta = startPt-closestPt;
2226 pvec.push_back(closestPt+delta*(rrp.offset/dist));
2227 }
2228 }
2229 }
2230 if(curDiag < rrp.minDiag) return;
2231 CoordType hs = (bb.max-bb.min)/2;
2232 for(int i=0;i<2;i++)
2233 for(int j=0;j<2;j++)
2234 for(int k=0;k<2;k++)
2235 SubdivideAndSample(m, pvec,
2236 BoxType(CoordType( bb.min[0]+i*hs[0], bb.min[1]+j*hs[1], bb.min[2]+k*hs[2]),
2237 CoordType(startPt[0]+i*hs[0], startPt[1]+j*hs[1], startPt[2]+k*hs[2]) ),
2238 rrp,curDiag
2239 );
2240
2241 }
2242}
2243}; // end sampling class
2244
2245template <class MeshType>
2246typename MeshType::ScalarType ComputePoissonDiskRadius(MeshType &origMesh, int sampleNum)
2247{
2248 typedef typename MeshType::ScalarType ScalarType;
2249 ScalarType meshArea = Stat<MeshType>::ComputeMeshArea(origMesh);
2250 // Manage approximately the PointCloud Case, use the half a area of the bbox.
2251 // TODO: If you had the radius a much better approximation could be done.
2252 if(meshArea ==0)
2253 {
2254 meshArea = (origMesh.bbox.DimX()*origMesh.bbox.DimY() +
2255 origMesh.bbox.DimX()*origMesh.bbox.DimZ() +
2256 origMesh.bbox.DimY()*origMesh.bbox.DimZ());
2257 }
2258 ScalarType diskRadius = sqrt(meshArea / (0.7 * M_PI * sampleNum)); // 0.7 is a density factor
2259 return diskRadius;
2260}
2261
2262
2263
2264template <class MeshType>
2265void MontecarloSampling(MeshType &m, // the mesh that has to be sampled
2266 MeshType &mm, // the mesh that will contain the samples
2267 int sampleNum) // the desired number sample, if zero you must set the radius to the wanted value
2268{
2269 typedef tri::MeshSampler<MeshType> BaseSampler;
2270 MeshSampler<MeshType> mcSampler(&mm);
2272}
2273
2274
2275template <class MeshType>
2276void MontecarloSampling(MeshType &m, // the mesh that has to be sampled
2277 std::vector<Point3f> &montercarloSamples, // the vector that will contain the set of points
2278 int sampleNum) // the desired number sample, if zero you must set the radius to the wanted value
2279{
2280 typedef tri::TrivialSampler<MeshType> BaseSampler;
2281 BaseSampler mcSampler(montercarloSamples);
2283}
2284
2285// Yet another simpler wrapper for the generation of a poisson disk distribution over a mesh.
2286//
2287template <class MeshType>
2288void PoissonSampling(MeshType &m, // the mesh that has to be sampled
2289 std::vector<typename MeshType::CoordType> &poissonSamples, // the vector that will contain the set of points
2290 int sampleNum, // the desired number sample, if zero you must set the radius to the wanted value
2291 typename MeshType::ScalarType &radius, // the Poisson Disk Radius (used if sampleNum==0, setted if sampleNum!=0)
2292 typename MeshType::ScalarType radiusVariance=1,
2293 typename MeshType::ScalarType PruningByNumberTolerance=0.04f,
2294 unsigned int randSeed=0)
2295
2296{
2297 typedef tri::TrivialSampler<MeshType> BaseSampler;
2298 typedef tri::MeshSampler<MeshType> MontecarloSampler;
2299
2300 typename tri::SurfaceSampling<MeshType, BaseSampler>::PoissonDiskParam pp;
2301 int t0=clock();
2302
2303// if(sampleNum>0) radius = tri::SurfaceSampling<MeshType,BaseSampler>::ComputePoissonDiskRadius(m,sampleNum);
2304 if(radius>0 && sampleNum==0) sampleNum = tri::SurfaceSampling<MeshType,BaseSampler>::ComputePoissonSampleNum(m,radius);
2305
2306 pp.pds.sampleNum = sampleNum;
2307 pp.randomSeed = randSeed;
2308 poissonSamples.clear();
2309// std::vector<Point3f> MontecarloSamples;
2310 MeshType MontecarloMesh;
2311
2312 // First step build the sampling
2313 MontecarloSampler mcSampler(MontecarloMesh);
2314 BaseSampler pdSampler(poissonSamples);
2315
2316 if(randSeed) tri::SurfaceSampling<MeshType,MontecarloSampler>::SamplingRandomGenerator().initialize(randSeed);
2317 tri::SurfaceSampling<MeshType,MontecarloSampler>::Montecarlo(m, mcSampler, std::max(10000,sampleNum*40));
2318 tri::UpdateBounding<MeshType>::Box(MontecarloMesh);
2319// tri::Build(MontecarloMesh, MontecarloSamples);
2320 int t1=clock();
2321 pp.pds.montecarloTime = t1-t0;
2322
2323 if(radiusVariance !=1)
2324 {
2325 pp.adaptiveRadiusFlag=true;
2326 pp.radiusVariance=radiusVariance;
2327 }
2328 if(sampleNum==0) tri::SurfaceSampling<MeshType,BaseSampler>::PoissonDiskPruning(pdSampler, MontecarloMesh, radius,pp);
2329 else tri::SurfaceSampling<MeshType,BaseSampler>::PoissonDiskPruningByNumber(pdSampler, MontecarloMesh, sampleNum, radius,pp,PruningByNumberTolerance);
2330 int t2=clock();
2331 pp.pds.totalTime = t2-t0;
2332}
2333
2337//
2338template <class MeshType>
2339void PoissonPruning(MeshType &m, // the mesh that has to be pruned
2340 std::vector<typename MeshType::VertexPointer> &poissonSamples, // the vector that will contain the chosen set of points
2341 float radius, unsigned int randSeed=0)
2342{
2343 typedef tri::TrivialPointerSampler<MeshType> BaseSampler;
2345 pp.randomSeed = randSeed;
2346
2348 BaseSampler pdSampler;
2350 poissonSamples = pdSampler.sampleVec;
2351}
2352
2353
2359template <class MeshType>
2360void PoissonPruning(MeshType &m, // the mesh that has to be pruned
2361 std::vector<typename MeshType::CoordType> &poissonSamples, // the vector that will contain the chosen set of points
2362 float radius, unsigned int randSeed=0)
2363{
2364 std::vector<typename MeshType::VertexPointer> poissonSamplesVP;
2365 PoissonPruning(m,poissonSamplesVP,radius,randSeed);
2366 poissonSamples.resize(poissonSamplesVP.size());
2367 for(size_t i=0;i<poissonSamplesVP.size();++i)
2368 poissonSamples[i]=poissonSamplesVP[i]->P();
2369}
2370
2371
2372
2378template <class MeshType>
2379void PoissonPruningExact(MeshType &m,
2380 std::vector<typename MeshType::VertexPointer> &poissonSamples,
2381 typename MeshType::ScalarType & radius,
2382 int sampleNum,
2383 float tolerance=0.04,
2384 int maxIter=20,
2385 unsigned int randSeed=0)
2386{
2387 size_t sampleNumMin = int(float(sampleNum)*(1.0f-tolerance)); // the expected values range.
2388 size_t sampleNumMax = int(float(sampleNum)*(1.0f+tolerance)); // e.g. any sampling in [sampleNumMin, sampleNumMax] is OK
2389 float RangeMinRad = m.bbox.Diag()/10.0f;
2390 float RangeMaxRad = m.bbox.Diag()/10.0f;
2391 size_t RangeMinSampleNum;
2392 size_t RangeMaxSampleNum;
2393 std::vector<typename MeshType::VertexPointer> poissonSamplesTmp;
2394
2395 do
2396 {
2397 RangeMinRad/=2.0f;
2398 PoissonPruning(m,poissonSamplesTmp,RangeMinRad,randSeed);
2399 RangeMinSampleNum = poissonSamplesTmp.size();
2400 } while(RangeMinSampleNum < sampleNumMin);
2401
2402 do
2403 {
2404 RangeMaxRad*=2.0f;
2405 PoissonPruning(m,poissonSamplesTmp,RangeMaxRad,randSeed);
2406 RangeMaxSampleNum = poissonSamplesTmp.size();
2407 } while(RangeMaxSampleNum > sampleNumMax);
2408
2409 float curRadius;
2410 int iterCnt=0;
2411 while(iterCnt<maxIter &&
2412 (poissonSamplesTmp.size() < sampleNumMin || poissonSamplesTmp.size() > sampleNumMax) )
2413 {
2414 curRadius=(RangeMaxRad+RangeMinRad)/2.0f;
2415 PoissonPruning(m,poissonSamplesTmp,curRadius,randSeed);
2416 //qDebug("(%6.3f:%5i %6.3f:%5i) Cur Radius %f -> %i sample instead of %i",RangeMinRad,RangeMinSampleNum,RangeMaxRad,RangeMaxSampleNum,curRadius,poissonSamplesTmp.size(),sampleNum);
2417 if(poissonSamplesTmp.size() > size_t(sampleNum))
2418 RangeMinRad = curRadius;
2419 if(poissonSamplesTmp.size() < size_t(sampleNum))
2420 RangeMaxRad = curRadius;
2421 }
2422
2423 swap(poissonSamples,poissonSamplesTmp);
2424 radius = curRadius;
2425}
2426} // end namespace tri
2427} // end namespace vcg
2428
2429#endif
2430
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:515
Definition: point_sampling.h:2177
Main Class of the Sampling framework.
Definition: point_sampling.h:476
static void Montecarlo(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:1181
static void HierarchicalPoissonDisk(MeshType &origMesh, VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, const struct PoissonDiskParam pp=PoissonDiskParam())
Definition: point_sampling.h:2033
static void VertexAreaUniform(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:710
static void VertexWeighted(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:672
static void VertexCrease(MeshType &m, VertexSampler &ps)
Definition: point_sampling.h:969
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:758
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:1316
static void PoissonDiskPruning(VertexSampler &ps, MeshType &montecarloMesh, ScalarType diskRadius, PoissonDiskParam &pp)
Definition: point_sampling.h:1941
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:1795
EdgeSamplingRoundingStrategy
The EdgeSamplingStrategy enum determines the sampling strategy for edge meshes. Given a sampling radi...
Definition: point_sampling.h:793
static void VertexBorder(MeshType &m, VertexSampler &ps)
Sample all the border vertices.
Definition: point_sampling.h:958
static void VertexBorderCorner(MeshType &m, VertexSampler &ps, ScalarType angleRad)
Sample all the border corner vertices.
Definition: point_sampling.h:944
static void EdgeMeshUniform(MeshType &m, VertexSampler &ps, float radius, EdgeSamplingRoundingStrategy strategy=Floor)
Definition: point_sampling.h:815
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:1407
static int Poisson(double lambda)
Definition: point_sampling.h:632
static void MontecarloPoisson(MeshType &m, VertexSampler &ps, int sampleNum)
Definition: point_sampling.h:1114
static void WeightedMontecarlo(MeshType &m, VertexSampler &ps, int sampleNum, float variance)
Definition: point_sampling.h:1224
static void InitRadiusHandleFromQuality(MeshType &sampleMesh, PerVertexFloatAttribute &rH, ScalarType diskRadius, ScalarType radiusVariance, bool invert)
Definition: point_sampling.h:1824
static void EdgeMontecarlo(MeshType &m, VertexSampler &ps, int sampleNum, bool sampleAllEdges)
Definition: point_sampling.h:1140
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:2379
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:2339
Definition: color4.h:30
Definition: point_sampling.h:1731
Definition: point_sampling.h:1715