Visual Computing Library  devel
Loading...
Searching...
No Matches
point_sampling.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
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 Mozilla Public License Version 2.0 as published *
13 * by the Mozilla 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 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_ALGORITHMS_MESH_POINT_SAMPLING_H
24#define VCL_ALGORITHMS_MESH_POINT_SAMPLING_H
25
26#include <vclib/algorithms/mesh/shuffle.h>
27#include <vclib/algorithms/mesh/stat.h>
28
29#include <vclib/mesh.h>
30#include <vclib/space/complex.h>
31
49namespace vcl {
50
72template<MeshConcept MeshType>
74 const MeshType& m,
75 std::vector<uint>& birthVertices,
76 bool onlySelected = false)
77{
78 using VertexType = MeshType::VertexType;
79 using PointType = VertexType::PositionType;
80
82
83 // Determine the number of vertices to sample
84 uint n = onlySelected ? vertexSelectionNumber(m) : m.vertexNumber();
85
86 // Reserve space in the sampler and birthVertices vectors
87 sampler.reserve(n);
88 birthVertices.reserve(n);
89 birthVertices.clear();
90
91 // Loop through all the vertices in the mesh and add them to the sampler if
92 // they are selected
93 for (const VertexType& v : m.vertices()) {
94 if (!onlySelected || v.selected()) {
95 sampler.add(v);
96 birthVertices.push_back(m.index(v));
97 }
98 }
99 return sampler;
100}
101
120template<MeshConcept MeshType>
121auto allVerticesPointSampling(const MeshType& m, bool onlySelected = false)
122{
123 std::vector<uint> v;
125}
126
150template<FaceMeshConcept MeshType>
152 const MeshType& m,
153 std::vector<uint>& birthFaces,
154 bool onlySelected = false)
155{
156 using PointType = MeshType::VertexType::PositionType;
157 using FaceType = MeshType::FaceType;
158
160
161 // Determine the number of vertices to sample
162 uint n = onlySelected ? faceSelectionNumber(m) : m.faceNumber();
163
164 // Reserve space in the sampler and birthVertices vectors
165 sampler.reserve(n);
166 birthFaces.reserve(n);
167 birthFaces.clear();
168
169 for (const FaceType& f : m.faces()) {
170 if (!onlySelected || f.selected()) {
171 sampler.add(f);
172 birthFaces.push_back(m.index(f));
173 }
174 }
175 return sampler;
176}
177
198template<FaceMeshConcept MeshType>
199auto allFacesPointSampling(const MeshType& m, bool onlySelected = false)
200{
201 std::vector<uint> v;
203}
204
224template<MeshConcept MeshType>
226 const MeshType& m,
227 uint nSamples,
228 std::vector<uint>& birthVertices,
229 bool onlySelected = false,
230 std::optional<uint> seed = std::nullopt)
231{
232 using PointType = MeshType::VertexType::PositionType;
233
234 uint vn = onlySelected ? vertexSelectionNumber(m) : m.vertexNumber();
235
236 if (nSamples >= vn) {
238 }
239
241
242 // Reserve space in the sampler and birthVertices vectors
243 ps.reserve(vn);
244 birthVertices.reserve(vn);
245 birthVertices.clear();
246
247 std::uniform_int_distribution<uint> dist(0, m.vertexContainerSize() - 1);
248
249 std::mt19937 gen = randomGenerator(seed);
250
251 std::vector<bool> visited(m.vertexContainerSize(), false);
252 uint nVisited = 0;
253
254 while (nVisited < nSamples) {
255 uint vi = dist(gen);
256 if (!m.vertex(vi).deleted() && !visited[vi] &&
257 (!onlySelected || m.vertex(vi).selected())) {
258 visited[vi] = true;
259 nVisited++;
260 ps.add(m.vertex(vi));
261 birthVertices.push_back(vi);
262 }
263 }
264
265 return ps;
266}
267
285template<MeshConcept MeshType>
287 const MeshType& m,
288 uint nSamples,
289 bool onlySelected = false,
290 std::optional<uint> seed = std::nullopt)
291{
292 std::vector<uint> v;
294}
295
318template<FaceMeshConcept MeshType>
320 const MeshType& m,
321 uint nSamples,
322 std::vector<uint>& birthFaces,
323 bool onlySelected = false,
324 std::optional<uint> seed = std::nullopt)
325{
326 using PointType = MeshType::VertexType::PositionType;
327
328 uint fn = onlySelected ? faceSelectionNumber(m) : m.faceNumber();
329
330 if (nSamples >= fn) {
332 }
333
335
336 // Reserve space in the sampler and birthFaces vectors
337 ps.reserve(fn);
338 birthFaces.reserve(fn);
339 birthFaces.clear();
340
341 std::uniform_int_distribution<uint> dist(0, m.faceContainerSize() - 1);
342
343 std::mt19937 gen = randomGenerator(seed);
344
345 std::vector<bool> visited(m.faceContainerSize(), false);
346 uint nVisited = 0;
347
348 while (nVisited < nSamples) {
349 uint fi = dist(gen);
350 if (!m.face(fi).deleted() && !visited[fi] &&
351 (!onlySelected || m.face(fi).selected())) {
352 visited[fi] = true;
353 nVisited++;
354 ps.add(m.face(fi));
355 birthFaces.push_back(fi);
356 }
357 }
358
359 return ps;
360}
361
382template<FaceMeshConcept MeshType>
384 const MeshType& m,
385 uint nSamples,
386 bool onlySelected = false,
387 std::optional<uint> seed = std::nullopt)
388{
389 std::vector<uint> v;
391}
392
417template<MeshConcept MeshType, typename ScalarType>
419 const MeshType& m,
420 const std::vector<ScalarType>& weights,
421 uint nSamples,
422 std::vector<uint>& birthVertices,
423 std::optional<uint> seed = std::nullopt)
424{
425 using PointType = MeshType::VertexType::PositionType;
426
427 if (nSamples >= m.vertexNumber()) {
429 }
430
432 ps.reserve(nSamples);
433 birthVertices.reserve(nSamples);
434 birthVertices.clear();
435
436 std::discrete_distribution<> dist(std::begin(weights), std::end(weights));
437
438 std::mt19937 gen = randomGenerator(seed);
439
440 std::vector<bool> visited(m.vertexContainerSize(), false);
441 uint nVisited = 0;
442
443 while (nVisited < nSamples) {
444 uint vi = dist(gen);
445 if (vi < m.vertexContainerSize() && !m.vertex(vi).deleted() &&
446 !visited[vi]) {
447 visited[vi] = true;
448 nVisited++;
449 ps.add(m.vertex(vi));
450 birthVertices.push_back(vi);
451 }
452 }
453
454 return ps;
455}
456
478template<MeshConcept MeshType, typename ScalarType>
480 const MeshType& m,
481 const std::vector<ScalarType>& weights,
482 uint nSamples,
483 std::optional<uint> seed = std::nullopt)
484{
485 std::vector<uint> v;
487}
488
514template<FaceMeshConcept MeshType, typename ScalarType>
516 const MeshType& m,
517 const std::vector<ScalarType>& weights,
518 uint nSamples,
519 std::vector<uint>& birthFaces,
520 std::optional<uint> seed = std::nullopt)
521{
522 using PointType = MeshType::VertexType::PositionType;
523
524 if (nSamples >= m.faceNumber()) {
525 return allFacesPointSampling(m);
526 }
527
529
530 // Reserve space in the sampler and birthFaces vectors
531 ps.reserve(nSamples);
532 birthFaces.reserve(nSamples);
533 birthFaces.clear();
534
535 std::discrete_distribution<> dist(std::begin(weights), std::end(weights));
536
537 std::mt19937 gen = randomGenerator(seed);
538
539 std::vector<bool> visited(m.faceContainerSize(), false);
540 uint nVisited = 0;
541
542 while (nVisited < nSamples) {
543 uint fi = dist(gen);
544 if (fi < m.faceContainerSize() && !m.face(fi).deleted() &&
545 !visited[fi]) {
546 visited[fi] = true;
547 nVisited++;
548 ps.add(m.face(fi));
549 birthFaces.push_back(fi);
550 }
551 }
552
553 return ps;
554}
555
578template<FaceMeshConcept MeshType, typename ScalarType>
580 const MeshType& m,
581 const std::vector<ScalarType>& weights,
582 uint nSamples,
583 std::optional<uint> seed = std::nullopt)
584{
585 std::vector<uint> v;
587}
588
602template<MeshConcept MeshType>
604 const MeshType& m,
605 uint nSamples,
606 std::optional<uint> seed = std::nullopt)
607{
608 requirePerVertexQuality(m);
609
610 using VertexType = MeshType::VertexType;
611 using QualityType = VertexType::QualityType;
612
613 std::vector<QualityType> weights;
614 weights.resize(m.vertexContainerSize(), 0);
615 for (const VertexType& v : m.vertices()) {
616 weights[m.index(v)] = v.quality();
617 }
618
620}
621
635template<FaceMeshConcept MeshType>
637 const MeshType& m,
638 uint nSamples,
639 std::optional<uint> seed = std::nullopt)
640{
642
643 using FaceType = MeshType::FaceType;
644 using QualityType = FaceType::QualityType;
645
646 std::vector<QualityType> weights;
647 weights.resize(m.faceContainerSize(), 0);
648 for (const FaceType& f : m.faces()) {
649 weights[m.index(f)] = f.quality();
650 }
651
653}
654
668template<FaceMeshConcept MeshType>
670 const MeshType& m,
671 uint nSamples,
672 std::optional<uint> seed = std::nullopt)
673{
674 using VertexType = MeshType::VertexType;
675 using ScalarType = VertexType::ScalarType;
676 using FaceType = MeshType::FaceType;
677
678 std::vector<ScalarType> weights(m.vertexContainerSize(), 0);
679 std::vector<uint> cnt(m.vertexContainerSize(), 0);
680
681 // for each vertex, store in weights the adjacent faces area and their
682 // number
683 for (const FaceType& f : m.faces()) {
684 ScalarType area = faceArea(f);
685 for (const VertexType* v : f.vertices()) {
686 weights[m.index(v)] += area;
687 cnt[m.index(v)]++;
688 }
689 }
690
691 // divide each area sum by the number of adjacent faces
692 for (uint i = 0; i < weights.size(); i++) {
693 if (cnt[i] > 0)
694 weights[i] /= cnt[i];
695 }
696
697 // use these weights to create a sapler
699}
700
713template<FaceMeshConcept MeshType>
715 const MeshType& m,
716 uint nSamples,
717 std::optional<uint> seed = std::nullopt)
718{
719 using FaceType = MeshType::FaceType;
720
721 std::vector<double> weights(m.faceContainerSize());
722
723 for (const FaceType& f : m.faces()) {
724 weights[m.index(f)] = faceArea(f);
725 }
726
728}
729
749template<FaceMeshConcept MeshType>
751 const MeshType& m,
752 uint nSamples,
753 std::vector<uint>& birthFaces,
754 std::optional<uint> seed = std::nullopt)
755{
756 using VertexType = MeshType::VertexType;
757 using PointType = VertexType::PositionType;
758 using ScalarType = PointType::ScalarType;
759 using FaceType = MeshType::FaceType;
760 using Interval = std::pair<ScalarType, const FaceType*>;
761
764
765 // Reserve space in the sampler and birthFaces vectors
766 sampler.reserve(nSamples);
767 birthFaces.reserve(nSamples);
768 birthFaces.clear();
769
770 std::uniform_real_distribution<ScalarType> dist(0, 1);
771
772 std::mt19937 gen = randomGenerator(seed);
773
774 std::vector<Interval> intervals(m.faceNumber());
775 uint i = 0;
776 ScalarType area = 0;
777 for (const FaceType& f : m.faces()) {
778 area += faceArea(f);
779 intervals[i] = std::make_pair(area, &f);
780 i++;
781 }
782
783 ScalarType meshArea = intervals.back().first;
784 for (uint i = 0; i < nSamples; i++) {
785 ScalarType val = meshArea * dist(gen);
786 // lower_bound returns the furthermost iterator i in [first, last) such
787 // that, for every iterator j in [first, i), *j < value. E.g. An
788 // iterator pointing to the first element "not less than" val, or end()
789 // if every element is less than val.
790 typename std::vector<Interval>::iterator it = std::lower_bound(
791 intervals.begin(),
792 intervals.end(),
793 std::make_pair(val, nullptr),
794 comparator);
795
796 sampler.add(
797 *it->second,
799 it->second->vertexNumber(), gen));
800 birthFaces.push_back(it->second->index());
801 }
802
803 return sampler;
804}
805
822template<FaceMeshConcept MeshType>
824 const MeshType& m,
825 uint nSamples,
826 std::optional<uint> seed = std::nullopt)
827{
828 std::vector<uint> birthFaces;
830}
831
832template<FaceMeshConcept MeshType>
833auto stratifiedMontecarloPointSampling(
834 const MeshType& m,
835 uint nSamples,
836 std::optional<uint> seed = std::nullopt)
837{
838 using FaceType = MeshType::FaceType;
839 using PointType = MeshType::VertexType::PositionType;
840 using ScalarType = PointType::ScalarType;
841
842 PointSampler<PointType> ps;
843
844 std::mt19937 gen = randomGenerator(seed);
845
846 double area = surfaceArea(m);
847 double samplePerAreaUnit = nSamples / area;
848 // Montecarlo sampling.
849 double floatSampleNum = 0.0;
850
851 for (const FaceType& f : m.faces()) {
852 // compute # samples in the current face (taking into account of the
853 // remainders)
854 floatSampleNum += faceArea(f) * samplePerAreaUnit;
855 int faceSampleNum = (int) floatSampleNum;
856 // for every sample p_i in T...
857 for (int i = 0; i < faceSampleNum; i++)
858 ps.add(
859 f,
860 randomPolygonBarycentricCoordinate<ScalarType>(
861 f.vertexNumber(), gen));
862 floatSampleNum -= (double) faceSampleNum;
863 }
864
865 return ps;
866}
867
891template<FaceMeshConcept MeshType>
893 const MeshType& m,
894 uint nSamples,
895 std::optional<uint> seed = std::nullopt)
896{
897 using FaceType = MeshType::FaceType;
898 using PointType = MeshType::VertexType::PositionType;
899 using ScalarType = PointType::ScalarType;
900
902
903 std::mt19937 gen = randomGenerator(seed);
904
905 ScalarType area = surfaceArea(m);
906 ScalarType samplePerAreaUnit = nSamples / area;
907
908 for (const FaceType& f : m.faces()) {
909 ScalarType areaT = faceArea(f);
911
912 // for every sample p_i in T...
913 for (int i = 0; i < faceSampleNum; i++)
914 ps.add(
915 f,
917 f.vertexNumber(), gen));
918 }
919
920 return ps;
921}
922
923template<FaceMeshConcept MeshType, typename ScalarType>
924auto vertexWeightedMontecarloPointSampling(
925 const MeshType& m,
926 const std::vector<ScalarType>& weights,
927 uint nSamples,
928 double variance,
929 std::optional<uint> seed = std::nullopt)
930{
931 using PointType = MeshType::VertexType::PositionType;
932 using FaceType = MeshType::FaceType;
933
934 // lambda function to compute radius weighted area of a face
935 auto weightedArea = [](const FaceType& f,
936 const MeshType& m,
937 const std::vector<ScalarType>& r) -> ScalarType {
938 ScalarType averageQ = 0;
939 for (uint i = 0; i < f.vertexNumber(); ++i)
940 averageQ += r[m.index(f.vertex(i))];
941
942 averageQ /= f.vertexNumber();
943 return averageQ * averageQ * faceArea(f);
944 };
945
946 PointSampler<PointType> ps;
947
948 std::mt19937 gen = randomGenerator(seed);
949
950 std::vector<ScalarType> radius =
951 vertexRadiusFromWeights(m, weights, 1.0, variance, true);
952
953 ScalarType wArea = 0;
954 for (const FaceType& f : m.faces())
955 wArea += weightedArea(f, m, radius);
956
957 ScalarType samplePerAreaUnit = nSamples / wArea;
958 // Montecarlo sampling.
959 double floatSampleNum = 0.0;
960 for (const FaceType& f : m.faces()) {
961 // compute # samples in the current face (taking into account of the
962 // remainders)
963 floatSampleNum += weightedArea(f, m, radius) * samplePerAreaUnit;
964 uint faceSampleNum = (uint) floatSampleNum;
965
966 // for every sample p_i in T...
967 for (uint i = 0; i < faceSampleNum; i++)
968 ps.add(
969 f,
970 randomPolygonBarycentricCoordinate<ScalarType>(
971 f.vertexNumber(), gen));
972
973 floatSampleNum -= (double) faceSampleNum;
974 }
975
976 return ps;
977}
978
979template<FaceMeshConcept MeshType>
980auto vertexQualityWeightedMontecarloPointSampling(
981 const MeshType& m,
982 uint nSamples,
983 double variance,
984 std::optional<uint> seed = std::nullopt)
985{
986 requirePerVertexQuality(m);
987
988 using VertexType = MeshType::VertexType;
989 using QualityType = VertexType::QualityType;
990
991 std::vector<QualityType> weights;
992 weights.resize(m.vertexContainerSize(), 0);
993 for (const VertexType& v : m.vertices()) {
994 weights[m.index(v)] = v.quality();
995 }
996
997 return vertexWeightedMontecarloPointSampling(
998 m, weights, nSamples, variance, seed);
999}
1000
1001} // namespace vcl
1002
1003#endif // VCL_ALGORITHMS_MESH_POINT_SAMPLING_H
A class representing a box in N-dimensional space.
Definition box.h:46
void add(const PointT &p)
Adds the given point to the current box, expanding this box in order to contain also the values of th...
Definition box.h:385
PointT size() const
Computes the size of the box.
Definition box.h:267
int poissonRandomNumber(double lambda, std::mt19937 &gen)
algorithm poisson random number (Knuth): init: Let L ← e^−λ, k ← 0 and p ← 1. do: k ← k + 1....
Definition random.h:120
std::mt19937 randomGenerator(std::optional< uint > seed=std::nullopt)
Creates a random number generator with an optional seed.
Definition random.h:45
auto faceArea(const FaceType &f)
Computes the area of a face. Works both for triangle and polygonal faces, and it is optimized in case...
Definition geometry.h:108
void requirePerFaceQuality(const MeshType &m)
This function asserts that a Mesh has a FaceContainer, the Face has a Quality Component,...
Definition face_requirements.h:1250
auto vertexWeightedPointSampling(const MeshType &m, const std::vector< ScalarType > &weights, uint nSamples, std::vector< uint > &birthVertices, std::optional< uint > seed=std::nullopt)
Samples the vertices in a weighted way, using the per vertex weights given as input....
Definition point_sampling.h:418
auto vertexUniformPointSampling(const MeshType &m, uint nSamples, std::vector< uint > &birthVertices, bool onlySelected=false, std::optional< uint > seed=std::nullopt)
Returns a PointSampler object that contains the given number of samples taken from the vertices of th...
Definition point_sampling.h:225
auto faceWeightedPointSampling(const MeshType &m, const std::vector< ScalarType > &weights, uint nSamples, std::vector< uint > &birthFaces, std::optional< uint > seed=std::nullopt)
Returns a PointSampler object that contains the given number of samples taken from the faces of the g...
Definition point_sampling.h:515
auto faceAreaWeightedPointSampling(const MeshType &m, uint nSamples, std::optional< uint > seed=std::nullopt)
Samples the faces in a weighted way, using the per face area. Each face has a probability of being ch...
Definition point_sampling.h:714
auto montecarloPoissonPointSampling(const MeshType &m, uint nSamples, std::optional< uint > seed=std::nullopt)
This function compute montecarlo distribution with an approximate number of samples exploiting the po...
Definition point_sampling.h:892
auto montecarloPointSampling(const MeshType &m, uint nSamples, std::vector< uint > &birthFaces, std::optional< uint > seed=std::nullopt)
Computes a montecarlo distribution with an exact number of samples. It works by generating a sequence...
Definition point_sampling.h:750
auto vertexAreaWeightedPointSampling(const MeshType &m, uint nSamples, std::optional< uint > seed=std::nullopt)
Samples the vertices in a weighted way, using the area. Each vertex has a probability of being chosen...
Definition point_sampling.h:669
auto faceQualityWeightedPointSampling(const MeshType &m, uint nSamples, std::optional< uint > seed=std::nullopt)
Samples the faces in a weighted way, using the per face Quality component. Each face has a probabilit...
Definition point_sampling.h:636
auto vertexQualityWeightedPointSampling(const MeshType &m, uint nSamples, std::optional< uint > seed=std::nullopt)
Samples the vertices in a weighted way, using the per vertex Quality component. Each vertex has a pro...
Definition point_sampling.h:603
auto faceUniformPointSampling(const MeshType &m, uint nSamples, std::vector< uint > &birthFaces, bool onlySelected=false, std::optional< uint > seed=std::nullopt)
Returns a PointSampler object that contains the given number of samples taken from the faces of the g...
Definition point_sampling.h:319
auto allFacesPointSampling(const MeshType &m, std::vector< uint > &birthFaces, bool onlySelected=false)
Returns a PointSampler object that contains all the faces contained in the given mesh.
Definition point_sampling.h:151
auto allVerticesPointSampling(const MeshType &m, std::vector< uint > &birthVertices, bool onlySelected=false)
Returns a PointSampler object that contains all the vertices contained in the given mesh.
Definition point_sampling.h:73
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92