psemek/libs/geom/include/psemek/geom/box.hpp

350 lines
7 KiB
C++

#pragma once
#include <psemek/geom/detail/array.hpp>
#include <psemek/geom/interval.hpp>
#include <psemek/geom/point.hpp>
#include <iostream>
namespace psemek::geom
{
template <typename T, std::size_t N>
struct box
{
typename detail::array<interval<T>, N>::type axes;
using point_type = point<T, N>;
using vector_type = vector<T, N>;
interval<T> & operator[](std::size_t i)
{
return axes[i];
}
interval<T> const & operator[](std::size_t i) const
{
return axes[i];
}
static box singleton(point_type const & p)
{
box b;
for (std::size_t i = 0; i < N; ++i)
b.axes[i] = interval<T>::singleton(p[i]);
return b;
}
static box full()
{
box b;
for (std::size_t i = 0; i < N; ++i)
b.axes[i] = interval<T>::full();
return b;
}
bool empty() const
{
for (auto const & i : axes)
if (i.empty())
return true;
return false;
}
T volume() const
{
T result = T{1};
for (auto const & i : axes)
result *= i.length();
return result;
}
geom::vector<T, N> dimensions() const
{
geom::vector<T, N> result;
for (std::size_t i = 0; i < N; ++i)
result[i] = axes[i].length();
return result;
}
point_type center() const
{
point_type p;
for (std::size_t i = 0; i < N; ++i)
p[i] = axes[i].center();
return p;
}
template <typename ... Ts>
point_type corner(Ts const & ... ts) const
{
static_assert(sizeof...(Ts) == N);
T w[N] = {static_cast<T>(ts)...};
point_type res;
for (std::size_t i = 0; i < N; ++i)
res[i] = lerp(axes[i], w[i]);
return res;
}
box & operator += (vector_type const & delta);
box & operator -= (vector_type const & delta);
box & operator &= (point_type const & p);
box & operator |= (point_type const & p);
box & operator &= (box const & b);
box & operator |= (box const & b);
};
template <typename T1, typename T, std::size_t N>
box<T1, N> cast(box<T, N> const & b)
{
box<T1, N> result;
for (std::size_t i = 0; i < N; ++i)
result[i] = cast<T1>(b[i]);
return result;
}
template <typename T, std::size_t N>
box<T, N> operator + (box<T, N> const & b, vector<T, N> const & delta)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b[i] + delta[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator + (vector<T, N> const & delta, box<T, N> const & b)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = delta[i] + b[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator - (box<T, N> const & b, vector<T, N> const & delta)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b[i] - delta[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator & (box<T, N> const & b, point<T, N> const & p)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b[i] & p[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator & (point<T, N> const & p, box<T, N> const & b)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = p[i] & b[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator | (box<T, N> const & b, point<T, N> const & p)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b[i] | p[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator | (point<T, N> const & p, box<T, N> const & b)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = p[i] | b[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator & (box<T, N> const & b1, box<T, N> const & b2)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b1[i] & b2[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> operator | (box<T, N> const & b1, box<T, N> const & b2)
{
box<T, N> result;
for (std::size_t i = 0; i < N; ++i)
{
result[i] = b1[i] | b2[i];
}
return result;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator += (vector<T, N> const & delta)
{
return *this = *this + delta;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator -= (vector<T, N> const & delta)
{
return *this = *this - delta;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator &= (point<T, N> const & p)
{
return *this = *this & p;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator |= (point<T, N> const & p)
{
return *this = *this | p;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator &= (box<T, N> const & b)
{
return *this = *this & b;
}
template <typename T, std::size_t N>
box<T, N> & box<T, N>::operator |= (box<T, N> const & b)
{
return *this = *this | b;
}
template <typename T, std::size_t N>
bool operator == (box<T, N> const & b1, box<T, N> const & b2)
{
for (std::size_t i = 0; i < N; ++i)
if (b1[i] != b2[i])
return false;
return true;
}
template <typename T, std::size_t N>
bool operator != (box<T, N> const & b1, box<T, N> const & b2)
{
return !(b1 == b2);
}
template <typename T, std::size_t N>
std::ostream & operator << (std::ostream & os, box<T, N> const & b)
{
for (std::size_t i = 0; i < N; ++i)
{
if (i != 0) os << 'x';
os << b[i];
}
return os;
}
template <typename T, std::size_t N>
point<T, N> clamp(point<T, N> p, box<T, N> const & b)
{
for (std::size_t i = 0; i < N; ++i)
p[i] = clamp(p[i], b[i]);
return p;
}
template <typename T, std::size_t N>
box<T, N> expand(box<T, N> b, T const & d)
{
for (std::size_t i = 0; i < N; ++i)
{
b[i] = expand(b[i], d);
}
return b;
}
template <typename T, std::size_t N>
box<T, N> expand(box<T, N> b, vector<T, N> const & d)
{
for (std::size_t i = 0; i < N; ++i)
{
b[i] = expand(b[i], d[i]);
}
return b;
}
template <typename T, std::size_t N>
box<T, N> shrink(box<T, N> b, T const & d)
{
return expand(b, -d);
}
template <typename T, std::size_t N>
box<T, N> shrink(box<T, N> b, vector<T, N> const & d)
{
return expand(b, -d);
}
template <typename T, std::size_t N>
box<T, N> span(point<T, N> const & p1, point<T, N> const & p2)
{
box<T, N> b;
for (std::size_t i = 0; i < N; ++i)
{
b.axes[i] = {p1[i], p2[i]};
if (b.axes[i].min > b.axes[i].max)
std::swap(b.axes[i].min, b.axes[i].max);
}
return b;
}
template <typename T, std::size_t N>
point<T, N> lerp(box<T, N> const & b, vector<T, N> const & v)
{
point<T, N> p;
for (std::size_t i = 0; i < N; ++i)
p[i] = lerp(b[i], v[i]);
return p;
}
template <typename T, std::size_t N>
vector<T, N> unlerp(box<T, N> const & b, point<T, N> const & p)
{
vector<T, N> v;
for (std::size_t i = 0; i < N; ++i)
v[i] = unlerp(b[i], p[i]);
return v;
}
template <typename T, std::size_t N>
bool isfinite(box<T, N> const & b)
{
for (std::size_t i = 0; i < N; ++i)
if (!isfinite(b[i]))
return false;
return true;
}
}