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 <array>
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 Vec3 e1 = v1 - v0;
117 Vec3 e2 = v2 - v0;
118 Vec3 pvec = dir.cross(e2);
119 float det = e1.dot(pvec);
120 if (std::fabs(det) < kEps) {
121 return false;
122 }
123 float inv_det = 1.0f / det;
124 Vec3 tvec = orig - v0;
125 u = tvec.dot(pvec) * inv_det;
126 if (u < -kEps || u > 1.0f + kEps) {
127 return false;
128 }
129 Vec3 qvec = tvec.cross(e1);
130 v = dir.dot(qvec) * inv_det;
131 if (v < -kEps || (u + v) > 1.0f + kEps) {
132 return false;
133 }
134 t = e2.dot(qvec) * inv_det;
135 return t > kEps;
136}
137
138// -----------------------------------------------------------------------------
139// Axis-aligned bounding box (AABB)
140// -----------------------------------------------------------------------------
141
151struct AABB
152{
156 Vec3 min{std::numeric_limits<float>::infinity(),
157 std::numeric_limits<float>::infinity(),
158 std::numeric_limits<float>::infinity()};
159
162 Vec3 max{-std::numeric_limits<float>::infinity(),
163 -std::numeric_limits<float>::infinity(),
164 -std::numeric_limits<float>::infinity()};
165
170 inline void expand(const Vec3 & p)
171 {
172 min = min.cwiseMin(p);
173 max = max.cwiseMax(p);
174 }
175
180 inline void expand(const AABB & b)
181 {
182 min = min.cwiseMin(b.min);
183 max = max.cwiseMax(b.max);
184 }
185
190 inline int longest_axis() const
191 {
192 Vec3 d = max - min;
193 if (d.x() >= d.y() && d.x() >= d.z()) {return 0;}
194 if (d.y() >= d.x() && d.y() >= d.z()) {return 1;}
195 return 2;
196 }
197
209 inline bool intersects_ray(
210 const Vec3 & o,
211 const Vec3 & d,
212 float tmax = 1e30f) const
213 {
214 const float kEps = 1e-12f;
215 float tmin_local = 0.0f;
216
217 for (int i = 0; i < 3; ++i) {
218 const float di = d[i];
219 const float oi = o[i];
220 const float min_i = min[i];
221 const float max_i = max[i];
222
223 if (std::fabs(di) < kEps) {
224 // Parallel to this slab: must be inside [min_i, max_i]
225 if (oi < min_i || oi > max_i) {return false;}
226 continue;
227 }
228
229 float inv = 1.0f / di;
230 float t0 = (min_i - oi) * inv;
231 float t1 = (max_i - oi) * inv;
232 if (t0 > t1) {std::swap(t0, t1);}
233
234 if (t0 > tmin_local) {tmin_local = t0;}
235 if (t1 < tmax) {tmax = t1;}
236
237 if (tmax < tmin_local) {return false;}
238 }
239 return tmax >= tmin_local && tmax > 0.0f;
240 }
241
252 inline bool contains_xy(const Vec3 & p, float z_eps) const
253 {
254 return p.x() >= min.x() && p.x() <= max.x() &&
255 p.y() >= min.y() && p.y() <= max.y() &&
256 p.z() >= min.z() - z_eps && p.z() <= max.z() + z_eps;
257 }
258
265 inline bool contains_xy_only(const Vec3 & p) const
266 {
267 return p.x() >= min.x() && p.x() <= max.x() &&
268 p.y() >= min.y() && p.y() <= max.y();
269 }
270};
271
272// -----------------------------------------------------------------------------
273// Closest point on triangle and point-triangle distance
274// -----------------------------------------------------------------------------
275
289 const Vec3 & p,
290 const Vec3 & a,
291 const Vec3 & b,
292 const Vec3 & c)
293{
294 const Vec3 ab = b - a;
295 const Vec3 ac = c - a;
296 const Vec3 ap = p - a;
297
298 float d1 = ab.dot(ap);
299 float d2 = ac.dot(ap);
300 if (d1 <= 0.0f && d2 <= 0.0f) {
301 return a;
302 }
303
304 const Vec3 bp = p - b;
305 float d3 = ab.dot(bp);
306 float d4 = ac.dot(bp);
307 if (d3 >= 0.0f && d4 <= d3) {
308 return b;
309 }
310
311 float vc = d1 * d4 - d3 * d2;
312 if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
313 float v = d1 / (d1 - d3);
314 return a + v * ab;
315 }
316
317 const Vec3 cp = p - c;
318 float d5 = ab.dot(cp);
319 float d6 = ac.dot(cp);
320 if (d6 >= 0.0f && d5 <= d6) {
321 return c;
322 }
323
324 float vb = d5 * d2 - d1 * d6;
325 if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
326 float w = d2 / (d2 - d6);
327 return a + w * ac;
328 }
329
330 float va = d3 * d6 - d5 * d4;
331 if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
332 float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
333 return b + w * (c - b);
334 }
335
336 float ab2 = ab.dot(ab);
337 float ac2 = ac.dot(ac);
338 float abac = ab.dot(ac);
339 float denom = (ab2 * ac2 - abac * abac);
340 if (std::fabs(denom) < 1e-20f) {
341 float da = (p - a).squaredNorm();
342 float db = (p - b).squaredNorm();
343 float dc = (p - c).squaredNorm();
344 if (da <= db && da <= dc) {return a;}
345 if (db <= dc) {return b;}
346 return c;
347 }
348 float v = (ac2 * d1 - abac * d2) / denom;
349 float w = (ab2 * d2 - abac * d1) / denom;
350 return a + v * ab + w * ac;
351}
352
367 const Vec3 & p,
368 const Vec3 & a,
369 const Vec3 & b,
370 const Vec3 & c,
371 Vec3 * closest = nullptr)
372{
373 Vec3 q = closest_point_on_triangle(p, a, b, c);
374 if (closest) {*closest = q;}
375 return (q - p).squaredNorm();
376}
377
378} // namespace navmap
379
380#endif // NAVMAP_CORE__GEOMETRY_HPP
Definition Geometry.hpp:40
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:366
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:288
Axis-aligned bounding box.
Definition Geometry.hpp:152
Vec3 max
Maximum corner (x_max, y_max, z_max).
Definition Geometry.hpp:162
bool contains_xy(const Vec3 &p, float z_eps) const
2D containment test on XY with tolerance in Z.
Definition Geometry.hpp:252
Vec3 min
Minimum corner (x_min, y_min, z_min).
Definition Geometry.hpp:156
bool contains_xy_only(const Vec3 &p) const
2D containment test on XY only (no Z check).
Definition Geometry.hpp:265
int longest_axis() const
Return the index of the longest axis (0=x, 1=y, 2=z).
Definition Geometry.hpp:190
void expand(const AABB &b)
Expand the box to include another box b (component-wise union).
Definition Geometry.hpp:180
bool intersects_ray(const Vec3 &o, const Vec3 &d, float tmax=1e30f) const
Robust ray-box intersection (slabs method).
Definition Geometry.hpp:209
void expand(const Vec3 &p)
Expand the box to include a point p.
Definition Geometry.hpp:170