💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1199 lines
35 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_MATRIX_HPP
  20. #define ANTKEEPER_MATH_MATRIX_HPP
  21. #include "math/vector.hpp"
  22. #include <cstddef>
  23. #include <istream>
  24. #include <iterator>
  25. #include <ostream>
  26. #include <type_traits>
  27. #include <utility>
  28. namespace math {
  29. /**
  30. * *n* by *m* column-major matrix.
  31. *
  32. * @tparam T Matrix element data type.
  33. * @tparam N Number of columns.
  34. * @tparam M Number of rows.
  35. *
  36. * @see https://en.wikipedia.org/wiki/Row-_and_column-major_order
  37. */
  38. template <typename T, std::size_t N, std::size_t M>
  39. struct matrix
  40. {
  41. /// Matrix element data type.
  42. typedef T element_type;
  43. /// Number of matrix columns.
  44. static constexpr std::size_t column_count = N;
  45. /// Number of matrix rows.
  46. static constexpr std::size_t row_count = M;
  47. /// Number of matrix elements.
  48. static constexpr std::size_t element_count = column_count * row_count;
  49. /// Matrix column vector data type.
  50. typedef vector<element_type, row_count> column_vector_type;
  51. /// Matrix row vector data type.
  52. typedef vector<element_type, column_count> row_vector_type;
  53. /// Array of matrix column vectors.
  54. column_vector_type columns[column_count];
  55. /**
  56. * Returns a reference to the column vector at a given index.
  57. *
  58. * @param i Index of a column vector.
  59. *
  60. * @return Reference to the column vector at index @p i.
  61. */
  62. /// @{
  63. constexpr inline column_vector_type& operator[](std::size_t i) noexcept
  64. {
  65. return columns[i];
  66. }
  67. constexpr inline const column_vector_type& operator[](std::size_t i) const noexcept
  68. {
  69. return columns[i];
  70. }
  71. constexpr inline column_vector_type& column(std::size_t i) noexcept
  72. {
  73. return columns[i];
  74. }
  75. constexpr inline const column_vector_type& column(std::size_t i) const noexcept
  76. {
  77. return columns[i];
  78. }
  79. /// @}
  80. /**
  81. * Returns a reference to the element at a given column-major index.
  82. *
  83. * @param i Column-major index of a matrix element.
  84. *
  85. * @return Reference to the element at column-major index @p i.
  86. */
  87. /// @{
  88. constexpr inline T& element(std::size_t i) noexcept
  89. {
  90. return columns[i / row_count][i % row_count];
  91. }
  92. constexpr inline const T& element(std::size_t i) const noexcept
  93. {
  94. return columns[i / row_count][i % row_count];
  95. }
  96. /// @}
  97. /// Returns a reference to the first column vector.
  98. /// @{
  99. constexpr inline column_vector_type& front() noexcept
  100. {
  101. return columns[0];
  102. }
  103. constexpr inline const column_vector_type& front() const noexcept
  104. {
  105. return columns[0];
  106. }
  107. /// @}
  108. /// Returns a reference to the last column vector.
  109. /// @{
  110. constexpr inline column_vector_type& back() noexcept
  111. {
  112. return elements[column_count - 1];
  113. }
  114. constexpr inline const column_vector_type& back() const noexcept
  115. {
  116. return elements[column_count - 1];
  117. }
  118. /// @}
  119. /**
  120. * Returns a pointer to the first element.
  121. *
  122. * @warning If matrix::element_type is not a POD type, elements may not be stored contiguously.
  123. */
  124. /// @{
  125. constexpr inline element_type* data() noexcept
  126. {
  127. return &columns[0][0];
  128. };
  129. constexpr inline const element_type* data() const noexcept
  130. {
  131. return &columns[0][0];
  132. };
  133. /// @}
  134. /// Returns an iterator to the first column vector.
  135. /// @{
  136. constexpr inline column_vector_type* begin() noexcept
  137. {
  138. return columns;
  139. }
  140. constexpr inline const column_vector_type* begin() const noexcept
  141. {
  142. return columns;
  143. }
  144. constexpr inline const column_vector_type* cbegin() const noexcept
  145. {
  146. return columns;
  147. }
  148. /// @}
  149. /// Returns an iterator to the column vector following the last column vector.
  150. /// @{
  151. constexpr inline column_vector_type* end() noexcept
  152. {
  153. return columns + column_count;
  154. }
  155. constexpr inline const column_vector_type* end() const noexcept
  156. {
  157. return columns + column_count;
  158. }
  159. constexpr inline const column_vector_type* cend() const noexcept
  160. {
  161. return columns + column_count;
  162. }
  163. /// @}
  164. /// Returns a reverse iterator to the first column vector of the reversed matrix.
  165. /// @{
  166. constexpr inline std::reverse_iterator<column_vector_type*> rbegin() noexcept
  167. {
  168. return std::reverse_iterator<column_vector_type*>(columns + column_count);
  169. }
  170. constexpr inline std::reverse_iterator<const column_vector_type*> rbegin() const noexcept
  171. {
  172. return std::reverse_iterator<const column_vector_type*>(columns + column_count);
  173. }
  174. constexpr inline std::reverse_iterator<const column_vector_type*> crbegin() const noexcept
  175. {
  176. return std::reverse_iterator<const column_vector_type*>(columns + column_count);
  177. }
  178. /// @}
  179. /// Returns a reverse iterator to the column vector following the last column vector of the reversed matrix.
  180. /// @{
  181. constexpr inline std::reverse_iterator<column_vector_type*> rend() noexcept
  182. {
  183. return std::reverse_iterator<column_vector_type*>(columns);
  184. }
  185. constexpr inline std::reverse_iterator<const column_vector_type*> rend() const noexcept
  186. {
  187. return std::reverse_iterator<const column_vector_type*>(columns);
  188. }
  189. constexpr inline std::reverse_iterator<const column_vector_type*> crend() const noexcept
  190. {
  191. return std::reverse_iterator<const column_vector_type*>(columns);
  192. }
  193. /// @}
  194. /// Returns the number of elements in the matrix.
  195. constexpr inline std::size_t size() const noexcept
  196. {
  197. return element_count;
  198. };
  199. /// @private
  200. template <class U, std::size_t... I>
  201. constexpr inline matrix<U, N, M> type_cast(std::index_sequence<I...>) const noexcept
  202. {
  203. return {vector<U, M>(columns[I])...};
  204. }
  205. /**
  206. * Type-casts the elements of this matrix using `static_cast`.
  207. *
  208. * @tparam U Target element type.
  209. *
  210. * @return Matrix containing the type-casted elements.
  211. */
  212. template <class U>
  213. constexpr inline explicit operator matrix<U, N, M>() const noexcept
  214. {
  215. return type_cast<U>(std::make_index_sequence<N>{});
  216. }
  217. /// @private
  218. template <std::size_t P, std::size_t O, std::size_t... I>
  219. constexpr inline matrix<T, P, O> size_cast(std::index_sequence<I...>) const noexcept
  220. {
  221. if constexpr (O == M)
  222. return {((I < N) ? columns[I] : matrix<T, P, O>::identity()[I]) ...};
  223. else
  224. return {((I < N) ? vector<T, O>(columns[I]) : matrix<T, P, O>::identity()[I]) ...};
  225. }
  226. /**
  227. * Size-casts this matrix to a matrix with different dimensions. Casting to greater dimensions causes new elements to be set to identity matrix elements.
  228. *
  229. * @tparam P Target number of columns.
  230. * @tparam O Target number of rows.
  231. *
  232. * @return *p* by *o* matrix.
  233. */
  234. template <std::size_t P, std::size_t O>
  235. constexpr inline explicit operator matrix<T, P, O>() const noexcept
  236. {
  237. return size_cast<P, O>(std::make_index_sequence<P>{});
  238. }
  239. /// Returns a zero matrix, where every element is equal to zero.
  240. static constexpr matrix zero() noexcept
  241. {
  242. return {};
  243. }
  244. /// @private
  245. template <std::size_t... I>
  246. static constexpr inline matrix one(std::index_sequence<I...>) noexcept
  247. {
  248. //return {column_vector_type::one() ...};
  249. // MSVC bug workaround (I must be referenced for parameter pack expansion)
  250. return {(I ? column_vector_type::one() : column_vector_type::one()) ...};
  251. }
  252. /// Returns a matrix of ones, where every element is equal to one.
  253. static constexpr matrix one() noexcept
  254. {
  255. return one(std::make_index_sequence<column_count>{});
  256. }
  257. /// @private
  258. template <std::size_t... I>
  259. static constexpr inline column_vector_type identity_column(std::size_t i, std::index_sequence<I...>) noexcept
  260. {
  261. return {(I == i ? T{1} : T{0}) ...};
  262. }
  263. /// @private
  264. template <std::size_t... I>
  265. static constexpr inline matrix identity(std::index_sequence<I...>) noexcept
  266. {
  267. return {identity_column(I, std::make_index_sequence<row_count>{}) ...};
  268. }
  269. /// Returns an identity matrix, with ones on the main diagonal and zeros elsewhere.
  270. static constexpr matrix identity() noexcept
  271. {
  272. return identity(std::make_index_sequence<column_count>{});
  273. }
  274. };
  275. /// 2x2 matrix.
  276. template <typename T>
  277. using matrix2 = matrix<T, 2, 2>;
  278. /// 2x2 matrix.
  279. template <typename T>
  280. using matrix2x2 = matrix<T, 2, 2>;
  281. /// 3x3 matrix.
  282. template <typename T>
  283. using matrix3 = matrix<T, 3, 3>;
  284. /// 3x3 matrix.
  285. template <typename T>
  286. using matrix3x3 = matrix<T, 3, 3>;
  287. /// 4x4 matrix.
  288. template <typename T>
  289. using matrix4 = matrix<T, 4, 4>;
  290. /// 4x4 matrix.
  291. template <typename T>
  292. using matrix4x4 = matrix<T, 4, 4>;
  293. /**
  294. * Adds two matrices.
  295. *
  296. * @param a First matrix.
  297. * @param b Second matrix.
  298. *
  299. * @return Sum of the two matrices.
  300. */
  301. template <class T, std::size_t N, std::size_t M>
  302. constexpr matrix<T, N, M> add(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept;
  303. /**
  304. * Adds a matrix and a scalar.
  305. *
  306. * @param a Matrix.
  307. * @param b scalar.
  308. *
  309. * @return Sum of the matrix and scalar.
  310. */
  311. template <class T, std::size_t N, std::size_t M>
  312. constexpr matrix<T, N, M> add(const matrix<T, N, M>& a, T b) noexcept;
  313. /**
  314. * Calculates the determinant of a square matrix.
  315. *
  316. * @param m Matrix of which to take the determinant.
  317. *
  318. * @return Determinant of @p m.
  319. *
  320. * @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
  321. */
  322. template <class T, std::size_t N>
  323. constexpr T determinant(const matrix<T, N, N>& m) noexcept;
  324. /**
  325. * Calculates the inverse of a square matrix.
  326. *
  327. * @param m Matrix of which to take the inverse.
  328. *
  329. * @return Inverse of matrix @p m.
  330. *
  331. * @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
  332. */
  333. template <class T, std::size_t N>
  334. constexpr matrix<T, N, N> inverse(const matrix<T, N, N>& m) noexcept;
  335. /**
  336. * Performs a component-wise multiplication of two matrices.
  337. *
  338. * @param x First matrix multiplicand.
  339. * @param y Second matrix multiplicand.
  340. */
  341. template <class T, std::size_t N, std::size_t M>
  342. constexpr matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept;
  343. /**
  344. * Divides a matrix by a matrix.
  345. *
  346. * @param a First matrix.
  347. * @param b Second matrix.
  348. * @return Result of the division.
  349. */
  350. template <class T, std::size_t N, std::size_t M>
  351. constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept;
  352. /**
  353. * Divides a matrix by a scalar.
  354. *
  355. * @param a Matrix.
  356. * @param b Scalar.
  357. * @return Result of the division.
  358. */
  359. template <class T, std::size_t N, std::size_t M>
  360. constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, T b) noexcept;
  361. /**
  362. * Divides a scalar by a matrix.
  363. *
  364. * @param a Scalar.
  365. * @param b Matrix.
  366. * @return Result of the division.
  367. */
  368. template <class T, std::size_t N, std::size_t M>
  369. constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept;
  370. /**
  371. * Creates a viewing transformation matrix.
  372. *
  373. * @param position Position of the view point.
  374. * @param target Position of the target.
  375. * @param up Normalized direction of the up vector.
  376. * @return Viewing transformation matrix.
  377. */
  378. template <class T>
  379. constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up);
  380. /**
  381. * Multiplies two matrices
  382. *
  383. * @tparam T Matrix element type.
  384. * @tparam N Number of columns in matrix @p a, and rows in matrix @p b.
  385. * @tparam M Number of rows in matrix @p a.
  386. * @tparam P Number of columns in matrix @p b.
  387. *
  388. * @param a First matrix.
  389. * @param b Second matrix.
  390. *
  391. * @return Product of `a * b`.
  392. */
  393. template <typename T, std::size_t N, std::size_t M, std::size_t P>
  394. constexpr matrix<T, P, M> mul(const matrix<T, N, M>& a, const matrix<T, P, N>& b) noexcept;
  395. /**
  396. * Multiplies a matrix by a scalar.
  397. *
  398. * @param a Matrix.
  399. * @param b Scalar.
  400. * @return Product of the matrix and the scalar.
  401. */
  402. template <class T, std::size_t N, std::size_t M>
  403. constexpr matrix<T, N, M> mul(const matrix<T, N, M>& a, T b) noexcept;
  404. /**
  405. * Calculates the product of a matrix and a row vector.
  406. *
  407. * @param a Matrix.
  408. * @param b Row vector
  409. *
  410. * @return Product of the matrix and the row vector.
  411. */
  412. template <typename T, std::size_t N, std::size_t M>
  413. constexpr typename matrix<T, N, M>::column_vector_type mul(const matrix<T, N, M>& a, const typename matrix<T, N, M>::row_vector_type& b) noexcept;
  414. /**
  415. * Calculates the product of a column vector and a matrix.
  416. *
  417. * @param a Column vector.
  418. * @param b Matrix.
  419. *
  420. * @return Product of the column vector and the matrix.
  421. */
  422. template <typename T, std::size_t N, std::size_t M>
  423. constexpr typename matrix<T, N, M>::row_vector_type mul(const typename matrix<T, N, M>::column_vector_type& a, const matrix<T, N, M>& b) noexcept;
  424. /**
  425. * Constructs a rotation matrix.
  426. *
  427. * @param angle Angle of rotation, in radians.
  428. * @param axis Axis of rotation
  429. * @return Rotation matrix.
  430. */
  431. template <class T>
  432. matrix<T, 3, 3> rotate(T angle, const vector<T, 3>& axis);
  433. /**
  434. * Produces a matrix which rotates Cartesian coordinates about the x-axis by a given angle.
  435. *
  436. * @param angle Angle of rotation, in radians.
  437. * @return Rotation matrix.
  438. */
  439. template <class T>
  440. matrix3<T> rotate_x(T angle);
  441. /**
  442. * Produces a matrix which rotates Cartesian coordinates about the y-axis by a given angle.
  443. *
  444. * @param angle Angle of rotation, in radians.
  445. * @return Rotation matrix.
  446. */
  447. template <class T>
  448. matrix3<T> rotate_y(T angle);
  449. /**
  450. * Produces a matrix which rotates Cartesian coordinates about the z-axis by a given angle.
  451. *
  452. * @param angle Angle of rotation, in radians.
  453. * @return Rotation matrix.
  454. */
  455. template <class T>
  456. matrix3<T> rotate_z(T angle);
  457. /**
  458. * Scales a matrix.
  459. *
  460. * @param m Matrix to scale.
  461. * @param v Scale vector.
  462. * @return Scaled matrix.
  463. */
  464. template <class T>
  465. constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
  466. /**
  467. * Subtracts a matrix from another matrix.
  468. *
  469. * @param a First matrix.
  470. * @param b Second matrix.
  471. *
  472. * @return Difference between the two matrices.
  473. */
  474. template <class T, std::size_t N, std::size_t M>
  475. constexpr matrix<T, N, M> sub(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept;
  476. /**
  477. * Subtracts a scalar from matrix.
  478. *
  479. * @param a Matrix.
  480. * @param b Scalar.
  481. *
  482. * @return Difference between the matrix and scalar.
  483. */
  484. template <class T, std::size_t N, std::size_t M>
  485. constexpr matrix<T, N, M> sub(const matrix<T, N, M>& a, T b) noexcept;
  486. /**
  487. * Subtracts a matrix from a scalar.
  488. *
  489. * @param a Scalar.
  490. * @param b Matrix.
  491. *
  492. * @return Difference between the scalar and matrix.
  493. */
  494. template <class T, std::size_t N, std::size_t M>
  495. constexpr matrix<T, N, M> sub(T a, const matrix<T, N, M>& b) noexcept;
  496. /**
  497. * Translates a matrix.
  498. *
  499. * @param m Matrix to translate.
  500. * @param v Translation vector.
  501. * @return Translated matrix.
  502. */
  503. template <class T>
  504. constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v);
  505. /**
  506. * Calculates the transpose of a matrix.
  507. *
  508. * @param m Matrix to transpose.
  509. *
  510. * @return Transposed matrix.
  511. */
  512. template <typename T, std::size_t N, std::size_t M>
  513. constexpr matrix<T, M, N> transpose(const matrix<T, N, M>& m) noexcept;
  514. /// @private
  515. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  516. constexpr inline matrix<T, N, M> add(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  517. {
  518. return {(a[I] + b[I]) ...};
  519. }
  520. template <class T, std::size_t N, std::size_t M>
  521. constexpr matrix<T, N, M> add(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  522. {
  523. return add(a, b, std::make_index_sequence<N>{});
  524. }
  525. /// @private
  526. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  527. constexpr inline matrix<T, N, M> add(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
  528. {
  529. return {(a[I] + b) ...};
  530. }
  531. template <class T, std::size_t N, std::size_t M>
  532. constexpr matrix<T, N, M> add(const matrix<T, N, M>& a, T b) noexcept
  533. {
  534. return add(a, b, std::make_index_sequence<N>{});
  535. }
  536. template <class T>
  537. constexpr T determinant(const matrix<T, 2, 2>& m) noexcept
  538. {
  539. return
  540. m[0][0] * m[1][1] -
  541. m[0][1] * m[1][0];
  542. }
  543. template <class T>
  544. constexpr T determinant(const matrix<T, 3, 3>& m) noexcept
  545. {
  546. return
  547. m[0][0] * m[1][1] * m[2][2] +
  548. m[0][1] * m[1][2] * m[2][0] +
  549. m[0][2] * m[1][0] * m[2][1] -
  550. m[0][0] * m[1][2] * m[2][1] -
  551. m[0][1] * m[1][0] * m[2][2] -
  552. m[0][2] * m[1][1] * m[2][0];
  553. }
  554. template <class T>
  555. constexpr T determinant(const matrix<T, 4, 4>& m) noexcept
  556. {
  557. return
  558. m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] -
  559. m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] +
  560. m[0][2] * m[1][1] * m[2][3] * m[3][0] - m[0][1] * m[1][2] * m[2][3] * m[3][0] -
  561. m[0][3] * m[1][2] * m[2][0] * m[3][1] + m[0][2] * m[1][3] * m[2][0] * m[3][1] +
  562. m[0][3] * m[1][0] * m[2][2] * m[3][1] - m[0][0] * m[1][3] * m[2][2] * m[3][1] -
  563. m[0][2] * m[1][0] * m[2][3] * m[3][1] + m[0][0] * m[1][2] * m[2][3] * m[3][1] +
  564. m[0][3] * m[1][1] * m[2][0] * m[3][2] - m[0][1] * m[1][3] * m[2][0] * m[3][2] -
  565. m[0][3] * m[1][0] * m[2][1] * m[3][2] + m[0][0] * m[1][3] * m[2][1] * m[3][2] +
  566. m[0][1] * m[1][0] * m[2][3] * m[3][2] - m[0][0] * m[1][1] * m[2][3] * m[3][2] -
  567. m[0][2] * m[1][1] * m[2][0] * m[3][3] + m[0][1] * m[1][2] * m[2][0] * m[3][3] +
  568. m[0][2] * m[1][0] * m[2][1] * m[3][3] - m[0][0] * m[1][2] * m[2][1] * m[3][3] -
  569. m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3];
  570. }
  571. template <class T>
  572. constexpr matrix<T, 2, 2> inverse(const matrix<T, 2, 2>& m) noexcept
  573. {
  574. const T inv_det = T{1} / determinant(m);
  575. return
  576. {
  577. m[1][1] * inv_det,
  578. -m[0][1] * inv_det,
  579. -m[1][0] * inv_det,
  580. m[0][0] * inv_det
  581. };
  582. }
  583. template <class T>
  584. constexpr matrix<T, 3, 3> inverse(const matrix<T, 3, 3>& m) noexcept
  585. {
  586. const T inv_det = T{1} / determinant(m);
  587. return
  588. {
  589. (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * inv_det,
  590. (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * inv_det,
  591. (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * inv_det,
  592. (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * inv_det,
  593. (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * inv_det,
  594. (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * inv_det,
  595. (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * inv_det,
  596. (m[0][1] * m[2][0] - m[0][0] * m[2][1]) * inv_det,
  597. (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * inv_det
  598. };
  599. }
  600. template <class T>
  601. constexpr matrix<T, 4, 4> inverse(const matrix<T, 4, 4>& m) noexcept
  602. {
  603. const T inv_det = T{1} / determinant(m);
  604. return
  605. {
  606. (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * inv_det,
  607. (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * inv_det,
  608. (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * inv_det,
  609. (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * inv_det,
  610. (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * inv_det,
  611. (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * inv_det,
  612. (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * inv_det,
  613. (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * inv_det,
  614. (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * inv_det,
  615. (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * inv_det,
  616. (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * inv_det,
  617. (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * inv_det,
  618. (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * inv_det,
  619. (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * inv_det,
  620. (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * inv_det,
  621. (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * inv_det
  622. };
  623. }
  624. /// @private
  625. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  626. constexpr inline matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  627. {
  628. return {(a[I] * b[I]) ...};
  629. }
  630. template <class T, std::size_t N, std::size_t M>
  631. constexpr matrix<T, N, M> componentwise_mul(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  632. {
  633. return componentwise_mul(a, b, std::make_index_sequence<N>{});
  634. }
  635. /// @private
  636. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  637. constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  638. {
  639. return {(a[I] / b[I]) ...};
  640. }
  641. template <class T, std::size_t N, std::size_t M>
  642. constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  643. {
  644. return div(a, b, std::make_index_sequence<N>{});
  645. }
  646. /// @private
  647. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  648. constexpr inline matrix<T, N, M> div(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
  649. {
  650. return {(a[I] / b) ...};
  651. }
  652. template <class T, std::size_t N, std::size_t M>
  653. constexpr matrix<T, N, M> div(const matrix<T, N, M>& a, T b) noexcept
  654. {
  655. return div(a, b, std::make_index_sequence<N>{});
  656. }
  657. /// @private
  658. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  659. constexpr inline matrix<T, N, M> div(T a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  660. {
  661. return {(a / b[I]) ...};
  662. }
  663. template <class T, std::size_t N, std::size_t M>
  664. constexpr matrix<T, N, M> div(T a, const matrix<T, N, M>& b) noexcept
  665. {
  666. return div(a, b, std::make_index_sequence<N>{});
  667. }
  668. template <class T>
  669. constexpr matrix<T, 4, 4> look_at(const vector<T, 3>& position, const vector<T, 3>& target, vector<T, 3> up)
  670. {
  671. vector<T, 3> forward = normalize(sub(target, position));
  672. vector<T, 3> right = normalize(cross(forward, up));
  673. up = cross(right, forward);
  674. matrix<T, 4, 4> m =
  675. {{
  676. {right[0], up[0], -forward[0], T(0)},
  677. {right[1], up[1], -forward[1], T(0)},
  678. {right[2], up[2], -forward[2], T(0)},
  679. {T(0), T(0), T(0), T(1)}
  680. }};
  681. return translate(m, negate(position));
  682. }
  683. template <typename T, std::size_t N, std::size_t M, std::size_t P>
  684. constexpr matrix<T, P, M> mul(const matrix<T, N, M>& a, const matrix<T, P, N>& b) noexcept
  685. {
  686. matrix<T, P, M> c = matrix<T, P, M>::zero();
  687. for (std::size_t i = 0; i < P; ++i)
  688. {
  689. for (std::size_t j = 0; j < M; ++j)
  690. {
  691. for (std::size_t k = 0; k < N; ++k)
  692. {
  693. c[i][j] += a[k][j] * b[i][k];
  694. }
  695. }
  696. }
  697. return c;
  698. }
  699. /// @private
  700. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  701. constexpr inline matrix<T, N, M> mul(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
  702. {
  703. return {(a[I] * b) ...};
  704. }
  705. template <class T, std::size_t N, std::size_t M>
  706. constexpr matrix<T, N, M> mul(const matrix<T, N, M>& a, T b) noexcept
  707. {
  708. return mul(a, b, std::make_index_sequence<N>{});
  709. }
  710. /// @private
  711. template <typename T, std::size_t N, std::size_t M, std::size_t... I>
  712. constexpr inline typename matrix<T, N, M>::column_vector_type mul(const matrix<T, N, M>& a, const typename matrix<T, N, M>::row_vector_type& b, std::index_sequence<I...>) noexcept
  713. {
  714. return ((a[I] * b[I]) + ...);
  715. }
  716. template <typename T, std::size_t N, std::size_t M>
  717. constexpr typename matrix<T, N, M>::column_vector_type mul(const matrix<T, N, M>& a, const typename matrix<T, N, M>::row_vector_type& b) noexcept
  718. {
  719. return mul(a, b, std::make_index_sequence<N>{});
  720. }
  721. /// @private
  722. template <typename T, std::size_t N, std::size_t M, std::size_t... I>
  723. constexpr inline typename matrix<T, N, M>::row_vector_type mul(const typename matrix<T, N, M>::column_vector_type& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  724. {
  725. return {dot(a, b[I]) ...};
  726. }
  727. template <typename T, std::size_t N, std::size_t M>
  728. constexpr typename matrix<T, N, M>::row_vector_type mul(const typename matrix<T, N, M>::column_vector_type& a, const matrix<T, N, M>& b) noexcept
  729. {
  730. return mul(a, b, std::make_index_sequence<N>{});
  731. }
  732. template <class T>
  733. matrix<T, 3, 3> rotate(T angle, const vector<T, 3>& axis)
  734. {
  735. const T c = std::cos(angle);
  736. const T s = std::sin(angle);
  737. const vector<T, 3> temp = mul(axis, T(1) - c);
  738. matrix<T, 3, 3> rotation;
  739. rotation[0][0] = axis[0] * temp[0] + c;
  740. rotation[0][1] = axis[1] * temp[0] + axis[2] * s;
  741. rotation[0][2] = axis[2] * temp[0] - axis[1] * s;
  742. rotation[1][0] = axis[0] * temp[1] - axis[2] * s;
  743. rotation[1][1] = axis[1] * temp[1] + c;
  744. rotation[1][2] = axis[2] * temp[1] + axis[0] * s;
  745. rotation[2][0] = axis[0] * temp[2] + axis[1] * s;
  746. rotation[2][1] = axis[1] * temp[2] - axis[0] * s;
  747. rotation[2][2] = axis[2] * temp[2] + c;
  748. return rotation;
  749. }
  750. template <class T>
  751. matrix3<T> rotate_x(T angle)
  752. {
  753. const T c = std::cos(angle);
  754. const T s = std::sin(angle);
  755. return matrix3<T>
  756. {
  757. T(1), T(0), T(0),
  758. T(0), c, s,
  759. T(0), -s, c
  760. };
  761. }
  762. template <class T>
  763. matrix3<T> rotate_y(T angle)
  764. {
  765. const T c = std::cos(angle);
  766. const T s = std::sin(angle);
  767. return matrix3<T>
  768. {
  769. c, T(0), -s,
  770. T(0), T(1), T(0),
  771. s, T(0), c
  772. };
  773. }
  774. template <class T>
  775. matrix3<T> rotate_z(T angle)
  776. {
  777. const T c = std::cos(angle);
  778. const T s = std::sin(angle);
  779. return matrix3<T>
  780. {
  781. c, s, T(0),
  782. -s, c, T(0),
  783. T(0), T(0), T(1)
  784. };
  785. }
  786. template <class T>
  787. constexpr matrix<T, 4, 4> scale(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
  788. {
  789. return mul(m, matrix<T, 4, 4>
  790. {{
  791. {v[0], T(0), T(0), T(0)},
  792. {T(0), v[1], T(0), T(0)},
  793. {T(0), T(0), v[2], T(0)},
  794. {T(0), T(0), T(0), T(1)}
  795. }});
  796. }
  797. /// @private
  798. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  799. constexpr inline matrix<T, N, M> sub(const matrix<T, N, M>& a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  800. {
  801. return {(a[I] - b[I]) ...};
  802. }
  803. template <class T, std::size_t N, std::size_t M>
  804. constexpr matrix<T, N, M> sub(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  805. {
  806. return sub(a, b, std::make_index_sequence<N>{});
  807. }
  808. /// @private
  809. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  810. constexpr inline matrix<T, N, M> sub(const matrix<T, N, M>& a, T b, std::index_sequence<I...>) noexcept
  811. {
  812. return {(a[I] - b) ...};
  813. }
  814. template <class T, std::size_t N, std::size_t M>
  815. constexpr matrix<T, N, M> sub(const matrix<T, N, M>& a, T b) noexcept
  816. {
  817. return sub(a, b, std::make_index_sequence<N>{});
  818. }
  819. /// @private
  820. template <class T, std::size_t N, std::size_t M, std::size_t... I>
  821. constexpr inline matrix<T, N, M> sub(T a, const matrix<T, N, M>& b, std::index_sequence<I...>) noexcept
  822. {
  823. return {(a - b[I]) ...};
  824. }
  825. template <class T, std::size_t N, std::size_t M>
  826. constexpr matrix<T, N, M> sub(T a, const matrix<T, N, M>& b) noexcept
  827. {
  828. return sub(a, b, std::make_index_sequence<N>{});
  829. }
  830. template <class T>
  831. constexpr matrix<T, 4, 4> translate(const matrix<T, 4, 4>& m, const vector<T, 3>& v)
  832. {
  833. return mul(m, matrix<T, 4, 4>
  834. {{
  835. {T(1), T(0), T(0), T(0)},
  836. {T(0), T(1), T(0), T(0)},
  837. {T(0), T(0), T(1), T(0)},
  838. {v[0], v[1], v[2], T(1)}
  839. }});
  840. }
  841. /// @private
  842. template <typename T, std::size_t N, std::size_t M, std::size_t... I>
  843. constexpr inline typename matrix<T, M, N>::column_vector_type transpose_column(const matrix<T, N, M>& m, std::size_t i, std::index_sequence<I...>) noexcept
  844. {
  845. return {m[I][i] ...};
  846. }
  847. /// @private
  848. template <typename T, std::size_t N, std::size_t M, std::size_t... I>
  849. constexpr inline matrix<T, M, N> transpose(const matrix<T, N, M>& m, std::index_sequence<I...>) noexcept
  850. {
  851. return {transpose_column(m, I, std::make_index_sequence<N>{}) ...};
  852. }
  853. template <typename T, std::size_t N, std::size_t M>
  854. constexpr matrix<T, M, N> transpose(const matrix<T, N, M>& m) noexcept
  855. {
  856. return transpose(m, std::make_index_sequence<M>{});
  857. }
  858. namespace operators {
  859. /// @copydoc add(const matrix<T, N, M>&, const matrix<T, N, M>&)
  860. template <class T, std::size_t N, std::size_t M>
  861. constexpr inline matrix<T, N, M> operator+(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  862. {
  863. return add(a, b);
  864. }
  865. /// @copydoc add(const matrix<T, N, M>&, T)
  866. /// @{
  867. template <class T, std::size_t N, std::size_t M>
  868. constexpr inline matrix<T, N, M> operator+(const matrix<T, N, M>& a, T b) noexcept
  869. {
  870. return add(a, b);
  871. }
  872. template <class T, std::size_t N, std::size_t M>
  873. constexpr inline matrix<T, N, M> operator+(T a, const matrix<T, N, M>& b) noexcept
  874. {
  875. return add(b, a);
  876. }
  877. /// @}
  878. /// @copydoc div(const matrix<T, N, M>&, const matrix<T, N, M>&)
  879. template <class T, std::size_t N, std::size_t M>
  880. constexpr inline matrix<T, N, M> operator/(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  881. {
  882. return div(a, b);
  883. }
  884. /// @copydoc div(const matrix<T, N, M>&, T)
  885. template <class T, std::size_t N, std::size_t M>
  886. constexpr inline matrix<T, N, M> operator/(const matrix<T, N, M>& a, T b) noexcept
  887. {
  888. return div(a, b);
  889. }
  890. /// @copydoc div(T, const matrix<T, N, M>&)
  891. template <class T, std::size_t N, std::size_t M>
  892. constexpr inline matrix<T, N, M> operator/(T a, const matrix<T, N, M>& b) noexcept
  893. {
  894. return div(a, b);
  895. }
  896. /// @copydoc mul(const matrix<T, N, M>&, const matrix<T, P, N>&)
  897. template <typename T, std::size_t N, std::size_t M, std::size_t P>
  898. constexpr inline matrix<T, P, M> operator*(const matrix<T, N, M>& a, const matrix<T, P, N>& b) noexcept
  899. {
  900. return mul(a, b);
  901. }
  902. /// @copydoc mul(const matrix<T, N, M>&, T)
  903. /// @{
  904. template <class T, std::size_t N, std::size_t M>
  905. constexpr inline matrix<T, N, M> operator*(const matrix<T, N, M>& a, T b) noexcept
  906. {
  907. return mul(a, b);
  908. }
  909. template <class T, std::size_t N, std::size_t M>
  910. constexpr inline matrix<T, N, M> operator*(T a, const matrix<T, N, M>& b) noexcept
  911. {
  912. return mul(b, a);
  913. }
  914. /// @}
  915. /// @copydoc mul(const matrix<T, N, M>&, const typename matrix<T, N, M>::row_vector_type&)
  916. template <typename T, std::size_t N, std::size_t M>
  917. constexpr inline typename matrix<T, N, M>::column_vector_type operator*(const matrix<T, N, M>& a, const typename matrix<T, N, M>::row_vector_type& b) noexcept
  918. {
  919. return mul(a, b);
  920. }
  921. /// @copydoc mul(const typename matrix<T, N, M>::column_vector_type&, const matrix<T, N, M>&)
  922. template <typename T, std::size_t N, std::size_t M>
  923. constexpr inline typename matrix<T, N, M>::row_vector_type operator*(const typename matrix<T, N, M>::column_vector_type& a, const matrix<T, N, M>& b) noexcept
  924. {
  925. return mul(a, b);
  926. }
  927. /// @copydoc sub(const matrix<T, N, M>&, const matrix<T, N, M>&)
  928. template <class T, std::size_t N, std::size_t M>
  929. constexpr inline matrix<T, N, M> operator-(const matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  930. {
  931. return sub(a, b);
  932. }
  933. /// @copydoc sub(const matrix<T, N, M>&, T)
  934. template <class T, std::size_t N, std::size_t M>
  935. constexpr inline matrix<T, N, M> operator-(const matrix<T, N, M>& a, T b) noexcept
  936. {
  937. return sub(a, b);
  938. }
  939. /// @copydoc sub(T, const matrix<T, N, M>&)
  940. template <class T, std::size_t N, std::size_t M>
  941. constexpr inline matrix<T, N, M> operator-(T a, const matrix<T, N, M>& b) noexcept
  942. {
  943. return sub(a, b);
  944. }
  945. /**
  946. * Adds two values and stores the result in the first value.
  947. *
  948. * @param a First value.
  949. * @param b Second value.
  950. * @return Reference to the first value.
  951. */
  952. /// @{
  953. template <class T, std::size_t N, std::size_t M>
  954. constexpr inline matrix<T, N, M>& operator+=(matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  955. {
  956. return (a = a + b);
  957. }
  958. template <class T, std::size_t N, std::size_t M>
  959. constexpr inline matrix<T, N, M>& operator+=(matrix<T, N, M>& a, T b) noexcept
  960. {
  961. return (a = a + b);
  962. }
  963. /// @}
  964. /**
  965. * Subtracts the first value by the second value and stores the result in the first value.
  966. *
  967. * @param a First value.
  968. * @param b Second value.
  969. * @return Reference to the first value.
  970. */
  971. /// @{
  972. template <class T, std::size_t N, std::size_t M>
  973. constexpr inline matrix<T, N, M>& operator-=(matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  974. {
  975. return (a = a - b);
  976. }
  977. template <class T, std::size_t N, std::size_t M>
  978. constexpr inline matrix<T, N, M>& operator-=(matrix<T, N, M>& a, T b) noexcept
  979. {
  980. return (a = a - b);
  981. }
  982. /// @}
  983. /**
  984. * Multiplies two values and stores the result in the first value.
  985. *
  986. * @param a First value.
  987. * @param b Second value.
  988. * @return Reference to the first value.
  989. */
  990. /// @{
  991. template <class T, std::size_t N>
  992. constexpr inline matrix<T, N, N>& operator*=(matrix<T, N, N>& a, matrix<T, N, N>& b) noexcept
  993. {
  994. return (a = a * b);
  995. }
  996. template <class T, std::size_t N, std::size_t M>
  997. constexpr inline matrix<T, N, M>& operator*=(matrix<T, N, M>& a, T b) noexcept
  998. {
  999. return (a = a * b);
  1000. }
  1001. /// @}
  1002. /**
  1003. * Divides the first value by the second value and stores the result in the first value.
  1004. *
  1005. * @param a First value.
  1006. * @param b Second value.
  1007. * @return Reference to the first value.
  1008. */
  1009. /// @{
  1010. template <class T, std::size_t N, std::size_t M>
  1011. constexpr inline matrix<T, N, M>& operator/=(matrix<T, N, M>& a, const matrix<T, N, M>& b) noexcept
  1012. {
  1013. return (a = a / b);
  1014. }
  1015. template <class T, std::size_t N, std::size_t M>
  1016. constexpr inline matrix<T, N, M>& operator/=(matrix<T, N, M>& a, T b) noexcept
  1017. {
  1018. return (a = a / b);
  1019. }
  1020. /// @}
  1021. /**
  1022. * Writes the elements of a matrix to an output stream, with each element delimeted by a space.
  1023. *
  1024. * @param os Output stream.
  1025. * @param m Matrix.
  1026. * @return Output stream.
  1027. */
  1028. template <class T, std::size_t N, std::size_t M>
  1029. std::ostream& operator<<(std::ostream& os, const matrix<T, N, M>& m)
  1030. {
  1031. for (std::size_t i = 0; i < m.size(); ++i)
  1032. {
  1033. if (i)
  1034. os << ' ';
  1035. os << m.element(i);
  1036. }
  1037. return os;
  1038. }
  1039. /**
  1040. * Reads the elements of a matrix from an input stream, with each element delimeted by a space.
  1041. *
  1042. * @param is Input stream.
  1043. * @param m Matrix.
  1044. * @return Input stream.
  1045. */
  1046. template <class T, std::size_t N, std::size_t M>
  1047. std::istream& operator>>(std::istream& is, matrix<T, N, M>& m)
  1048. {
  1049. for (std::size_t i = 0; i < m.size(); ++i)
  1050. is >> m.element(i);
  1051. return is;
  1052. }
  1053. } // namespace operators
  1054. } // namespace math
  1055. using namespace math::operators;
  1056. #endif // ANTKEEPER_MATH_MATRIX_HPP