utility 2026.1.9
A comprehensive C++ utilities library tailored for the development of modern desktop and extended reality (XR) applications.
Loading...
Searching...
No Matches
ray.hpp
Go to the documentation of this file.
1/*
2 Copyright (c) 2026 ETIB Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
32#pragma once
33
34#include <ostream>
35#include <stdexcept>
36#include <type_traits>
37#include <utility>
38#include <ostream>
39
40#include "utility/graphic/position.hpp"
41
42#include "utility/math/vector.hpp"
43
44#include "utility/graphic/mesh.hpp"
45
46namespace utility::graphic
47{
52 template<typename Type>
60 template<CanBeRayComponent RayComponentType> class Ray
61 {
62 private:
63 protected:
68
73
79 static void validateDirection(
81 {
82 const RayComponentType squaredLength = direction[0] * direction[0]
83 + direction[1] * direction[1] + direction[2] * direction[2];
84 if (squaredLength == RayComponentType {}) {
85 throw std::invalid_argument("Ray direction must be non-zero");
86 }
87 }
88
89 public:
94 Ray(void)
95 : _origin()
96 {
98 _direction[0] = RayComponentType { 1 };
99 }
100
114
119 Ray(const Ray &other)
120 : _origin(other._origin)
121 , _direction(other._direction)
122 {
123 }
124
129 Ray(Ray &&other) noexcept
130 : _origin(std::move(other._origin))
131 , _direction(std::move(other._direction))
132 {
133 }
134
140 Ray &operator=(const Ray &other)
141 {
142 if (this != &other) {
143 _origin = other._origin;
144 _direction = other._direction;
145 }
146 return *this;
147 }
148
154 Ray &operator=(Ray &&other) noexcept
155 {
156 if (this != &other) {
157 _origin = std::move(other._origin);
158 _direction = std::move(other._direction);
159 }
160 return *this;
161 }
162
163 // Destructor
164 ~Ray(void) = default;
165
174
183
189 {
190 return _origin;
191 }
192
203
209 {
210 return _direction;
211 }
212
217 const Position<RayComponentType> &origin(void) const noexcept
218 {
219 return _origin;
220 }
221
227 {
228 return _direction;
229 }
230
236 {
237 return math::normalize(_direction);
238 }
239
246 pointAt(RayComponentType distanceParameter) const
247 {
248 return _origin + (_direction * distanceParameter);
249 }
250
257 at(RayComponentType distanceParameter) const
258 {
259 return pointAt(distanceParameter);
260 }
261
267 {
268 _origin += offset;
269 }
270
277 {
278 return Ray(_origin + offset, _direction);
279 }
280
286 bool operator==(const Ray &other) const
287 {
288 return _origin == other._origin && _direction == other._direction;
289 }
290
296 bool operator!=(const Ray &other) const
297 {
298 return !(*this == other);
299 }
300
313 template<typename RectanglePoseType>
314 bool intersectRectangle(const RectanglePoseType &rectanglePose,
315 const math::Vector2F &rectangleSize) const
316 {
317 const auto rectangleOrientation = rectanglePose.getOrientation();
318
320 rectangleOrientation.getRight();
322 rectangleOrientation.getUp();
323 const math::Vector<RayComponentType, 3> planeNormal =
324 rectangleOrientation.getForward();
325
326 const RayComponentType halfWidth =
327 static_cast<RayComponentType>(rectangleSize[0])
328 / RayComponentType { 2 };
329 const RayComponentType halfHeight =
330 static_cast<RayComponentType>(rectangleSize[1])
331 / RayComponentType { 2 };
332
334 math::Vector<RayComponentType, 3>(rectanglePose.getPosition());
335
336 // The rectangle's position is treated as its top-left corner. The
337 // center is found by extending half the width along the rectangle's
338 // right axis and half the height along its up axis.
339 const math::Vector<RayComponentType, 3> rectangleCenter =
340 topLeft + right * halfWidth + up * halfHeight;
341
342 const RayComponentType denominator =
343 math::dot(_direction, planeNormal);
344
345 if (denominator == RayComponentType {}) {
346 const math::Vector<RayComponentType, 3> toOrigin =
348 - rectangleCenter;
349
350 if (math::dot(toOrigin, planeNormal) == RayComponentType {}) {
351 return true;
352 }
353 return false;
354 }
355
356 const math::Vector<RayComponentType, 3> toCenter =
358
359 const RayComponentType t =
360 math::dot(toCenter, planeNormal) / denominator;
361
362 if (t < RayComponentType {}) {
363 return false;
364 }
365
366 const math::Vector<RayComponentType, 3> intersectionPoint =
367 pointAt(t);
368 const math::Vector<RayComponentType, 3> localPoint =
369 intersectionPoint - rectangleCenter;
370
371 const RayComponentType rightCoord = math::dot(localPoint, right);
372 const RayComponentType upCoord = math::dot(localPoint, up);
373
374 return (rightCoord >= -halfWidth && rightCoord <= halfWidth
375 && upCoord >= -halfHeight && upCoord <= halfHeight);
376 }
377
387 float length, float radius, int segments,
388 utility::graphic::Color32Bit color = { 255, 255, 255, 255 }) const
389 {
390 utility::graphic::Mesh mesh({}, {});
391
392 auto dir = utility::math::normalize(_direction);
393
394 utility::math::Vector3F up { 0.0f, 1.0f, 0.0f };
395
396 // If the ray is almost parallel to Up, choose another axis.
397 if (std::abs(utility::math::dot(dir, up)) > 0.99f)
398 up = utility::math::Vector3F { 1.0f, 0.0f, 0.0f };
399
400 auto right =
401 utility::math::normalize(utility::math::cross(dir, up));
402 auto realUp = utility::math::cross(right, dir);
403
405 utility::math::Vector3F end = start + dir * length;
406
407 for (int i = 0; i < segments; ++i) {
408 float a0 = 2.0f * M_PI * i / segments;
409 float a1 = 2.0f * M_PI * (i + 1) / segments;
410
411 auto offset0 = right * (std::cos(a0) * radius)
412 + realUp * (std::sin(a0) * radius);
413
414 auto offset1 = right * (std::cos(a1) * radius)
415 + realUp * (std::sin(a1) * radius);
416
417 uint32_t base =
418 static_cast<uint32_t>(mesh.getVertices().size());
419
421
422 vertex.setColor(color);
423
424 auto p0 = start + offset0;
425 auto p1 = start + offset1;
426 auto p2 = end + offset0;
427 auto p3 = end + offset1;
428
429 vertex.setPosition(
430 utility::graphic::PositionF(p0.x, p0.y, p0.z));
431 mesh.addVertex(vertex);
432
433 vertex.setPosition(
434 utility::graphic::PositionF(p1.x, p1.y, p1.z));
435 mesh.addVertex(vertex);
436
437 vertex.setPosition(
438 utility::graphic::PositionF(p2.x, p2.y, p2.z));
439 mesh.addVertex(vertex);
440
441 vertex.setPosition(
442 utility::graphic::PositionF(p3.x, p3.y, p3.z));
443 mesh.addVertex(vertex);
444
445 mesh.addIndex(base + 0);
446 mesh.addIndex(base + 1);
447 mesh.addIndex(base + 2);
448
449 mesh.addIndex(base + 2);
450 mesh.addIndex(base + 1);
451 mesh.addIndex(base + 3);
452 }
453
454 return mesh;
455 }
456 };
457
462
467
474 std::ostream &operator<<(std::ostream &stream, const RayF &ray);
475
482 std::ostream &operator<<(std::ostream &stream, const RayD &ray);
483
484} // namespace utility::graphic
The Mesh class represents a 3D mesh used for rendering in a graphics application.
Definition mesh.hpp:25
Position in 3D space represented as a vector of three PositionComponentType components (x,...
Definition position.hpp:53
Geometric ray with arithmetic component type and fixed dimension.
Definition ray.hpp:61
math::Vector< RayComponentType, 3 > at(RayComponentType distanceParameter) const
Alias for pointAt to match common ray APIs.
Definition ray.hpp:257
Ray(void)
Default constructor creating a ray at origin along the first axis.
Definition ray.hpp:94
const Position< RayComponentType > & origin(void) const noexcept
Access the ray origin by const reference.
Definition ray.hpp:217
void setDirection(const math::Vector< RayComponentType, 3 > &direction)
Set the ray direction.
Definition ray.hpp:198
void setOrigin(const math::Vector< RayComponentType, 3 > &origin)
Set the ray origin.
Definition ray.hpp:170
utility::graphic::Mesh convertToMesh(float length, float radius, int segments, utility::graphic::Color32Bit color={ 255, 255, 255, 255 }) const
Convert the ray into a mesh representation for visualization.
Definition ray.hpp:386
math::Vector< RayComponentType, 3 > normalizedDirection() const
Get a normalized copy of the ray direction.
Definition ray.hpp:235
Ray & operator=(Ray &&other) noexcept
Move assignment operator.
Definition ray.hpp:154
math::Vector< RayComponentType, 3 > getOrigin() const
Get the ray origin.
Definition ray.hpp:188
const math::Vector< RayComponentType, 3 > & direction(void) const noexcept
Access the ray direction by const reference.
Definition ray.hpp:226
Ray(Ray &&other) noexcept
Move constructor.
Definition ray.hpp:129
bool operator==(const Ray &other) const
Equality comparison.
Definition ray.hpp:286
Ray & operator=(const Ray &other)
Copy assignment operator.
Definition ray.hpp:140
Ray translated(const math::Vector< RayComponentType, 3 > &offset) const
Get translated ray copy.
Definition ray.hpp:276
bool operator!=(const Ray &other) const
Inequality comparison.
Definition ray.hpp:296
void translate(const math::Vector< RayComponentType, 3 > &offset)
Translate ray origin by the provided offset.
Definition ray.hpp:266
math::Vector< RayComponentType, 3 > pointAt(RayComponentType distanceParameter) const
Evaluate a point on the ray at the provided parameter.
Definition ray.hpp:246
bool intersectRectangle(const RectanglePoseType &rectanglePose, const math::Vector2F &rectangleSize) const
Check for intersection with an axis-aligned rectangle plane.
Definition ray.hpp:314
static void validateDirection(const math::Vector< RayComponentType, 3 > &direction)
Validate that a direction vector is non-zero.
Definition ray.hpp:79
Ray(math::Vector< RayComponentType, 3 > origin, math::Vector< RayComponentType, 3 > direction)
Construct ray from origin and direction.
Definition ray.hpp:107
math::Vector< RayComponentType, 3 > getDirection(void) const
Get the ray direction.
Definition ray.hpp:208
void setOrigin(const Position< RayComponentType > &origin)
Set the ray origin using a Position value.
Definition ray.hpp:179
Ray(const Ray &other)
Copy constructor.
Definition ray.hpp:119
Position< RayComponentType > _origin
Origin point of the ray.
Definition ray.hpp:67
math::Vector< RayComponentType, 3 > _direction
Direction vector of the ray (must be non-zero).
Definition ray.hpp:72
Vertex type containing common mesh attributes.
Definition vertex.hpp:38
void setPosition(const Position< VectorComponent > &position)
Set vertex position.
Definition vertex.hpp:87
void setColor(const Color32Bit &color)
Set vertex color.
Definition vertex.hpp:142
3D vector class inheriting from glm::vec3.
Definition vector.hpp:83
Concept to constrain position component type.
Definition position.hpp:43
Concept to ensure the type can be used as a ray component.
Definition ray.hpp:53
Concept to constrain vector component type.
Definition vector.hpp:72