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 SamplerConcept 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 SamplerConcept 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 SamplerConcept 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 SamplerConcept 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<SamplerType>(
214 m2, nSamples, birth, false, seed);
215 }
216 else if constexpr (METHOD == HAUSDORFF_EDGE_UNIFORM) {
217 // todo
218 }
219 else {
220 sampler = montecarloPointSampling<SamplerType>(
221 m2, nSamples, birth, seed);
222 }
223
224 log.log(5, meshName2 + " sampled.");
225 log.startNewTask(
226 5, 100, "Computing distance between samples and " + meshName1 + "...");
227
228 auto res = samplerMeshHausdorff(m1, sampler, log);
229
230 log.endTask("Distance between samples and " + meshName1 + " computed.");
231
232 return res;
233}
234
235} // namespace detail
236
237template<
238 MeshConcept MeshType1,
239 MeshConcept MeshType2,
240 LoggerConcept LogType = NullLogger>
241HausdorffDistResult hausdorffDistance(
242 const MeshType1& m1,
243 const MeshType2& m2,
244 LogType& log = nullLogger,
245 HausdorffSamplingMethod sampMethod = HAUSDORFF_VERTEX_UNIFORM,
246 uint nSamples = 0,
247 std::optional<uint> seed = std::nullopt)
248{
249 if (nSamples == 0)
250 nSamples = m2.vertexNumber();
251
252 std::vector<uint> birth;
253
254 switch (sampMethod) {
255 case HAUSDORFF_VERTEX_UNIFORM: {
256 ConstVertexSampler<typename MeshType2::VertexType> sampler;
257
258 return detail::hausdorffDistance<HAUSDORFF_VERTEX_UNIFORM>(
259 m1, m2, nSamples, seed, sampler, birth, log);
260 }
261
262 case HAUSDORFF_EDGE_UNIFORM: {
263 // todo
264 return HausdorffDistResult();
265 }
266 case HAUSDORFF_MONTECARLO: {
267 PointSampler<typename MeshType2::VertexType::PositionType> sampler;
268
269 return detail::hausdorffDistance<HAUSDORFF_MONTECARLO>(
270 m1, m2, nSamples, seed, sampler, birth, log);
271 }
272 default: assert(0); return HausdorffDistResult();
273 }
274}
275
276} // namespace vcl
277
278#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
constexpr detail::AddressOfView addrOf
The addrOf view applies the address-of operator & on the input view.
Definition pointers.h:120
Definition distance.h:34