]> git.localhorst.tv Git - orbi.git/blob - src/graphics/Vector.h
rotatable arm for character entities
[orbi.git] / src / graphics / Vector.h
1 #ifndef ORBI_VECTOR_H_
2 #define ORBI_VECTOR_H_
3
4 #include <algorithm>
5 #include <cmath>
6 #include <limits>
7 #include <ostream>
8 #include <SDL.h>
9
10
11 namespace orbi {
12
13 template<class Scalar>
14 class Vector {
15
16 public:
17         constexpr Vector() : x(0), y(0) { }
18         constexpr Vector(Scalar x, Scalar y) : x(x), y(y) { }
19
20         template<class Other>
21         constexpr Vector(Vector<Other> other) : x(other.x), y(other.y) { }
22
23         static Vector<Scalar> FromPolar(Scalar rad, Scalar az) {
24                 return Vector<Scalar>(rad * std::cos(az), rad * std::sin(az));
25         }
26
27         static constexpr Vector<Scalar> unit45 = Vector<Scalar>(-0.7071, 0.7071);
28
29 public:
30         Vector<Scalar> &operator +=(Vector<Scalar> other) {
31                 x += other.x;
32                 y += other.y;
33                 return *this;
34         }
35         Vector<Scalar> &operator -=(Vector<Scalar> other) {
36                 x -= other.x;
37                 y -= other.y;
38                 return *this;
39         }
40         Vector<Scalar> &operator *=(Scalar factor) {
41                 x *= factor;
42                 y *= factor;
43                 return *this;
44         }
45         Vector<Scalar> &operator /=(Scalar factor) {
46                 x /= factor;
47                 y /= factor;
48                 return *this;
49         }
50
51         SDL_Point ToPoint() const {
52                 SDL_Point p;
53                 p.x = x;
54                 p.y = y;
55                 return p;
56         }
57
58 public:
59         Scalar x;
60         Scalar y;
61
62 };
63
64 template<class T>
65 constexpr Vector<T> Vector<T>::unit45;
66
67 /// specialization with same layout as SDL_Point
68 template<>
69 class Vector<int>
70 : public SDL_Point {
71
72 public:
73         constexpr Vector() : SDL_Point({0, 0}) { }
74         constexpr Vector(int x, int y) : SDL_Point({x, y}) { }
75
76         template<class Other>
77         constexpr Vector(Vector<Other> other)
78         : SDL_Point({int(other.x), int(other.y)}) { }
79
80 public:
81         Vector<int> &operator +=(Vector<int> other) {
82                 x += other.x;
83                 y += other.y;
84                 return *this;
85         }
86         Vector<int> &operator -=(Vector<int> other) {
87                 x -= other.x;
88                 y -= other.y;
89                 return *this;
90         }
91
92         SDL_Point ToPoint() const {
93                 return *this;
94         }
95
96 };
97
98
99 template<class Scalar>
100 constexpr Vector<Scalar> operator -(Vector<Scalar> v) {
101         return Vector<Scalar>(-v.x, -v.y);
102 }
103
104
105 template<class Scalar>
106 constexpr Vector<Scalar> operator +(Vector<Scalar> lhs, Vector<Scalar> rhs) {
107         return Vector<Scalar>(lhs.x + rhs.x, lhs.y + rhs.y);
108 }
109
110 template<class Scalar>
111 constexpr Vector<Scalar> operator -(Vector<Scalar> lhs, Vector<Scalar> rhs) {
112         return Vector<Scalar>(lhs.x - rhs.x, lhs.y - rhs.y);
113 }
114
115
116 template<class Scalar>
117 constexpr Vector<Scalar> operator *(Vector<Scalar> lhs, Scalar rhs) {
118         return Vector<Scalar>(lhs.x * rhs, lhs.y * rhs);
119 }
120
121 template<class Scalar>
122 constexpr Vector<Scalar> operator *(Scalar lhs, Vector<Scalar> rhs) {
123         return rhs * lhs;
124 }
125 template<class Scalar>
126 constexpr Vector<Scalar> operator *(Vector<Scalar> lhs, Vector<Scalar> rhs) {
127         return Vector<Scalar>(lhs.x * rhs.x, lhs.y * rhs.y);
128 }
129
130
131 template<class Scalar>
132 constexpr Vector<Scalar> operator /(Vector<Scalar> lhs, Scalar rhs) {
133         return Vector<Scalar>(lhs.x / rhs, lhs.y / rhs);
134 }
135
136 template<class Scalar>
137 constexpr Vector<Scalar> operator /(Scalar lhs, Vector<Scalar> rhs) {
138         return rhs / lhs;
139 }
140 template<class Scalar>
141 constexpr Vector<Scalar> operator /(Vector<Scalar> lhs, Vector<Scalar> rhs) {
142         return Vector<Scalar>(lhs.x / rhs.x, lhs.y / rhs.y);
143 }
144
145
146 template<class Scalar>
147 constexpr bool operator ==(Vector<Scalar> lhs, Vector<Scalar> rhs) {
148         return lhs.x == rhs.x && lhs.y == rhs.y;
149 }
150 template<class Scalar>
151 constexpr bool operator !=(Vector<Scalar> lhs, Vector<Scalar> rhs) {
152         return lhs.x != rhs.x && lhs.y != rhs.y;
153 }
154
155
156 template<class Scalar>
157 constexpr bool IsZero(Vector<Scalar> v) {
158         return std::abs(v.x) < std::numeric_limits<Scalar>::epsilon()
159                 && std::abs(v.y) < std::numeric_limits<Scalar>::epsilon();
160 }
161
162 template<class Scalar>
163 constexpr Vector<Scalar> abs(Vector<Scalar> v) {
164         return Vector<Scalar>(std::abs(v.x), std::abs(v.y));
165 }
166 template<class Scalar>
167 inline Vector<Scalar> round(Vector<Scalar> v) {
168         return Vector<Scalar>(std::round(v.x), std::round(v.y));
169 }
170 template<>
171 inline Vector<float> round(Vector<float> v) {
172         return Vector<float>(std::roundf(v.x), std::roundf(v.y));
173 }
174 template<class Scalar>
175 constexpr Vector<Scalar> min(Vector<Scalar> lhs, Vector<Scalar> rhs) {
176         return Vector<Scalar>(std::min(lhs.x, rhs.x), std::min(lhs.y, rhs.y));
177 }
178 template<class Scalar>
179 constexpr Vector<Scalar> max(Vector<Scalar> lhs, Vector<Scalar> rhs) {
180         return Vector<Scalar>(std::max(lhs.x, rhs.x), std::max(lhs.y, rhs.y));
181 }
182
183
184 template<class Scalar>
185 constexpr Scalar Cross2D(Vector<Scalar> lhs, Vector<Scalar> rhs) {
186         return (lhs.x * rhs.y) - (lhs.y * rhs.x);
187 }
188 template<class Scalar>
189 constexpr Scalar Dot(Vector<Scalar> lhs, Vector<Scalar> rhs) {
190         return (lhs.x * rhs.x) + (lhs.y * rhs.y);
191 }
192 template<class Scalar>
193 constexpr Scalar Length(Vector<Scalar> v) {
194         return std::sqrt(Dot(v, v));
195 }
196 template<class Scalar>
197 constexpr Vector<Scalar> Norm(Vector<Scalar> v) {
198         return v / Length(v);
199 }
200
201 template<class Scalar>
202 constexpr Vector<Scalar> Rotate90(Vector<Scalar> v) {
203         return Vector<Scalar>(-v.y, v.x);
204 }
205 template<class Scalar>
206 constexpr Vector<Scalar> Rotate180(Vector<Scalar> v) {
207         return -v;
208 }
209 template<class Scalar>
210 constexpr Vector<Scalar> Rotate270(Vector<Scalar> v) {
211         return Vector<Scalar>(v.y, -v.x);
212 }
213 // angle given in radians
214 template<class Scalar, class Float>
215 inline Vector<Scalar> Rotate(Vector<Scalar> v, Float by) {
216         Float sine(std::sin(by));
217         Float cosine(std::cos(by));
218         return Vector<Scalar>(v.x * cosine - v.y * sine, v.x * sine + v.y * cosine);
219 }
220
221 /// reflect v along normalized n
222 template<class Scalar>
223 inline Vector<Scalar> Reflect(Vector<Scalar> v, Vector<Scalar> n) {
224         const Scalar dd = Scalar(2) * Dot(v, n);
225         return Vector<Scalar>(v.x - (dd * n.x), v.y - (dd * n.y));
226 }
227 /// project v onto normalized n
228 template<class Scalar>
229 inline Vector<Scalar> Project(Vector<Scalar> v, Vector<Scalar> n) {
230         return Dot(v, n) * n;
231 }
232
233
234 template<class Scalar>
235 inline std::ostream &operator <<(std::ostream &out, Vector<Scalar> v) {
236         return out << '<' << v.x << ',' << v.y << '>';
237 }
238
239 }
240
241
242 namespace std {
243
244 template<class Scalar>
245 constexpr orbi::Vector<Scalar> min(
246                 orbi::Vector<Scalar> lhs,
247                 orbi::Vector<Scalar> rhs
248 ) {
249         return orbi::Vector<Scalar>(
250                 min(lhs.x, rhs.x),
251                 min(lhs.y, rhs.y)
252         );
253 }
254
255 template<class Scalar>
256 constexpr orbi::Vector<Scalar> max(
257                 orbi::Vector<Scalar> lhs,
258                 orbi::Vector<Scalar> rhs
259 ) {
260         return orbi::Vector<Scalar>(
261                 max(lhs.x, rhs.x),
262                 max(lhs.y, rhs.y)
263         );
264 }
265
266 }
267
268 #endif