Visual Computing Library  devel
Loading...
Searching...
No Matches
distance.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_DISTANCE_H
24#define VCL_ALGORITHMS_MESH_DISTANCE_H
25
26#include <vclib/algorithms/mesh/point_sampling.h>
27
28#include <vclib/mesh.h>
29#include <vclib/space/complex.h>
30
31namespace vcl {
32
34{
35 double minDist = std::numeric_limits<double>::max();
36 double maxDist = std::numeric_limits<double>::lowest();
37 double meanDist = 0;
38 double RMSDist = 0;
39 Histogram<double> histogram;
40};
41
42enum HausdorffSamplingMethod {
43 HAUSDORFF_VERTEX_UNIFORM = 0,
44 HAUSDORFF_EDGE_UNIFORM,
45 HAUSDORFF_MONTECARLO
46};
47
48namespace detail {
49
50template<
51 MeshConcept MeshType,
52 PointSamplerConcept SamplerType,
53 typename GridType,
54 LoggerConcept LogType>
55HausdorffDistResult hausdorffDist(
56 const MeshType& m,
57 const SamplerType& s,
58 const GridType& g,
59 LogType& log)
60{
61 using PointSampleType = SamplerType::PointType;
62 using ScalarType = PointSampleType::ScalarType;
63
64 HausdorffDistResult res;
65 res.histogram = Histogramd(0, m.boundingBox().diagonal() / 100, 100);
66
67 log.log(
68 5,
69 "Computing distances for " + std::to_string(s.size()) + " samples...");
70
71 log.startProgress("", s.size());
72
73 std::mutex mutex;
74
75 uint ns = 0;
76 uint i = 0;
77 parallelFor(s, [&](const PointSampleType& sample) {
78 // for (const PointSampleType& sample : s) {
79 ScalarType dist = std::numeric_limits<ScalarType>::max();
80 const auto iter = g.closestValue(sample, dist);
81
82 if (iter != g.end()) {
83 mutex.lock();
84 ns++;
85 if (dist > res.maxDist)
86 res.maxDist = dist;
87 if (dist < res.minDist)
88 res.minDist = dist;
89 res.meanDist += dist;
90 res.RMSDist += dist * dist;
91 res.histogram.addValue(dist);
92 mutex.unlock();
93 }
94
95 log.progress(++i);
96 // }
97 });
98
99 log.endProgress();
100 log.log(100, "Computed " + std::to_string(ns) + " distances.");
101 if (ns != s.size()) {
102 log.log(
103 100,
104 std::to_string(s.size() - ns) +
105 " samples were not counted because no closest vertex/face "
106 "was found.",
107 LogType::WARNING_LOG);
108 }
109
110 res.meanDist /= ns;
111 res.RMSDist = std::sqrt(res.RMSDist / ns);
112
113 return res;
114}
115
116template<
117 MeshConcept MeshType,
118 PointSamplerConcept SamplerType,
119 LoggerConcept LogType>
120HausdorffDistResult samplerMeshHausdorff(
121 const MeshType& m,
122 const SamplerType& s,
123 LogType& log) requires (!HasFaces<MeshType>)
124{
125 using VertexType = MeshType::VertexType;
126
127 std::string meshName = "first mesh";
128 if constexpr (HasName<MeshType>) {
129 meshName = m.name();
130 }
131
132 log.log(0, "Building Grid on " + meshName + " vertices...");
133
134 StaticGrid3<const VertexType*> grid(m.vertices() | views::addrOf);
135 grid.build();
136
137 log.log(5, "Grid built.");
138
139 return hausdorffDist(m, s, grid, log);
140}
141
142template<
143 FaceMeshConcept MeshType,
144 PointSamplerConcept SamplerType,
145 LoggerConcept LogType>
146HausdorffDistResult samplerMeshHausdorff(
147 const MeshType& m,
148 const SamplerType& s,
149 LogType& log)
150{
151 using VertexType = MeshType::VertexType;
152 using FaceType = MeshType::FaceType;
153 using ScalarType = VertexType::PositionType::ScalarType;
154
155 std::string meshName = "first mesh";
156 if constexpr (HasName<MeshType>) {
157 meshName = m.name();
158 }
159 if (m.faceNumber() == 0) {
160 log.log(0, "Building Grid on " + meshName + " vertices...");
161
162 StaticGrid3<const VertexType*, ScalarType> grid(
163 m.vertices() | views::addrOf);
164 grid.build();
165
166 log.log(5, "Grid built.");
167
168 return hausdorffDist(m, s, grid, log);
169 }
170 else {
171 log.log(0, "Building Grid on " + meshName + " faces...");
172
173 StaticGrid3<const FaceType*, ScalarType> grid(
174 m.faces() | views::addrOf);
175 grid.build();
176
177 log.log(5, "Grid built.");
178
179 return hausdorffDist(m, s, grid, log);
180 }
181}
182
183template<
184 uint METHOD,
185 MeshConcept MeshType1,
186 MeshConcept MeshType2,
187 PointSamplerConcept SamplerType,
188 LoggerConcept LogType>
189HausdorffDistResult hausdorffDistance(
190 const MeshType1& m1,
191 const MeshType2& m2,
192 uint nSamples,
193 std::optional<uint> seed,
194 SamplerType& sampler,
195 std::vector<uint>& birth,
196 LogType& log)
197{
198 std::string meshName1 = "first mesh";
199 std::string meshName2 = "second mesh";
200 if constexpr (HasName<MeshType1>) {
201 meshName1 = m1.name();
202 }
203 if constexpr (HasName<MeshType2>) {
204 meshName2 = m2.name();
205 }
206
207 log.log(
208 0,
209 "Sampling " + meshName2 + " with " + std::to_string(nSamples) +
210 " samples...");
211
212 if constexpr (METHOD == HAUSDORFF_VERTEX_UNIFORM) {
213 sampler = vertexUniformPointSampling(m2, nSamples, birth, false, seed);
214 }
215 else if constexpr (METHOD == HAUSDORFF_EDGE_UNIFORM) {
216 // todo
217 }
218 else {
219 sampler = montecarloPointSampling(m2, nSamples, birth, seed);
220 }
221
222 log.log(5, meshName2 + " sampled.");
223 log.startNewTask(
224 5, 100, "Computing distance between samples and " + meshName1 + "...");
225
226 auto res = samplerMeshHausdorff(m1, sampler, log);
227
228 log.endTask("Distance between samples and " + meshName1 + " computed.");
229
230 return res;
231}
232
233} // namespace detail
234
235template<
236 MeshConcept MeshType1,
237 MeshConcept MeshType2,
238 LoggerConcept LogType = NullLogger>
239HausdorffDistResult hausdorffDistance(
240 const MeshType1& m1,
241 const MeshType2& m2,
242 LogType& log = nullLogger,
243 HausdorffSamplingMethod sampMethod = HAUSDORFF_VERTEX_UNIFORM,
244 uint nSamples = 0,
245 std::optional<uint> seed = std::nullopt)
246{
247 if (nSamples == 0)
248 nSamples = m2.vertexNumber();
249
250 std::vector<uint> birth;
251
252 switch (sampMethod) {
253 case HAUSDORFF_VERTEX_UNIFORM: {
254 PointSampler<typename MeshType2::VertexType::PositionType> sampler;
255
256 return detail::hausdorffDistance<HAUSDORFF_VERTEX_UNIFORM>(
257 m1, m2, nSamples, seed, sampler, birth, log);
258 }
259
260 case HAUSDORFF_EDGE_UNIFORM: {
261 // todo
262 return HausdorffDistResult();
263 }
264 case HAUSDORFF_MONTECARLO: {
265 if constexpr (FaceMeshConcept<MeshType2>) {
266 PointSampler<typename MeshType2::VertexType::PositionType> sampler;
267
268 return detail::hausdorffDistance<HAUSDORFF_MONTECARLO>(
269 m1, m2, nSamples, seed, sampler, birth, log);
270 }
271 else {
272 throw std::runtime_error(
273 "Monte Carlo sampling requires a FaceMeshConcept for the "
274 "second mesh.");
275 }
276 }
277 default: assert(0); return HausdorffDistResult();
278 }
279}
280
281} // namespace vcl
282
283#endif // VCL_ALGORITHMS_MESH_DISTANCE_H
A class representing a box in N-dimensional space.
Definition box.h:46
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:123
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 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
constexpr detail::AddressOfView addrOf
The addrOf view applies the address-of operator & on the input view.
Definition pointers.h:120
Definition distance.h:34