aboutsummaryrefslogtreecommitdiff
path: root/include/cru/platform/Matrix.hpp
blob: 47917d47a531e7414cf0f08e8e9c18e84ef253fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#pragma once
#include "GraphicsBase.hpp"

#include <cmath>
#include <optional>

namespace cru::platform {
struct Matrix {
  float m11;
  float m12;
  float m21;
  float m22;
  float m31;
  float m32;

  Matrix() {}

  Matrix(float m11, float m12, float m21, float m22, float m31, float m32) {
    this->m11 = m11;
    this->m12 = m12;
    this->m21 = m21;
    this->m22 = m22;
    this->m31 = m31;
    this->m32 = m32;
  }

  bool IsIdentity() const {
    return m11 == 1.0f && m12 == 0.0f && m21 == 0.0f && m22 == 1.0f &&
           m31 == 0.0f && m32 == 0.0f;
  }

  Matrix& operator*=(const Matrix& matrix) {
    *this = Product(*this, matrix);
    return *this;
  }

  Matrix operator*(const Matrix& matrix) const {
    return Product(*this, matrix);
  }

  Point TransformPoint(const Point& point) const {
    return Point{point.x * m11 + point.y * m21 + m31,
                 point.x * m12 + point.y * m22 + m32};
  }

  Rect TransformRect(const Rect& rect, bool normalize = true) const {
    Point lefttop = TransformPoint(rect.GetLeftTop()),
          rightbottom = TransformPoint(rect.GetRightBottom());
    auto result =
        Rect::FromVertices(lefttop.x, lefttop.y, rightbottom.x, rightbottom.y);
    if (normalize) result = result.Normalize();
    return result;
  }

  static Matrix Identity() {
    return Matrix{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
  }

  static Matrix Translation(float x, float y) {
    return Matrix{1.0f, 0.0f, 0.0f, 1.0f, x, y};
  }

  static Matrix Translation(const Point& point) {
    return Translation(point.x, point.y);
  }

  static Matrix Scale(float sx, float sy) {
    return Matrix{sx, 0.0f, 0.0f, sy, 0.0f, 0.0f};
  }

  // Clockwise.
  static Matrix Rotation(float angle) {
    float r = AngleToRadian(angle);
    float s = std::sin(r);
    float c = std::cos(r);

    return Matrix{c, s, -s, c, 0.0f, 0.0f};
  }

  static Matrix Skew(float sx, float sy) {
    return Matrix{1.0f, sx, sy, 1.0f, 0.0f, 0.0f};
  }

  static Matrix Product(const Matrix& a, const Matrix& b) {
    return Matrix{a.m11 * b.m11 + a.m12 * b.m21,
                  a.m11 * b.m12 + a.m12 * b.m22,
                  a.m21 * b.m11 + a.m22 * b.m21,
                  a.m21 * b.m12 + a.m22 * b.m22,
                  a.m31 * b.m11 + a.m32 * b.m21 + b.m31,
                  a.m31 * b.m12 + a.m32 * b.m22 + b.m32};
  }

  std::optional<Matrix> Inverted() const {
    if (m11 * m22 == m12 * m21) return std::nullopt;
    Matrix result;
    result.m11 = m22 / (m11 * m22 - m12 * m21);
    result.m12 = m12 / (m12 * m21 - m11 * m22);
    result.m21 = m21 / (m12 * m21 - m11 * m22);
    result.m22 = m11 / (m11 * m22 - m12 * m21);
    result.m31 = (m21 * m32 - m22 * m31) / (m11 * m22 - m12 * m21);
    result.m32 = (m31 * m12 - m11 * m32) / (m11 * m22 - m12 * m21);
    return result;
  }

 private:
  static constexpr float PI = 3.1415926535f;

  static float AngleToRadian(float angle) { return angle / 180.f * PI; }
};
}  // namespace cru::platform