1 #ifndef MSP_GEOMETRY_SHAPE_H_
2 #define MSP_GEOMETRY_SHAPE_H_
6 #include <msp/linal/vector.h>
7 #include "boundingbox.h"
9 #include "surfacepoint.h"
22 Base class and interface for geometric shapes. Shapes may be bounded or
23 unbounded. They are always considered to be solid, i.e. have a distinct inside
26 template<typename T, unsigned D>
33 BoundingBox<T, D> bounding_box;
41 virtual Shape *clone() const = 0;
43 virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned detail = 0) const = 0;
45 BoundingBox<T, D> bisect_axis_aligned_bounding_box(unsigned) const;
47 virtual bool contains(const LinAl::Vector<T, D> &) const = 0;
48 bool check_intersection(const Ray<T, D> &) const;
49 virtual unsigned get_max_ray_intersections() const = 0;
50 virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const = 0;
51 std::vector<SurfacePoint<T, D> > get_intersections(const Ray<T, D> &) const;
52 virtual Coverage get_coverage(const BoundingBox<T, D> &) const = 0;
55 template<typename T, unsigned D>
56 inline BoundingBox<T, D> Shape<T, D>::bisect_axis_aligned_bounding_box(unsigned detail) const
59 throw std::invalid_argument("Shape::bisect_axis_aligned_bounding_box");
61 std::list<CoverageCell> queue;
62 queue.push_back(CoverageCell());
63 CoverageCell &root = queue.front();
65 root.bounding_box = get_axis_aligned_bounding_box();
66 if(root.bounding_box.is_space())
67 return root.bounding_box;
69 root.coverage = get_coverage(root.bounding_box);
70 if(root.coverage==FULL_COVERAGE)
71 return root.bounding_box;
73 LinAl::Vector<T, D> tight_min_pt = root.bounding_box.get_maximum_point();
74 LinAl::Vector<T, D> tight_max_pt = root.bounding_box.get_minimum_point();
78 CoverageCell &cell = queue.front();
80 const LinAl::Vector<T, D> &min_pt = cell.bounding_box.get_minimum_point();
81 const LinAl::Vector<T, D> &max_pt = cell.bounding_box.get_maximum_point();
82 LinAl::Vector<T, D> center = (min_pt+max_pt)/T(2);
84 for(unsigned i=0; i<(1<<D); ++i)
87 child.level = cell.level+1;
89 LinAl::Vector<T, D> child_min_pt = min_pt;
90 LinAl::Vector<T, D> child_max_pt = max_pt;
91 for(unsigned j=0; j<D; ++j)
94 child_min_pt[j] = center[j];
96 child_max_pt[j] = center[j];
98 child.bounding_box = BoundingBox<T, D>(child_min_pt, child_max_pt);
100 child.coverage = get_coverage(child.bounding_box);
101 if(child.coverage==FULL_COVERAGE || (child.level==detail && child.coverage!=NO_COVERAGE))
103 for(unsigned j=0; j<D; ++j)
105 tight_min_pt[j] = std::min(tight_min_pt[j], child_min_pt[j]);
106 tight_max_pt[j] = std::max(tight_max_pt[j], child_max_pt[j]);
109 else if(child.coverage==PARTIAL_COVERAGE)
110 queue.push_back(child);
116 return BoundingBox<T, D>(tight_min_pt, tight_max_pt);
119 template<typename T, unsigned D>
120 inline bool Shape<T, D>::check_intersection(const Ray<T, D> &ray) const
122 return get_intersections(ray, 0, 1);
125 template<typename T, unsigned D>
126 inline std::vector<SurfacePoint<T, D> > Shape<T, D>::get_intersections(const Ray<T, D> &ray) const
128 unsigned max_isect = get_max_ray_intersections();
129 std::vector<SurfacePoint<T, D> > points(max_isect);
130 unsigned count = get_intersections(ray, &points[0], max_isect);
131 points.resize(count);
135 } // namespace Geometry