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