libdonut 2.3.6
Application framework for cross-platform game development in C++20
Loading...
Searching...
No Matches
shapes.hpp
Go to the documentation of this file.
1#ifndef DONUT_SHAPES_HPP
2#define DONUT_SHAPES_HPP
3
4#include <donut/math.hpp>
5
6namespace donut {
7
14template <length_t L, typename T>
15using Point = vec<L, T>;
16
23template <length_t L, typename T>
24using Length = vec<L, T>;
25
32template <length_t L, typename T>
37
44template <length_t L, typename T>
45struct Sphere {
48
54 [[nodiscard]] constexpr bool contains(const Point<L, T>& point) const noexcept;
55};
56
62template <typename T>
63struct Circle {
66
72 constexpr operator Sphere<2, T>() const noexcept {
73 return Sphere<2, T>{.center = center, .radius = radius};
74 }
75
81 [[nodiscard]] constexpr bool contains(const Point<2, T>& point) const noexcept;
82};
83
90template <length_t L, typename T>
91struct Capsule {
94
100 [[nodiscard]] constexpr bool contains(const Point<L, T>& point) const noexcept;
101};
102
109template <length_t L, typename T>
110struct Box {
113
119 [[nodiscard]] constexpr bool contains(const Point<L, T>& point) const noexcept;
120};
121
127template <typename T>
128struct Rectangle {
131
137 constexpr operator Box<2, T>() const noexcept {
138 return Box<2, T>{.min = position, .max = position + size};
139 }
140
146 [[nodiscard]] constexpr bool contains(const Point<2, T>& point) const noexcept;
147};
148
156template <length_t L, typename T>
157[[nodiscard]] constexpr Box<L, T> getAabbOf(const LineSegment<L, T>& line) noexcept {
158 return {
159 .min = min(line.pointA, line.pointB),
160 .max = max(line.pointA, line.pointB),
161 };
162}
163
171template <length_t L, typename T>
172[[nodiscard]] constexpr Box<L, T> getAabbOf(const Sphere<L, T>& sphere) noexcept {
173 return {
174 .min = sphere.center - Length<L, T>{sphere.radius},
175 .max = sphere.center + Length<L, T>{sphere.radius},
176 };
177}
178
186template <typename T>
187[[nodiscard]] constexpr Box<2, T> getAabbOf(const Circle<T>& circle) noexcept {
188 return {
189 .min = circle.center - Length<2, T>{circle.radius},
190 .max = circle.center + Length<2, T>{circle.radius},
191 };
192}
193
201template <length_t L, typename T>
202[[nodiscard]] constexpr Box<L, T> getAabbOf(const Capsule<L, T>& capsule) noexcept {
203 return {
204 .min = min(capsule.centerLine.pointA, capsule.centerLine.pointB) - Length<L, T>{capsule.radius},
205 .max = max(capsule.centerLine.pointA, capsule.centerLine.pointB) + Length<L, T>{capsule.radius},
206 };
207}
208
216template <length_t L, typename T>
217[[nodiscard]] constexpr Box<L, T> getAabbOf(const Box<L, T>& box) noexcept {
218 return box;
219}
220
228template <typename T>
229[[nodiscard]] constexpr Box<2, T> getAabbOf(const Rectangle<T>& rectangle) noexcept {
230 return static_cast<Box<2, T>>(rectangle);
231}
232
242template <length_t L, typename T>
243[[nodiscard]] constexpr bool intersects(const Sphere<L, T>& a, const Sphere<L, T>& b) noexcept {
244 return distance2(a.center, b.center) < length2(a.radius + b.radius);
245}
246
256template <typename T>
257[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const Circle<T>& b) noexcept {
258 return intersects(static_cast<Sphere<2, T>>(a), static_cast<Sphere<2, T>>(b));
259}
260
270template <length_t L, typename T>
271[[nodiscard]] constexpr bool intersects(const Box<L, T>& a, const Box<L, T>& b) noexcept {
272 for (length_t i = 0; i < L; ++i) {
273 if (a.min[i] >= b.max[i] || a.max[i] <= b.min[i]) {
274 return false;
275 }
276 }
277 return true;
278}
279
289template <typename T>
290[[nodiscard]] constexpr bool intersects(const Rectangle<T>& a, const Rectangle<T>& b) noexcept {
291 return intersects(static_cast<Box<2, T>>(a), static_cast<Box<2, T>>(b));
292}
293
303template <typename T>
304[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const Sphere<2, T>& b) noexcept {
305 return intersects(static_cast<Sphere<2, T>>(a), b);
306}
307
317template <typename T>
318[[nodiscard]] constexpr bool intersects(const Sphere<2, T>& a, const Circle<T>& b) noexcept {
319 return intersects(b, a);
320}
321
331template <typename T>
332[[nodiscard]] constexpr bool intersects(const Rectangle<T>& a, const Box<2, T>& b) noexcept {
333 return intersects(static_cast<Box<2, T>>(a), b);
334}
335
345template <typename T>
346[[nodiscard]] constexpr bool intersects(const Box<2, T>& a, const Rectangle<T>& b) noexcept {
347 return intersects(b, a);
348}
349
359template <length_t L, typename T>
360[[nodiscard]] constexpr bool intersects(const Sphere<L, T>& a, const Box<L, T>& b) noexcept {
361 return distance2(a.center, clamp(a.center, b.min, b.max)) < length2(a.radius);
362}
363
373template <length_t L, typename T>
374[[nodiscard]] constexpr bool intersects(const Box<L, T>& a, const Sphere<L, T>& b) noexcept {
375 return intersects(b, a);
376}
377
387template <typename T>
388[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const Box<2, T>& b) noexcept {
389 return intersects(static_cast<Sphere<2, T>>(a), b);
390}
391
401template <typename T>
402[[nodiscard]] constexpr bool intersects(const Box<2, T>& a, const Circle<T>& b) noexcept {
403 return intersects(b, a);
404}
405
415template <typename T>
416[[nodiscard]] constexpr bool intersects(const Sphere<2, T>& a, const Rectangle<T>& b) noexcept {
417 return intersects(a, static_cast<Box<2, T>>(b));
418}
419
429template <typename T>
430[[nodiscard]] constexpr bool intersects(const Rectangle<T>& a, const Sphere<2, T>& b) noexcept {
431 return intersects(b, a);
432}
433
443template <typename T>
444[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const Rectangle<T>& b) noexcept {
445 return intersects(static_cast<Sphere<2, T>>(a), static_cast<Box<2, T>>(b));
446}
447
457template <typename T>
458[[nodiscard]] constexpr bool intersects(const Rectangle<T>& a, const Circle<T>& b) noexcept {
459 return intersects(b, a);
460}
461
471template <length_t L, typename T>
472[[nodiscard]] constexpr bool intersects(const Sphere<L, T>& a, const Capsule<L, T>& b) noexcept {
473 const T combinedRadiusSquared = length2(a.radius + b.radius);
474 const vec<L, T> linePointAToPointB = b.centerLine.pointB - b.centerLine.pointA;
475 const vec<L, T> linePointAToSphereCenter = a.center - b.centerLine.pointA;
476 const T linePointAToSphereCenterAlongLine = dot(linePointAToSphereCenter, linePointAToPointB);
477 if (linePointAToSphereCenterAlongLine <= 0.0f) {
478 return length2(linePointAToSphereCenter) < combinedRadiusSquared;
479 }
480 const vec<L, T> linePointBToSphereCenter = a.center - b.centerLine.pointB;
481 const T linePointBToSphereCenterAlongLine = dot(linePointBToSphereCenter, linePointAToPointB);
482 if (linePointBToSphereCenterAlongLine >= 0.0f) {
483 return length2(linePointBToSphereCenter) < combinedRadiusSquared;
484 }
485 const vec<L, T> lineToSphereCenterOrthogonal = linePointAToSphereCenter - linePointAToPointB * (linePointAToSphereCenterAlongLine / length2(linePointAToPointB));
486 return length2(lineToSphereCenterOrthogonal) < combinedRadiusSquared;
487}
488
498template <length_t L, typename T>
499[[nodiscard]] constexpr bool intersects(const Capsule<L, T>& a, const Sphere<L, T>& b) noexcept {
500 return intersects(b, a);
501}
502
512template <typename T>
513[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const Capsule<2, T>& b) noexcept {
514 return intersects(static_cast<Sphere<2, T>>(a), b);
515}
516
526template <typename T>
527[[nodiscard]] constexpr bool intersects(const Capsule<2, T>& a, const Circle<T>& b) noexcept {
528 return intersects(b, a);
529}
530
540template <length_t L, typename T>
541[[nodiscard]] constexpr bool intersects(const Sphere<L, T>& a, const LineSegment<L, T>& b) noexcept {
542 return intersects(a, Capsule<L, T>{.centerLine = b, .radius = T{0}});
543}
544
554template <length_t L, typename T>
555[[nodiscard]] constexpr bool intersects(const LineSegment<L, T>& a, const Sphere<L, T>& b) noexcept {
556 return intersects(b, a);
557}
558
568template <typename T>
569[[nodiscard]] constexpr bool intersects(const Circle<T>& a, const LineSegment<2, T>& b) noexcept {
570 return intersects(static_cast<Sphere<2, T>>(a), b);
571}
572
582template <typename T>
583[[nodiscard]] constexpr bool intersects(const LineSegment<2, T>& a, const Circle<T>& b) noexcept {
584 return intersects(b, a);
585}
586
587template <length_t L, typename T>
588constexpr bool Sphere<L, T>::contains(const Point<L, T>& point) const noexcept {
589 return distance2(center, point) < length2(radius);
590}
591
592template <typename T>
593constexpr bool Circle<T>::contains(const Point<2, T>& point) const noexcept {
594 return static_cast<Sphere<2, T>>(*this).contains(point);
595}
596
597template <length_t L, typename T>
598constexpr bool Capsule<L, T>::contains(const Point<L, T>& point) const noexcept {
599 return intersects(*this, Sphere<L, T>{.center = point, .radius = T{0}});
600}
601
602template <length_t L, typename T>
603constexpr bool Box<L, T>::contains(const Point<L, T>& point) const noexcept {
604 for (length_t i = 0; i < L; ++i) {
605 if (point[i] < min[i] || point[i] >= max[i]) {
606 return false;
607 }
608 }
609 return true;
610}
611
612template <typename T>
613constexpr bool Rectangle<T>::contains(const Point<2, T>& point) const noexcept {
614 return static_cast<Box<2, T>>(*this).contains(point);
615}
616
617} // namespace donut
618
619#endif
Definition Application.hpp:9
vec< L, T > Point
Generic point in space.
Definition shapes.hpp:15
vec< L, T > Length
Generic length in space.
Definition shapes.hpp:24
constexpr Box< L, T > getAabbOf(const LineSegment< L, T > &line) noexcept
Get the axis-aligned bounding box of a line segment.
Definition shapes.hpp:157
constexpr bool intersects(const Sphere< L, T > &a, const Sphere< L, T > &b) noexcept
Check if two spheres intersect.
Definition shapes.hpp:243
Generic axis-aligned box shape with minimum and maximum extents.
Definition shapes.hpp:110
constexpr bool contains(const Point< L, T > &point) const noexcept
Check if a given point is contained within the extents of this box.
Definition shapes.hpp:603
Point< L, T > max
Position with the maximum coordinates of the box extents on each coordinate axis.
Definition shapes.hpp:112
Point< L, T > min
Position with the minimum coordinates of the box extents on each coordinate axis.
Definition shapes.hpp:111
Generic capsule shape with a center line segment and radius.
Definition shapes.hpp:91
T radius
Radius of the capsule from the center line.
Definition shapes.hpp:93
LineSegment< L, T > centerLine
Center line of the capsule.
Definition shapes.hpp:92
constexpr bool contains(const Point< L, T > &point) const noexcept
Check if a given point is contained within the extents of this capsule.
Definition shapes.hpp:598
Flat 2D circle shape with a center and radius.
Definition shapes.hpp:63
T radius
Radius of the circle.
Definition shapes.hpp:65
Point< 2, T > center
Position of the center of the circle.
Definition shapes.hpp:64
constexpr bool contains(const Point< 2, T > &point) const noexcept
Check if a given point is contained within the extents of this circle.
Definition shapes.hpp:593
Generic line segment between two points.
Definition shapes.hpp:33
Point< L, T > pointA
Position of the first point of the line segment.
Definition shapes.hpp:34
Point< L, T > pointB
Position of the second point of the line segment.
Definition shapes.hpp:35
Flat 2D axis-aligned rectangle shape with a position and size.
Definition shapes.hpp:128
Length< 2, T > size
Width and height of the rectangle.
Definition shapes.hpp:130
Point< 2, T > position
Position of the bottom left corner of the rectangle.
Definition shapes.hpp:129
constexpr bool contains(const Point< 2, T > &point) const noexcept
Check if a given point is contained within the extents of this rectangle.
Definition shapes.hpp:613
Generic sphere shape with a center and radius.
Definition shapes.hpp:45
T radius
Radius of the sphere.
Definition shapes.hpp:47
constexpr bool contains(const Point< L, T > &point) const noexcept
Check if a given point is contained within the extents of this sphere.
Definition shapes.hpp:588
Point< L, T > center
Position of the center of the sphere.
Definition shapes.hpp:46