/* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include "BLI_assert.h" #include "BLI_math_base.h" #include "BLI_math_matrix.h" #include "BLI_math_vec_types.hh" #include "BLI_math_vector.h" namespace blender { struct float3x3 { /* A 3x3 matrix in column major order. */ float values[3][3]; float3x3() = default; float3x3(const float *matrix) { memcpy(values, matrix, sizeof(float) * 3 * 3); } float3x3(const float matrix[3][3]) : float3x3(static_cast(matrix[0])) { } static float3x3 zero() { float3x3 result; zero_m3(result.values); return result; } static float3x3 identity() { float3x3 result; unit_m3(result.values); return result; } static float3x3 from_translation(const float2 translation) { float3x3 result = identity(); result.values[2][0] = translation.x; result.values[2][1] = translation.y; return result; } static float3x3 from_rotation(float rotation) { float3x3 result = zero(); const float cosine = std::cos(rotation); const float sine = std::sin(rotation); result.values[0][0] = cosine; result.values[0][1] = sine; result.values[1][0] = -sine; result.values[1][1] = cosine; result.values[2][2] = 1.0f; return result; } static float3x3 from_scale(const float2 scale) { float3x3 result = zero(); result.values[0][0] = scale.x; result.values[1][1] = scale.y; result.values[2][2] = 1.0f; return result; } static float3x3 from_translation_rotation_scale(const float2 translation, float rotation, const float2 scale) { float3x3 result; const float cosine = std::cos(rotation); const float sine = std::sin(rotation); result.values[0][0] = scale.x * cosine; result.values[0][1] = scale.x * sine; result.values[0][2] = 0.0f; result.values[1][0] = scale.y * -sine; result.values[1][1] = scale.y * cosine; result.values[1][2] = 0.0f; result.values[2][0] = translation.x; result.values[2][1] = translation.y; result.values[2][2] = 1.0f; return result; } static float3x3 from_normalized_axes(const float2 translation, const float2 horizontal, const float2 vertical) { BLI_ASSERT_UNIT_V2(horizontal); BLI_ASSERT_UNIT_V2(vertical); float3x3 result; result.values[0][0] = horizontal.x; result.values[0][1] = horizontal.y; result.values[0][2] = 0.0f; result.values[1][0] = vertical.x; result.values[1][1] = vertical.y; result.values[1][2] = 0.0f; result.values[2][0] = translation.x; result.values[2][1] = translation.y; result.values[2][2] = 1.0f; return result; } /* Construct a transformation that is pivoted around the given origin point. So for instance, * from_origin_transformation(from_rotation(M_PI_2), float2(0.0f, 2.0f)) * will construct a transformation representing a 90 degree rotation around the point (0, 2). */ static float3x3 from_origin_transformation(const float3x3 &transformation, const float2 origin) { return from_translation(origin) * transformation * from_translation(-origin); } operator float *() { return &values[0][0]; } operator const float *() const { return &values[0][0]; } float *operator[](const int64_t index) { BLI_assert(index >= 0); BLI_assert(index < 3); return &values[index][0]; } const float *operator[](const int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < 3); return &values[index][0]; } using c_style_float3x3 = float[3][3]; c_style_float3x3 &ptr() { return values; } const c_style_float3x3 &ptr() const { return values; } friend float3x3 operator*(const float3x3 &a, const float3x3 &b) { float3x3 result; mul_m3_m3m3(result.values, a.values, b.values); return result; } friend float3 operator*(const float3x3 &a, const float3 &b) { float3 result; mul_v3_m3v3(result, a.values, b); return result; } void operator*=(const float3x3 &other) { mul_m3_m3_post(values, other.values); } friend float2 operator*(const float3x3 &transformation, const float2 &vector) { float2 result; mul_v2_m3v2(result, transformation.values, vector); return result; } friend float2 operator*(const float3x3 &transformation, const float (*vector)[2]) { return transformation * float2(vector); } float3x3 transposed() const { float3x3 result; transpose_m3_m3(result.values, values); return result; } float3x3 inverted() const { float3x3 result; invert_m3_m3(result.values, values); return result; } float2 scale_2d() const { float2 scale; mat3_to_size_2d(scale, values); return scale; } friend bool operator==(const float3x3 &a, const float3x3 &b) { return equals_m3m3(a.values, b.values); } }; } // namespace blender