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