math rect class

This commit is contained in:
2018-10-24 18:38:36 +07:00
parent a491cb1bf3
commit 552e16222c
4 changed files with 332 additions and 0 deletions

View File

@@ -11,6 +11,7 @@
#include "mat2.hpp" #include "mat2.hpp"
#include "mat3.hpp" #include "mat3.hpp"
#include "mat4.hpp" #include "mat4.hpp"
#include "rect.hpp"
#include "trig.hpp" #include "trig.hpp"
#include "unit.hpp" #include "unit.hpp"
#include "vec2.hpp" #include "vec2.hpp"

View File

@@ -28,6 +28,9 @@ namespace e2d
template < typename T > template < typename T >
class mat4; class mat4;
template < typename T >
class rect;
template < typename T, typename Tag > template < typename T, typename Tag >
class unit; class unit;
@@ -79,6 +82,13 @@ namespace e2d
using m4hi = mat4<i16>; using m4hi = mat4<i16>;
using m4hu = mat4<u16>; using m4hu = mat4<u16>;
using r4d = rect<f64>;
using r4f = rect<f32>;
using r4i = rect<i32>;
using r4u = rect<u32>;
using r4hi = rect<i16>;
using r4hu = rect<u16>;
struct deg_tag {}; struct deg_tag {};
struct rad_tag {}; struct rad_tag {};

View File

@@ -0,0 +1,212 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#pragma once
#include "_math.hpp"
#include "vec2.hpp"
namespace e2d
{
template < typename T >
class rect final {
static_assert(
std::is_arithmetic<T>::value,
"type of 'rect' must be arithmetic");
public:
using self_type = rect;
using value_type = T;
public:
vec2<T> position;
vec2<T> size;
public:
rect() noexcept = default;
rect(const rect& other) noexcept = default;
rect& operator=(const rect& other) noexcept = default;
rect(T w, T h) noexcept;
rect(T x, T y, T w, T h) noexcept;
rect(const vec2<T>& nsize) noexcept;
rect(const vec2<T>& nposition, const vec2<T>& nsize) noexcept;
template < typename To >
rect<To> cast_to() const noexcept;
};
}
namespace e2d
{
template < typename T >
rect<T>::rect(T w, T h) noexcept
: size(w, h) {}
template < typename T >
rect<T>::rect(T x, T y, T w, T h) noexcept
: position(x, y)
, size(w, h) {}
template < typename T >
rect<T>::rect(const vec2<T>& nsize) noexcept
: size(nsize) {}
template < typename T >
rect<T>::rect(const vec2<T>& nposition, const vec2<T>& nsize) noexcept
: position(nposition)
, size(nsize) {}
template < typename T >
template < typename To >
rect<To> rect<T>::cast_to() const noexcept {
return {
position.template cast_to<To>(),
size.template cast_to<To>()};
}
}
namespace e2d
{
//
// make_rect
//
template < typename T >
rect<T> make_rect(T w, T h) noexcept {
return {w, h};
}
template < typename T >
rect<T> make_rect(T x, T y, T w, T h) noexcept {
return {x, y, w, h};
}
template < typename T >
rect<T> make_rect(const vec2<T>& size) noexcept {
return {size};
}
template < typename T >
rect<T> make_rect(const vec2<T>& position, const vec2<T>& size) noexcept {
return {position, size};
}
//
// rect (==,!=) rect
//
template < typename T >
bool operator==(const rect<T>& l, const rect<T>& r) noexcept {
return l.position == r.position
&& l.size == r.size;
}
template < typename T >
bool operator!=(const rect<T>& l, const rect<T>& r) noexcept {
return !(l == r);
}
//
// rect (<,>,<=,>=) rect
//
template < typename T >
bool operator<(const rect<T>& l, const rect<T>& r) noexcept {
return l.size.x * l.size.y < r.size.x * r.size.y;
}
template < typename T >
bool operator>(const rect<T>& l, const rect<T>& r) noexcept {
return r < l;
}
template < typename T >
bool operator<=(const rect<T>& l, const rect<T>& r) noexcept {
return !(r < l);
}
template < typename T >
bool operator>=(const rect<T>& l, const rect<T>& r) noexcept {
return !(l < r);
}
}
namespace e2d { namespace math
{
//
// approximately
//
template < typename T >
bool approximately(
const rect<T>& l,
const rect<T>& r,
T precision = math::default_precision<T>()) noexcept
{
return math::approximately(l.position, r.position, precision)
&& math::approximately(l.size, r.size, precision);
}
//
// minimum/maximum
//
template < typename T >
vec2<T> minimum(const rect<T>& r) noexcept {
return math::minimized(r.position, r.position + r.size);
}
template < typename T >
vec2<T> maximum(const rect<T>& r) noexcept {
return math::maximized(r.position, r.position + r.size);
}
//
// area
//
template < typename T >
T area(const rect<T>& r) noexcept {
return r.size.x * r.size.y;
}
template < typename T >
T abs_area(const rect<T>& r) noexcept {
return math::abs(r.size.x * r.size.y);
}
//
// merged
//
template < typename T >
rect<T> merged(const rect<T>& l, const rect<T>& r) noexcept {
const vec2<T> min = math::minimized(minimum(l), minimum(r));
const vec2<T> max = math::maximized(maximum(l), maximum(r));
return { min, max - min };
}
//
// inside
//
template < typename T >
bool inside(const rect<T>& r, const vec2<T>& p) noexcept {
const vec2<T> min = minimum(r);
const vec2<T> max = maximum(r);
return p.x >= min.x && p.x <= max.x
&& p.y >= min.y && p.y <= max.y;
}
//
// contains_nan
//
template < typename T >
bool contains_nan(const rect<T>& r) noexcept {
return math::contains_nan(r.position)
|| math::contains_nan(r.size);
}
}}

View File

@@ -0,0 +1,109 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018 Matvey Cherevko
******************************************************************************/
#include "_math.hpp"
using namespace e2d;
TEST_CASE("rect") {
{
REQUIRE(r4i().position == v2i(0,0));
REQUIRE(r4i().size == v2i(0,0));
REQUIRE(r4i(1,2).position == v2i(0,0));
REQUIRE(r4i(1,2).size == v2i(1,2));
REQUIRE(r4i(1,2,3,4).position == v2i(1,2));
REQUIRE(r4i(1,2,3,4).size == v2i(3,4));
REQUIRE(r4i(v2i{1,2}).position == v2i(0,0));
REQUIRE(r4i(v2i{1,2}).size == v2i(1,2));
REQUIRE(r4i(v2i{1,2},v2i{3,4}).position == v2i(1,2));
REQUIRE(r4i(v2i{1,2},v2i{3,4}).size == v2i(3,4));
}
{
REQUIRE(r4f(1,2,3,4).cast_to<i32>() == r4i(1,2,3,4));
}
{
REQUIRE(make_rect(2,1) == r4i(0,0,2,1));
REQUIRE(make_rect(4,3,2,1) == r4i(4,3,2,1));
REQUIRE(make_rect(v2i{2,1}) == r4i(0,0,2,1));
REQUIRE(make_rect(v2i{4,3},v2i{2,1}) == r4i(4,3,2,1));
}
{
auto r0 = r4i(1,2,3,4);
auto r1 = r4i(r0);
REQUIRE(r1 == r4i(1,2,3,4));
r1 = r4i(4,3,2,1);
REQUIRE(r1 == r4i(4,3,2,1));
}
{
REQUIRE(r4i(1,2,3,4) == r4i(1,2,3,4));
REQUIRE_FALSE(r4i(1,2,3,4) == r4i(1,2,4,3));
REQUIRE_FALSE(r4i(1,2,3,4) == r4i(2,1,3,4));
REQUIRE_FALSE(r4i(1,2,3,4) == r4i(2,1,4,3));
REQUIRE_FALSE(r4i(1,2,3,4) != r4i(1,2,3,4));
REQUIRE(r4i(1,2,3,4) != r4i(1,2,4,3));
REQUIRE(r4i(1,2,3,4) != r4i(2,1,3,4));
REQUIRE(r4i(1,2,3,4) != r4i(2,1,4,3));
}
{
REQUIRE(r4i(4,4) < r4i(4,5));
REQUIRE_FALSE(r4i(4,4) < r4i(3,4));
REQUIRE_FALSE(r4i(4,4) < r4i(4,3));
}
{
REQUIRE(math::approximately(r4i(1,2,3,4), r4i(1,2,4,5), 1));
REQUIRE_FALSE(math::approximately(r4i(1,2,3,4), r4i(1,2,4,5)));
}
{
REQUIRE(math::minimum(r4i(1,2,3,4)) == v2i(1,2));
REQUIRE(math::minimum(r4i(1,2,-3,5)) == v2i(-2,2));
REQUIRE(math::minimum(r4i(1,2,3,-5)) == v2i(1,-3));
REQUIRE(math::minimum(r4i(1,2,-3,-5)) == v2i(-2,-3));
REQUIRE(math::maximum(r4i(1,2,3,4)) == v2i(4,6));
REQUIRE(math::maximum(r4i(1,2,-3,5)) == v2i(1,7));
REQUIRE(math::maximum(r4i(1,2,3,-5)) == v2i(4,2));
REQUIRE(math::maximum(r4i(1,2,-3,-5)) == v2i(1,2));
REQUIRE(math::area(r4i(1,2,3,4)) == 12);
REQUIRE(math::area(r4i(1,2,3,-4)) == -12);
REQUIRE(math::area(r4i(1,2,-3,4)) == -12);
REQUIRE(math::area(r4i(1,2,-3,-4)) == 12);
REQUIRE(math::abs_area(r4i(1,2,3,4)) == 12);
REQUIRE(math::abs_area(r4i(1,2,3,-4)) == 12);
REQUIRE(math::abs_area(r4i(1,2,-3,4)) == 12);
REQUIRE(math::abs_area(r4i(1,2,-3,-4)) == 12);
REQUIRE(math::merged(r4i(1,2,3,4), r4i(1,2,3,4)) == r4i(1,2,3,4));
REQUIRE(math::merged(r4i(1,2,3,4), r4i(0,1,3,4)) == r4i(0,1,4,5));
REQUIRE(math::merged(r4i(1,2,3,4), r4i(1,2,4,5)) == r4i(1,2,4,5));
REQUIRE(math::merged(r4i(1,2,3,4), r4i(0,1,4,5)) == r4i(0,1,4,5));
REQUIRE(math::merged(r4i(1,2,3,4), r4i(1,2,-3,-5)) == r4i(-2,-3,6,9));
REQUIRE(math::merged(r4i(-1,-2,3,4), r4i(1,2,-3,-5)) == r4i(-2,-3,4,5));
REQUIRE(math::inside(r4i(1,2,3,4), v2i(1,2)));
REQUIRE(math::inside(r4i(1,2,3,4), v2i(4,5)));
REQUIRE_FALSE(math::inside(r4i(1,2,3,4), v2i(4,7)));
REQUIRE_FALSE(math::inside(r4i(1,2,3,4), v2i(0,5)));
REQUIRE(math::inside(r4i(1,2,-3,-4), v2i(1,2)));
REQUIRE(math::inside(r4i(1,2,-3,-4), v2i(-1,-2)));
REQUIRE_FALSE(math::inside(r4i(1,2,-3,-4), v2i(2,2)));
REQUIRE_FALSE(math::inside(r4i(1,2,-3,-4), v2i(1,3)));
REQUIRE_FALSE(math::inside(r4i(1,2,-3,-4), v2i(-3,2)));
REQUIRE_FALSE(math::inside(r4i(1,2,-3,-4), v2i(1,-3)));
REQUIRE_FALSE(math::contains_nan(r4i(1,2,3,4)));
REQUIRE_FALSE(math::contains_nan(r4f(1.f,2.f,3.f,4.f)));
REQUIRE(math::contains_nan(r4f(1.f,std::numeric_limits<f32>::quiet_NaN())));
REQUIRE(math::contains_nan(r4f(std::numeric_limits<f32>::infinity(), 1.f)));
}
}