coord: move operators out of subclasses

This commit is contained in:
Danny Robson 2015-03-06 01:09:37 +11:00
parent 872499360f
commit 439bb19679
14 changed files with 387 additions and 677 deletions

View File

@ -26,22 +26,6 @@
#include <iterator>
//-----------------------------------------------------------------------------
// HACK: point multiplication isn't defined, but it's way more convenient than
// casting between vector/coord
namespace util {
template <typename T>
util::point2f
operator* (T a, util::point2f b)
{
return {
a * b.data[0],
a * b.data[1]
};
}
}
//-----------------------------------------------------------------------------
template <size_t S>
util::bezier<S>::bezier (const util::point2f (&_points)[S+1])
@ -147,10 +131,10 @@ namespace util {
const auto &v = m_coeffs;
return {
-1 * v[0] +3 * v[1] -3 * v[2] +1 * v[3],
3 * v[0] -6 * v[1] +3 * v[2],
-3 * v[0] +3 * v[1],
1 * v[0]
-1.f * v[0] +3.f * v[1] -3.f * v[2] +1.f * v[3],
3.f * v[0] -6.f * v[1] +3.f * v[2],
-3.f * v[0] +3.f * v[1],
1.f * v[0]
};
}
}
@ -165,9 +149,9 @@ namespace util {
auto &v = m_coeffs;
return {
+1 * v[2] -2 * v[1] + 1 * v[0],
-2 * v[2] +2 * v[1],
+1 * v[2]
+1.f * v[2] -2.f * v[1] + 1.f * v[0],
-2.f * v[2] +2.f * v[1],
+1.f * v[2]
};
}
}
@ -182,8 +166,8 @@ namespace util {
auto &v = m_coeffs;
return {
-1 * v[1] + 1 * v[0],
+1 * v[1],
-1.f * v[1] + 1.f * v[0],
+1.f * v[1],
};
}
}
@ -378,12 +362,10 @@ util::bezier<S>::region (void) const
y1 = max (y1, m_points[i].y);
}
return {
x0,
y0,
x1 - x0,
y1 - y0
};
util::point2f p0 { x0, y0 };
util::point2f p1 { x1, y1 };
return { p0, p1 };
}

View File

@ -20,15 +20,30 @@
#ifndef __UTIL_COORD_HPP
#define __UTIL_COORD_HPP
#include "../preprocessor.hpp"
#include "../platform.hpp"
#include <algorithm>
#include <iterator>
#include <type_traits>
#include <cstdlib>
namespace util {
template <size_t,typename> class point;
template <size_t,typename> class extent;
template <size_t,typename> class vector;
namespace detail {
///////////////////////////////////////////////////////////////////////
// tags for accessor names
struct rgba { };
struct xyzw { };
struct stpq { };
struct whd { };
///////////////////////////////////////////////////////////////////////
// Disable GCC warnings about validity of anonyous structures in
// unions. Push comes to shove I'll manually redsign everything to
// keep this syntax anyway.
@ -40,14 +55,6 @@ namespace util {
#pragma GCC diagnostic ignored "-Wgnu"
#endif
//---------------------------------------------------------------------
// tags for accessor names
struct rgba { };
struct xyzw { };
struct stpq { };
struct whd { };
template <size_t S, typename T, typename...>
struct coord_base {
T data[S];
@ -145,8 +152,9 @@ namespace util {
};
};
#pragma GCC diagnostic pop
//---------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////
// coord types are not really intended to have arbitrary dimension, so
// don't add specialisations (or a general case) without a decent
// reason.
@ -157,6 +165,7 @@ namespace util {
template <typename T, typename ...tags>
struct coord_init<1,T,tags...> : public coord_base<1,T,tags...>
{
using coord_base<1,T,tags...>::coord_base;
coord_init () = default;
coord_init (T v0):
coord_base<1,T,tags...> ({v0})
@ -168,6 +177,7 @@ namespace util {
template <typename T, typename ...tags>
struct coord_init<2,T,tags...> : public coord_base<2,T,tags...>
{
using coord_base<2,T,tags...>::coord_base;
coord_init () = default;
coord_init (T v0, T v1):
coord_base<2,T,tags...> ({ v0, v1 })
@ -179,6 +189,7 @@ namespace util {
template <typename T, typename ...tags>
struct coord_init<3,T,tags...> : public coord_base<3,T,tags...>
{
using coord_base<3,T,tags...>::coord_base;
coord_init () = default;
coord_init (T v0, T v1, T v2):
coord_base<3,T,tags...> ({v0, v1, v2})
@ -190,14 +201,14 @@ namespace util {
template <typename T, typename ...tags>
struct coord_init<4,T,tags...> : public coord_base<4,T,tags...>
{
using coord_base<4,T,tags...>::coord_base;
coord_init () = default;
coord_init (T v0, T v1, T v2, T v3):
coord_base<4,T,tags...> ({ v0, v1, v2, v3 })
{ ; }
};
////---------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename ...tags>
struct coord : public coord_init<S,T,tags...> {
static_assert (S > 0, "coord dimensions must be strictly positive");
@ -206,17 +217,19 @@ namespace util {
static constexpr size_t dimension = S;
static constexpr size_t elements = S;
size_t size (void) const { return S; }
// constructors
using coord_init<S,T,tags...>::coord_init;
coord () = default;
size_t size (void) const { return S; }
explicit coord (T v)
{ std::fill (std::begin (this->data), std::end (this->data), v); }
coord (const coord<S,T,tags...> &rhs) = default;
coord& operator= (const coord<S,T,tags...> &rhs) = default;
// element accessors
T& operator[] (size_t i) { return this->data[i]; }
T operator[] (size_t i) const { return this->data[i]; }
@ -228,19 +241,138 @@ namespace util {
};
////---------------------------------------------------------------------
// XXX: Unsure whether this should really be defined for arbitrary
// types in a semantic sense, but practicality suggestes this is the
// best option; point/vector dot product is too useful.
template <size_t S, typename T, typename ...tag_a, typename ...tag_b>
T dot (const coord<S,T,tag_a...> &a, const coord<S,T,tag_b...> &b)
{
return std::inner_product (std::begin (a.data),
std::end (a.data),
std::begin (b.data),
T {0});
}
#pragma GCC diagnostic pop
///////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class A,
template <size_t,typename> class B
>
struct coord_traits { };
template <size_t S, typename T> struct coord_traits<S,T,extent,extent> { typedef extent<S,T> result; };
template <size_t S, typename T> struct coord_traits<S,T,extent,vector> { typedef extent<S,T> result; };
template <size_t S, typename T> struct coord_traits<S,T,point,extent> { typedef point<S,T> result; };
template <size_t S, typename T> struct coord_traits<S,T,point,vector> { typedef point<S,T> result; };
template <size_t S, typename T> struct coord_traits<S,T,vector,vector> { typedef vector<S,T> result; };
}
///////////////////////////////////////////////////////////////////////////
// vector operators
#define ELEMENT_OP(OP) \
template < \
size_t S, \
typename T, \
template <size_t,typename> class A, \
template <size_t,typename> class B \
> \
typename detail::coord_traits<S,T,A,B>::result \
operator OP (A<S,T> a, B<S,T> b) \
{ \
typename detail::coord_traits<S,T,A,B>::result out; \
for (size_t i = 0; i < S; ++i) \
out[i] = a[i] OP b[i]; \
return out; \
} \
\
template < \
size_t S, \
typename T, \
template <size_t,typename> class A, \
template <size_t,typename> class B \
> \
typename detail::coord_traits<S,T,A,B>::result& \
operator PASTE(OP,=) (A<S,T>& a, B<S,T> b) \
{ \
for (size_t i = 0; i < S; ++i) \
a[i] PASTE(OP,=) b[i]; \
return a; \
}
ELEMENT_OP(+)
ELEMENT_OP(-)
ELEMENT_OP(*)
ELEMENT_OP(/)
#undef ELEMENT_OP
///////////////////////////////////////////////////////////////////////////
// scalar operators
#define SCALAR_OP(OP) \
template <size_t S, typename T, template <size_t,typename> class K> \
K<S,T> \
operator OP (T t, K<S,T> k) \
{ \
K<S,T> out; \
for (size_t i = 0; i < S; ++i) \
out[i] = t OP k[i]; \
return out; \
} \
\
template <size_t S, typename T, template <size_t,typename> class K> \
K<S,T> \
operator OP (K<S,T> k, T t) \
{ \
K<S,T> out; \
for (size_t i = 0; i < S; ++i) \
out[i] = t OP k[i]; \
return out; \
}
SCALAR_OP(+)
SCALAR_OP(-)
SCALAR_OP(*)
SCALAR_OP(/)
#undef SCALAR_OP
#define SCALAR_OP(OP) \
template <size_t S, typename T, template <size_t,typename> class K> \
K<S,T>& \
operator OP (K<S,T> &k, T t) \
{ \
for (size_t i = 0; i < S; ++i) \
k[i] OP t; \
return k; \
}
SCALAR_OP(+=)
SCALAR_OP(-=)
SCALAR_OP(*=)
SCALAR_OP(/=)
#undef SCALAR_OP
///////////////////////////////////////////////////////////////////////////
// logic operators
template <size_t S, typename T, template <size_t,typename> class K>
bool operator== (K<S,T> a, K<S,T> b)
{ return std::equal (std::begin (a), std::end (a), std::begin (b)); }
template <size_t S, typename T, template <size_t,typename> class K>
bool operator!= (K<S,T> a, K<S,T> b)
{ return !(a == b); }
///////////////////////////////////////////////////////////////////////////
// special operators
template <size_t S, typename T> vector<S,T> operator- (point<S,T> a, point<S,T> b)
{
vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out[i] = a[i] - b[i];
return out;
}
template <size_t S, typename T, template<size_t,typename> class A, template <size_t,typename> class B>
T dot (A<S,T> a, B<S,T> b)
{
T sum { 0 };
for (size_t i = 0; i < S; ++i)
sum += a[i] * b[i];
return sum;
}
}

View File

@ -27,9 +27,12 @@
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
util::extent<S,T>::extent (vector<S,T> _v):
extent (_v.x, _v.y)
{ ; }
util::extent<S,T>::extent (vector<S,T> _v)
{
std::copy (std::begin (_v.data),
std::end (_v.data),
std::begin (this->data));
}
///////////////////////////////////////////////////////////////////////////////
@ -87,32 +90,6 @@ util::extent<S,T>::empty (void) const
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
util::extent<S,T>
util::extent<S,T>::operator+ (vector<S,T> rhs) const
{
extent<S,T> out;
std::adjacent_difference (std::begin (this->data),
std::end (this->data),
std::begin (rhs.data),
std::plus<T> ());
return out;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
bool
util::extent<S,T>::operator ==(const extent& rhs) const
{
return std::equal (std::begin (this->data),
std::end (this->data),
std::begin (rhs.data),
almost_equal<T>);
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
const util::extent<S,T> util::extent<S,T>::MIN { 0 };
@ -131,7 +108,9 @@ namespace debug {
struct validator<util::extent,S,T> {
static bool is_valid (const util::extent<S,T> &e)
{
return e.w >= 0 && e.h >= 0;
return std::all_of (std::begin (e.data),
std::end (e.data),
[] (auto i) { return i >= 0; });
}
};
}
@ -148,7 +127,11 @@ template <size_t S, typename T>
std::ostream&
util::operator<< (std::ostream &os, util::extent<S,T> e)
{
os << "[" << e.w << ", " << e.h << "]";
os << "[";
std::copy (std::begin (e.data),
std::end (e.data),
std::ostream_iterator<T> (os, ", "));
os << "]";
return os;
}

View File

@ -30,8 +30,10 @@ namespace util {
* A pure two-dimensional size, without positioning
*/
template <size_t S, typename T>
struct extent : public detail::coord<S,T,detail::whd> {
struct extent : public detail::coord<S,T,detail::whd>
{
using detail::coord<S,T,detail::whd>::coord;
extent () = default;
extent (vector<S,T>);
@ -43,12 +45,6 @@ namespace util {
bool empty (void) const;
extent<S,T> operator+ (vector<S,T>) const;
bool operator ==(const extent& rhs) const;
bool operator !=(const extent& rhs) const
{ return !(*this == rhs); }
template <typename U>
extent<S,U> cast (void) const;
@ -63,6 +59,7 @@ namespace util {
typedef extent<2,int> extent2i;
typedef extent<2,size_t> extent2u;
typedef extent<2,float> extent2f;
typedef extent<2,double> extent2d;
template <size_t S, typename T>
std::ostream& operator<< (std::ostream&, util::extent<S,T>);

View File

@ -236,8 +236,8 @@ cellular::eval (double x, double y) const {
for (signed x_off = -1; x_off <= 1; ++x_off) {
auto pos = point2d (double (x_off), double (y_off));
auto off = generate<vector2d> (x_int + x_off, y_int + y_off, this->seed);
off += 1;
off /= 2;
off += 1.;
off /= 2.;
CHECK (off.x >= 0 && off.x <= 1.0);
CHECK (off.y >= 0 && off.y <= 1.0);

117
point.cpp
View File

@ -27,112 +27,6 @@
using namespace std;
#if defined(COMPILER_GCC)
#pragma GCC optimize("-O3")
#endif
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>&
util::point<S,T>::operator*= (T f) {
for (auto &i: this->data)
i *= f;
return *this;
}
template <size_t S, typename T>
util::point<S,T>
util::point<S,T>::operator* (T f) const {
util::point<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * f;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>&
util::point<S,T>::operator/= (T f)
{
std::transform (std::begin (this->data),
std::end (this->data),
std::begin (this->data),
[f] (auto i) { return i / f; });
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>
util::point<S,T>::operator/ (T f) const
{
point<S,T> out;
std::transform (std::begin (this->data),
std::end (this->data),
std::begin (out.data),
[f] (auto i) { return i / f; });
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>
util::point<S,T>::operator- (const vector<S,T> &rhs) const {
util::point<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs.data[i];
return out;
}
template <size_t S, typename T>
util::point<S,T>&
util::point<S,T>::operator-= (const util::vector<S,T> &rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] -= rhs.data[i];
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>
util::point<S,T>::operator+ (const vector<S,T> &rhs) const {
util::point<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] + rhs.data[i];
return out;
}
template <size_t S, typename T>
util::point<S,T>&
util::point<S,T>::operator+= (const util::vector<S,T> &rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] += rhs.data[i];
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::point<S,T>::operator- (const point<S,T> &rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs.data[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
@ -146,17 +40,6 @@ util::point<S,T>::to (const point<S,T> &rhs) const {
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
util::point<S,T>::operator== (const util::point<S,T> &rhs) const
{
return std::equal (std::begin (this->data),
std::end (this->data),
std::begin (rhs.data));
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void

View File

@ -20,6 +20,7 @@
#ifndef __UTIL_POINT_HPP
#define __UTIL_POINT_HPP
#include "extent.hpp"
#include "vector.hpp"
#include "detail/coord.hpp"
@ -31,7 +32,8 @@
namespace util {
/// An n-dimensional position in space.
template <size_t S, typename T>
struct point : public detail::coord<S,T,detail::xyzw> {
struct point : public detail::coord<S,T,detail::xyzw>
{
using detail::coord<S,T,detail::xyzw>::coord;
// point operators
@ -41,22 +43,6 @@ namespace util {
vector<S,T> to (const point&) const;
// arithetic operators
point<S,T>& operator*= (T);
point<S,T> operator* (T) const;
point<S,T>& operator/= (T);
point<S,T> operator/ (T) const;
vector<S,T> operator- (const point<S,T>&) const;
point<S,T> operator- (const vector<S,T>&) const;
point<S,T>& operator-= (const vector<S,T>&);
point<S,T> operator+ (const vector<S,T>&) const;
point<S,T>& operator+= (const vector<S,T>&);
// logical operators
bool operator== (const point<S,T>&) const;
template <size_t D> point<D,T> redim (void) const;
template <size_t D> point<D,T> redim (const util::point<D,T> &fill) const;
template <size_t D> point<D,T> redim (T fill) const;

View File

@ -52,7 +52,7 @@ quaternion<T>::rotation (vector<3,T> from, vector<3,T> to) {
auto v = util::cross (from, to);
return {
std::acos (from.dot (to)),
std::acos (dot (from, to)),
v.x,
v.y,
v.z

View File

@ -36,12 +36,10 @@ util::region<S,T>::region (extent_t _extent):
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>::region (point_t _point,
extent_t _size):
x (_point.x),
y (_point.y),
w (_size.w),
h (_size.h)
util::region<S,T>::region (point_t _p,
extent_t _e):
p (_p),
e (_e)
{ ; }
@ -50,19 +48,25 @@ template <size_t S, typename T>
util::region<S,T>::region (point_t _a,
point_t _b):
region (_a, _b - _a)
{ ; }
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>::region (std::array<T,S*2> args)
{
CHECK_GE (_b.x, _a.x);
CHECK_GE (_b.y, _a.y);
std::copy (&args[0], &args[S], p.data);
std::copy (&args[S], &args[S*2], e.data);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>::region (position_type _x,
position_type _y,
size_type _w,
size_type _h):
region (point_t {_x, _y}, extent<S,T> {_w, _h})
{ ; }
util::region<S,T>::region (position_type _p,
size_type _e):
region (point_t {_p}, extent_t {_e})
{
}
//-----------------------------------------------------------------------------
@ -70,7 +74,7 @@ template <size_t S, typename T>
typename util::region<S,T>::size_type
util::region<S,T>::area (void) const
{
return w * h;
return e.area ();
}
@ -79,7 +83,7 @@ template <size_t S, typename T>
typename util::region<S,T>::size_type
util::region<S,T>::diameter (void) const
{
return static_cast<size_type> (std::sqrt (w * w + h * h));
return e.diameter ();
}
@ -88,19 +92,17 @@ template <size_t S, typename T>
typename util::region<S,T>::extent_t
util::region<S,T>::magnitude (void) const
{
return { w, h };
return e;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::extent_t
util::region<S,T>::magnitude (extent_t e)
util::region<S,T>::magnitude (extent_t _e)
{
w = e.w;
h = e.h;
return magnitude ();
e = _e;
return e;
}
@ -109,11 +111,9 @@ template <size_t S, typename T>
void
util::region<S,T>::scale (T factor)
{
x -= (w * factor - w) / T{2};
y -= (h * factor - h) / T{2};
w = w * factor;
h = h * factor;
auto o = (e * factor - e) / T{2};
p -= o;
e *= factor;
}
@ -126,24 +126,12 @@ util::region<S,T>::empty (void) const
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::rebase (point_t p)
{
x = p.x;
y = p.y;
return base ();
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::base (void) const
{
return { x, y };
return p;
}
@ -152,7 +140,7 @@ template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::away (void) const
{
return { x + w, y + h };
return p + e;
}
@ -161,51 +149,49 @@ template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::centre (void) const
{
T cx = x + w / T{2},
cy = y + h / T{2};
return point_t { cx, cy };
return p + e / T{2};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::closest (point_t p) const
util::region<S,T>::closest (point_t q) const
{
return {
p.x < x ? x :
p.x > x + w ? x + w :
p.x,
point_t out;
p.y < y ? y :
p.y > y + h ? y + h :
p.y
};
for (size_t i = 0; i < S; ++i)
out[i] = q[i] < p[i] ? p[i] :
q[i] > p[i] ? p[i] + e[i] :
q[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
util::region<S,T>::includes (point_t p) const
util::region<S,T>::includes (point_t q) const
{
return p.x >= x &&
p.y >= y &&
p.x - x <= w &&
p.y - y <= h;
for (size_t i = 0; i < S; ++i)
if (q[i] < p[i] || q[i] > p[i] + e[i])
return false;
return true;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
util::region<S,T>::contains (point_t p) const
util::region<S,T>::contains (point_t q) const
{
return p.x > x &&
p.y > y &&
p.x - x < w &&
p.y - y < h;
for (size_t i = 0; i < S; ++i)
if (q[i] <= p[i] || q[i] >= p[i] + e[i])
return false;
return true;
}
@ -216,33 +202,32 @@ template <size_t S, typename T>
bool
util::region<S,T>::intersects (region<S,T> rhs) const
{
return x < rhs.x + rhs.w &&
rhs.x < x + w &&
y < rhs.y + rhs.h &&
rhs.y < y + h;
for (size_t i = 0; i < S; ++i)
if (p[i] >= rhs.p[i] + rhs.e[i] ||
rhs.p[i] >= p[i] + e[i])
{ return false; }
return true;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void
util::region<S,T>::constrain (point_t &p) const
util::region<S,T>::constrain (point_t &q) const
{
p.x = std::min (std::max (p.x, x), x + w);
p.y = std::min (std::max (p.y, y), y + h);
for (size_t i = 0; i < S; ++i)
q[i] = limit (q[i], p[i], p[i] + e[i]);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::constrained (point_t p) const
util::region<S,T>::constrained (point_t q) const
{
point_t v;
v.x = std::min (std::max (p.x, x), x + w);
v.y = std::min (std::max (p.y, y), y + h);
return v;
constrain (q);
return q;
}
@ -251,41 +236,54 @@ template<size_t S, typename T>
util::region<S,T>
util::region<S,T>::intersection (region<S,T> rhs) const
{
T newx1 = max (x, rhs.x),
newy1 = max (y, rhs.y),
newx2 = min (x + sign_cast<T> (w), rhs.x + sign_cast<T> (rhs.w)),
newy2 = min (y + sign_cast<T> (h), rhs.y + sign_cast<T> (rhs.h));
// find the intersection corners
point_t a, b;
if (newx2 < newx1 || newy2 < newy1)
throw std::logic_error ("No overlap");
for (size_t i = 0; i < S; ++i) {
a[i] = max (p[i], rhs.p[i]);
b[i] = min (p[i] + e[i], rhs.p[i] + rhs.e[i]);
size_type nw = sign_cast<size_type> (newx2 - newx1);
size_type nh = sign_cast<size_type> (newy2 - newy1);
return util::region<S,T> (newx1, newy1, nw, nh);
}
if (b[i] < a[i])
throw std::logic_error ("no overlap");
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::inset (T mag)
{
CHECK_GE (w, 2 * mag);
CHECK_GE (h, 2 * mag);
return { x + mag, y + mag, w - 2 * mag, h - 2 * mag };
return { a, b };
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::expand (T _w, T _h)
util::region<S,T>::resize (extent<S,T> _e)
{
x -= _w;
y -= _h;
w += _w * 2;
h += _h * 2;
e = _e;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::inset (T mag)
{
// ensure we have enough space to inset
CHECK (std::all_of (std::begin (e.data),
std::end (e.data),
[mag] (auto i) { return i >= 2 * mag; }));
return {
p + mag,
e - 2 * mag
};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::expand (vector<S,T> v)
{
p -= v;
e += v * T{2};
return *this;
}
@ -296,20 +294,18 @@ template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::expand (T mag)
{
return expand (mag, mag);
return expand ({mag});
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::expanded (T _w, T _h) const
util::region<S,T>::expanded (vector<S,T> v) const
{
return {
x - _w,
y - _h,
w + _w * 2,
h + _h * 2,
p - v,
e + v * T{2}
};
}
@ -319,7 +315,7 @@ template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::expanded (T mag) const
{
return expanded (mag, mag);
return expanded ({mag});
}
@ -328,7 +324,7 @@ template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::operator+ (vector<S,T> rhs) const
{
return { x + rhs.x, y + rhs.y, w, h };
return { p + rhs, e };
}
@ -337,7 +333,7 @@ template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::operator- (vector<S,T> rhs) const
{
return { x - rhs.x, y - rhs.y, w, h };
return { p - rhs, e };
}
@ -346,10 +342,7 @@ template <size_t S, typename T>
bool
util::region<S,T>::operator== (region rhs) const
{
return almost_equal (x, rhs.x) &&
almost_equal (y, rhs.y) &&
almost_equal (w, rhs.w) &&
almost_equal (h, rhs.h);
return p == rhs.p && e == rhs.e;
}
@ -357,8 +350,8 @@ util::region<S,T>::operator== (region rhs) const
template <size_t S, typename T>
void
util::region<S,T>::sanity (void) const {
CHECK_GE (w, 0);
CHECK_GE (h, 0);
CHECK_GE (e.area (), 0);
static_assert(!std::is_floating_point<T>::value,
"Floating point types need width and height checks");
}
@ -368,15 +361,13 @@ util::region<S,T>::sanity (void) const {
namespace util {
template <>
void region<2,double>::sanity (void) const {
CHECK_GE (w, 0);
CHECK_GE (h, 0);
CHECK_GE (e.area (), 0);
}
template <>
void region<2,float>::sanity (void) const {
CHECK_GE (w, 0);
CHECK_GE (h, 0);
CHECK_GE (e.area (), 0);
}
}
@ -393,22 +384,20 @@ template <size_t S, typename T>
const util::region<S,T>
util::region<S,T>::MAX (
std::numeric_limits<T>::lowest () / 2,
std::numeric_limits<T>::lowest () / 2,
std::numeric_limits<T>::max (),
std::numeric_limits<T>::max ()
);
template <size_t S, typename T>
const util::region<S,T>
util::region<S,T>::UNIT (0, 0, 1, 1);
util::region<S,T>::UNIT ({0}, {1});
//-----------------------------------------------------------------------------
template <size_t S, typename T>
std::ostream&
util::operator<< (std::ostream &os, const util::region<S,T> &rhs) {
os << "region(" << rhs.x << ", " << rhs.y << ", " << rhs.w << ", " << rhs.h << ")";
os << "region(" << rhs.p << ", " << rhs.e << ")";
return os;
}

View File

@ -35,22 +35,43 @@ namespace util {
using position_type = T;
using size_type = typename try_unsigned<T>::type;
static constexpr size_t dimension = S;
static constexpr size_t elements = dimension * 2;
using value_type = T;
using extent_t = util::extent<S,size_type>;
using point_t = util::point<S,position_type>;
position_type x, y;
size_type w, h;
using value_type = T;
//---------------------------------------------------------------------
static constexpr size_t dimension = S;
static constexpr size_t elements = extent_t::elements + point_t::elements;
#pragma GCC diagnostic push
#if defined(COMPILER_GCC)
#pragma GCC diagnostic ignored "-pedantic"
#endif
#if defined(COMPILER_CLANG)
#pragma GCC diagnostic ignored "-Wgnu"
#endif
union {
struct {
point_t p;
extent_t e;
};
struct {
T x, y;
T w, h;
};
};
#pragma GCC diagnostic pop
//---------------------------------------------------------------------
region () = default;
region (extent_t);
region (point_t, extent_t);
region (point_t, point_t);
region (T _x, T _y, size_type _w, size_type _h);
region (std::array<T,S*2>);
region (position_type, size_type);
//---------------------------------------------------------------------
size_type area (void) const;
size_type diameter (void) const;
extent_t magnitude (void) const;
@ -60,13 +81,13 @@ namespace util {
bool empty (void) const;
point_t rebase (point_t);
//---------------------------------------------------------------------
point_t base (void) const;
point_t away (void) const;
point_t centre (void) const;
point_t closest (point_t) const;
//---------------------------------------------------------------------
// Point and region relation queries
bool includes (point_t) const; // inclusive of borders
bool contains (point_t) const; // exclusive of borders
@ -79,14 +100,17 @@ namespace util {
// Compute binary region combinations
region intersection (region<S,T>) const;
//---------------------------------------------------------------------
region& resize (extent<S,T>);
// Compute a region `mag` units into the region
region inset (T mag);
region expanded (T mag) const;
region expanded (T w, T h) const;
region expanded (vector<S,T>) const;
region& expand (T mag);
region& expand (T w, T h);
region& expand (vector<S,T>);
// arithmetic operators
region operator+ (vector<S,T>) const;

View File

@ -167,15 +167,20 @@ template <>
void
test_region<1> (void)
{
static const util::bezier<1> upright ({{0.f, 0.f}, {100.f, 100.f}});
static const util::bezier<1> downleft ({{100.f, 100.f}, {0.f, 0.f}});
static const util::bezier<1> vertical ({{0.f, 0.f}, {0.f, 100.f}});
static const util::bezier<1> horizontal ({{0.f, 0.f}, {100.f, 0.f}});
util::point2f p0 { 0, 0 },
p1 { 100, 0 },
p2 { 100, 100 },
p3 { 0, 100 };
CHECK_EQ (upright.region (), util::region2f (0.f, 0.f, 100.f, 100.f));
CHECK_EQ (downleft.region (), util::region2f (0.f, 0.f, 100.f, 100.f));
CHECK_EQ (vertical.region (), util::region2f (0.f, 0.f, 0.f, 100.f));
CHECK_EQ (horizontal.region (), util::region2f (0.f, 0.f, 100.f, 0.f));
static const util::bezier<1> upright ({p0, p2});
static const util::bezier<1> downleft ({p2, p0});
static const util::bezier<1> vertical ({p0, p3});
static const util::bezier<1> horizontal ({p0, p2});
CHECK_EQ (upright.region (), util::region2f (p0, p2));
CHECK_EQ (downleft.region (), util::region2f (p0, p2));
CHECK_EQ (vertical.region (), util::region2f (p0, p3));
CHECK_EQ (horizontal.region (), util::region2f (p0, p2));
}
@ -184,9 +189,13 @@ template <>
void
test_region<2> (void)
{
static const util::bezier<2> upright({{0.f, 0.f}, {50.f, 50.f}, {100.f, 100.f}});
util::point2f p0 { 0, 0 },
p1 { 50, 50 },
p2 { 100, 100 };
CHECK_EQ (upright.region (), util::region2f (0.0f, 0.f, 100.f, 100.0f));
static const util::bezier<2> upright({p0, p1, p2});
CHECK_EQ (upright.region (), util::region2f (p0, p2));
}
@ -195,9 +204,14 @@ template <>
void
test_region<3> (void)
{
static const util::bezier<3> upright({{0.f, 0.f}, {33.f, 33.f}, {67.f, 67.f}, {100.f, 100.f}});
util::point2f p0 { 0, 0 },
p1 { 33, 33 },
p2 { 67, 67 },
p3 { 100, 100 };
CHECK_EQ (upright.region (), util::region2f (0.0f, 0.f, 100.f, 100.0f));
static const util::bezier<3> upright({p0, p1, p2, p3});
CHECK_EQ (upright.region (), util::region2f (p0, p3));
}

View File

@ -7,8 +7,14 @@ using namespace util;
int
main (int, char **) {
{
region2d a {32.7, -6.09703, 0.8, 2};
region2d b {33.5, -4.5, 0.5, 0.5};
util::point2d ap { 32.7, -6.09703 };
util::extent2d ae { 0.8, 2. };
util::point2d bp {33.5, -4.5};
util::extent2d be { 0.5, 0.5 };
region2d a (ap, ae);
region2d b (bp, be);
CHECK (!a.intersects (b));
}
@ -19,13 +25,16 @@ main (int, char **) {
CHECK_EQ (region2d::UNIT.area (), 1.0);
CHECK_EQ (region2f::UNIT.area (), 1.0f);
CHECK (region2u (0, 0, 2, 2).includes (point2u {1, 1}));
CHECK (region2u (0, 0, 2, 2).includes (point2u {0, 0}));
CHECK (region2u (0, 0, 2, 2).includes (point2u {2, 2}));
util::point2u p0 { 0 };
util::extent2u e0 { 2 };
CHECK ( region2u (0, 0, 2, 2).contains (point2u {1, 1}));
CHECK (!region2u (0, 0, 2, 2).contains (point2u {0, 0}));
CHECK (!region2u (0, 0, 2, 2).contains (point2u {2, 2}));
CHECK (region2u (p0, e0).includes (point2u {1, 1}));
CHECK (region2u (p0, e0).includes (point2u {0, 0}));
CHECK (region2u (p0, e0).includes (point2u {2, 2}));
CHECK ( region2u (p0, e0).contains (point2u {1, 1}));
CHECK (!region2u (p0, e0).contains (point2u {0, 0}));
CHECK (!region2u (p0, e0).contains (point2u {2, 2}));
//CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01)));
//CHECK (region<2,intmax_t> (0, 0, 10, 10).contains (point2d (0.4, 0.01)));

View File

@ -28,209 +28,11 @@
#include <limits>
#include <numeric>
#if defined(COMPILER_GCC)
#pragma GCC optimize("-O3")
#endif
//-----------------------------------------------------------------------------
using namespace util;
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator* (T rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * rhs;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator*= (T rhs) {
for (auto &i: this->data)
i *= rhs;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator* (const vector<S,T> &rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * rhs.data[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator*= (const vector<S,T> &rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] *= rhs.data[i];
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator/ (T rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] / rhs;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator/= (T rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] /= rhs;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator+ (const util::vector<S,T> &rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] + rhs.data[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator+ (T rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] + rhs;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator+= (const util::vector<S,T> &rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] += rhs.data[i];
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator+= (T rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] += rhs;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator- (void) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = -this->data[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator- (const util::vector<S,T> &rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs.data[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator-= (const util::vector<S,T> &rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] -= rhs.data[i];
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>
util::vector<S,T>::operator- (T rhs) const {
util::vector<S,T> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator-= (T rhs) {
for (size_t i = 0; i < S; ++i)
this->data[i] -= rhs;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::vector<S,T>&
util::vector<S,T>::operator= (const util::vector<S,T> &rhs) {
std::copy (std::begin (rhs.data), std::end (rhs.data), std::begin (this->data));
return *this;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
bool
util::vector<S,T>::operator== (const util::vector<S,T> &rhs) const {
for (size_t i = 0; i < S; ++i)
if (!almost_equal (this->data[i], rhs.data[i]))
return false;
return true;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T
@ -306,16 +108,6 @@ util::polar_to_cartesian (const util::vector<2,T> &v) {
};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T
util::vector<S,T>::dot (const util::vector<S,T> &rhs) const {
T total { 0 };
for (size_t i = 0; i < S; ++i)
total += this->data[i] * rhs.data[i];
return total;
}
//-----------------------------------------------------------------------------
template <typename T>
@ -386,44 +178,6 @@ util::vector<S,T>::sanity (void) const {
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
util::vector<S,T>
util::operator* (U a, const util::vector<S,T> &b)
{
return b * T(a);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T, typename U>
util::vector<S,T>
util::operator+ (U a, const util::vector<S,T> &b)
{
return b + T(a);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T, typename U>
util::vector<S,T>
util::operator- (U a, const util::vector<S,T> &b)
{
return a + (-b);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T
util::dot (vector<S,T> a, vector<S,T> b)
{
return std::inner_product (std::begin (a),
std::end (a),
std::begin (b),
T{0});
}
///////////////////////////////////////////////////////////////////////////////
// ostream
@ -460,12 +214,6 @@ util::operator>> (const json::tree::node &node, util::vector<S,T> &v) {
#define INSTANTIATE_S_T(S,T) \
template struct util::vector<S,T>; \
template util::vector<S,T> util::operator* (int, const util::vector<S,T>&); \
template util::vector<S,T> util::operator* (unsigned, const util::vector<S,T>&); \
template util::vector<S,T> util::operator* (float, const util::vector<S,T>&); \
template util::vector<S,T> util::operator+ (T, const util::vector<S,T>&); \
template util::vector<S,T> util::operator- (T, const util::vector<S,T>&); \
template T util::dot (util::vector<S,T>, util::vector<S,T>); \
template std::ostream& util::operator<< (std::ostream&, const util::vector<S,T> &v);\
template const json::tree::node& util::operator>> (const json::tree::node&, util::vector<S,T>&);

View File

@ -32,35 +32,6 @@ namespace util {
struct vector : public detail::coord<S,T,detail::xyzw,detail::stpq> {
using detail::coord<S,T,detail::xyzw,detail::stpq>::coord;
// arithmetic operators
vector<S,T> operator* (T) const;
vector<S,T>& operator*=(T);
vector<S,T> operator/ (T) const;
vector<S,T>& operator/=(T);
vector<S,T> operator+ (T) const;
vector<S,T>& operator+=(T);
vector<S,T> operator- (T) const;
vector<S,T>& operator-=(T);
// element operators
vector<S,T> operator* (const vector<S,T>&) const;
vector<S,T>& operator*=(const vector<S,T>&);
vector<S,T> operator+ (const vector<S,T>&) const;
vector<S,T>& operator+=(const vector<S,T>&);
vector<S,T> operator- (void) const;
vector<S,T> operator- (const vector<S,T>&) const;
vector<S,T>& operator-=(const vector<S,T>&);
vector<S, T>& operator =(const vector<S,T>&);
// logical operators
bool operator== (const vector<S,T>&) const;
bool is_zero (void) const;
// vector operators
@ -70,8 +41,6 @@ namespace util {
T difference (const vector<S,T>&) const;
T difference2 (const vector<S,T>&) const;
T dot (const vector<S,T>&) const;
vector<S,T>& normalise (void);
vector<S,T> normalised [[gnu::warn_unused_result]] (void) const;
@ -93,12 +62,6 @@ namespace util {
template <typename T> vector<3,T> spherical_to_cartesian (const vector<3,T>&);
template <typename T> vector<3,T> cartesian_to_spherical (const vector<3,T>&);
template <size_t S, typename T, typename U> vector<S,T> operator* (U, const vector<S,T>&);
template <size_t S, typename T, typename U> vector<S,T> operator+ (U, const vector<S,T>&);
template <size_t S, typename T, typename U> vector<S,T> operator- (U, const vector<S,T>&);
template <size_t S, typename T> T dot (vector<S,T>, vector<S,T>);
// output and serialisation operators
template <size_t S, typename T> std::ostream& operator<< (std::ostream&, const vector<S,T>&);