AABBtree  0.0.1
A C++ non-recursive ND AABB tree
Loading...
Searching...
No Matches
Ray.hxx
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2026, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The AABBtree project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * davide.stocco@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11// DISCLAIMER: The code in this file is a modified version of the Eigen library.
12
13#pragma once
14
15#ifndef AABBTREE_RAY_HXX
16#define AABBTREE_RAY_HXX
17
18#include "AABBtree/Box.hxx"
19
20namespace AABBtree {
21
38template <typename Real, Integer N> class Ray {
39 static_assert(std::is_floating_point<Real>::value,
40 "Ray Real type must be a floating-point type.");
41 static_assert(N > 0, "Ray dimension must be positive.");
42
45
48
49public:
55 ~Ray() = default;
56
63 Ray() = default;
64
70
76 Ray(Point const &o, Vector const &d) : m_origin(o), m_direction(d) {}
77
85 template <typename = std::enable_if<N == 1>>
86 Ray(Real const o, Real const d) : m_origin(o), m_direction(d) {}
87
97 template <typename = std::enable_if<N == 2>>
98 Ray(Real const o_x, Real const o_y, Real const d_x, Real const d_y)
99 : m_origin(o_x, o_y), m_direction(d_x, d_y) {}
100
112 template <typename = std::enable_if<N == 3>>
113 Ray(Real const o_x, Real const o_y, Real const o_z, Real const d_x,
114 Real const d_y, Real const d_z)
115 : m_origin(o_x, o_y, o_z), m_direction(d_x, d_y, d_z) {}
116
122 template <typename OtherReal>
123 explicit Ray(Ray<OtherReal, N> const &r)
124 : m_origin(r.m_origin.template cast<Real>()),
125 m_direction(r.m_direction.template cast<Real>()) {}
126
133 template <typename NewReal> Ray<NewReal, N> cast() const {
134 if constexpr (std::is_same<Real, NewReal>::value) {
135 return *this;
136 }
137 return Ray<NewReal, N>(m_origin.template cast<NewReal>(),
138 m_direction.template cast<NewReal>());
139 }
140
145 Point &origin() { return m_origin; }
146
151 Point const &origin() const { return m_origin; }
152
158
163 Vector const &direction() const { return m_direction; }
164
170 m_direction.normalize();
171 return *this;
172 }
173
178 Ray normalized() const { return Ray(m_origin, m_direction.normalized()); }
179
185 bool
186 is_approx(Ray const &r,
187 Real const tol = Eigen::NumTraits<Real>::dummy_precision()) const {
188 return m_origin.isApprox(r.m_origin, tol) &&
189 m_direction.isApprox(r.m_direction, tol);
190 }
191
197 Ray &translate(Vector const &t) {
198 m_origin += t;
199 return *this;
200 }
201
207 Ray translated(Vector const &t) const {
208 return Ray(m_origin + t, m_direction);
209 }
210
217 template <typename Transform> Ray transformed(Transform const &t) const {
218 return Ray(m_origin.transform(t), m_direction.rotate(t));
219 }
220
227 template <typename Transform> Ray &transform(Transform const &t) {
228 m_origin.transform(t);
229 m_direction.rotate(t);
230 return *this;
231 }
232
239 bool contains(Point const &p,
240 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
241 Vector v((p - m_origin).normalized());
242 return std::abs(v.cross(m_direction).norm()) < tol &&
243 v.dot(m_direction) >= -tol;
244 }
245
253 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
254 if (b.contains(m_origin)) {
255 return true;
256 }
257 Point const &b_min{b.min()};
258 Point const &b_max{b.max()};
259 Vector t_min, t_max;
260 t_min.setConstant(-std::numeric_limits<Real>::infinity());
261 t_max.setConstant(std::numeric_limits<Real>::infinity());
262 for (Integer i{0}; i < N; ++i) {
263 if (std::abs(m_direction[i]) > tol) {
264 t_min[i] = (b_min[i] - m_origin[i]) / m_direction[i];
265 t_max[i] = (b_max[i] - m_origin[i]) / m_direction[i];
266 if (t_min[i] > t_max[i]) {
267 std::swap(t_min[i], t_max[i]);
268 }
269 } else if (m_origin[i] < b_min[i] || m_origin[i] > b_max[i]) {
270 return false;
271 }
272 }
273 Real t_entry{t_min.maxCoeff()};
274 Real t_exit{t_max.minCoeff()};
275 return t_entry <= t_exit && t_exit >= -tol;
276 }
277
286 bool intersect(Box<Real, N> const &b, Point &c, Point &f,
287 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
288 if (b.contains(m_origin)) {
289 return true;
290 }
291 Point const &b_min{b.min()};
292 Point const &b_max{b.max()};
293 Vector t_min, t_max;
294 t_min.setConstant(-std::numeric_limits<Real>::infinity());
295 t_max.setConstant(std::numeric_limits<Real>::infinity());
296 for (Integer i{0}; i < N; ++i) {
297 if (std::abs(m_direction[i]) > tol) {
298 t_min[i] = (b_min[i] - m_origin[i]) / m_direction[i];
299 t_max[i] = (b_max[i] - m_origin[i]) / m_direction[i];
300 if (t_min[i] > t_max[i]) {
301 std::swap(t_min[i], t_max[i]);
302 }
303 } else if (m_origin[i] < b_min[i] || m_origin[i] > b_max[i]) {
304 return false;
305 }
306 }
307 Real t_entry{t_min.maxCoeff()};
308 Real t_exit{t_max.minCoeff()};
309 if (t_entry > t_exit && t_exit < -tol) {
310 return false;
311 }
312 c = m_origin + t_entry * m_direction;
313 f = m_origin + t_exit * m_direction;
314 return true;
315 }
316
323 Real
325 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
326 Real t{(p - m_origin).dot(m_direction) / m_direction.squaredNorm()};
327 return (m_origin + std::max(static_cast<Real>(-tol), t) * m_direction - p)
328 .squaredNorm();
329 }
330
339 Real
341 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
342 Real t{(p - m_origin).transpose().dot(m_direction) /
343 m_direction.squaredNorm()};
344 c = m_origin + std::max(static_cast<Real>(-tol), t) * m_direction;
345 return (c - p).squaredNorm();
346 }
347
354 Real distance(Point const &p,
355 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
356 return std::sqrt(this->squared_distance(p, tol));
357 }
358
367 Real distance(Point const &p, Point &c,
368 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
369 return std::sqrt(this->squared_distance(p, c, tol));
370 }
371
382 Box<Real, N> const &b,
383 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
384 Point p1, p2;
385 return this->squared_interior_distance(b, p1, p2, tol);
386 }
387
400 Box<Real, N> const &b, Point &p1, Point &p2,
401 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
402 if (b.contains(m_origin)) {
403 return 0.0;
404 }
405 Point const &b_min{b.min()};
406 Point const &b_max{b.max()};
407
408 // Compute intersection parameters
409 Vector t_min, t_max;
410 t_min.setConstant(-std::numeric_limits<Real>::infinity());
411 t_max.setConstant(std::numeric_limits<Real>::infinity());
412 for (Integer i{0}; i < N; ++i) {
413 if (std::abs(m_direction[i]) > tol) {
414 t_min[i] = (b_min[i] - m_origin[i]) / m_direction[i];
415 t_max[i] = (b_max[i] - m_origin[i]) / m_direction[i];
416 if (t_min[i] > t_max[i]) {
417 std::swap(t_min[i], t_max[i]);
418 }
419 } else if (m_origin[i] < b_min[i] || m_origin[i] > b_max[i]) {
420 // Ray is parallel and outside the box and non-intersecting
422 Vector sides{b_max - b_min};
423 this->distance(p2, p1);
424 for (Integer j{0}; j < N; ++j) {
425 if (j == i) {
426 continue;
427 }
428 if (m_direction[j] > 0.0) {
429 p1[j] += 0.5 * sides[j];
430 p2[j] += 0.5 * sides[j];
431 } else {
432 p1[j] -= 0.5 * sides[j];
433 p2[j] -= 0.5 * sides[j];
434 }
435 }
436 return (p2 - m_origin).norm();
437 }
438 }
439
440 // Compute global intersection range
441 Real t_entry{t_min.maxCoeff()}, t_exit{t_max.minCoeff()};
442 if (t_entry <= t_exit && t_exit >= 0.0) {
443 return 0.0;
444 }
445
446 // Compute closest point if no intersection
447 for (Integer i{0}; i < N; ++i) {
448 if (m_origin[i] < b_min[i]) {
449 p2[i] = b_min[i];
450 } else if (m_origin[i] > b_max[i]) {
451 p2[i] = b_max[i];
452 } else {
453 p2[i] = m_origin[i];
454 }
455 }
456
457 // Project closest point onto the ray
458 Vector v(p2 - m_origin);
459 Real t_proj{v.dot(m_direction) / m_direction.squaredNorm()};
460 if (t_proj < 0.0) {
461 p1 = m_origin;
462 return v.norm();
463 }
464
465 p1 = m_origin + t_proj * m_direction;
466 ;
467 return (p2 - p1).squaredNorm();
468 }
469
480 Box<Real, N> const &b,
481 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
482 return std::sqrt(this->squared_interior_distance(b, tol));
483 }
484
497 Box<Real, N> const &b, Point &p1, Point &p2,
498 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
499 return std::sqrt(
500 static_cast<Real>(this->squared_interior_distance(b, p1, p2, tol)));
501 }
502
513 Box<Real, N> const &b,
514 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
515 Point p1, p2;
516 return this->squared_exterior_distance(b, p1, p2, tol);
517 }
518
529 Box<Real, N> const &b, Point &p1, Point &p2,
530 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
531 if (b.contains(m_origin)) {
532 return 0.0;
533 }
534 Point const &b_min{b.min()};
535 Point const &b_max{b.max()};
536
537 // Compute intersection parameters
538 Vector t_min, t_max;
539 t_min.setConstant(-std::numeric_limits<Real>::infinity());
540 t_max.setConstant(std::numeric_limits<Real>::infinity());
541 for (Integer i{0}; i < N; ++i) {
542 if (std::abs(m_direction[i]) > tol) {
543 t_min[i] = (b_min[i] - m_origin[i]) / m_direction[i];
544 t_max[i] = (b_max[i] - m_origin[i]) / m_direction[i];
545 if (t_min[i] > t_max[i]) {
546 std::swap(t_min[i], t_max[i]);
547 }
548 } else if (m_origin[i] < b_min[i] || m_origin[i] > b_max[i]) {
549 // Ray is parallel and outside the box and non-intersecting
551 Vector sides{b_max - b_min};
552 this->distance(p2, p1);
553 for (Integer j{0}; j < N; ++j) {
554 if (j == i) {
555 continue;
556 }
557 if (m_direction[j] > 0.0) {
558 p1[j] -= 0.5 * sides[j];
559 p2[j] -= 0.5 * sides[j];
560 } else {
561 p1[j] += 0.5 * sides[j];
562 p2[j] += 0.5 * sides[j];
563 }
564 }
565 return (p2 - m_origin).norm();
566 }
567 }
568
569 // Compute global intersection range
570 Real t_entry{t_min.maxCoeff()}, t_exit{t_max.minCoeff()};
571 if (t_entry <= t_exit && t_exit >= 0) {
572 return 0.0;
573 }
574
575 // Compute closest point if no intersection
576 for (Integer i{0}; i < N; ++i) {
577 if (m_origin[i] < b_min[i]) {
578 p2[i] = b_max[i];
579 } else if (m_origin[i] > b_max[i]) {
580 p2[i] = b_min[i];
581 } else {
582 p2[i] = m_origin[i];
583 }
584 }
585
586 // Project closest point onto the ray
587 Vector v(p2 - m_origin);
588 Real t_proj{v.dot(m_direction) / m_direction.squaredNorm()};
589 if (t_proj < 0.0) {
590 p1 = m_origin;
591 return v.norm();
592 }
593
594 p1 = m_origin + t_proj * m_direction;
595 ;
596 return (p2 - p1).squaredNorm();
597 }
598
609 Box<Real, N> const &b,
610 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
611 return std::sqrt(this->squared_exterior_distance(b, tol));
612 }
613
626 Box<Real, N> const &b, Point &p1, Point &p2,
627 Real tol = Eigen::NumTraits<Real>::dummy_precision()) const {
628 return std::sqrt(this->squared_exterior_distance(b, p1, p2, tol));
629 }
630
635 void print(std::ostream &os) const {
636 os << "RAY INFO" << std::endl
637 << "\to = " << m_origin.transpose() << std::endl
638 << "\td = " << m_direction.transpose() << std::endl;
639 }
640
641}; // class Ray
642
650template <typename Real, Integer N>
651std::ostream &operator<<(std::ostream &os, Ray<Real, N> const &r) {
652 r.print(os);
653 return os;
654}
655
656} // namespace AABBtree
657
658#endif // AABBTREE_Ray_HXX
A class representing an axis-aligned bounding box (AABB) in N-dimensional space.
Definition Box.hxx:50
Real interior_distance(Point const &p) const
Definition Box.hxx:576
Real exterior_distance(Point const &p) const
Definition Box.hxx:638
bool contains(Point const &p) const
Definition Box.hxx:468
Point const & min() const
Definition Box.hxx:176
Point const & max() const
Definition Box.hxx:188
A mathematical ray in N-dimensional space.
Definition Ray.hxx:38
Real distance(Point const &p, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:354
Point const & origin() const
Definition Ray.hxx:151
void print(std::ostream &os) const
Definition Ray.hxx:635
Real interior_distance(Box< Real, N > const &b, Point &p1, Point &p2, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:496
Vector const & direction() const
Definition Ray.hxx:163
AABBtree::Point< Real, N > Point
Definition Ray.hxx:43
Real interior_distance(Box< Real, N > const &b, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:479
Vector m_direction
Definition Ray.hxx:47
Ray(Ray const &r)
Definition Ray.hxx:69
Ray & transform(Transform const &t)
Definition Ray.hxx:227
bool contains(Point const &p, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:239
bool is_approx(Ray const &r, Real const tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:186
Ray translated(Vector const &t) const
Definition Ray.hxx:207
Real squared_distance(Point const &p, Point &c, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:340
Ray normalized() const
Definition Ray.hxx:178
Real squared_interior_distance(Box< Real, N > const &b, Point &p1, Point &p2, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:399
Ray(Ray< OtherReal, N > const &r)
Definition Ray.hxx:123
Ray transformed(Transform const &t) const
Definition Ray.hxx:217
Vector & direction()
Definition Ray.hxx:157
Ray(Point const &o, Vector const &d)
Definition Ray.hxx:76
AABBtree::Vector< Real, N > Vector
Definition Ray.hxx:44
Ray(Real const o, Real const d)
Definition Ray.hxx:86
Ray()=default
Ray< NewReal, N > cast() const
Definition Ray.hxx:133
Point & origin()
Definition Ray.hxx:145
Real squared_exterior_distance(Box< Real, N > const &b, Point &p1, Point &p2, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:528
Point m_origin
Definition Ray.hxx:46
Ray(Real const o_x, Real const o_y, Real const o_z, Real const d_x, Real const d_y, Real const d_z)
Definition Ray.hxx:113
Real distance(Point const &p, Point &c, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:367
Ray & normalize()
Definition Ray.hxx:169
bool intersect(Box< Real, N > const &b, Point &c, Point &f, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:286
Ray(Real const o_x, Real const o_y, Real const d_x, Real const d_y)
Definition Ray.hxx:98
Real squared_distance(Point const &p, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:324
Real squared_exterior_distance(Box< Real, N > const &b, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:512
bool intersects(Box< Real, N > const &b, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:252
Real squared_interior_distance(Box< Real, N > const &b, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:381
~Ray()=default
Real exterior_distance(Box< Real, N > const &b, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:608
Real exterior_distance(Box< Real, N > const &b, Point &p1, Point &p2, Real tol=Eigen::NumTraits< Real >::dummy_precision()) const
Definition Ray.hxx:625
Ray & translate(Vector const &t)
Definition Ray.hxx:197
Namespace for the AABBtree library.
Definition AABBtree.hh:81
Eigen::Vector< Real, N > Point
Definition AABBtree.hh:105
std::ostream & operator<<(std::ostream &os, Box< Real, N > const &b)
Definition Box.hxx:963
Eigen::Vector< Real, N > Vector
Definition AABBtree.hh:104
AABBTREE_DEFAULT_INTEGER_TYPE Integer
The Integer type used in the AABBtree class.
Definition AABBtree.hh:89