Antkeeper  0.0.1
closest-point.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef ANTKEEPER_GEOM_CLOSEST_POINT_HPP
21 #define ANTKEEPER_GEOM_CLOSEST_POINT_HPP
22 
32 #include <algorithm>
33 #include <cmath>
34 #include <tuple>
35 
36 namespace geom {
37 
49 template <class T, std::size_t N>
50 [[nodiscard]] constexpr point<T, N> closest_point(const ray<T, N>& a, const point<T, N>& b) noexcept
51 {
52  return a.extrapolate(std::max<T>(T{0}, math::dot(b - a.origin, a.direction)));
53 }
54 
66 template <class T, std::size_t N>
67 [[nodiscard]] constexpr point<T, N> closest_point(const line_segment<T, N>& ab, const point<T, N>& c) noexcept
68 {
69  const auto direction_ab = ab.b - ab.a;
70 
71  const auto distance_ab = math::dot(c - ab.a, direction_ab);
72  if (distance_ab <= T{0})
73  {
74  return ab.a;
75  }
76  else
77  {
78  const auto sqr_length_ab = math::sqr_length(direction_ab);
79  if (distance_ab >= sqr_length_ab)
80  {
81  return ab.b;
82  }
83  else
84  {
85  return ab.a + direction_ab * (distance_ab / sqr_length_ab);
86  }
87  }
88 }
89 
103 template <class T, std::size_t N>
104 [[nodiscard]] constexpr std::tuple<point<T, N>, point<T, N>> closest_point(const line_segment<T, N>& ab, const line_segment<T, N>& cd) noexcept
105 {
106  const auto direction_ab = ab.b - ab.a;
107  const auto direction_cd = cd.b - cd.a;
108  const auto direction_ca = ab.a - cd.a;
109 
110  const auto sqr_length_ab = math::sqr_length(direction_ab);
111  const auto sqr_length_cd = math::sqr_length(direction_cd);
112  const auto cd_dot_ca = math::dot(direction_cd, direction_ca);
113 
114  if (sqr_length_ab <= T{0})
115  {
116  if (sqr_length_cd <= T{0})
117  {
118  // Both segments are points
119  return {ab.a, cd.a};
120  }
121  else
122  {
123  // Segment ab is a point
124  return
125  {
126  ab.a,
127  cd.a + direction_cd * std::min<T>(std::max<T>(cd_dot_ca / sqr_length_cd, T{0}), T{1})
128  };
129  }
130  }
131  else
132  {
133  const auto ab_dot_ca = math::dot(direction_ab, direction_ca);
134 
135  if (sqr_length_cd <= T{0})
136  {
137  // Segment cd is a point
138  return
139  {
140  ab.a + direction_ab * std::min<T>(std::max<T>(-ab_dot_ca / sqr_length_ab, T{0}), T{1}),
141  cd.a
142  };
143  }
144  else
145  {
146  const auto ab_dot_cd = math::dot(direction_ab, direction_cd);
147 
148  const auto den = sqr_length_ab * sqr_length_cd - ab_dot_cd * ab_dot_cd;
149 
150  auto distance_ab = (den) ? std::min<T>(std::max<T>((ab_dot_cd * cd_dot_ca - ab_dot_ca * sqr_length_cd) / den, T{0}), T{1}) : T{0};
151  auto distance_cd = (ab_dot_cd * distance_ab + cd_dot_ca) / sqr_length_cd;
152 
153  if (distance_cd < T{0})
154  {
155  return
156  {
157  ab.a + direction_ab * std::min<T>(std::max<T>(-ab_dot_ca / sqr_length_ab, T{0}), T{1}),
158  cd.a
159  };
160  }
161  else if (distance_cd > T{1})
162  {
163  return
164  {
165  ab.a + direction_ab * std::min<T>(std::max<T>((ab_dot_cd - ab_dot_ca) / sqr_length_ab, T{0}), T{1}),
166  cd.b
167  };
168  }
169 
170  return
171  {
172  ab.a + direction_ab * distance_ab,
173  cd.a + direction_cd * distance_cd
174  };
175  }
176  }
177 }
178 
190 template <class T, std::size_t N>
191 [[nodiscard]] constexpr point<T, N> closest_point(const hyperplane<T, N>& a, const point<T, N>& b) noexcept
192 {
193  return b - a.normal * (math::dot(a.normal, b) + a.constant);
194 }
195 
212 template <class T>
213 [[nodiscard]] constexpr std::tuple<point<T, 3>, triangle_region> closest_point(const point<T, 3>& a, const point<T, 3>& b, const point<T, 3>& c, const point<T, 3>& p) noexcept
214 {
215  const auto ab = b - a;
216  const auto ac = c - a;
217  const auto ap = p - a;
218  const auto ap_dot_ab = math::dot(ap, ab);
219  const auto ap_dot_ac = math::dot(ap, ac);
220  if (ap_dot_ab <= T{0} && ap_dot_ac <= T{0})
221  {
222  return {a, triangle_region::a};
223  }
224 
225  const auto bc = c - b;
226  const auto bp = p - b;
227  const auto bp_dot_ba = math::dot(bp, a - b);
228  const auto bp_dot_bc = math::dot(bp, bc);
229  if (bp_dot_ba <= T{0} && bp_dot_bc <= T{0})
230  {
231  return {b, triangle_region::b};
232  }
233 
234  const auto cp = p - c;
235  const auto cp_dot_ca = math::dot(cp, a - c);
236  const auto cp_dot_cb = math::dot(cp, b - c);
237  if (cp_dot_ca <= T{0} && cp_dot_cb <= T{0})
238  {
239  return {c, triangle_region::c};
240  }
241 
242  const auto n = math::cross(ab, ac);
243  const auto pa = a - p;
244  const auto pb = b - p;
245  const auto vc = math::dot(n, math::cross(pa, pb));
246  if (vc <= T{0} && ap_dot_ab >= T{0} && bp_dot_ba >= T{0})
247  {
248  return {a + ap_dot_ab / (ap_dot_ab + bp_dot_ba) * ab, triangle_region::ab};
249  }
250 
251  const auto pc = c - p;
252  const auto va = math::dot(n, math::cross(pb, pc));
253  if (va <= T{0} && bp_dot_bc >= T{0} && cp_dot_cb >= T{0})
254  {
255  return {b + bp_dot_bc / (bp_dot_bc + cp_dot_cb) * bc, triangle_region::bc};
256  }
257 
258  const auto vb = math::dot(n, math::cross(pc, pa));
259  if (vb <= T{0} && ap_dot_ac >= T{0} && cp_dot_ca >= T{0})
260  {
261  return {a + ap_dot_ac / (ap_dot_ac + cp_dot_ca) * ac, triangle_region::ca};
262  }
263 
264  const auto u = va / (va + vb + vc);
265  const auto v = vb / (va + vb + vc);
266  const auto w = T{1} - u - v;
267 
268  return {a * u + b * v + c * w, triangle_region::abc};
269 }
270 
271 template <class T>
272 [[nodiscard]] inline constexpr std::tuple<point<T, 3>, triangle_region> closest_point(const triangle<T, 3>& tri, const point<T, 3>& p) noexcept
273 {
274  return closest_point(tri.a, tri.b, tri.c, p);
275 }
277 
289 template <class T, std::size_t N>
290 [[nodiscard]] point<T, N> closest_point(const hypersphere<T, N>& a, const point<T, N>& b)
291 {
292  const auto ab = b - a.center;
293  const auto d = math::sqr_length(ab);
294  return d > a.radius * a.radius ? a.center + ab * (a.radius / std::sqrt(d)) : b;
295 }
296 
308 template <class T, std::size_t N>
309 [[nodiscard]] point<T, N> closest_point(const hypercapsule<T, N>& a, const point<T, N>& b)
310 {
311  const auto c = closest_point(a.segment, b);
312  const auto cb = b - c;
313  const auto d = math::sqr_length(cb);
314  return d > a.radius * a.radius ? c + cb * (a.radius / std::sqrt(d)) : b;
315 }
316 
328 template <class T, std::size_t N>
329 [[nodiscard]] constexpr point<T, N> closest_point(const hyperrectangle<T, N>& a, const point<T, N>& b) noexcept
330 {
331  return math::min(math::max(b, a.min), a.max);
332 }
333 
334 } // namespace geom
335 
336 #endif // ANTKEEPER_GEOM_CLOSEST_POINT_HPP
Geometric algorithms.
triangle_region
Voronoi regions of a triangle.
Definition: coordinates.hpp:34
@ a
Vertex A region.
@ ab
Edge AB region.
@ c
Vertex C region.
@ bc
Edge BC region.
@ ca
Edge CA region.
@ abc
Face ABC region.
@ b
Vertex B region.
constexpr point< T, N > closest_point(const ray< T, N > &a, const point< T, N > &b) noexcept
Calculates the closest point on a ray to a point.
constexpr vector< T, N > max(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the maximum elements of two vectors.
Definition: vector.hpp:1328
constexpr T sqr_length(const quaternion< T > &q) noexcept
Calculates the square length of a quaternion.
Definition: quaternion.hpp:744
constexpr vector< T, 3 > cross(const vector< T, 3 > &x, const vector< T, 3 > &y) noexcept
Calculates the cross product of two vectors.
Definition: vector.hpp:1095
vector< T, N > sqrt(const vector< T, N > &x)
Takes the square root of each element.
constexpr T dot(const quaternion< T > &a, const quaternion< T > &b) noexcept
Calculates the dot product of two quaternions.
Definition: quaternion.hpp:572
constexpr vector< T, N > min(const vector< T, N > &x, const vector< T, N > &y)
Returns a vector containing the minimum elements of two vectors.
Definition: vector.hpp:1347
n-dimensional capsule.
n-dimensional plane.
Definition: hyperplane.hpp:36
n-dimensional axis-aligned rectangle.
n-dimensional sphere.
Definition: hypersphere.hpp:37
n-dimensional line segment.
Half of a line proceeding from an initial point.
Definition: ray.hpp:38
n-dimensional triangle.
Definition: triangle.hpp:36
n-dimensional vector.
Definition: vector.hpp:44