Kale
Loading...
Searching...
No Matches
Matrix.hpp
Go to the documentation of this file.
1/*
2 Copyright 2022 Rishi Challa
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#pragma once
18
20
21#include <array>
22#include <algorithm>
23#include <ostream>
24#include <iomanip>
25#include <type_traits>
26#include <limits>
27
28#ifdef KALE_DEBUG
29#include <stdexcept>
30#endif
31
32#include <nlohmann/json.hpp>
33
34namespace Kale {
35
40 using JSON = nlohmann::json;
41
48 template <size_t w, size_t h, typename T>
49 class Matrix {
50 public:
51
55 std::array<T, w*h> data;
56
61 data.fill(static_cast<T>(0));
62 }
63
74 Matrix(const std::array<T, w*h>& arr) : data(arr) {
75 // Empty Body
76 }
77
88 Matrix(std::array<T, w*h>&& arr) : data(std::move(arr)) {
89 // Empty Body
90 }
91
96 inline size_t width() const {
97 return w;
98 }
99
104 inline size_t height() const {
105 return h;
106 }
107
115 inline T& operator[](size_t i) {
116 #ifdef KALE_DEBUG
117 if (i > w*h) throw std::runtime_error("Invalid matrix index");
118 #endif
119 return data[i];
120 }
121
129 inline const T& operator[](size_t i) const {
130 #ifdef KALE_DEBUG
131 if (i > w*h) throw std::runtime_error("Invalid matrix index");
132 #endif
133 return data[i];
134 }
135
143 inline T& operator()(size_t col, size_t row) {
144 #ifdef KALE_DEBUG
145 if (col > w || row > h) throw std::runtime_error("Invalid matrix column/row");
146 #endif
147 return data[row * w + col];
148 }
149
157 inline const T& operator()(size_t col, size_t row) const {
158 #ifdef KALE_DEBUG
159 if (col > w || row > h) throw std::runtime_error("Invalid matrix column/row");
160 #endif
161 return data[row * w + col];
162 }
163
170 inline T& get(size_t i) {
171 return data[i];
172 }
173
180 inline const T& get(size_t i) const {
181 return data[i];
182 }
183
190 inline T& get(size_t col, size_t row) {
191 return data[row * w + col];
192 }
193
200 inline const T& get(size_t col, size_t row) const {
201 return data[row * w + col];
202 }
203
210 Matrix<w, h, T> mat;
211 for (size_t i = 0; i < w*h; i++) mat.data[i] = data[i] + other.data[i];
212 return mat;
213 }
214
221 for (size_t i = 0; i < w*h; i++) other.data[i] += data[i];
222 return Matrix<w, h, T>(std::move(other));
223 }
224
229 void operator+=(const Matrix<w, h, T>& other) {
230 for (size_t i = 0; i < w*h; i++) data[i] += other.data[i];
231 }
232
239 Matrix<w, h, T> mat;
240 for (size_t i = 0; i < w*h; i++) mat.data[i] = data[i] - other.data[i];
241 return mat;
242 }
243
250 for (size_t i = 0; i < w*h; i++) other.data[i] = data[i] - other.data[i];
251 return Matrix<w, h, T>(std::move(other));
252 }
253
258 void operator-=(const Matrix<w, h, T>& other) {
259 for (size_t i = 0; i < w*h; i++) data[i] -= other.data[i];
260 }
261
268 Matrix<w, h, T> mat;
269 for (size_t i = 0; i < w*h; i++) mat.data[i] = data[i] * scalar;
270 return mat;
271 }
272
277 void operator*=(T scalar) {
278 for (size_t i = 0; i < w*h; i++) data[i] *= scalar;
279 }
280
286 template <size_t w2> Matrix<w2, h, T> operator*(const Matrix<w2, w, T>& other) const {
288 for (size_t i = 0; i < h; i++)
289 for (size_t j = 0; j < w2; j++)
290 for (size_t k = 0; k < w; k++)
291 mat.get(j, i) += get(k, i) * other.get(j, k);
292 return mat;
293 }
294
300 Matrix<h, w, T> mat;
301 for (size_t c = 0; c < w; c++)
302 for (size_t r = 0; r < h; r++)
303 mat.get(r, c) = get(c, r);
304 return mat;
305 }
306
307 // >------------------- Elementary Row Operations -------------------<
308
315 void swapRows(size_t row1, size_t row2) {
316 #ifdef KALE_DEBUG
317 if (row1 > h || row2 > h) throw std::runtime_error("Invalid matrix row");
318 #endif
319 std::swap_ranges(data.begin() + row1 * w, data.begin() + row1 * w + w, data.begin() + row2 * w);
320 }
321
328 void scaleRow(size_t row, T scalar) {
329 #ifdef KALE_DEBUG
330 if (row > h) throw std::runtime_error("Invalid matrix row");
331 #endif
332 for (size_t x = 0; x < w; x++) {
333 get(x, row) *= scalar;
334 }
335 }
336
344 void addScaledRow(size_t row1, size_t row2, T scalar) {
345 #ifdef KALE_DEBUG
346 if (row1 > h || row2 > h) throw std::runtime_error("Invalid matrix row");
347 #endif
348 for (size_t x = 0; x < w; x++) {
349 get(x, row1) += scalar * get(x, row2);
350 }
351 }
352
353 // >------------------- Template Specializations -------------------<
354
360 template <size_t W = w, size_t H = h> typename std::enable_if<W == 2 && H == 2, Vector2<T>>::type
361 operator*(const Vector2<T>& vec) const {
362 return Vector2<T>(data[0] * vec.x + data[1] * vec.y, data[2] * vec.x + data[2] * vec.y);
363 }
364
370 template <size_t W = w, size_t H = h> typename std::enable_if<W == 2 && H == 2, Vector2<T>>::type
371 operator*(Vector2<T>&& vec) const {
372 vec.x = data[0] * vec.x + data[1] * vec.y;
373 vec.y = data[2] * vec.x + data[2] * vec.y;
374 return Vector2<T>(std::move(vec));
375 }
376
382 template <size_t W = w, size_t H = h> typename std::enable_if<W == 3 && H == 3, Vector3<T>>::type
383 operator*(const Vector3<T>& vec) const {
384 return Vector3<T>(
385 data[0] * vec.x + data[1] * vec.y + data[2] * vec.z,
386 data[3] * vec.x + data[4] * vec.y + data[5] * vec.z,
387 data[6] * vec.x + data[7] * vec.y + data[8] * vec.z
388 );
389 }
390
396 template <size_t W = w, size_t H = h> typename std::enable_if<W == 3 && H == 3, Vector3<T>>::type
397 operator*(Vector3<T>&& vec) const {
398 vec.x = data[0] * vec.x + data[1] * vec.y + data[2] * vec.z;
399 vec.y = data[3] * vec.x + data[4] * vec.y + data[5] * vec.z;
400 vec.z = data[6] * vec.x + data[7] * vec.y + data[8] * vec.z;
401 return Vector3<T>(std::move(vec));
402 }
403
409 template <size_t W = w, size_t H = h> typename std::enable_if<W == 4 && H == 4, Vector4<T>>::type
410 operator*(const Vector4<T>& vec) const {
411 return Vector4<T>(
412 data[0] * vec.x + data[1] * vec.y + data[2] * vec.z + data[3] * vec.w,
413 data[4] * vec.x + data[5] * vec.y + data[6] * vec.z + data[7] * vec.w,
414 data[8] * vec.x + data[9] * vec.y + data[10] * vec.z + data[11] * vec.w,
415 data[12] * vec.x + data[13] * vec.y + data[14] * vec.z + data[15] * vec.w
416 );
417 }
418
424 template <size_t W = w, size_t H = h> typename std::enable_if<W == 4 && H == 4, Vector4<T>>::type
425 operator*(Vector4<T>&& vec) const {
426 vec.x = data[0] * vec.x + data[1] * vec.y + data[2] * vec.z + data[3] * vec.w;
427 vec.y = data[4] * vec.x + data[5] * vec.y + data[6] * vec.z + data[7] * vec.w;
428 vec.z = data[8] * vec.x + data[9] * vec.y + data[10] * vec.z + data[11] * vec.w;
429 vec.w = data[12] * vec.x + data[13] * vec.y + data[14] * vec.z + data[15] * vec.w;
430 return Vector4<T>(std::move(vec));
431 }
432
438 template <typename R, size_t W = w, size_t H = h>
439 typename std::enable_if<W == 2 && H == 2, R>::type det() const {
440
441 return static_cast<R>(data[0] * data[3] - data[1] * data[2]);
442 }
443
449 template <typename R, size_t W = w, size_t H = h>
450 typename std::enable_if<W == 3 && H == 3, R>::type det() const {
451 return static_cast<R>(
452 data[0] * data[4] * data[8] +
453 data[1] * data[5] * data[6] +
454 data[2] * data[3] * data[7] -
455 data[6] * data[4] * data[2] -
456 data[7] * data[5] * data[0] -
457 data[8] * data[3] * data[1]
458 );
459 }
460
466 template <typename R, size_t W = w, size_t H = h>
467 typename std::enable_if<W == H && (W > 3) && std::is_signed<R>::value, R>::type det() const {
468 throw std::runtime_error("Matrix Determinants are Unimplemented");
469 }
470
475 template <size_t W = w, size_t H = h>
476 typename std::enable_if<W == 2 && H == 2, Matrix<W, H, T>>::type inverse() {
477 return Matrix<W, H, T>({
478 data[3], -data[1],
479 -data[2], data[0]
480 }) * (static_cast<T>(1)/det<T>());
481 }
482
487 template <size_t W = w, size_t H = h>
488 typename std::enable_if<W == 3 && H == 3, Matrix<W, H, T>>::type inverse() {
489 auto calc = [&](size_t a, size_t b, size_t c, size_t d) -> T {
490 return Matrix<2, 2, T>({data[a], data[b], data[c], data[d]}).template det<T>();
491 };
492 return Matrix<3, 3, T>({
493 calc(4, 5, 7, 8), -calc(1, 2, 7, 8), calc(1, 2, 4, 5),
494 -calc(3, 5, 6, 8), calc(0, 2, 6, 8), -calc(0, 2, 3, 5),
495 calc(3, 4, 6, 7), -calc(0, 1, 6, 7), calc(0, 1, 3, 4)
496 }) * (static_cast<T>(1)/det<T>());
497 }
498 };
499
504
509
514
515 template <size_t w, size_t h> using MatrixI = Matrix<w, h, int>;
516 template <size_t w, size_t h> using MatrixL = Matrix<w, h, long>;
517 template <size_t w, size_t h> using MatrixF = Matrix<w, h, float>;
518 template <size_t w, size_t h> using MatrixD = Matrix<w, h, double>;
519
523 template <size_t w, size_t h, typename T>
524 std::ostream& operator<<(std::ostream& os, const Kale::Matrix<w, h, T>& mat) {
525 os << "Mat(Width: " << w << ", Height: " << h << ") :";
526 for (size_t y = 0; y < h; y++) {
527 os << "\n";
528 for (size_t x = 0; x < w; x++) {
529 os << std::setw(5) << std::setfill(' ') << mat(x, y) << " ";
530 }
531 }
532 return os;
533 }
534
538 template <size_t w, size_t h, typename T>
539 void from_json(const JSON& j, Matrix<w, h, T>& p) {
540 p = j.get<std::array<T, w*h>>();
541 }
542
546 template <size_t w, size_t h, typename T>
547 void to_json(JSON& j, const Matrix<w, h, T>& p) {
548 j = JSON(p.data);
549 }
550
551}
T & get(size_t col, size_t row)
Definition Matrix.hpp:190
Matrix(const std::array< T, w *h > &arr)
Definition Matrix.hpp:74
void operator-=(const Matrix< w, h, T > &other)
Definition Matrix.hpp:258
T & get(size_t i)
Definition Matrix.hpp:170
size_t width() const
Definition Matrix.hpp:96
T & operator[](size_t i)
Definition Matrix.hpp:115
std::enable_if< W==4 &&H==4, Vector4< T > >::type operator*(const Vector4< T > &vec) const
Definition Matrix.hpp:410
std::enable_if< W==3 &&H==3, Vector3< T > >::type operator*(const Vector3< T > &vec) const
Definition Matrix.hpp:383
std::enable_if< W==3 &&H==3, R >::type det() const
Definition Matrix.hpp:450
const T & get(size_t col, size_t row) const
Definition Matrix.hpp:200
Matrix< h, w, T > transpose() const
Definition Matrix.hpp:299
void operator+=(const Matrix< w, h, T > &other)
Definition Matrix.hpp:229
std::enable_if< W==3 &&H==3, Vector3< T > >::type operator*(Vector3< T > &&vec) const
Definition Matrix.hpp:397
std::enable_if< W==2 &&H==2, R >::type det() const
Definition Matrix.hpp:439
Matrix< w, h, T > operator+(const Matrix< w, h, T > &other) const
Definition Matrix.hpp:209
void scaleRow(size_t row, T scalar)
Definition Matrix.hpp:328
size_t height() const
Definition Matrix.hpp:104
std::enable_if< W==2 &&H==2, Vector2< T > >::type operator*(const Vector2< T > &vec) const
Definition Matrix.hpp:361
Matrix< w, h, T > operator*(T scalar) const
Definition Matrix.hpp:267
std::enable_if< W==H &&(W >3)&&std::is_signed< R >::value, R >::type det() const
Definition Matrix.hpp:467
const T & get(size_t i) const
Definition Matrix.hpp:180
std::array< T, w *h > data
Definition Matrix.hpp:55
std::enable_if< W==2 &&H==2, Matrix< W, H, T > >::type inverse()
Definition Matrix.hpp:476
std::enable_if< W==2 &&H==2, Vector2< T > >::type operator*(Vector2< T > &&vec) const
Definition Matrix.hpp:371
Matrix(std::array< T, w *h > &&arr)
Definition Matrix.hpp:88
void swapRows(size_t row1, size_t row2)
Definition Matrix.hpp:315
Matrix< w2, h, T > operator*(const Matrix< w2, w, T > &other) const
Definition Matrix.hpp:286
Matrix< w, h, T > operator+(Matrix< w, h, T > &&other) const
Definition Matrix.hpp:220
Matrix< w, h, T > operator-(const Matrix< w, h, T > &other) const
Definition Matrix.hpp:238
const T & operator()(size_t col, size_t row) const
Definition Matrix.hpp:157
void addScaledRow(size_t row1, size_t row2, T scalar)
Definition Matrix.hpp:344
void operator*=(T scalar)
Definition Matrix.hpp:277
T & operator()(size_t col, size_t row)
Definition Matrix.hpp:143
const T & operator[](size_t i) const
Definition Matrix.hpp:129
std::enable_if< W==4 &&H==4, Vector4< T > >::type operator*(Vector4< T > &&vec) const
Definition Matrix.hpp:425
Matrix< w, h, T > operator-(Matrix< w, h, T > &&other) const
Definition Matrix.hpp:249
std::enable_if< W==3 &&H==3, Matrix< W, H, T > >::type inverse()
Definition Matrix.hpp:488
Matrix< 3, 3, double > Matrix3d
Definition Matrix.hpp:508
Matrix< 2, 2, float > Matrix2f
Definition Matrix.hpp:502
nlohmann::json JSON
Definition Scene.hpp:39
void to_json(JSON &j, const Matrix< w, h, T > &p)
Definition Matrix.hpp:547
Matrix< 3, 3, int > Matrix3i
Definition Matrix.hpp:505
Matrix< 3, 3, long > Matrix3l
Definition Matrix.hpp:506
Matrix< 2, 2, double > Matrix2d
Definition Matrix.hpp:503
Matrix< 4, 4, int > Matrix4i
Definition Matrix.hpp:510
Matrix< 2, 2, int > Matrix2i
Definition Matrix.hpp:500
void from_json(const JSON &j, Matrix< w, h, T > &p)
Definition Matrix.hpp:539
Matrix< 4, 4, long > Matrix4l
Definition Matrix.hpp:511
Matrix< 3, 3, float > Matrix3f
Definition Matrix.hpp:507
Matrix< 2, 2, long > Matrix2l
Definition Matrix.hpp:501
Matrix< 4, 4, double > Matrix4d
Definition Matrix.hpp:513
std::ostream & operator<<(std::ostream &os, const Kale::Matrix< w, h, T > &mat)
Definition Matrix.hpp:524
Matrix< 4, 4, float > Matrix4f
Definition Matrix.hpp:512