mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-12-22 06:09:49 +01:00
Math: add Mat3x3 (#14)
This commit is contained in:
parent
d97af4f6bd
commit
a9f85a4bca
4 changed files with 215 additions and 1 deletions
59
include/hyprutils/math/Mat3x3.hpp
Normal file
59
include/hyprutils/math/Mat3x3.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
#include "./Misc.hpp"
|
||||
|
||||
namespace Hyprutils {
|
||||
namespace Math {
|
||||
class CBox;
|
||||
class Vector2D;
|
||||
|
||||
class Mat3x3 {
|
||||
public:
|
||||
Mat3x3();
|
||||
Mat3x3(std::array<float, 9>);
|
||||
Mat3x3(std::vector<float>);
|
||||
|
||||
/* create an identity 3x3 matrix */
|
||||
static Mat3x3 identity();
|
||||
|
||||
/* create an output projection matrix */
|
||||
static Mat3x3 outputProjection(const Vector2D& size, eTransform transform);
|
||||
|
||||
/* get the matrix as an array, in a RTL TTB order. */
|
||||
std::array<float, 9> getMatrix() const;
|
||||
|
||||
/* create a box projection matrix */
|
||||
Mat3x3 projectBox(const CBox& box, eTransform transform, float rot = 0.F /* rad, CCW */) const;
|
||||
|
||||
/* in-place functions */
|
||||
Mat3x3& transform(eTransform transform);
|
||||
Mat3x3& rotate(float rot /* rad, CCW */);
|
||||
Mat3x3& scale(const Vector2D& scale);
|
||||
Mat3x3& scale(const float scale);
|
||||
Mat3x3& translate(const Vector2D& offset);
|
||||
Mat3x3& transpose();
|
||||
Mat3x3& multiply(const Mat3x3& other);
|
||||
|
||||
/* misc utils */
|
||||
Mat3x3 copy() const;
|
||||
std::string toString() const;
|
||||
|
||||
bool operator==(const Mat3x3& other) const {
|
||||
return other.matrix == matrix;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Mat3x3& mat) {
|
||||
os << mat.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<float, 9> matrix;
|
||||
};
|
||||
}
|
||||
}
|
145
src/math/Mat3x3.cpp
Normal file
145
src/math/Mat3x3.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include <hyprutils/math/Mat3x3.hpp>
|
||||
#include <hyprutils/math/Vector2D.hpp>
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
#include <format>
|
||||
|
||||
using namespace Hyprutils::Math;
|
||||
|
||||
static std::unordered_map<eTransform, Mat3x3> transforms = {
|
||||
{HYPRUTILS_TRANSFORM_NORMAL, std::array<float, 9>{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_90, std::array<float, 9>{0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_180, std::array<float, 9>{-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_270, std::array<float, 9>{0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED, std::array<float, 9>{-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_90, std::array<float, 9>{0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_180, std::array<float, 9>{1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
{HYPRUTILS_TRANSFORM_FLIPPED_270, std::array<float, 9>{0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}},
|
||||
};
|
||||
|
||||
Mat3x3::Mat3x3() {
|
||||
matrix = {0};
|
||||
}
|
||||
|
||||
Mat3x3::Mat3x3(std::array<float, 9> mat) : matrix(mat) {
|
||||
;
|
||||
}
|
||||
|
||||
Mat3x3::Mat3x3(std::vector<float> mat) {
|
||||
for (size_t i = 0; i < 9; ++i) {
|
||||
matrix.at(i) = mat.size() < i ? mat.at(i) : 0.F;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::identity() {
|
||||
return Mat3x3(std::array<float, 9>{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f});
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::outputProjection(const Vector2D& size, eTransform transform) {
|
||||
Mat3x3 mat;
|
||||
|
||||
const auto& t = transforms.at(transform);
|
||||
float x = 2.0f / size.x;
|
||||
float y = 2.0f / size.y;
|
||||
|
||||
// Rotation + reflection
|
||||
mat.matrix[0] = x * t.matrix[0];
|
||||
mat.matrix[1] = x * t.matrix[1];
|
||||
mat.matrix[3] = y * t.matrix[3];
|
||||
mat.matrix[4] = y * t.matrix[4];
|
||||
|
||||
// Translation
|
||||
mat.matrix[2] = -copysign(1.0f, mat.matrix[0] + mat.matrix[1]);
|
||||
mat.matrix[5] = -copysign(1.0f, mat.matrix[3] + mat.matrix[4]);
|
||||
|
||||
// Identity
|
||||
mat.matrix[8] = 1.0f;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
std::array<float, 9> Mat3x3::getMatrix() const {
|
||||
return matrix;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::projectBox(const CBox& box, eTransform transform, float rot /* rad, CCW */) const {
|
||||
Mat3x3 mat = Mat3x3::identity();
|
||||
|
||||
const auto boxSize = box.size();
|
||||
|
||||
mat.translate(box.pos());
|
||||
|
||||
if (rot != 0) {
|
||||
mat.translate(boxSize / 2);
|
||||
mat.rotate(rot);
|
||||
mat.translate(-boxSize / 2);
|
||||
}
|
||||
|
||||
mat.scale(boxSize);
|
||||
|
||||
if (transform != HYPRUTILS_TRANSFORM_NORMAL) {
|
||||
mat.translate({0.5, 0.5});
|
||||
mat.transform(transform);
|
||||
mat.translate({-0.5, -0.5});
|
||||
}
|
||||
|
||||
return this->copy().multiply(mat);
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::transform(eTransform transform) {
|
||||
multiply(transforms.at(transform));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::rotate(float rot) {
|
||||
multiply(std::array<float, 9>{(float)cos(rot), (float)-sin(rot), 0.0f, (float)sin(rot), (float)cos(rot), 0.0f, 0.0f, 0.0f, 1.0f});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::scale(const Vector2D& scale_) {
|
||||
multiply(std::array<float, 9>{(float)scale_.x, 0.0f, 0.0f, 0.0f, (float)scale_.y, 0.0f, 0.0f, 0.0f, 1.0f});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::scale(const float scale_) {
|
||||
return scale({scale_, scale_});
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::translate(const Vector2D& offset) {
|
||||
multiply(std::array<float, 9>{1.0f, 0.0f, (float)offset.x, 0.0f, 1.0f, (float)offset.y, 0.0f, 0.0f, 1.0f});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::transpose() {
|
||||
matrix = std::array<float, 9>{matrix[0], matrix[3], matrix[6], matrix[1], matrix[4], matrix[7], matrix[2], matrix[5], matrix[8]};
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3& Mat3x3::multiply(const Mat3x3& other) {
|
||||
std::array<float, 9> product;
|
||||
|
||||
product[0] = matrix[0] * other.matrix[0] + matrix[1] * other.matrix[3] + matrix[2] * other.matrix[6];
|
||||
product[1] = matrix[0] * other.matrix[1] + matrix[1] * other.matrix[4] + matrix[2] * other.matrix[7];
|
||||
product[2] = matrix[0] * other.matrix[2] + matrix[1] * other.matrix[5] + matrix[2] * other.matrix[8];
|
||||
|
||||
product[3] = matrix[3] * other.matrix[0] + matrix[4] * other.matrix[3] + matrix[5] * other.matrix[6];
|
||||
product[4] = matrix[3] * other.matrix[1] + matrix[4] * other.matrix[4] + matrix[5] * other.matrix[7];
|
||||
product[5] = matrix[3] * other.matrix[2] + matrix[4] * other.matrix[5] + matrix[5] * other.matrix[8];
|
||||
|
||||
product[6] = matrix[6] * other.matrix[0] + matrix[7] * other.matrix[3] + matrix[8] * other.matrix[6];
|
||||
product[7] = matrix[6] * other.matrix[1] + matrix[7] * other.matrix[4] + matrix[8] * other.matrix[7];
|
||||
product[8] = matrix[6] * other.matrix[2] + matrix[7] * other.matrix[5] + matrix[8] * other.matrix[8];
|
||||
|
||||
matrix = product;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::copy() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string Mat3x3::toString() const {
|
||||
return std::format("[mat3x3: {}, {}, {}, {}, {}, {}, {}, {}, {}]", matrix.at(0), matrix.at(1), matrix.at(2), matrix.at(3), matrix.at(4), matrix.at(5), matrix.at(6),
|
||||
matrix.at(7), matrix.at(8));
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <hyprutils/math/Region.hpp>
|
||||
#include <hyprutils/math/Mat3x3.hpp>
|
||||
#include "shared.hpp"
|
||||
|
||||
using namespace Hyprutils::Math;
|
||||
|
@ -85,5 +86,14 @@ int main(int argc, char** argv, char** envp) {
|
|||
EXPECT(box.inside(CBox(0, 0, 100, 100)), false);
|
||||
}
|
||||
|
||||
// Test matrices
|
||||
{
|
||||
Mat3x3 jeremy = Mat3x3::outputProjection({1920, 1080}, HYPRUTILS_TRANSFORM_FLIPPED_90);
|
||||
Mat3x3 matrixBox = jeremy.projectBox(CBox{10, 10, 200, 200}, HYPRUTILS_TRANSFORM_NORMAL).translate({100, 100}).scale({1.25F, 1.5F}).transpose();
|
||||
|
||||
Mat3x3 expected = std::array<float, 9>{0, 0.46296296, 0, 0.3125, 0, 0, 19.84375, 36.055557, 1};
|
||||
EXPECT(matrixBox, expected);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace Colors {
|
|||
|
||||
#define EXPECT(expr, val) \
|
||||
if (const auto RESULT = expr; RESULT != (val)) { \
|
||||
std::cout << Colors::RED << "Failed: " << Colors::RESET << #expr << ", expected " << #val << " but got " << RESULT << "\n"; \
|
||||
std::cout << Colors::RED << "Failed: " << Colors::RESET << #expr << ", expected " << val << " but got " << RESULT << "\n"; \
|
||||
ret = 1; \
|
||||
} else { \
|
||||
std::cout << Colors::GREEN << "Passed " << Colors::RESET << #expr << ". Got " << val << "\n"; \
|
||||
|
|
Loading…
Reference in a new issue