public:
virtual ~CompositeShape();
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
virtual bool contains(const LinAl::Vector<T, D> &) const;
virtual unsigned get_max_ray_intersections() const { return max_isect; }
virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
}
template<typename T, unsigned D, typename O>
-inline BoundingBox<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(unsigned detail) const
{
+ if(detail)
+ return this->bisect_axis_aligned_bounding_box(detail);
+
BoundingBox<T, D> aabb;
for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
{
const Shape<T, D-1> &get_base() const { return *base; }
T get_length() const { return length; }
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
{
- BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box();
+ BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box(detail);
T half_length = length/T(2);
return BoundingBox<T, D>(compose(base_bbox.get_minimum_point(), -half_length),
compose(base_bbox.get_maximum_point(), half_length));
const LinAl::Vector<T, D> &get_normal() const { return normal; }
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box(unsigned) const
{
// XXX If the normal is aligned to an axis, should the bounding box reflect that?
return ~BoundingBox<T, D>();
const LinAl::Vector<T, D> &get_dimensions() const { return dimensions; }
T get_dimension(unsigned) const;
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> HyperBox<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HyperBox<T, D>::get_axis_aligned_bounding_box(unsigned) const
{
LinAl::Vector<T, D> half_dim = dimensions/T(2);
return BoundingBox<T, D>(-half_dim, half_dim);
T get_radius() const { return radius; }
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box(unsigned) const
{
LinAl::Vector<T, D> extent;
for(unsigned i=0; i<D; ++i)
const Shape<T, D> &get_shape() const { return *shape; }
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
{
- return ~shape->get_axis_aligned_bounding_box();
+ return ~shape->get_axis_aligned_bounding_box(detail);
}
template<typename T, unsigned D>
#ifndef MSP_GEOMETRY_SHAPE_H_
#define MSP_GEOMETRY_SHAPE_H_
+#include <list>
#include <vector>
#include <msp/linal/vector.h>
#include "boundingbox.h"
class Shape
{
protected:
+ struct CoverageCell
+ {
+ unsigned level;
+ BoundingBox<T, D> bounding_box;
+ Coverage coverage;
+ };
+
Shape() { }
public:
virtual ~Shape() { }
virtual Shape *clone() const = 0;
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const = 0;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned detail = 0) const = 0;
+protected:
+ BoundingBox<T, D> bisect_axis_aligned_bounding_box(unsigned) const;
+public:
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;
virtual Coverage get_coverage(const BoundingBox<T, D> &) const = 0;
};
+template<typename T, unsigned D>
+inline BoundingBox<T, D> Shape<T, D>::bisect_axis_aligned_bounding_box(unsigned detail) const
+{
+ if(!detail)
+ throw std::invalid_argument("Shape::bisect_axis_aligned_bounding_box");
+
+ std::list<CoverageCell> queue;
+ queue.push_back(CoverageCell());
+ CoverageCell &root = queue.front();
+ root.level = 0;
+ root.bounding_box = get_axis_aligned_bounding_box();
+ if(root.bounding_box.is_space())
+ return root.bounding_box;
+
+ root.coverage = get_coverage(root.bounding_box);
+ if(root.coverage==FULL_COVERAGE)
+ return root.bounding_box;
+
+ LinAl::Vector<T, D> tight_min_pt = root.bounding_box.get_maximum_point();
+ LinAl::Vector<T, D> tight_max_pt = root.bounding_box.get_minimum_point();
+
+ while(!queue.empty())
+ {
+ CoverageCell &cell = queue.front();
+
+ const LinAl::Vector<T, D> &min_pt = cell.bounding_box.get_minimum_point();
+ const LinAl::Vector<T, D> &max_pt = cell.bounding_box.get_maximum_point();
+ LinAl::Vector<T, D> center = (min_pt+max_pt)/T(2);
+
+ for(unsigned i=0; i<(1<<D); ++i)
+ {
+ CoverageCell child;
+ child.level = cell.level+1;
+
+ LinAl::Vector<T, D> child_min_pt = min_pt;
+ LinAl::Vector<T, D> child_max_pt = max_pt;
+ for(unsigned j=0; j<D; ++j)
+ {
+ if((i>>j)&1)
+ child_min_pt[j] = center[j];
+ else
+ child_max_pt[j] = center[j];
+ }
+ child.bounding_box = BoundingBox<T, D>(child_min_pt, child_max_pt);
+
+ child.coverage = get_coverage(child.bounding_box);
+ if(child.coverage==FULL_COVERAGE || (child.level==detail && child.coverage!=NO_COVERAGE))
+ {
+ for(unsigned j=0; j<D; ++j)
+ {
+ tight_min_pt[j] = std::min(tight_min_pt[j], child_min_pt[j]);
+ tight_max_pt[j] = std::max(tight_max_pt[j], child_max_pt[j]);
+ }
+ }
+ else if(child.coverage==PARTIAL_COVERAGE)
+ queue.push_back(child);
+ }
+
+ queue.pop_front();
+ }
+
+ return BoundingBox<T, D>(tight_min_pt, tight_max_pt);
+}
+
template<typename T, unsigned D>
inline bool Shape<T, D>::check_intersection(const Ray<T, D> &ray) const
{
const Shape<T, D> &get_shape() const { return *shape; }
const AffineTransformation<T, D> &get_transformation() const { return transformation; }
- virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+ virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) 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 BoundingBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
{
+ if(detail)
+ return this->bisect_axis_aligned_bounding_box(detail);
+
return transformation.transform(shape->get_axis_aligned_bounding_box());
}