--- /dev/null
+#ifndef MSP_GEOMETRY_BOUNDINGBOX_H_
+#define MSP_GEOMETRY_BOUNDINGBOX_H_
+
+#include <algorithm>
+#include <stdexcept>
+#include <msp/linal/vector.h>
+
+namespace Msp {
+namespace Geometry {
+
+template<typename T, unsigned D>
+class BoundingBox
+{
+private:
+ LinAl::Vector<T, D> min_pt;
+ LinAl::Vector<T, D> max_pt;
+ bool empty;
+ bool negated;
+
+public:
+ BoundingBox();
+ BoundingBox(const LinAl::Vector<T, D> &, const LinAl::Vector<T, D> &);
+
+ static BoundingBox negate(const BoundingBox &);
+
+ const LinAl::Vector<T, D> &get_minimum_point() const { return min_pt; }
+ T get_minimum_coordinate(unsigned i) const { return min_pt[i]; }
+ const LinAl::Vector<T, D> &get_maximum_point() const { return max_pt; }
+ T get_maximum_coordinate(unsigned i) const { return max_pt[i]; }
+ bool is_empty() const { return empty; }
+ bool is_negated() const { return negated; }
+};
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D>::BoundingBox():
+ empty(true),
+ negated(false)
+{ }
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D>::BoundingBox(const LinAl::Vector<T, D> &n, const LinAl::Vector<T, D> &x):
+ min_pt(n),
+ max_pt(x),
+ empty(false),
+ negated(false)
+{
+ for(unsigned i=0; i<D; ++i)
+ if(min_pt[i]>max_pt[i])
+ throw std::invalid_argument("BoundingBox::BoundingBox");
+}
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D> BoundingBox<T, D>::negate(const BoundingBox<T, D> &bb)
+{
+ BoundingBox<T, D> result = bb;
+ result.negated = !bb.negated;
+ return result;
+}
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D> operator&(const BoundingBox<T, D> &bb1, const BoundingBox<T, D> &bb2)
+{
+ if(bb1.is_empty() || bb2.is_empty())
+ return BoundingBox<T, D>();
+
+ if(bb1.is_negated())
+ {
+ if(bb2.is_negated())
+ return ~((~bb1)|(~bb2));
+ else
+ return bb2&bb1;
+ }
+
+ LinAl::Vector<T, D> result_min;
+ LinAl::Vector<T, D> result_max;
+
+ if(bb2.is_negated())
+ {
+ // This is effectively subtraction of (non-negated) bb2 from bb1
+ int uncovered_axis = -1;
+ for(unsigned i=0; i<D; ++i)
+ if(bb1.get_minimum_coordinate(i)<bb2.get_minimum_coordinate(i) || bb1.get_maximum_coordinate(i)>bb2.get_maximum_coordinate(i))
+ {
+ if(uncovered_axis!=-1)
+ return bb1;
+ uncovered_axis = i;
+ }
+
+ if(uncovered_axis==-1)
+ return BoundingBox<T, D>();
+
+ result_min = bb1.get_minimum_point();
+ result_max = bb1.get_maximum_point();
+ if(bb2.get_minimum_coordinate(uncovered_axis)<bb1.get_minimum_coordinate(uncovered_axis))
+ result_min[uncovered_axis] = bb2.get_maximum_coordinate(uncovered_axis);
+ else
+ result_max[uncovered_axis] = bb2.get_minimum_coordinate(uncovered_axis);
+ }
+ else
+ {
+ for(unsigned i=0; i<D; ++i)
+ {
+ result_min[i] = std::max(bb1.get_minimum_coordinate(i), bb1.get_minimum_coordinate(i));
+ result_max[i] = std::min(bb1.get_minimum_coordinate(i), bb1.get_minimum_coordinate(i));
+ if(result_min[i]>result_max[i])
+ return BoundingBox<T, D>();
+ }
+ }
+
+ return BoundingBox<T, D>(result_min, result_max);
+}
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D> operator|(const BoundingBox<T, D> &bb1, const BoundingBox<T, D> &bb2)
+{
+ if(bb1.is_empty())
+ return bb2;
+ if(bb2.is_empty())
+ return bb1;
+
+ if(bb1.is_negated())
+ return ~((~bb1)&(~bb2));
+ else if(bb2.is_negated())
+ return ~((~bb2)&(~bb1));
+
+ LinAl::Vector<T, D> result_min;
+ LinAl::Vector<T, D> result_max;
+ for(unsigned i=0; i<D; ++i)
+ {
+ result_min[i] = std::min(bb1.get_minimum_coordinate(i), bb1.get_minimum_coordinate(i));
+ result_max[i] = std::max(bb1.get_minimum_coordinate(i), bb1.get_minimum_coordinate(i));
+ }
+
+ return BoundingBox<T, D>(result_min, result_max);
+}
+
+template<typename T, unsigned D>
+inline BoundingBox<T, D> operator~(const BoundingBox<T, D> &bb)
+{
+ return BoundingBox<T, D>::negate(bb);
+}
+
+} // namespace Geometry
+} // namespace Msp
+
+#endif
#include <stdexcept>
#include <vector>
+#include "boundingbox.h"
#include "shape.h"
namespace Msp {
public:
virtual ~CompositeShape();
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const;
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D, typename O>
-inline HyperBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
{
- HyperBox<T, D> aabb;
+ BoundingBox<T, D> aabb;
for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
{
if(i==shapes.begin())
const Shape<T, D-1> &get_base() const { return *base; }
T get_length() const { return length; }
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const;
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D>
-inline HyperBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box() const
{
- HyperBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box();
- return HyperBox<T, D>(LinAl::Vector<T, D>(base_bbox.get_dimensions(), length));
+ BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box();
+ T half_length = length/T(2);
+ return BoundingBox<T, D>(LinAl::Vector<T, D>(base_bbox.get_minimum_point(), -half_length),
+ LinAl::Vector<T, D>(base_bbox.get_maximum_point(), half_length));
}
template<typename T, unsigned D>
#ifndef MSP_GEOMETRY_HALFSPACE_H_
#define MSP_GEOMETRY_HALFSPACE_H_
+#include "boundingbox.h"
#include "shape.h"
namespace Msp {
const LinAl::Vector<T, D> &get_normal() const { return normal; }
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const { return 1; }
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D>
-inline HyperBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box() const
{
- // XXX Implement this properly
- return HyperBox<T, D>();
+ // XXX If the normal is aligned to an axis, should the bounding box reflect that?
+ return ~BoundingBox<T, D>();
}
template<typename T, unsigned D>
#include <cmath>
#include <stdexcept>
#include <msp/linal/vector.h>
+#include "boundingbox.h"
#include "ray.h"
#include "shape.h"
#include "surfacepoint.h"
const LinAl::Vector<T, D> &get_dimensions() const { return dimensions; }
T get_dimension(unsigned) const;
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const { return *this; }
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const { return 2; }
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
return dimensions[i];
}
+template<typename T, unsigned D>
+inline BoundingBox<T, D> HyperBox<T, D>::get_axis_aligned_bounding_box() const
+{
+ LinAl::Vector<T, D> half_dim = dimensions/T(2);
+ return BoundingBox<T, D>(-half_dim, half_dim);
+}
+
template<typename T, unsigned D>
inline bool HyperBox<T, D>::contains(const LinAl::Vector<T, D> &point) const
{
#include <cmath>
#include <stdexcept>
#include <msp/linal/vector.h>
-#include "hyperbox.h"
+#include "boundingbox.h"
#include "ray.h"
#include "shape.h"
#include "surfacepoint.h"
T get_radius() const { return radius; }
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const { return 2; }
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D>
-inline HyperBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box() const
{
- LinAl::Vector<T, D> dimensions;
+ LinAl::Vector<T, D> extent;
for(unsigned i=0; i<D; ++i)
- dimensions[i] = radius;
- return HyperBox<T, D>(dimensions);
+ extent[i] = radius;
+ return BoundingBox<T, D>(-extent, extent);
}
template<typename T, unsigned D>
template<typename T, unsigned D>
struct IntersectionOps
{
- static HyperBox<T, D> combine_aabb(const HyperBox<T, D> &, const HyperBox<T, D> &);
+ static BoundingBox<T, D> combine_aabb(const BoundingBox<T, D> &a, const BoundingBox<T, D> &b) { return a&b; }
static bool init_inside() { return true; }
static bool combine_inside(bool a, bool b) { return a && b; }
static bool is_inside_decided(bool a) { return !a; }
return new Intersection<T, D>(*this);
}
-
-template<typename T, unsigned D>
-inline HyperBox<T, D> IntersectionOps<T, D>::combine_aabb(const HyperBox<T, D> &box1, const HyperBox<T, D> &box2)
-{
- LinAl::Vector<T, D> dimensions;
- for(unsigned i=0; i<D; ++i)
- dimensions[i] = std::min(box1.get_dimension(i), box2.get_dimension(i));
- return HyperBox<T, D>(dimensions);
-}
-
} // namespace Geometry
} // namespace Msp
#ifndef MSP_GEOMETRY_NEGATION_H_
#define MSP_GEOMETRY_NEGATION_H_
+#include "boundingbox.h"
#include "shape.h"
namespace Msp {
const Shape<T, D> &get_shape() const { return *shape; }
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const { return shape->get_max_ray_intersections(); }
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D>
-inline HyperBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box() const
{
- // XXX How do we handle this correctly? In particular negation of a negation?
- return HyperBox<T, D>();
+ return ~shape->get_axis_aligned_bounding_box();
}
template<typename T, unsigned D>
namespace Geometry {
template<typename T, unsigned D>
-class HyperBox;
+class BoundingBox;
template<typename T, unsigned D>
class Ray;
virtual Shape *clone() const = 0;
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const = 0;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const = 0;
virtual bool contains(const LinAl::Vector<T, D> &) const = 0;
bool check_intersection(const Ray<T, D> &) const;
virtual unsigned get_max_ray_intersections() const = 0;
#define MSP_GEOMETRY_TRANSFORMEDSHAPE_H_
#include "affinetransformation.h"
+#include "boundingbox.h"
#include "ray.h"
#include "shape.h"
const Shape<T, D> &get_shape() const { return *shape; }
const AffineTransformation<T, D> &get_transformation() const { return transformation; }
- virtual HyperBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
private:
Ray<T, D> make_local_ray(const Ray<T, D> &) const;
}
template<typename T, unsigned D>
-inline HyperBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box() const
{
- // XXX This is not correct for most shapes
- return shape->get_axis_aligned_bounding_box();
+ BoundingBox<T, D> inner_bbox = shape->get_axis_aligned_bounding_box();
+
+ LinAl::Vector<T, D> min_pt;
+ LinAl::Vector<T, D> max_pt;
+ for(unsigned i=0; i<(1<<D); ++i)
+ {
+ LinAl::Vector<T, D> point;
+ for(unsigned j=0; j<D; ++j)
+ point[j] = ((i>>j)&1 ? inner_bbox.get_maximum_coordinate(j) : inner_bbox.get_minimum_coordinate(j));
+
+ point = transformation.transform(point);
+
+ for(unsigned j=0; j<D; ++j)
+ {
+ min_pt[j] = std::min(min_pt[j], point[j]);
+ max_pt[j] = std::max(min_pt[j], point[j]);
+ }
+ }
+
+ return BoundingBox<T, D>(min_pt, max_pt);
}
template<typename T, unsigned D>
template<typename T, unsigned D>
struct UnionOps
{
- static HyperBox<T, D> combine_aabb(const HyperBox<T, D> &, const HyperBox<T, D> &);
+ static BoundingBox<T, D> combine_aabb(const BoundingBox<T, D> &a, const BoundingBox<T, D> &b) { return a|b; }
static bool init_inside() { return false; }
static bool combine_inside(bool a, bool b) { return a || b; }
static bool is_inside_decided(bool a) { return a; }
return new Union<T, D>(*this);
}
-
-template<typename T, unsigned D>
-inline HyperBox<T, D> UnionOps<T, D>::combine_aabb(const HyperBox<T, D> &box1, const HyperBox<T, D> &box2)
-{
- LinAl::Vector<T, D> dimensions;
- for(unsigned i=0; i<D; ++i)
- dimensions[i] = std::max(box1.get_dimension(i), box2.get_dimension(i));
- return HyperBox<T, D>(dimensions);
-}
-
} // namespace Geometry
} // namespace Msp