mirror of
https://github.com/BlackMATov/vmath.hpp.git
synced 2025-12-15 12:39:47 +07:00
basic matrix type
This commit is contained in:
@@ -6,4 +6,5 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vmath_mat.hpp"
|
||||
#include "vmath_vec.hpp"
|
||||
|
||||
@@ -35,3 +35,21 @@ namespace vmath_hpp
|
||||
using vec3f = vec<float, 3>;
|
||||
using vec4f = vec<float, 4>;
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
class mat;
|
||||
|
||||
using mat2i = mat<int, 2>;
|
||||
using mat3i = mat<int, 3>;
|
||||
using mat4i = mat<int, 4>;
|
||||
|
||||
using mat2b = mat<bool, 2>;
|
||||
using mat3b = mat<bool, 3>;
|
||||
using mat4b = mat<bool, 4>;
|
||||
|
||||
using mat2f = mat<float, 2>;
|
||||
using mat3f = mat<float, 3>;
|
||||
using mat4f = mat<float, 4>;
|
||||
}
|
||||
|
||||
223
headers/vmath.hpp/vmath_mat.hpp
Normal file
223
headers/vmath.hpp/vmath_mat.hpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vmath_fwd.hpp"
|
||||
#include "vmath_vec.hpp"
|
||||
|
||||
namespace vmath_hpp::detail
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
class mat_base;
|
||||
|
||||
template < typename T >
|
||||
class mat_base<T, 2> {
|
||||
public:
|
||||
vec<T, 2> rows[2];
|
||||
public:
|
||||
constexpr mat_base() : rows{
|
||||
{1, 0},
|
||||
{0, 1},
|
||||
} {}
|
||||
|
||||
constexpr explicit mat_base(uninit_t) {}
|
||||
|
||||
constexpr mat_base(
|
||||
T m11, T m12,
|
||||
T m21, T m22)
|
||||
: rows{
|
||||
{m11, m12},
|
||||
{m21, m22}} {}
|
||||
|
||||
constexpr mat_base(
|
||||
const vec<T, 2>& row0,
|
||||
const vec<T, 2>& row1)
|
||||
: rows{row0, row1} {}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
class mat_base<T, 3> {
|
||||
public:
|
||||
vec<T, 3> rows[3];
|
||||
public:
|
||||
constexpr mat_base() : rows{
|
||||
{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, 1},
|
||||
} {}
|
||||
|
||||
constexpr explicit mat_base(uninit_t) {}
|
||||
|
||||
constexpr mat_base(
|
||||
T m11, T m12, T m13,
|
||||
T m21, T m22, T m23,
|
||||
T m31, T m32, T m33)
|
||||
: rows{
|
||||
{m11, m12, m13},
|
||||
{m21, m22, m23},
|
||||
{m31, m32, m33}} {}
|
||||
|
||||
constexpr mat_base(
|
||||
const vec<T, 3>& row0,
|
||||
const vec<T, 3>& row1,
|
||||
const vec<T, 3>& row2)
|
||||
: rows{row0, row1, row2} {}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
class mat_base<T, 4> {
|
||||
public:
|
||||
vec<T, 4> rows[4];
|
||||
public:
|
||||
constexpr mat_base() : rows{
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
} {}
|
||||
|
||||
constexpr explicit mat_base(uninit_t) {}
|
||||
|
||||
constexpr mat_base(
|
||||
T m11, T m12, T m13, T m14,
|
||||
T m21, T m22, T m23, T m24,
|
||||
T m31, T m32, T m33, T m34,
|
||||
T m41, T m42, T m43, T m44)
|
||||
: rows{
|
||||
{m11, m12, m13, m14},
|
||||
{m21, m22, m23, m24},
|
||||
{m31, m32, m33, m34},
|
||||
{m41, m42, m43, m44}} {}
|
||||
|
||||
constexpr mat_base(
|
||||
const vec<T, 4>& row0,
|
||||
const vec<T, 4>& row1,
|
||||
const vec<T, 4>& row2,
|
||||
const vec<T, 4>& row3)
|
||||
: rows{row0, row1, row2, row3} {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
class mat final : public detail::mat_base<T, Size> {
|
||||
public:
|
||||
using self_type = mat;
|
||||
using base_type = detail::mat_base<T, Size>;
|
||||
using value_type = vec<T, Size>;
|
||||
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
public:
|
||||
using base_type::rows;
|
||||
using base_type::mat_base;
|
||||
|
||||
mat(mat&&) = default;
|
||||
mat& operator=(mat&&) = default;
|
||||
|
||||
mat(const mat&) = default;
|
||||
mat& operator=(const mat&) = default;
|
||||
|
||||
void swap(mat& other) noexcept(std::is_nothrow_swappable_v<T>) {
|
||||
for ( std::size_t i = 0; i < Size; ++i ) {
|
||||
using std::swap;
|
||||
swap(rows[i], other.rows[i]);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr iterator begin() noexcept { return iterator(rows); }
|
||||
constexpr const_iterator begin() const noexcept { return const_iterator(rows); }
|
||||
constexpr const_iterator cbegin() const noexcept { return const_iterator(rows); }
|
||||
|
||||
constexpr iterator end() noexcept { return iterator(rows + Size); }
|
||||
constexpr const_iterator end() const noexcept { return const_iterator(rows + Size); }
|
||||
constexpr const_iterator cend() const noexcept { return const_iterator(rows + Size); }
|
||||
|
||||
constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
|
||||
constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
|
||||
constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
|
||||
|
||||
constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
|
||||
constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
|
||||
constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
|
||||
|
||||
constexpr size_type size() const noexcept { return Size; }
|
||||
constexpr size_type max_size() const noexcept { return Size; }
|
||||
constexpr bool empty() const noexcept { return !Size; }
|
||||
|
||||
constexpr value_type& operator[](size_type index) noexcept {
|
||||
return rows[index];
|
||||
}
|
||||
|
||||
constexpr const value_type& operator[](size_type index) const noexcept {
|
||||
return rows[index];
|
||||
}
|
||||
|
||||
constexpr value_type& at(size_type index) {
|
||||
if ( index < Size ) {
|
||||
return rows[index];
|
||||
}
|
||||
throw std::out_of_range("mat::at");
|
||||
}
|
||||
|
||||
constexpr const value_type& at(size_type index) const {
|
||||
if ( index < Size ) {
|
||||
return rows[index];
|
||||
}
|
||||
throw std::out_of_range("mat::at");
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
void swap(mat<T, Size>& l, mat<T, Size>& r) noexcept(noexcept(l.swap(r))) {
|
||||
l.swap(r);
|
||||
}
|
||||
}
|
||||
|
||||
namespace vmath_hpp
|
||||
{
|
||||
template < typename T, std::size_t Size >
|
||||
constexpr bool operator==(const mat<T, Size>& l, const mat<T, Size>& r) {
|
||||
for ( std::size_t i = 0; i < Size; ++i ) {
|
||||
if ( !(l[i] == r[i]) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
constexpr bool operator!=(const mat<T, Size>& l, const mat<T, Size>& r) {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
template < typename T, std::size_t Size >
|
||||
constexpr bool operator<(const mat<T, Size>& l, const mat<T, Size>& r) {
|
||||
for ( std::size_t i = 0; i < Size; ++i ) {
|
||||
if ( l[i] < r[i] ) {
|
||||
return true;
|
||||
}
|
||||
if ( r[i] < l[i] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
204
untests/vmath_mat_tests.cpp
Normal file
204
untests/vmath_mat_tests.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/vmath.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <vmath.hpp/vmath_mat.hpp>
|
||||
|
||||
#define CATCH_CONFIG_FAST_COMPILE
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("vmath/mat") {
|
||||
using namespace vmath_hpp;
|
||||
|
||||
SECTION("sizeof") {
|
||||
STATIC_REQUIRE(sizeof(mat2i{}) == sizeof(int) * 2 * 2);
|
||||
STATIC_REQUIRE(sizeof(mat3i{}) == sizeof(int) * 3 * 3);
|
||||
STATIC_REQUIRE(sizeof(mat4i{}) == sizeof(int) * 4 * 4);
|
||||
}
|
||||
|
||||
SECTION("ctors") {
|
||||
{
|
||||
STATIC_REQUIRE(mat2i()[0] == vec2i(1,0));
|
||||
STATIC_REQUIRE(mat2i()[1] == vec2i(0,1));
|
||||
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4)[0] == vec2i(1,2));
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4)[1] == vec2i(3,4));
|
||||
|
||||
STATIC_REQUIRE(mat2i({1,2},{3,4})[0] == vec2i(1,2));
|
||||
STATIC_REQUIRE(mat2i({1,2},{3,4})[1] == vec2i(3,4));
|
||||
}
|
||||
{
|
||||
constexpr mat2i v(1,2,3,4);
|
||||
constexpr mat2i v2 = v;
|
||||
STATIC_REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
{
|
||||
constexpr mat2i v(1,2,3,4);
|
||||
constexpr mat2i v2 = std::move(v);
|
||||
STATIC_REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("operator=") {
|
||||
{
|
||||
mat2i v(1,2,3,4);
|
||||
mat2i v2;
|
||||
v2 = v;
|
||||
REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
{
|
||||
mat2i v(1,2,3,4);
|
||||
mat2i v2;
|
||||
v2 = std::move(v);
|
||||
REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("swap") {
|
||||
{
|
||||
mat2i v1(1,2,3,4);
|
||||
mat2i v2(4,5,6,7);
|
||||
v1.swap(v2);
|
||||
REQUIRE(v1 == mat2i(4,5,6,7));
|
||||
REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
{
|
||||
mat2i v1(1,2,3,4);
|
||||
mat2i v2(4,5,6,7);
|
||||
swap(v1, v2);
|
||||
REQUIRE(v1 == mat2i(4,5,6,7));
|
||||
REQUIRE(v2 == mat2i(1,2,3,4));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("iter") {
|
||||
{
|
||||
mat2i v{1,2,3,4};
|
||||
mat2i::iterator i = v.begin();
|
||||
REQUIRE(*i++ == vec2i{1,2});
|
||||
REQUIRE(*i++ == vec2i{3,4});
|
||||
REQUIRE(v.end() == i);
|
||||
}
|
||||
{
|
||||
const mat2i v{1,2,3,4};
|
||||
mat2i::const_iterator i = v.begin();
|
||||
REQUIRE(*i++ == vec2i{1,2});
|
||||
REQUIRE(*i++ == vec2i{3,4});
|
||||
REQUIRE(v.end() == i);
|
||||
}
|
||||
{
|
||||
mat2i v{1,2,3,4};
|
||||
for ( auto i = v.begin(); i < v.end(); ++i ) {
|
||||
*i = vec2i(i->x() * 2, i->y() * 2);
|
||||
}
|
||||
REQUIRE(v == mat2i(2,4,6,8));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("riter") {
|
||||
{
|
||||
mat2i v{1,2,3,4};
|
||||
mat2i::reverse_iterator i = v.rbegin();
|
||||
REQUIRE(*i++ == vec2i{3,4});
|
||||
REQUIRE(*i++ == vec2i{1,2});
|
||||
REQUIRE(v.rend() == i);
|
||||
for ( auto j = v.rbegin(); j < v.rend(); ++j ) {
|
||||
*j = vec2i(j->x() * 2, j->y() * 2);
|
||||
}
|
||||
REQUIRE(v == mat2i(2,4,6,8));
|
||||
}
|
||||
{
|
||||
const mat2i v{1,2,3,4};
|
||||
mat2i::const_reverse_iterator i = v.rbegin();
|
||||
REQUIRE(*i++ == vec2i{3,4});
|
||||
REQUIRE(*i++ == vec2i{1,2});
|
||||
REQUIRE(v.rend() == i);
|
||||
}
|
||||
{
|
||||
mat2i v{1,2,3,4};
|
||||
for ( auto i = v.rbegin(); i < v.rend(); ++i ) {
|
||||
*i = vec2i(i->x() * 2, i->y() * 2);
|
||||
}
|
||||
REQUIRE(v == mat2i(2,4,6,8));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("size/max_size/empty") {
|
||||
STATIC_REQUIRE(mat<int, 2>().size() == 2);
|
||||
STATIC_REQUIRE(mat<int, 2>().max_size() == 2);
|
||||
STATIC_REQUIRE_FALSE(mat<int, 2>().empty());
|
||||
|
||||
STATIC_REQUIRE(mat<int, 3>().size() == 3);
|
||||
STATIC_REQUIRE(mat<int, 3>().max_size() == 3);
|
||||
STATIC_REQUIRE_FALSE(mat<int, 3>().empty());
|
||||
}
|
||||
|
||||
SECTION("operator[]") {
|
||||
{
|
||||
STATIC_REQUIRE(mat2i()[0] == vec2i(1,0));
|
||||
STATIC_REQUIRE(mat2i()[1] == vec2i(0,1));
|
||||
|
||||
STATIC_REQUIRE(mat3i()[0] == vec3i(1,0,0));
|
||||
STATIC_REQUIRE(mat3i()[1] == vec3i(0,1,0));
|
||||
STATIC_REQUIRE(mat3i()[2] == vec3i(0,0,1));
|
||||
|
||||
STATIC_REQUIRE(mat4i()[0] == vec4i(1,0,0,0));
|
||||
STATIC_REQUIRE(mat4i()[1] == vec4i(0,1,0,0));
|
||||
STATIC_REQUIRE(mat4i()[2] == vec4i(0,0,1,0));
|
||||
STATIC_REQUIRE(mat4i()[3] == vec4i(0,0,0,1));
|
||||
}
|
||||
{
|
||||
mat2i v;
|
||||
v[0] = vec2i(1,2);
|
||||
v[1] = vec2i(3,4);
|
||||
REQUIRE(v == mat2i(1,2,3,4));
|
||||
}
|
||||
{
|
||||
mat3i v;
|
||||
v[0] = vec3i(1,2,3);
|
||||
v[1] = vec3i(4,5,6);
|
||||
v[2] = vec3i(7,8,9);
|
||||
REQUIRE(v == mat3i(1,2,3,4,5,6,7,8,9));
|
||||
}
|
||||
{
|
||||
mat4i v;
|
||||
v[0] = vec4i(1,2,3,4);
|
||||
v[1] = vec4i(5,6,7,8);
|
||||
v[2] = vec4i(9,10,11,12);
|
||||
v[3] = vec4i(13,14,15,16);
|
||||
REQUIRE(v == mat4i(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("at") {
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4).at(0) == vec2i(1,2));
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4).at(1) == vec2i(3,4));
|
||||
REQUIRE_THROWS_AS(mat2i(1,2,3,4).at(2), std::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("operator==/operator!=") {
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4) == mat2i(1,2,3,4));
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) == mat2i(2,2,3,4));
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) == mat2i(1,3,3,4));
|
||||
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) != mat2i(1,2,3,4));
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4) != mat2i(2,2,3,4));
|
||||
STATIC_REQUIRE(mat2i(1,2,3,4) != mat2i(1,3,3,4));
|
||||
}
|
||||
|
||||
SECTION("operator<") {
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) < mat2i(1,2,3,4));
|
||||
|
||||
STATIC_REQUIRE(mat2i(1,1,3,4) < mat2i(1,2,3,4));
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) < mat2i(1,1,3,4));
|
||||
|
||||
STATIC_REQUIRE(mat2i(0,3,3,4) < mat2i(1,2,3,4));
|
||||
STATIC_REQUIRE_FALSE(mat2i(1,2,3,4) < mat2i(0,3,3,4));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user