blob: e619711caabceab728349059086277e490669053 [file] [log] [blame]
#ifndef RTTL_BOX_HXX
#define RTTL_BOX_HXX
#include "RTVec.hxx"
namespace RTTL {
template<int N, typename DataType, int align = 0>
class RTBox_t {
public:
typedef RTVec_t<N, DataType, align> RTVec;
RTBox_t() {
// _NO_ default initialization!
}
RTBox_t(const RTVec& cmin, const RTVec& cmax): m_min(cmin), m_max(cmax) {}
RTBox_t(const RTVec* pts, int npts) {
set(pts[0]);
for (int i = 1; i < npts; i++)
extend(pts[i]);
}
RTBox_t(const RTVec& pt1, const RTVec& pt2, const RTVec& pt3) {
// Triangle's BB.
set(pt1);
extend(pt2);
extend(pt3);
}
RTBox_t(const RTBox_t& b) : m_min(b.m_min), m_max(b.m_max) {}
_INLINE void reset();
_INLINE void setEmpty() { reset(); }
/// Return index of the longest/shortest side
_INLINE DataType maxSide() const { return (m_max - m_min).maximum(); }
_INLINE DataType minSide() const { return (m_max - m_min).minimum(); }
/// Return index of the longest/sortest side
_INLINE int maxIndex() const { return (m_max - m_min).maxIndex(); }
_INLINE int minIndex() const { return (m_max - m_min).minIndex(); }
//// Return dimension in which box has zero width or -1 otherwise
_INLINE int flat() const {
for (int i = 0; i < N; i++)
if (m_min[i] == m_max[i])
return i;
return -1;
}
/// Return true if this box is valid (that is, min <= max).
_INLINE bool isValid() const {
// Zero-width sides are allowed.
return m_max >= m_min;
}
/// Volume, valid for any dimension.
_INLINE DataType volume() const {
DataType v = 1;
for (int i = 0; i < N; i++)
v *= (m_max[i] - m_min[i]);
return v;
}
/// Box area. Valid for 2D and 3D, for other dimensions first 3 components will be used.
_INLINE DataType area() const {
DataType a = (m_max[0]-m_min[0]) * (m_max[1]-m_min[1]);
if (N >= 3) {
a = 2 * (a +
(m_max[0]-m_min[0]) * (m_max[2]-m_min[2]) +
(m_max[1]-m_min[1]) * (m_max[2]-m_min[2]));
}
return a;
}
_INLINE void set(const RTVec& v) {
m_min = v;
m_max = v;
}
_INLINE void extend(const RTVec* pts, int npts) {
for (int i = 0; i < npts; i++)
extend(pts[i]);
}
_INLINE void around(const RTVec* pts, int npts) {
assert(npts >= 1);
set(pts[0]);
extend(pts+1, npts-1);
}
_INLINE void extend(const RTVec& v) {
m_min.setMin(v);
m_max.setMax(v);
}
_INLINE void extend(const RTBox_t& b) {
m_min.setMin(b.m_min);
m_max.setMax(b.m_max);
}
_INLINE void extend(const DataType& v) {
m_min.setMin(v);
m_max.setMax(v);
}
_INLINE RTBox_t intersection(const RTBox_t& b) const {
return *this - b;
}
_INLINE RTBox_t clip(const RTBox_t& b) const {
return *this - b;
}
_INLINE bool intersect(const RTBox_t& b) const {
return intersection(b).isValid();
}
/// point n is inside this
_INLINE bool enclose(const RTVec& v) const {
return (v >= m_min) && (v <= m_max);
}
_INLINE bool encloseAny(const RTVec* pts, int npts) const {
for (int i = 0; i < npts; i++)
if (enclose(pts[i])) return true;
return false;
}
_INLINE bool encloseAll(const RTVec* pts, int npts) const {
for (int i = 0; i < npts; i++)
if (!enclose(pts[i])) return false;
return true;
}
/// point v is strictly inside this box
_INLINE bool isStrictlyEnclose(const RTVec& v) const {
return (v > m_min) && (v < m_max);
}
/// point v is strictly inside this extended box
_INLINE bool isStrictlyEnclose(const RTVec& v, DataType off) const {
RTVec shift(off);
return (v > m_min + shift) && (v < m_max - shift);
}
/// this box is occluded by b
_INLINE bool isInside(const RTBox_t& b) const {
return (m_min >= b.m_min) && (m_max <= b.m_max);
}
/// this box is completely occluded by b
_INLINE bool isStrictlyInside(const RTBox_t& b) const {
return (m_min > b.m_min) && (m_max < b.m_max);
}
/// this box is completely occluded by extended b
_INLINE bool isStrictlyInside(const RTBox_t& b, DataType off) const {
RTVec shift(off);
return (m_min > b.m_min - shift) && (m_max < b.m_max + shift);
}
_INLINE void enlarge(DataType f) {
m_max += f;
m_min -= f;
}
_INLINE RTVec sides() const {
return m_max - m_min;
}
_INLINE RTVec diameter() const {
return m_max - m_min;
}
_INLINE RTVec center() const {
return 0.5f*(m_max + m_min);
}
// Operators.
_INLINE bool operator==(const RTBox_t& b) const {
return m_min == b.m_min && m_max == b.m_max;
}
_INLINE bool operator!=(const RTBox_t& b) const {
return m_min != b.m_min || m_max != b.m_max;
}
_INLINE const RTVec& operator[](const int i) const {
assert(i >= 0 && i < 2);
return *(&m_min + i);
}
_INLINE RTVec& operator[](const int i) {
assert(i >= 0 && i < 2);
return *(&m_min + i);
}
_INLINE const RTBox_t& operator=(const RTBox_t& b) {
m_min = b.m_min;
m_max = b.m_max;
return *this;
}
/// Return union.
_INLINE RTBox_t operator+(const RTBox_t& b) const {
RTBox_t r = *this;
r.m_min.setMin(b.m_min);
r.m_max.setMax(b.m_max);
return r;
}
/// return intersection -- could result in invalid box
_INLINE RTBox_t operator-(const RTBox_t& b) const {
RTBox_t r = *this;
r.m_min.setMax(b.m_min);
r.m_max.setMin(b.m_max);
return r;
}
_INLINE RTBox_t operator*(DataType f) const {
return RTBox_t(m_min*f, m_max*f);
}
/// set *this to union
_INLINE void operator+=(const RTBox_t& b) {
extend(b);
}
/// set *this to intersection -- could result in invalid box
_INLINE void operator-=(const RTBox_t& b) {
m_min.setMax(b.m_min);
m_max.setMin(b.m_max);
}
_INLINE const RTBox_t& operator*=(DataType f) {
m_min *= f;
m_max *= f;
return *this;
}
_INLINE const RTBox_t& operator/=(DataType f) {
m_min /= f;
m_max /= f;
return *this;
}
/// not valid for floats
_INLINE const RTBox_t& operator%=(DataType f) {
m_min %= f;
m_max %= f;
return *this;
}
RTVec m_min;
RTVec m_max;
};
/// Generic reset and its specialization.
template<int N, typename DataType, int align>
void RTBox_t<N, DataType, align>::reset() {
// Invalidate the current box.
m_min = RTVec_t<N, DataType, align>( RTVec_t<N, DataType, align>::infinity());
m_max = RTVec_t<N, DataType, align>(-RTVec_t<N, DataType, align>::infinity());
}
template<>
_INLINE void RTBox_t<1,sse_f>::reset() {
// Invalidate the current box.
m_min = _mm_set_ps1(+FLT_MAX);
m_max = _mm_set_ps1(-FLT_MAX);
}
template<int N, typename DataType, int align>
_INLINE RTBox_t<N, DataType, align> operator*(DataType f, const RTBox_t<N, DataType, align>& q) {
return q * f;
}
template<int N, typename DataType, int align>
_INLINE ostream& operator<<(ostream& out, const RTBox_t<N, DataType, align>& b) {
out << "[" << b.m_min << "," << b.m_max << "]";
return out;
}
#if 1
/// SSE implementation of 3D box of floats.
class RTBox3a : public RTBox_t<1, sse_f> {
public:
_INLINE sse_f center() const { return *RTBox_t<1, sse_f>::center(); }
_INLINE sse_f diameter() const { return *RTBox_t<1, sse_f>::diameter(); }
#ifdef RT_EMULATE_SSE
// No alignment in emulation mode -- has to create 3D boxes to compute area/volume.
_INLINE float volume() const {
return RTBox_t<3, float, 0>(min3f(), max3f()).volume();
}
_INLINE float area() const {
return RTBox_t<3, float, 0>(min3f(), max3f()).area();
}
#else
/// Treat this as aligned box of 3D vectors (which it is really is).
_INLINE float volume() const {
return ((RTBox_t<3, float, 16>*)this)->volume();
}
_INLINE float area() const {
float a3 = ((RTBox_t<3, float, 16>*)this)->area();
//float a4 = ((RTBox_t<4, float, 16>*)this)->area();
//cout << a3 << "\t" << a4 << endl;
return a3;
}
#endif
_INLINE RTVec3f& min3f() const {
return (RTVec3f&)m_min;
}
_INLINE RTVec3f& max3f() const {
return (RTVec3f&)m_max;
}
_INLINE RTVec3f& operator[](const int i) {
assert(i >= 0 && i < 2);
return (i == 0) ? *(RTVec3f*)&m_min[0] : *(RTVec3f*)&m_max[0];
}
_INLINE sse_f &min_f() { return m_min[0]; }
_INLINE sse_f &max_f() { return m_max[0]; }
_INLINE sse_f min_f() const { return m_min[0]; }
_INLINE sse_f max_f() const { return m_max[0]; }
};
#else
class RTBox3a : public RTBox_t<1, RTVec3f, RTData_t<1, RTVec3f, 16> > {
public:
RTBox3a() {}
RTBox3a(const sse_f& _min, const sse_f& _max) {
min_f() = _min;
max_f() = _max;
}
_INLINE RTVec3f& operator[](const int i) {
assert(i >= 0 && i < 2);
return (i == 0) ? m_min[0] : m_max[0];
}
_INLINE void extend(const sse_f &v) {
min_f() = min(min_f(),v);
max_f() = max(max_f(),v);
}
_INLINE void extend(const RTBox3a &box) {
min_f() = min(min_f(),box.min_f());
max_f() = max(max_f(),box.max_f());
}
_INLINE sse_f center() const {
return 0.5f*(min_f() + max_f());
}
_INLINE sse_f diameter() const {
return max_f() - min_f();
}
_INLINE void setEmpty() {
min_f() = _mm_set_ps1(+FLT_MAX);
max_f() = _mm_set_ps1(-FLT_MAX);
}
_INLINE sse_f &min_f() { return *(sse_f*)&m_min; }
_INLINE sse_f &max_f() { return *(sse_f*)&m_max; }
_INLINE sse_f &min_f() const { return *(sse_f*)&m_min; }
_INLINE sse_f &max_f() const { return *(sse_f*)&m_max; }
/// Treat this as aligned box of 3D vectors (which it is really is).
_INLINE float volume() const {
return ((RTBox_t<3, float, RTData_t<3, float, 16> >*)this)->volume();
}
_INLINE float area() const {
return ((RTBox_t<3, float, RTData_t<3, float, 16> >*)this)->area();
}
};
#endif
};
typedef RTTL::RTBox_t<2, float> RTBox2f;
typedef RTTL::RTBox_t<3, float> RTBox3f;
typedef RTTL::RTBox_t<4, float> RTBox4f;
typedef RTTL::RTBox_t<2, int> RTBox2i;
typedef RTTL::RTBox_t<3, int> RTBox3i;
typedef RTTL::RTBox_t<4, int> RTBox4i;
typedef RTTL::RTBox3a RTBoxSSE;
#endif