Visual Computing Library
Loading...
Searching...
No Matches
misc.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_CORE_DISTANCE_MISC_H
24#define VCL_ALGORITHMS_CORE_DISTANCE_MISC_H
25
26#include <vclib/algorithms/core/bounding_box.h>
27#include <vclib/concepts/space/triangle.h>
28#include <vclib/space/core/plane.h>
29#include <vclib/space/core/segment.h>
30
31namespace vcl {
32
45template<PointConcept PointType>
46auto distance(const PointType& point0, const PointType& point1)
47{
48 return point0.dist(point1);
49}
50
68template<Point3Concept PointType, PlaneConcept PlaneType>
70 const PointType& point,
71 const PlaneType& plane,
72 bool signedDist = false)
73{
74 auto dist = plane.direction().dot(point) - plane.offset();
75 if (!signedDist)
76 dist = std::abs(dist);
77 return dist;
78}
79
85template<PlaneConcept PlaneType, Point3Concept PointType>
87 const PlaneType& plane,
88 const PointType& point,
89 bool signedDist = false)
90{
91 return distance(point, plane, signedDist);
92}
93
111template<PointConcept PointType, SegmentConcept SegmentType>
113 const PointType& point,
114 const SegmentType& segment,
115 PointType& closestPoint) requires (PointType::DIM == SegmentType::DIM)
116{
117 using ScalarType = PointType::ScalarType;
118
119 ScalarType dist;
120
121 PointType dir = segment.direction();
122 ScalarType esn = dir.squaredNorm();
123
124 if (esn < std::numeric_limits<ScalarType>::min()) {
125 closestPoint = segment.midPoint();
126 }
127 else {
128 ScalarType t = ((point - segment.p0()).dot(dir)) / esn;
129 if (t < 0)
130 t = 0;
131 else if (t > 1)
132 t = 1;
133
134 closestPoint = segment.p0() * (1 - t) + segment.p1() * t;
135 }
136 dist = point.dist(closestPoint);
137 return dist;
138}
139
154template<PointConcept PointType, SegmentConcept SegmentType>
155auto distance(const PointType& point, const SegmentType& segment)
156 requires (PointType::DIM == SegmentType::DIM)
157{
158 PointType closestPoint;
159 return distance(point, segment, closestPoint);
160}
161
167template<SegmentConcept SegmentType, PointConcept PointType>
168auto distance(const SegmentType& segment, const PointType& point)
169 requires (PointType::DIM == SegmentType::DIM)
170{
171 return distance(point, segment);
172}
173
200template<
201 Point3Concept PointType,
202 Triangle3Concept TriangleType,
203 typename ScalarType>
205 const PointType& p,
206 const TriangleType& triangle,
207 ScalarType maxDist,
208 PointType& closest,
209 bool signedDist = false)
210{
211 using TPointType = TriangleType::PointType;
212
213 ScalarType dist;
214
215 // Extract the coordinates of the vertices of the face.
216 const TPointType& tp0 = triangle.point(0);
217 const TPointType& tp1 = triangle.point(1);
218 const TPointType& tp2 = triangle.point(2);
219
220 // If the face is degenerate (i.e. its normal vector has zero length),
221 // consider it as a segment.
222 if (triangle.normal().norm() == 0) {
223 // Calculate the bounding box of the face.
225 Segment3<ScalarType> s(box.min(), box.max());
226 // If the diagonal of the bounding box is greater than zero, calculate
227 // the distance between the query point and the segment.
228 if (box.diagonal() > 0) {
229 dist = distance(p, s, closest);
230 }
231 else {
232 // If the diagonal of the bounding box is zero, set the closest
233 // point to be the minimum corner of the bounding box and calculate
234 // the distance between the query point and this point.
235 closest = box.min();
236 dist = p.dist(closest);
237 }
238 }
239 else {
240 // Calculate the distance between the query point and the plane of the
241 // triangle.
243 dist = distance(p, fPlane, true);
244
245 if (std::abs(dist) >= maxDist)
246 return std::abs(dist);
247
248 // Project the query point onto the triangle plane to obtain the closest
249 // point on the triangle.
250 closest = p - fPlane.direction() * dist;
251
252 // Calculate the three edges of the triangle.
254 fEdge[0] = tp1 - tp0;
255 fEdge[1] = tp2 - tp1;
256 fEdge[2] = tp0 - tp2;
257
258 // Determine the best axis to use for projection by finding the axis
259 // with the largest component of the normal vector.
260 int bestAxis;
261 if (std::abs(triangle.normal()[0]) > std::abs(triangle.normal()[1])) {
262 if (std::abs(triangle.normal()[0]) > std::abs(triangle.normal()[2]))
263 bestAxis = 0;
264 else
265 bestAxis = 2;
266 }
267 else {
268 if (std::abs(triangle.normal()[1]) > std::abs(triangle.normal()[2]))
269 bestAxis = 1; /* 1 > 0 ? 2 */
270 else
271 bestAxis = 2; /* 2 > 1 ? 2 */
272 }
273
274 // Scale the edges by the inverse of the projection direction on the
275 // best axis.
276 ScalarType scaleFactor = 1 / fPlane.direction()[bestAxis];
277 fEdge[0] *= scaleFactor;
278 fEdge[1] *= scaleFactor;
279 fEdge[2] *= scaleFactor;
280
281 // Compute barycentric coordinates of closest point
282 ScalarType b0, b1, b2;
283 int ba = (bestAxis + 2) % 3;
284 int bb = (bestAxis + 1) % 3;
285
287 b0 = fEdge[1][bb] * (closest[ba] - tp1[ba]) -
288 fEdge[1][ba] * (closest[bb] - tp1[bb]);
289 if (b0 <= 0) {
290 return distance(p, s0, closest);
291 }
292 b1 = fEdge[2][bb] * (closest[ba] - tp2[ba]) -
293 fEdge[2][ba] * (closest[bb] - tp2[bb]);
294 if (b1 <= 0) {
295 return distance(p, s1, closest);
296 }
297 b2 = fEdge[0][bb] * (closest[ba] - tp0[ba]) -
298 fEdge[0][ba] * (closest[bb] - tp0[bb]);
299 if (b2 <= 0) {
300 return distance(p, s2, closest);
301 }
302
303 const ScalarType EPS = ScalarType(0.000001);
304 ScalarType b = min(b0, b1, b2);
305 if (b < EPS * triangle.area()) {
306 ScalarType bt;
307 if (b == b0)
308 bt = distance(p, s0, closest);
309 else if (b == b1)
310 bt = distance(p, s1, closest);
311 else {
312 assert(b == b2);
313 bt = distance(p, s2, closest);
314 }
315 dist = bt;
316 }
317
318 if (!signedDist)
319 dist = std::abs(dist);
320 }
321
322 return dist;
323}
324
342template<
343 Point3Concept PointType,
344 Triangle3Concept TriangleType,
345 typename ScalarType>
347 const PointType& p,
348 const TriangleType& triangle,
349 ScalarType maxDist,
350 bool signedDist = false)
351{
352 PointType closest;
353 return boundedDistance(p, triangle, maxDist, closest, signedDist);
354}
355
371template<
372 Point3Concept PointType,
373 Triangle3Concept TriangleType,
374 typename ScalarType>
376 const PointType& p,
377 const TriangleType& triangle,
378 PointType& closest,
379 bool signedDist = false)
380{
381 ScalarType maxDist = std::numeric_limits<ScalarType>::max();
382 return boundedDistance(p, triangle, maxDist, closest, signedDist);
383}
384
399template<
400 Point3Concept PointType,
401 Triangle3Concept TriangleType,
402 typename ScalarType>
404 const PointType& p,
405 const TriangleType& triangle,
406 bool signedDist = false)
407{
408 PointType closest;
409
410 ScalarType maxDist = std::numeric_limits<ScalarType>::max();
411 return boundedDistance(p, triangle, maxDist, closest, signedDist);
412}
413
419template<
420 Triangle3Concept TriangleType,
421 Point3Concept PointType,
422 typename ScalarType>
424 const TriangleType& triangle,
425 const PointType& p,
426 bool signedDist = false)
427{
428 return distance(p, triangle, signedDist);
429}
430
431} // namespace vcl
432
433#endif // VCL_ALGORITHMS_CORE_DISTANCE_MISC_H
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
PointT & p0()
Returns the first endpoint of the segment.
Definition segment.h:83
PointT & p1()
Returns the second endpoint of the segment.
Definition segment.h:97
auto boundingBox(const PointType &p)
Compute the bounding box of a single point.
Definition bounding_box.h:65
auto boundedDistance(const PointType &p, const FaceType &f, ScalarType maxDist, PointType &closest, bool signedDist=false)
Compute the distance between a 3D point and a face.
Definition element.h:110
auto distance(const VertexType &v, const PointType &p)
Computes the distance between a Vertex and a 3D point.
Definition element.h:50
constexpr auto min(const T &p1, const T &p2)
Returns the minimum between the two parameters.
Definition min_max.h:42