NavMap
Loading...
Searching...
No Matches
Geometry.hpp
Go to the documentation of this file.
1// Copyright 2025 Intelligent Robotics Lab
2//
3// This file is part of the project Easy Navigation (EasyNav in short)
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
28
29#ifndef NAVMAP_CORE__GEOMETRY_HPP_
30#define NAVMAP_CORE__GEOMETRY_HPP_
31
32#include <Eigen/Core>
33#include <Eigen/Geometry>
34#include <limits>
35#include <cmath>
36#include <algorithm>
37#include <utility>
38
39namespace navmap
40{
41
45using Vec3 = Eigen::Vector3f;
46
47// -----------------------------------------------------------------------------
48// Basic triangle geometry
49// -----------------------------------------------------------------------------
50
61inline float triangle_area(const Vec3 & a, const Vec3 & b, const Vec3 & c)
62{
63 return 0.5f * ((b - a).cross(c - a)).norm();
64}
65
77inline Vec3 triangle_normal(const Vec3 & a, const Vec3 & b, const Vec3 & c)
78{
79 Vec3 n = (b - a).cross(c - a);
80 float len = n.norm();
81 return len > 1e-12f ? n / len : Vec3(0.0f, 0.0f, 1.0f);
82}
83
106 const Vec3 & orig,
107 const Vec3 & dir,
108 const Vec3 & v0,
109 const Vec3 & v1,
110 const Vec3 & v2,
111 float & t,
112 float & u,
113 float & v)
114{
115 const float kEps = 1e-8f;
116 // Barycentric slack, relative: a ray through a shared edge hits both NavCels, never neither
117 const float kBary = 1e-5f;
118 Vec3 e1 = v1 - v0;
119 Vec3 e2 = v2 - v0;
120 Vec3 pvec = dir.cross(e2);
121 float det = e1.dot(pvec);
122 if (std::fabs(det) < kEps) {
123 return false;
124 }
125 float inv_det = 1.0f / det;
126 Vec3 tvec = orig - v0;
127 u = tvec.dot(pvec) * inv_det;
128 if (u < -kBary || u > 1.0f + kBary) {
129 return false;
130 }
131 Vec3 qvec = tvec.cross(e1);
132 v = dir.dot(qvec) * inv_det;
133 if (v < -kBary || (u + v) > 1.0f + kBary) {
134 return false;
135 }
136 t = e2.dot(qvec) * inv_det;
137 return t > kEps;
138}
139
140// -----------------------------------------------------------------------------
141// Axis-aligned bounding box (AABB)
142// -----------------------------------------------------------------------------
143
147inline float point_segment_distance(const Vec3 & p, const Vec3 & a, const Vec3 & b)
148{
149 const Vec3 ab = b - a;
150 const float len2 = ab.squaredNorm();
151 const float t = len2 > 0.0f ? std::clamp((p - a).dot(ab) / len2, 0.0f, 1.0f) : 0.0f;
152 return (p - (a + t * ab)).norm();
153}
154
164struct AABB
165{
169 Vec3 min{std::numeric_limits<float>::infinity(),
170 std::numeric_limits<float>::infinity(),
171 std::numeric_limits<float>::infinity()};
172
175 Vec3 max{-std::numeric_limits<float>::infinity(),
176 -std::numeric_limits<float>::infinity(),
177 -std::numeric_limits<float>::infinity()};
178
183 inline void expand(const Vec3 & p)
184 {
185 min = min.cwiseMin(p);
186 max = max.cwiseMax(p);
187 }
188
193 inline void expand(const AABB & b)
194 {
195 min = min.cwiseMin(b.min);
196 max = max.cwiseMax(b.max);
197 }
198
203 inline int longest_axis() const
204 {
205 Vec3 d = max - min;
206 if (d.x() >= d.y() && d.x() >= d.z()) {return 0;}
207 if (d.y() >= d.x() && d.y() >= d.z()) {return 1;}
208 return 2;
209 }
210
222 inline bool intersects_ray(
223 const Vec3 & o,
224 const Vec3 & d,
225 float tmax = 1e30f) const
226 {
227 const float kEps = 1e-12f;
228 float tmin_local = 0.0f;
229
230 for (int i = 0; i < 3; ++i) {
231 const float di = d[i];
232 const float oi = o[i];
233 const float min_i = min[i];
234 const float max_i = max[i];
235
236 if (std::fabs(di) < kEps) {
237 // Parallel to this slab: must be inside [min_i, max_i]
238 if (oi < min_i || oi > max_i) {return false;}
239 continue;
240 }
241
242 float inv = 1.0f / di;
243 float t0 = (min_i - oi) * inv;
244 float t1 = (max_i - oi) * inv;
245 if (t0 > t1) {std::swap(t0, t1);}
246
247 if (t0 > tmin_local) {tmin_local = t0;}
248 if (t1 < tmax) {tmax = t1;}
249
250 if (tmax < tmin_local) {return false;}
251 }
252 return tmax >= tmin_local && tmax > 0.0f;
253 }
254
265 inline bool contains_xy(const Vec3 & p, float z_eps) const
266 {
267 return p.x() >= min.x() && p.x() <= max.x() &&
268 p.y() >= min.y() && p.y() <= max.y() &&
269 p.z() >= min.z() - z_eps && p.z() <= max.z() + z_eps;
270 }
271
278 inline bool contains_xy_only(const Vec3 & p) const
279 {
280 return p.x() >= min.x() && p.x() <= max.x() &&
281 p.y() >= min.y() && p.y() <= max.y();
282 }
283};
284
285// -----------------------------------------------------------------------------
286// Closest point on triangle and point-triangle distance
287// -----------------------------------------------------------------------------
288
302 const Vec3 & p,
303 const Vec3 & a,
304 const Vec3 & b,
305 const Vec3 & c)
306{
307 const Vec3 ab = b - a;
308 const Vec3 ac = c - a;
309 const Vec3 ap = p - a;
310
311 float d1 = ab.dot(ap);
312 float d2 = ac.dot(ap);
313 if (d1 <= 0.0f && d2 <= 0.0f) {
314 return a;
315 }
316
317 const Vec3 bp = p - b;
318 float d3 = ab.dot(bp);
319 float d4 = ac.dot(bp);
320 if (d3 >= 0.0f && d4 <= d3) {
321 return b;
322 }
323
324 float vc = d1 * d4 - d3 * d2;
325 if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
326 float v = d1 / (d1 - d3);
327 return a + v * ab;
328 }
329
330 const Vec3 cp = p - c;
331 float d5 = ab.dot(cp);
332 float d6 = ac.dot(cp);
333 if (d6 >= 0.0f && d5 <= d6) {
334 return c;
335 }
336
337 float vb = d5 * d2 - d1 * d6;
338 if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
339 float w = d2 / (d2 - d6);
340 return a + w * ac;
341 }
342
343 float va = d3 * d6 - d5 * d4;
344 if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
345 float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
346 return b + w * (c - b);
347 }
348
349 float ab2 = ab.dot(ab);
350 float ac2 = ac.dot(ac);
351 float abac = ab.dot(ac);
352 float denom = (ab2 * ac2 - abac * abac);
353 if (std::fabs(denom) < 1e-20f) {
354 float da = (p - a).squaredNorm();
355 float db = (p - b).squaredNorm();
356 float dc = (p - c).squaredNorm();
357 if (da <= db && da <= dc) {return a;}
358 if (db <= dc) {return b;}
359 return c;
360 }
361 float v = (ac2 * d1 - abac * d2) / denom;
362 float w = (ab2 * d2 - abac * d1) / denom;
363 return a + v * ab + w * ac;
364}
365
380 const Vec3 & p,
381 const Vec3 & a,
382 const Vec3 & b,
383 const Vec3 & c,
384 Vec3 * closest = nullptr)
385{
386 Vec3 q = closest_point_on_triangle(p, a, b, c);
387 if (closest) {*closest = q;}
388 return (q - p).squaredNorm();
389}
390
391} // namespace navmap
392
393#endif // NAVMAP_CORE__GEOMETRY_HPP_
Definition Combine.hpp:39
float point_triangle_squared_distance(const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &c, Vec3 *closest=nullptr)
Squared distance between point and triangle, with optional closest pt.
Definition Geometry.hpp:379
Eigen::Vector3f Vec3
3D vector alias used across NavMap geometry.
Definition Geometry.hpp:45
float triangle_area(const Vec3 &a, const Vec3 &b, const Vec3 &c)
Compute the area of a triangle ABC.
Definition Geometry.hpp:61
Vec3 triangle_normal(const Vec3 &a, const Vec3 &b, const Vec3 &c)
Compute a unit normal of triangle ABC.
Definition Geometry.hpp:77
bool ray_triangle_intersect(const Vec3 &orig, const Vec3 &dir, const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, float &t, float &u, float &v)
Möller–Trumbore ray–triangle intersection.
Definition Geometry.hpp:105
Vec3 closest_point_on_triangle(const Vec3 &p, const Vec3 &a, const Vec3 &b, const Vec3 &c)
Compute the closest point on triangle ABC to point P.
Definition Geometry.hpp:301
float point_segment_distance(const Vec3 &p, const Vec3 &a, const Vec3 &b)
Distance from point p to segment [a, b] (a point if a == b).
Definition Geometry.hpp:147
Axis-aligned bounding box.
Definition Geometry.hpp:165
Vec3 max
Maximum corner (x_max, y_max, z_max).
Definition Geometry.hpp:175
bool contains_xy(const Vec3 &p, float z_eps) const
2D containment test on XY with tolerance in Z.
Definition Geometry.hpp:265
Vec3 min
Minimum corner (x_min, y_min, z_min).
Definition Geometry.hpp:169
bool contains_xy_only(const Vec3 &p) const
2D containment test on XY only (no Z check).
Definition Geometry.hpp:278
int longest_axis() const
Return the index of the longest axis (0=x, 1=y, 2=z).
Definition Geometry.hpp:203
void expand(const AABB &b)
Expand the box to include another box b (component-wise union).
Definition Geometry.hpp:193
bool intersects_ray(const Vec3 &o, const Vec3 &d, float tmax=1e30f) const
Robust ray-box intersection (slabs method).
Definition Geometry.hpp:222
void expand(const Vec3 &p)
Expand the box to include a point p.
Definition Geometry.hpp:183