350 lines
7 KiB
C++
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;
|
|
}
|
|
|
|
}
|