1 /** @addtogroup basic_math
2 * @{
3 */
4 /*
5 Copyright (C) 2016 D Levin (https://www.kfrlib.com)
6 This file is part of KFR
7
8 KFR is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 KFR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with KFR.
20
21 If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
22 Buying a commercial license is mandatory as soon as you develop commercial activities without
23 disclosing the source code of your own applications.
24 See https://www.kfrlib.com for details.
25 */
26 #pragma once
27
28 #include "scaled.hpp"
29
30 namespace kfr
31 {
32 inline namespace CMT_ARCH_NAME
33 {
34
35 template <typename T, int maximum = 1>
36 struct point
37 {
38 constexpr point() noexcept = default;
pointkfr::CMT_ARCH_NAME::point39 constexpr point(const vec<T, 2>& v) noexcept : v(v) {}
pointkfr::CMT_ARCH_NAME::point40 constexpr point(T x, T y) noexcept : v(x, y) {}
41
42 template <typename U, int Umax>
operator point<U,Umax>kfr::CMT_ARCH_NAME::point43 operator point<U, Umax>() const
44 {
45 return convert_scaled<U, Umax, maximum>(v);
46 }
operator ==kfr::CMT_ARCH_NAME::point47 constexpr bool operator==(const point& c) const { return all(v == c.v); }
operator !=kfr::CMT_ARCH_NAME::point48 constexpr bool operator!=(const point& c) const { return !operator==(c); }
49
operator +(const point & p1,const point & p2)50 constexpr friend point operator+(const point& p1, const point& p2) { return p1.v + p2.v; }
operator -(const point & p1,const point & p2)51 constexpr friend point operator-(const point& p1, const point& p2) { return p1.v - p2.v; }
operator *(const point & p1,const point & p2)52 constexpr friend point operator*(const point& p1, const point& p2) { return p1.v * p2.v; }
operator -(const point & p1)53 constexpr friend point operator-(const point& p1) { return -p1.v; }
54
flippedkfr::CMT_ARCH_NAME::point55 constexpr point flipped() const { return kfr::swap(v); }
56
distancekfr::CMT_ARCH_NAME::point57 T distance(const point& pt) const { return std::sqrt(sqr(pt.x - x) + sqr(pt.y - y)); }
58
operator []kfr::CMT_ARCH_NAME::point59 T operator[](size_t i) const { return v[i]; }
operator []kfr::CMT_ARCH_NAME::point60 T& operator[](size_t i) { return a[i]; }
61
roundkfr::CMT_ARCH_NAME::point62 constexpr point round() const { return kfr::round(v); }
floorkfr::CMT_ARCH_NAME::point63 constexpr point floor() const { return kfr::floor(v); }
ceilkfr::CMT_ARCH_NAME::point64 constexpr point ceil() const { return kfr::ceil(v); }
trunckfr::CMT_ARCH_NAME::point65 constexpr point trunc() const { return kfr::trunc(v); }
66
67 union {
68 struct
69 {
70 T x;
71 T y;
72 };
73 struct
74 {
75 vec<T, 2> v;
76 };
77 struct
78 {
79 T a[2];
80 };
81 };
82 };
83
84 template <typename T, int maximum = 1>
85 struct size
86 {
87 constexpr size() noexcept = default;
sizekfr::CMT_ARCH_NAME::size88 constexpr size(T x, T y) noexcept : v(x, y) {}
sizekfr::CMT_ARCH_NAME::size89 constexpr explicit size(T xy) noexcept : v(xy, xy) {}
sizekfr::CMT_ARCH_NAME::size90 constexpr size(const vec<T, 2>& v) noexcept : v(v) {}
91
92 template <typename U, int Umax>
operator size<U,Umax>kfr::CMT_ARCH_NAME::size93 operator size<U, Umax>() const noexcept
94 {
95 return convert_scaled<U, Umax, maximum>(v);
96 }
97
roundkfr::CMT_ARCH_NAME::size98 constexpr size round() const { return kfr::round(v); }
floorkfr::CMT_ARCH_NAME::size99 constexpr size floor() const { return kfr::floor(v); }
ceilkfr::CMT_ARCH_NAME::size100 constexpr size ceil() const { return kfr::ceil(v); }
trunckfr::CMT_ARCH_NAME::size101 constexpr size trunc() const { return kfr::trunc(v); }
102
flippedkfr::CMT_ARCH_NAME::size103 constexpr size flipped() const { return kfr::swap(v); }
104
operator +(const size & s1,const size & s2)105 constexpr friend size operator+(const size& s1, const size& s2) { return s1.v + s2.v; }
operator -(const size & s1,const size & s2)106 constexpr friend size operator-(const size& s1, const size& s2) { return s1.v - s2.v; }
operator *(const size & s1,const size & s2)107 constexpr friend size operator*(const size& s1, const size& s2) { return s1.v * s2.v; }
operator *(const size & s1,T s2)108 constexpr friend size operator*(const size& s1, T s2) { return s1.v * s2; }
operator *(T s1,const size & s2)109 constexpr friend size operator*(T s1, const size& s2) { return s1 * s2.v; }
areakfr::CMT_ARCH_NAME::size110 constexpr T area() const { return x * y; }
111
operator []kfr::CMT_ARCH_NAME::size112 T operator[](size_t i) const { return v[i]; }
operator []kfr::CMT_ARCH_NAME::size113 T& operator[](size_t i) { return a[i]; }
114
operator ==kfr::CMT_ARCH_NAME::size115 constexpr bool operator==(const size& c) const { return all(v == c.v); }
operator !=kfr::CMT_ARCH_NAME::size116 constexpr bool operator!=(const size& c) const { return !operator==(c); }
117 union {
118 struct
119 {
120 T x;
121 T y;
122 };
123 struct
124 {
125 T width;
126 T height;
127 };
128 struct
129 {
130 vec<T, 2> v;
131 };
132 struct
133 {
134 T a[2];
135 };
136 };
137 };
138
139 template <typename T, int maximum = 1>
140 struct border
141 {
borderkfr::CMT_ARCH_NAME::border142 constexpr border() noexcept : v() {}
borderkfr::CMT_ARCH_NAME::border143 constexpr explicit border(T value) noexcept : v(value) {}
borderkfr::CMT_ARCH_NAME::border144 constexpr border(T h, T v) noexcept : v(h, v, h, v) {}
borderkfr::CMT_ARCH_NAME::border145 constexpr border(T x1, T y1, T x2, T y2) noexcept : v(x1, y1, x2, y2) {}
146
roundkfr::CMT_ARCH_NAME::border147 constexpr border round() const { return kfr::round(v); }
floorkfr::CMT_ARCH_NAME::border148 constexpr border floor() const { return kfr::floor(v); }
ceilkfr::CMT_ARCH_NAME::border149 constexpr border ceil() const { return kfr::ceil(v); }
trunckfr::CMT_ARCH_NAME::border150 constexpr border trunc() const { return kfr::trunc(v); }
151
sizekfr::CMT_ARCH_NAME::border152 kfr::size<T> size() const { return { x1 + x2, y1 + y2 }; }
153
horizontalkfr::CMT_ARCH_NAME::border154 T horizontal() const { return x1 + x2; }
verticalkfr::CMT_ARCH_NAME::border155 T vertical() const { return y1 + y2; }
156
startingkfr::CMT_ARCH_NAME::border157 point<T> starting() const { return { x1, y1 }; }
trailingkfr::CMT_ARCH_NAME::border158 point<T> trailing() const { return { x2, y2 }; }
159
operator ==kfr::CMT_ARCH_NAME::border160 constexpr bool operator==(const border& c) const { return all(v == c.v); }
operator !=kfr::CMT_ARCH_NAME::border161 constexpr bool operator!=(const border& c) const { return !(operator==(c)); }
162 union {
163 struct
164 {
165 T x1;
166 T y1;
167 T x2;
168 T y2;
169 };
170 struct
171 {
172 vec<T, 4> v;
173 };
174 };
175 };
176
177 using i32border = border<i32>;
178 using f32border = border<f32>;
179
180 template <typename T, int maximum = 1>
181 struct vector4
182 {
vector4kfr::CMT_ARCH_NAME::vector4183 constexpr vector4(T x, T y, T z, T w) : v(x, y, z, w) {}
vector4kfr::CMT_ARCH_NAME::vector4184 constexpr vector4(const vec<T, 4>& v) : v(v) {}
185 constexpr vector4() = default;
186
operator ==kfr::CMT_ARCH_NAME::vector4187 constexpr bool operator==(const vector4& c) const { return all(v == c.v); }
operator !=kfr::CMT_ARCH_NAME::vector4188 constexpr bool operator!=(const vector4& c) const { return !operator==(c); }
189
190 union {
191 struct
192 {
193 T x;
194 T y;
195 T z;
196 T w;
197 };
198 struct
199 {
200 point<T> p1;
201 point<T> p2;
202 };
203 struct
204 {
205 vec<T, 4> v;
206 };
207 };
208 };
209
210 template <typename T, int maximum = 1>
211 struct rectangle
212 {
rectanglekfr::CMT_ARCH_NAME::rectangle213 constexpr rectangle(T x1, T y1, T x2, T y2) : v(x1, y1, x2, y2) {}
rectanglekfr::CMT_ARCH_NAME::rectangle214 constexpr rectangle(const vec<T, 4>& v) : v(v) {}
215
216 template <typename U, int Umax>
operator rectangle<U,Umax>kfr::CMT_ARCH_NAME::rectangle217 operator rectangle<U, Umax>() const
218 {
219 return convert_scaled<U, Umax, maximum>(v);
220 }
rectanglekfr::CMT_ARCH_NAME::rectangle221 constexpr rectangle(const point<T>& point, const size<T>& size) : v(point.v, point.v + size.v) {}
rectanglekfr::CMT_ARCH_NAME::rectangle222 constexpr rectangle(const point<T>& point1, const point<T>& point2) : v(point1.v, point2.v) {}
rectanglekfr::CMT_ARCH_NAME::rectangle223 constexpr rectangle(const point<T>& base, const kfr::size<T>& dim, const point<T>& alignment)
224 : v(base.v - dim.v * alignment.v, base.v + dim.v * (1 - alignment.v))
225 {
226 }
227 constexpr rectangle() = default;
228
emptykfr::CMT_ARCH_NAME::rectangle229 constexpr bool empty() const noexcept { return width() <= 0 || height() <= 0; }
230
sizekfr::CMT_ARCH_NAME::rectangle231 constexpr kfr::size<T, maximum> size() const { return high(v) - low(v); }
232
areakfr::CMT_ARCH_NAME::rectangle233 constexpr T area() const { return size().area(); }
widthkfr::CMT_ARCH_NAME::rectangle234 constexpr T width() const { return x2 - x1; }
heightkfr::CMT_ARCH_NAME::rectangle235 constexpr T height() const { return y2 - y1; }
236
min_sidekfr::CMT_ARCH_NAME::rectangle237 constexpr T min_side() const { return std::min(width(), height()); }
max_sidekfr::CMT_ARCH_NAME::rectangle238 constexpr T max_side() const { return std::max(width(), height()); }
239
centerkfr::CMT_ARCH_NAME::rectangle240 point<T, maximum> center() const { return at(0.5f, 0.5f); }
241
to_norm_coordkfr::CMT_ARCH_NAME::rectangle242 point<T> to_norm_coord(const point<T>& pt) const { return (pt.v - p1.v) / (p1.v - p1.v); }
to_norm_coordkfr::CMT_ARCH_NAME::rectangle243 point<T> to_norm_coord(const point<T>& pt, const point<T>& ifoutside) const
244 {
245 if (!contains(pt))
246 return ifoutside;
247 return (pt.v - p1.v) / (p2.v - p1.v);
248 }
249
splitkfr::CMT_ARCH_NAME::rectangle250 rectangle split(const point<float>& point1, const kfr::size<float>& size) const noexcept
251 {
252 const vec<float, 2> point2 = point1.v + size.v;
253 return concat(cast<T>(p1.v + this->size().v * point1.v), cast<T>(p1.v + this->size().v * point2));
254 }
splitkfr::CMT_ARCH_NAME::rectangle255 rectangle split(float x, float y, float w, float h) const noexcept { return split({ x, y }, { w, h }); }
256
cut_h_startkfr::CMT_ARCH_NAME::rectangle257 rectangle cut_h_start(T width, bool partial = false)
258 {
259 if (empty() || (!partial && this->width() < width))
260 return rectangle();
261 width = std::min(width, this->width());
262 const rectangle result = with_width(width);
263 apply_padding(width, 0, 0, 0);
264 return result;
265 }
cut_v_startkfr::CMT_ARCH_NAME::rectangle266 rectangle cut_v_start(T height, bool partial = false)
267 {
268 if (empty() || (!partial && this->height() < height))
269 return rectangle();
270 height = std::min(height, this->height());
271 const rectangle result = with_height(height);
272 apply_padding(0, height, 0, 0);
273 return result;
274 }
cut_h_endkfr::CMT_ARCH_NAME::rectangle275 rectangle cut_h_end(T width, bool partial = false)
276 {
277 if (empty() || (!partial && this->width() < width))
278 return rectangle();
279 width = std::min(width, this->width());
280 width = this->width() - width;
281 const rectangle result = with_padding(width, 0, 0, 0);
282 apply_width(width);
283 return result;
284 }
cut_v_endkfr::CMT_ARCH_NAME::rectangle285 rectangle cut_v_end(T height, bool partial = false)
286 {
287 if (empty() || (!partial && this->height() < height))
288 return rectangle();
289 height = std::min(height, this->height());
290 height = this->height() - height;
291 const rectangle result = with_padding(0, height, 0, 0);
292 apply_height(height);
293 return result;
294 }
295
atkfr::CMT_ARCH_NAME::rectangle296 point<T> at(const point<float>& pt) const noexcept { return p1.v + point<T>(pt.v * size().v); }
atkfr::CMT_ARCH_NAME::rectangle297 point<T> at(float x, float y) const noexcept
298 {
299 return p1.v + point<T>(point<float>{ x, y }.v * size().v);
300 }
301
apply_startkfr::CMT_ARCH_NAME::rectangle302 void apply_start(const point<T, maximum>& p) { v = concat(p.v, p.v + size()); }
apply_startkfr::CMT_ARCH_NAME::rectangle303 void apply_start(T x, T y) { v = concat(pack(x, y), pack(x, y) + size()); }
apply_sizekfr::CMT_ARCH_NAME::rectangle304 void apply_size(const kfr::size<T, maximum>& s) { v = concat(low(v), low(v) + s.v); }
apply_sizekfr::CMT_ARCH_NAME::rectangle305 void apply_size(T w, T h) { v = concat(low(v), low(v) + pack(w, h)); }
apply_widthkfr::CMT_ARCH_NAME::rectangle306 void apply_width(T w) { apply_size(w, height()); }
apply_heightkfr::CMT_ARCH_NAME::rectangle307 void apply_height(T h) { apply_size(width(), h); }
apply_offsetkfr::CMT_ARCH_NAME::rectangle308 void apply_offset(T x, T y) { v += vec<T, 4>(x, y, x, y); }
apply_offsetkfr::CMT_ARCH_NAME::rectangle309 void apply_offset(const point<T>& p) { v += repeat<2>(p.v); }
apply_scalekfr::CMT_ARCH_NAME::rectangle310 void apply_scale(T x, T y) { v *= vec<T, 4>(x, y, x, y); }
apply_marginkfr::CMT_ARCH_NAME::rectangle311 void apply_margin(T h, T v) { v += vec<T, 4>(-h, -v, +h, +v); }
apply_paddingkfr::CMT_ARCH_NAME::rectangle312 void apply_padding(T h, T v) { v += vec<T, 4>(+h, +v, -h, -v); }
apply_marginkfr::CMT_ARCH_NAME::rectangle313 void apply_margin(T m) { v += vec<T, 4>(-m, -m, +m, +m); }
apply_paddingkfr::CMT_ARCH_NAME::rectangle314 void apply_padding(T p) { v += vec<T, 4>(+p, +p, -p, -p); }
apply_marginkfr::CMT_ARCH_NAME::rectangle315 void apply_margin(const border<T>& m) { v += vec<T, 4>(-1, -1, 1, 1) * m.v; }
apply_paddingkfr::CMT_ARCH_NAME::rectangle316 void apply_padding(const border<T>& p) { v += vec<T, 4>(1, 1, -1, -1) * p.v; }
apply_paddingkfr::CMT_ARCH_NAME::rectangle317 void apply_padding(T x1, T y1, T x2, T y2) { v += vec<T, 4>(+x1, +y1, -x2, -y2); }
318
aligned_rectkfr::CMT_ARCH_NAME::rectangle319 rectangle aligned_rect(const kfr::size<T>& inner_size, const point<float>& alignment) const
320 {
321 const kfr::size<T> sz = inner_size; // kfr::min(inner_size.v, this->size().v);
322 const kfr::size<T> gap = size() - sz;
323 const vec<T, 2> p = p1.v + cast<T>(gap.v * alignment.v);
324 return rectangle(concat(p, p + sz.v));
325 }
aligned_rectkfr::CMT_ARCH_NAME::rectangle326 rectangle aligned_rect(T width, T height, float align_x, float align_y) const
327 {
328 return aligned_rect({ width, height }, { align_x, align_y });
329 }
330
with_startkfr::CMT_ARCH_NAME::rectangle331 constexpr rectangle with_start(const point<T, maximum>& p) const { return concat(p.v, p.v + size()); }
with_startkfr::CMT_ARCH_NAME::rectangle332 constexpr rectangle with_start(T x, T y) const { return concat(pack(x, y), pack(x, y) + size()); }
with_sizekfr::CMT_ARCH_NAME::rectangle333 constexpr rectangle with_size(const kfr::size<T, maximum>& s) const
334 {
335 return concat(low(v), low(v) + s.v);
336 }
with_sizekfr::CMT_ARCH_NAME::rectangle337 constexpr rectangle with_size(T w, T h) const { return concat(low(v), low(v) + pack(w, h)); }
with_widthkfr::CMT_ARCH_NAME::rectangle338 constexpr rectangle with_width(T w) const { return with_size(w, height()); }
with_heightkfr::CMT_ARCH_NAME::rectangle339 constexpr rectangle with_height(T h) const { return with_size(width(), h); }
with_offsetkfr::CMT_ARCH_NAME::rectangle340 constexpr rectangle with_offset(const point<T>& p) const { return v + vec<T, 4>(p.v, p.v); }
with_offsetkfr::CMT_ARCH_NAME::rectangle341 constexpr rectangle with_offset(T x, T y) const { return v + vec<T, 4>(x, y, x, y); }
with_scalekfr::CMT_ARCH_NAME::rectangle342 constexpr rectangle with_scale(T x, T y) const { return v * vec<T, 4>(x, y, x, y); }
with_marginkfr::CMT_ARCH_NAME::rectangle343 constexpr rectangle with_margin(T h, T v) const { return this->v + vec<T, 4>(-h, -v, +h, +v); }
with_paddingkfr::CMT_ARCH_NAME::rectangle344 constexpr rectangle with_padding(T h, T v) const { return this->v + vec<T, 4>(+h, +v, -h, -v); }
with_paddingkfr::CMT_ARCH_NAME::rectangle345 constexpr rectangle with_padding(T x1, T y1, T x2, T y2) const
346 {
347 return v + vec<T, 4>(+x1, +y1, -x2, -y2);
348 }
with_marginkfr::CMT_ARCH_NAME::rectangle349 constexpr rectangle with_margin(T m) const { return v + vec<T, 4>(-m, -m, +m, +m); }
with_paddingkfr::CMT_ARCH_NAME::rectangle350 constexpr rectangle with_padding(T p) const { return v + vec<T, 4>(+p, +p, -p, -p); }
351
with_paddingkfr::CMT_ARCH_NAME::rectangle352 constexpr rectangle with_padding(const border<T>& p) const { return v + vec<T, 4>(1, 1, -1, -1) * p.v; }
with_marginkfr::CMT_ARCH_NAME::rectangle353 constexpr rectangle with_margin(const border<T>& m) const { return v + vec<T, 4>(-1, -1, 1, 1) * m.v; }
354
flippedkfr::CMT_ARCH_NAME::rectangle355 constexpr rectangle flipped() const { return kfr::swap(v); }
356
roundkfr::CMT_ARCH_NAME::rectangle357 constexpr rectangle round() const { return kfr::round(v); }
floorkfr::CMT_ARCH_NAME::rectangle358 constexpr rectangle floor() const { return kfr::floor(v); }
ceilkfr::CMT_ARCH_NAME::rectangle359 constexpr rectangle ceil() const { return kfr::ceil(v); }
trunckfr::CMT_ARCH_NAME::rectangle360 constexpr rectangle trunc() const { return kfr::trunc(v); }
361
containskfr::CMT_ARCH_NAME::rectangle362 bool contains(const point<T, maximum>& pt) const { return all(pt.v >= p1.v && pt.v < p2.v); }
363
operator <<kfr::CMT_ARCH_NAME::rectangle364 bool operator<<(const point<T, maximum>& pt) const { return contains(pt); }
365
operator ==kfr::CMT_ARCH_NAME::rectangle366 constexpr bool operator==(const rectangle& c) const { return all(v == c.v); }
operator !=kfr::CMT_ARCH_NAME::rectangle367 constexpr bool operator!=(const rectangle& c) const { return !(*this == c); }
368
operator &kfr::CMT_ARCH_NAME::rectangle369 constexpr rectangle operator&(const rectangle& c) const
370 {
371 return blend<0, 0, 1, 1>(min(v, c.v), max(v, c.v));
372 }
operator |kfr::CMT_ARCH_NAME::rectangle373 constexpr rectangle operator|(const rectangle& c) const
374 {
375 return blend<1, 1, 0, 0>(min(v, c.v), max(v, c.v));
376 }
377
operator &=kfr::CMT_ARCH_NAME::rectangle378 rectangle& operator&=(const rectangle& c) { return *this = *this & c; }
operator |=kfr::CMT_ARCH_NAME::rectangle379 rectangle& operator|=(const rectangle& c) { return *this = *this | c; }
380
381 union {
382 struct
383 {
384 T x1;
385 T y1;
386 T x2;
387 T y2;
388 };
389 struct
390 {
391 point<T> p1;
392 point<T> p2;
393 };
394 struct
395 {
396 vec<T, 4> v;
397 };
398 };
399 };
400
401 using f32rectangle = rectangle<f32>;
402 using f32point = point<f32>;
403 using i32point = point<i32>;
404 using f32size = size<f32>;
405 using i32size = size<i32>;
406 using i32rectangle = rectangle<i32>;
407 using i32vector4 = vector4<i32>;
408 using f32vector4 = vector4<f32>;
409
410 template <typename T>
min(const size<T> & a,const size<T> & b)411 CMT_INTRINSIC size<T> min(const size<T>& a, const size<T>& b)
412 {
413 return { min(a.x, b.x), min(a.y, b.y) };
414 }
415 template <typename T>
max(const size<T> & a,const size<T> & b)416 CMT_INTRINSIC size<T> max(const size<T>& a, const size<T>& b)
417 {
418 return { max(a.x, b.x), max(a.y, b.y) };
419 }
420
421 /// @brief 2D matrix
422 template <typename T>
423 struct matrix
424 {
425 union {
426 vec<T, 6> v;
427 struct
428 {
429 T a, b, c, d, e, f;
430 };
431 };
432
matrixkfr::CMT_ARCH_NAME::matrix433 matrix() : v{ 1, 0, 0, 1, 0, 0 } {}
434
matrixkfr::CMT_ARCH_NAME::matrix435 matrix(T a, T b, T c, T d, T e, T f) : v{ a, b, c, d, e, f } {}
436
translatekfr::CMT_ARCH_NAME::matrix437 static matrix translate(T x, T y) { return matrix{ 1, 0, 0, 1, x, y }; }
scalekfr::CMT_ARCH_NAME::matrix438 static matrix scale(T x, T y) { return matrix{ x, 0, 0, y, 0, 0 }; }
rotatekfr::CMT_ARCH_NAME::matrix439 static matrix rotate(T angle) { return matrix{ cos(angle), sin(angle), -sin(angle), cos(angle), 0, 0 }; }
440
rotate90kfr::CMT_ARCH_NAME::matrix441 static matrix rotate90(int angle)
442 {
443 static const matrix m[4] = {
444 { 1, 0, 0, 1, 0, 0 }, { 0, 1, -1, 0, 0, 0 }, { -1, 0, 0, -1, 0, 0 }, { 0, -1, 1, 0, 0, 0 }
445 };
446 return m[angle % 4];
447 }
448
fullkfr::CMT_ARCH_NAME::matrix449 std::array<std::array<T, 3>, 3> full() const
450 {
451 return { { { a, b, T() }, { c, d, T() }, { e, f, T(1) } } };
452 }
453
operator *(const matrix<T> & m,const matrix<T> & n)454 friend matrix<T> operator*(const matrix<T>& m, const matrix<T>& n)
455 {
456 const std::array<std::array<T, 3>, 3> mm = m.full();
457 const std::array<std::array<T, 3>, 3> nn = n.full();
458 std::array<std::array<T, 3>, 3> a;
459 for (size_t i = 0; i < 3; i++)
460 {
461 for (size_t j = 0; j < 3; j++)
462 {
463 T sum = 0;
464 for (size_t k = 0; k < 3; k++)
465 {
466 sum += mm[i][k] * nn[k][j];
467 }
468 a[i][j] = sum;
469 }
470 }
471 return { a[0][0], a[0][1], a[1][0], a[1][1], a[2][0], a[2][1] };
472 }
473
operator *(const point<T> & pt,const matrix<T> & m)474 friend point<T> operator*(const point<T>& pt, const matrix<T>& m)
475 {
476 return { pt.x * m.a + pt.y * m.c + m.e, pt.y * m.d + pt.x * m.b + m.f };
477 }
478 };
479
480 using f32matrix = matrix<f32>;
481 } // namespace CMT_ARCH_NAME
482 } // namespace kfr
483
484 namespace cometa
485 {
486 template <typename T, int maximum>
487 struct representation<kfr::point<T, maximum>>
488 {
489 using type = std::string;
getcometa::representation490 static std::string get(const kfr::point<T, maximum>& value) noexcept
491 {
492 return as_string("point(", value.x, ", ", value.y, ")");
493 }
494 };
495 template <typename T, int maximum>
496 struct representation<kfr::size<T, maximum>>
497 {
498 using type = std::string;
getcometa::representation499 static std::string get(const kfr::size<T, maximum>& value) noexcept
500 {
501 return as_string("size(", value.x, ", ", value.y, ")");
502 }
503 };
504 template <typename T, int maximum>
505 struct representation<kfr::border<T, maximum>>
506 {
507 using type = std::string;
getcometa::representation508 static std::string get(const kfr::border<T, maximum>& value) noexcept
509 {
510 return as_string("border(", value.x1, ", ", value.y1, ", ", value.x2, ", ", value.y2, ")");
511 }
512 };
513 template <typename T, int maximum>
514 struct representation<kfr::rectangle<T, maximum>>
515 {
516 using type = std::string;
getcometa::representation517 static std::string get(const kfr::rectangle<T, maximum>& value) noexcept
518 {
519 return as_string("rectangle(", value.x1, ", ", value.y1, ", ", value.x2, ", ", value.y2, ")");
520 }
521 };
522 } // namespace cometa
523