ASW Lib
A.D.S. Games SDL Wrapper Library. A library targeted at Allegro4 users who want to switch to SDL3 and use modern c++.
Loading...
Searching...
No Matches
geometry.h
Go to the documentation of this file.
1
8
9#ifndef ASW_GEOMETRY_H
10#define ASW_GEOMETRY_H
11
12#include <algorithm>
13#include <cmath>
14#include <concepts>
15#include <cstddef>
16#include <optional>
17#include <type_traits>
18#include <vector>
19
20namespace asw {
21
27template <typename T> class Vec2 {
28public:
31 using Real = std::conditional_t<std::is_floating_point_v<T>, T, float>;
32
35 Vec2() = default;
36
42 Vec2(T x, T y)
43 : x(x)
44 , y(y)
45 {
46 }
47
52 Real angle(const Vec2& other) const
53 {
54 return std::atan2(static_cast<Real>(y - other.y), static_cast<Real>(x - other.x));
55 }
56
61 Real angle() const
62 {
63 if (x == 0 && y == 0) {
64 return 0;
65 }
66 return std::atan2(static_cast<Real>(y), static_cast<Real>(x));
67 }
68
76 static Vec2 from_angle(T angle, T length = T(1))
77 requires std::floating_point<T>
78 {
79 return Vec2(std::cos(angle) * length, std::sin(angle) * length);
80 }
81
86 Real distance(const Vec2& other) const
87 {
88 return std::hypot(static_cast<Real>(x - other.x), static_cast<Real>(y - other.y));
89 }
90
99 Real distance_to_segment(const Vec2& start, const Vec2& end) const
100 {
101 const auto seg_x = static_cast<Real>(end.x - start.x);
102 const auto seg_y = static_cast<Real>(end.y - start.y);
103 const auto rel_x = static_cast<Real>(x - start.x);
104 const auto rel_y = static_cast<Real>(y - start.y);
105
106 const Real length_sq = (seg_x * seg_x) + (seg_y * seg_y);
107 const Real t = length_sq > Real(0)
108 ? std::clamp(((rel_x * seg_x) + (rel_y * seg_y)) / length_sq, Real(0), Real(1))
109 : Real(0);
110
111 return std::hypot(rel_x - (seg_x * t), rel_y - (seg_y * t));
112 }
113
119 T dot(const Vec2& other) const
120 {
121 return (x * other.x) + (y * other.y);
122 }
123
129 T cross(const Vec2& other) const
130 {
131 return (x * other.y) - (y * other.x);
132 }
133
139 {
140 return std::sqrt(static_cast<Real>((x * x) + (y * y)));
141 }
142
149 requires std::floating_point<T>
150 {
151 const T length = magnitude();
152 if (length == T(0)) {
153 return Vec2(T(0), T(0));
154 }
155
156 return Vec2(x / length, y / length);
157 }
158
164 Vec2 operator+(const Vec2& other) const
165 {
166 return Vec2(x + other.x, y + other.y);
167 }
168
174 Vec2 operator-(const Vec2& other) const
175 {
176 return Vec2(x - other.x, y - other.y);
177 }
178
184 Vec2 operator*(const T scalar) const
185 {
186 return Vec2(x * scalar, y * scalar);
187 }
188
194 Vec2 operator/(const T scalar) const
195 {
196 return Vec2(x / scalar, y / scalar);
197 }
198
204 Vec2 operator%(const T scalar) const
205 {
206 return Vec2(x % scalar, y % scalar);
207 }
208
214 Vec2& operator+=(const Vec2& other)
215 {
216 x += other.x;
217 y += other.y;
218 return *this;
219 }
220
226 Vec2& operator-=(const Vec2& other)
227 {
228 x -= other.x;
229 y -= other.y;
230 return *this;
231 }
232
238 Vec2& operator*=(const T scalar)
239 {
240 x *= scalar;
241 y *= scalar;
242 return *this;
243 }
244
250 Vec2& operator/=(const T scalar)
251 {
252 x /= scalar;
253 y /= scalar;
254 return *this;
255 }
256
262 Vec2& operator%=(const T scalar)
263 {
264 x %= scalar;
265 y %= scalar;
266 return *this;
267 }
268
274 bool operator==(const Vec2& other) const = default;
275
277 T x { 0 };
278
280 T y { 0 };
281};
282
288template <typename T> class Vec3 {
289public:
292 using Real = std::conditional_t<std::is_floating_point_v<T>, T, float>;
293
296 Vec3() = default;
297
304 Vec3(T x, T y, T z)
305 : x(x)
306 , y(y)
307 , z(z)
308 {
309 }
310
315 Real angle(const Vec3& other) const
316 {
317 const auto magnitudes = magnitude() * other.magnitude();
318 if (magnitudes == Real(0)) {
319 return 0;
320 }
321
322 // Rounding can push the ratio just past 1, which acos turns into NaN
323 const auto ratio = static_cast<Real>(dot(other)) / magnitudes;
324 return std::acos(std::clamp(ratio, Real(-1), Real(1)));
325 }
326
331 Real distance(const Vec3& other) const
332 {
333 return std::sqrt(static_cast<Real>((x - other.x) * (x - other.x)
334 + (y - other.y) * (y - other.y) + (z - other.z) * (z - other.z)));
335 }
336
342 T dot(const Vec3& other) const
343 {
344 return (x * other.x) + (y * other.y) + (z * other.z);
345 }
346
352 Vec3 cross(const Vec3& other) const
353 {
354 return Vec3((y * other.z) - (z * other.y), (z * other.x) - (x * other.z),
355 (x * other.y) - (y * other.x));
356 }
357
363 {
364 return std::sqrt(static_cast<Real>((x * x) + (y * y) + (z * z)));
365 }
366
372 Vec3 operator+(const Vec3& other) const
373 {
374 return Vec3(x + other.x, y + other.y, z + other.z);
375 }
376
382 Vec3 operator-(const Vec3& other) const
383 {
384 return Vec3(x - other.x, y - other.y, z - other.z);
385 }
386
392 Vec3 operator*(const T scalar) const
393 {
394 return Vec3(x * scalar, y * scalar, z * scalar);
395 }
396
402 Vec3 operator/(const T scalar) const
403 {
404 return Vec3(x / scalar, y / scalar, z / scalar);
405 }
406
412 Vec3 operator%(const T scalar) const
413 {
414 return Vec3(x % scalar, y % scalar, z % scalar);
415 }
416
422 Vec3& operator+=(const Vec3& other)
423 {
424 x += other.x;
425 y += other.y;
426 z += other.z;
427 return *this;
428 }
429
435 Vec3& operator-=(const Vec3& other)
436 {
437 x -= other.x;
438 y -= other.y;
439 z -= other.z;
440 return *this;
441 }
442
448 Vec3& operator*=(const T scalar)
449 {
450 x *= scalar;
451 y *= scalar;
452 z *= scalar;
453 return *this;
454 }
455
461 Vec3& operator/=(const T scalar)
462 {
463 x /= scalar;
464 y /= scalar;
465 z /= scalar;
466 return *this;
467 }
468
474 Vec3& operator%=(const T scalar)
475 {
476 x %= scalar;
477 y %= scalar;
478 z %= scalar;
479 return *this;
480 }
481
487 bool operator==(const Vec3& other) const = default;
488
490 T x { 0 };
491
493 T y { 0 };
494
496 T z { 0 };
497};
498
504template <typename T> class Quad {
505public:
509 : position(0, 0)
510 , size(0, 0)
511 {
512 }
513
521 , size(size)
522 {
523 }
524
532 Quad(T x, T y, T width, T height)
533 : position(x, y)
534 , size(width, height)
535 {
536 }
537
543 void set_position(T x, T y)
544 {
545 position = Vec2<T>(x, y);
546 }
547
553 void set_size(T width, T height)
554 {
555 size = Vec2<T>(width, height);
556 }
557
563 {
564 return Vec2<T>(position.x + (size.x / 2.0F), position.y + (size.y / 2.0F));
565 }
566
574 bool contains(const Vec2<T>& point) const
575 {
576 return contains(point.x, point.y);
577 }
578
586 bool contains(T x, T y) const
587 {
588 return x >= position.x && x < position.x + size.x && y >= position.y
589 && y < position.y + size.y;
590 }
591
597 bool collides(const Quad& other) const
598 {
599 bool is_outside = position.x + size.x <= other.position.x || // a is left of b
600 other.position.x + other.size.x <= position.x || // b is left of a
601 position.y + size.y <= other.position.y || // a is above b
602 other.position.y + other.size.y <= position.y; // b is above a
603
604 return !is_outside;
605 }
606
613 Vec2<T> closest_point(const Vec2<T>& point) const
614 {
615 // The size can be negative, clamp between the edges in either order
616 const T x1 = position.x + size.x;
617 const T y1 = position.y + size.y;
618 return Vec2<T>(std::clamp(point.x, std::min(position.x, x1), std::max(position.x, x1)),
619 std::clamp(point.y, std::min(position.y, y1), std::max(position.y, y1)));
620 }
621
627 typename Vec2<T>::Real distance_to(const Vec2<T>& point) const
628 {
629 return closest_point(point).distance(point);
630 }
631
640 Vec2<T> get_push_out(const Quad& other) const
641 {
642 if (!collides(other)) {
643 return Vec2<T>(T(0), T(0));
644 }
645
646 const T left = (position.x + size.x) - other.position.x;
647 const T right = (other.position.x + other.size.x) - position.x;
648 const T up = (position.y + size.y) - other.position.y;
649 const T down = (other.position.y + other.size.y) - position.y;
650
651 const T push_x = left < right ? -left : right;
652 const T push_y = up < down ? -up : down;
653
654 if (std::min(left, right) < std::min(up, down)) {
655 return Vec2<T>(push_x, T(0));
656 }
657
658 return Vec2<T>(T(0), push_y);
659 }
660
661 // Collision
662 bool collides_bottom(const Quad& other) const
663 {
664 return position.y < other.position.y + other.size.y
665 && position.y + size.y > other.position.y + other.size.y;
666 }
667
668 bool collides_top(const Quad& other) const
669 {
670 return position.y + size.y > other.position.y && position.y < other.position.y;
671 }
672
673 bool collides_left(const Quad& other) const
674 {
675 return position.x + size.x > other.position.x && position.x < other.position.x;
676 }
677
678 bool collides_right(const Quad& other) const
679 {
680 return position.x < other.position.x + other.size.x
681 && position.x + size.x > other.position.x + other.size.x;
682 }
683
689 Quad operator+(const Quad<T>& quad) const
690 {
691 return Quad(position + quad.position, size + quad.size);
692 }
693
699 Quad operator-(const Quad<T>& quad) const
700 {
701 return Quad(position - quad.position, size - quad.size);
702 }
703
709 Quad operator*(const T scalar) const
710 {
711 return Quad(position * scalar, size * scalar);
712 }
713
719 Quad operator/(const T scalar) const
720 {
721 return Quad(position / scalar, size / scalar);
722 }
723
726
729};
730
738
740template <typename T> using Polygon = std::vector<Vec2<T>>;
742
743namespace geometry {
744
751 template <typename T> typename Vec2<T>::Real signed_area(const Polygon<T>& polygon)
752 {
753 using Real = typename Vec2<T>::Real;
754 Real area = 0;
755 for (std::size_t i = 0; i < polygon.size(); ++i) {
756 area += static_cast<Real>(polygon[i].cross(polygon[(i + 1) % polygon.size()]));
757 }
758 return area / Real(2);
759 }
760
766 template <typename T> Quad<T> bounds(const Polygon<T>& polygon)
767 {
768 if (polygon.empty()) {
769 return { };
770 }
771
772 Vec2<T> lo = polygon.front();
773 Vec2<T> hi = polygon.front();
774 for (const auto& p : polygon) {
775 lo = { std::min(lo.x, p.x), std::min(lo.y, p.y) };
776 hi = { std::max(hi.x, p.x), std::max(hi.y, p.y) };
777 }
778 return { lo, hi - lo };
779 }
780
789 template <typename T>
791 const Vec2<T>& point, const Vec2<T>& a, const Vec2<T>& b, const Vec2<T>& c)
792 {
793 const T d1 = (b - a).cross(point - a);
794 const T d2 = (c - b).cross(point - b);
795 const T d3 = (a - c).cross(point - c);
796 const bool has_neg = d1 < 0 || d2 < 0 || d3 < 0;
797 const bool has_pos = d1 > 0 || d2 > 0 || d3 > 0;
798 return !(has_neg && has_pos);
799 }
800
810 std::optional<float> ray_hit(
811 const Vec2f& origin, const Vec2f& direction, const Vec2f& a, const Vec2f& b);
812
825 Polygonf visibility(const Vec2f& from, float radius, const std::vector<Polygonf>& occluders,
826 float direction = 0.0F, float cone = 0.0F);
827
833 void visibility(Polygonf& result, const Vec2f& from, float radius,
834 const std::vector<Polygonf>& occluders, float direction = 0.0F, float cone = 0.0F);
835
842 void visibility(Polygonf& result, const Vec2f& from, float radius,
843 const std::vector<Polygonf>& occluders, const std::vector<Quadf>& occluder_bounds,
844 float direction = 0.0F, float cone = 0.0F);
845
846} // namespace geometry
847
848} // namespace asw
849
850#endif // ASW_GEOMETRY_H
A 2D rectangle in space.
Definition geometry.h:504
Quad operator-(const Quad< T > &quad) const
Subtract another rectangle's position and size from this one.
Definition geometry.h:699
bool collides_top(const Quad &other) const
Definition geometry.h:668
Quad operator+(const Quad< T > &quad) const
Add another rectangle's position and size to this one.
Definition geometry.h:689
Quad operator/(const T scalar) const
Divide the rectangle by a scalar.
Definition geometry.h:719
Vec2< T >::Real distance_to(const Vec2< T > &point) const
Get the distance from a point to the edge of the rectangle.
Definition geometry.h:627
Quad()
Default constructor for the Quad class.
Definition geometry.h:508
bool collides(const Quad &other) const
Check if a rectangle is inside the rectangle.
Definition geometry.h:597
Quad(const Vec2< T > &position, const Vec2< T > &size)
Constructor for the Quad class.
Definition geometry.h:519
bool collides_left(const Quad &other) const
Definition geometry.h:673
Vec2< T > get_center() const
Get center of the rectangle.
Definition geometry.h:562
bool collides_bottom(const Quad &other) const
Definition geometry.h:662
Quad(T x, T y, T width, T height)
Constructor for the Quad class.
Definition geometry.h:532
Vec2< T > size
The size of the rectangle.
Definition geometry.h:728
Vec2< T > position
The position of the rectangle.
Definition geometry.h:725
void set_size(T width, T height)
Set the size of the rectangle.
Definition geometry.h:553
bool collides_right(const Quad &other) const
Definition geometry.h:678
Quad operator*(const T scalar) const
Multiply the rectangle by a scalar.
Definition geometry.h:709
Vec2< T > closest_point(const Vec2< T > &point) const
Get the point in or on the rectangle closest to another point.
Definition geometry.h:613
Vec2< T > get_push_out(const Quad &other) const
Get the smallest move that pushes this rectangle out of another. Useful to stop a moving box from ent...
Definition geometry.h:640
bool contains(const Vec2< T > &point) const
Check if a point is inside the rectangle. The left and top edges are inside, the right and bottom edg...
Definition geometry.h:574
bool contains(T x, T y) const
Check if coordinates are inside the rectangle. The left and top edges are inside, the right and botto...
Definition geometry.h:586
void set_position(T x, T y)
Set the position of the rectangle.
Definition geometry.h:543
A 2D vector in space.
Definition geometry.h:27
T cross(const Vec2 &other) const
Calculate the cross product of two vectors.
Definition geometry.h:129
bool operator==(const Vec2 &other) const =default
Equality operator for the Vec2 class.
Real angle() const
Calculate the angle of the vector.
Definition geometry.h:61
Vec2 operator+(const Vec2 &other) const
Addition operator for the Vec2 class.
Definition geometry.h:164
Vec2 operator/(const T scalar) const
Division operator for the Vec2 class.
Definition geometry.h:194
Vec2 & operator-=(const Vec2 &other)
Subtraction assignment operator for the Vec2 class.
Definition geometry.h:226
Vec2()=default
Default constructor for the Vec2 class.
Vec2 operator%(const T scalar) const
Modulo the Vec2 object by a scalar.
Definition geometry.h:204
Vec2 & operator%=(const T scalar)
Modulo assignment operator for the Vec2 class.
Definition geometry.h:262
T y
The y component of the vector.
Definition geometry.h:280
T x
The x component of the vector.
Definition geometry.h:277
std::conditional_t< std::is_floating_point_v< T >, T, float > Real
Type used for lengths and angles. Integer vectors use float so results are not truncated.
Definition geometry.h:31
Vec2 operator*(const T scalar) const
Multiplication operator for the Vec2 class.
Definition geometry.h:184
Real magnitude() const
Calculate the magnitude of the vector.
Definition geometry.h:138
Vec2 & operator/=(const T scalar)
Division assignment operator for the Vec2 class.
Definition geometry.h:250
Vec2(T x, T y)
Constructor for the Vec2 class.
Definition geometry.h:42
Vec2 & operator*=(const T scalar)
Multiplication assignment operator for the Vec2 class.
Definition geometry.h:238
Real angle(const Vec2 &other) const
Get angle of two vectors.
Definition geometry.h:52
Real distance_to_segment(const Vec2 &start, const Vec2 &end) const
Get the distance from this point to the nearest point on a line segment. Useful for beams,...
Definition geometry.h:99
Vec2 normalized() const
Get a vector with the same direction and a length of one.
Definition geometry.h:148
Vec2 operator-(const Vec2 &other) const
Subtraction operator for the Vec2 class.
Definition geometry.h:174
Real distance(const Vec2 &other) const
Get distance between two vectors.
Definition geometry.h:86
Vec2 & operator+=(const Vec2 &other)
Addition assignment operator for the Vec2 class.
Definition geometry.h:214
T dot(const Vec2 &other) const
Calculate the dot product of two vectors.
Definition geometry.h:119
static Vec2 from_angle(T angle, T length=T(1))
Create a vector pointing at an angle.
Definition geometry.h:76
A 3D vector in space.
Definition geometry.h:288
T z
The z component of the vector.
Definition geometry.h:496
Vec3()=default
Default constructor for the Vec3 class.
Vec3(T x, T y, T z)
Constructor for the Vec3 class.
Definition geometry.h:304
Real angle(const Vec3 &other) const
Get angle between two vectors (in 3D space).
Definition geometry.h:315
Real magnitude() const
Calculate the magnitude of the vector.
Definition geometry.h:362
Vec3 operator/(const T scalar) const
Division operator for the Vec3 class.
Definition geometry.h:402
T x
The x component of the vector.
Definition geometry.h:490
Vec3 cross(const Vec3 &other) const
Calculate the cross product of two vectors.
Definition geometry.h:352
Vec3 & operator-=(const Vec3 &other)
Subtraction assignment operator for the Vec3 class.
Definition geometry.h:435
T dot(const Vec3 &other) const
Calculate the dot product of two vectors.
Definition geometry.h:342
Vec3 operator%(const T scalar) const
Modulo the Vec3 object by a scalar.
Definition geometry.h:412
Real distance(const Vec3 &other) const
Get distance between two vectors.
Definition geometry.h:331
Vec3 operator+(const Vec3 &other) const
Addition operator for the Vec3 class.
Definition geometry.h:372
T y
The y component of the vector.
Definition geometry.h:493
std::conditional_t< std::is_floating_point_v< T >, T, float > Real
Type used for lengths and angles. Integer vectors use float so results are not truncated.
Definition geometry.h:292
Vec3 & operator*=(const T scalar)
Multiplication assignment operator for the Vec3 class.
Definition geometry.h:448
Vec3 & operator/=(const T scalar)
Division assignment operator for the Vec3 class.
Definition geometry.h:461
bool operator==(const Vec3 &other) const =default
Equality operator for the Vec3 class.
Vec3 operator-(const Vec3 &other) const
Subtraction operator for the Vec3 class.
Definition geometry.h:382
Vec3 & operator+=(const Vec3 &other)
Addition assignment operator for the Vec3 class.
Definition geometry.h:422
Vec3 & operator%=(const T scalar)
Modulo assignment operator for the Vec3 class.
Definition geometry.h:474
Vec3 operator*(const T scalar) const
Multiplication operator for the Vec3 class.
Definition geometry.h:392
Polygonf visibility(const Vec2f &from, float radius, const std::vector< Polygonf > &occluders, float direction=0.0F, float cone=0.0F)
Find the area that can be seen from a point.
Definition geometry.cpp:104
std::optional< float > ray_hit(const Vec2f &origin, const Vec2f &direction, const Vec2f &a, const Vec2f &b)
Find where a ray hits a line segment.
Definition geometry.cpp:86
Vec2< T >::Real signed_area(const Polygon< T > &polygon)
Get the signed area of a polygon.
Definition geometry.h:751
bool point_in_triangle(const Vec2< T > &point, const Vec2< T > &a, const Vec2< T > &b, const Vec2< T > &c)
Check if a point is inside a triangle. Points on an edge are inside.
Definition geometry.h:790
Quad< T > bounds(const Polygon< T > &polygon)
Get the smallest rectangle that holds every corner of a polygon.
Definition geometry.h:766
Definition camera.cpp:16
Polygon< float > Polygonf
Definition geometry.h:741
std::vector< Vec2< T > > Polygon
A polygon, as its corners in order. The last corner joins the first.
Definition geometry.h:740