]> git.tdb.fi Git - libs/math.git/blob - source/geometry/compositeshape.h
Implement bounding boxes with a separate class
[libs/math.git] / source / geometry / compositeshape.h
1 #ifndef MSP_GEOMETRY_COMPOSITESHAPE_H_
2 #define MSP_GEOMETRY_COMPOSITESHAPE_H_
3
4 #include <stdexcept>
5 #include <vector>
6 #include "boundingbox.h"
7 #include "shape.h"
8
9 namespace Msp {
10 namespace Geometry {
11
12 /**
13 Common operations for shapes composed of other shapes.
14 */
15 template<typename T, unsigned D, typename O>
16 class CompositeShape: public Shape<T, D>
17 {
18 protected:
19         typedef O Ops;
20         typedef std::vector<Shape<T, D> *> ShapeArray;
21
22         ShapeArray shapes;
23
24         CompositeShape() { }
25         CompositeShape(const Shape<T, D> &, const Shape<T, D> &);
26         CompositeShape(const CompositeShape &);
27         CompositeShape &operator=(const CompositeShape &);
28         template<typename Iter>
29         void init_from_iter_range(const Iter &, const Iter &);
30 public:
31         virtual ~CompositeShape();
32
33         virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
34         virtual bool contains(const LinAl::Vector<T, D> &) const;
35         virtual unsigned get_max_ray_intersections() const;
36         virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
37 };
38
39 template<typename T, unsigned D, typename O>
40 inline CompositeShape<T, D, O>::CompositeShape(const Shape<T, D> &s1, const Shape<T, D> &s2)
41 {
42         shapes.reserve(2);
43         shapes.push_back(s1.clone());
44         shapes.push_back(s2.clone());
45 }
46
47 template<typename T, unsigned D, typename O>
48 template<typename Iter>
49 inline void CompositeShape<T, D, O>::init_from_iter_range(const Iter &begin, const Iter &end)
50 {
51         if(begin==end)
52                 throw std::invalid_argument("CompositeShape::init_from_iter_range");
53
54         for(Iter i=begin; i!=end; ++i)
55                 shapes.push_back((*i)->clone());
56 }
57
58 template<typename T, unsigned D, typename O>
59 inline CompositeShape<T, D, O>::CompositeShape(const CompositeShape<T, D, O> &other)
60 {
61         shapes.reserve(other.shapes.size());
62         for(typename ShapeArray::const_iterator i=other.shapes.begin(); i!=other.shapes.end(); ++i)
63                 shapes.push_back((*i)->clone());
64 }
65
66 template<typename T, unsigned D, typename O>
67 inline CompositeShape<T, D, O>::~CompositeShape()
68 {
69         for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
70                 delete *i;
71 }
72
73 template<typename T, unsigned D, typename O>
74 inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
75 {
76         BoundingBox<T, D> aabb;
77         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
78         {
79                 if(i==shapes.begin())
80                         aabb = (*i)->get_axis_aligned_bounding_box();
81                 else
82                         aabb = Ops::combine_aabb(aabb, (*i)->get_axis_aligned_bounding_box());
83         }
84         return aabb;
85 }
86
87 template<typename T, unsigned D, typename O>
88 inline bool CompositeShape<T, D, O>::contains(const LinAl::Vector<T, D> &point) const
89 {
90         bool inside = Ops::init_inside();
91         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
92         {
93                 inside = Ops::combine_inside(inside, (*i)->contains(point));
94                 if(Ops::is_inside_decided(inside))
95                         break;
96         }
97         return inside;
98 }
99
100 template<typename T, unsigned D, typename O>
101 inline unsigned CompositeShape<T, D, O>::get_max_ray_intersections() const
102 {
103         unsigned max_isect = 0;
104         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
105                 max_isect += (*i)->get_max_ray_intersections();
106         return max_isect;
107 }
108
109 template<typename T, unsigned D, typename O>
110 inline unsigned CompositeShape<T, D, O>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
111 {
112         unsigned n = 0;
113         for(typename ShapeArray::const_iterator i=shapes.begin(); (n<size && i!=shapes.end()); ++i)
114         {
115                 unsigned base = n;
116                 unsigned count = (*i)->get_intersections(ray, points+base, size-base);
117                 for(unsigned j=0; (n<size && j<count); ++j)
118                 {
119                         SurfacePoint<T, D> &pt = points[base+j];
120
121                         bool surface = Ops::init_surface();
122                         for(typename ShapeArray::const_iterator k=shapes.begin(); k!=shapes.end(); ++k)
123                                 if(k!=i)
124                                         surface = Ops::combine_surface(surface, (*k)->contains(pt.position));
125
126                         if(surface)
127                         {
128                                 if(points && base+j!=n)
129                                         points[n] = pt;
130
131                                 ++n;
132                         }
133                 }
134         }
135
136         sort_points(points, n);
137
138         return n;
139 }
140
141 } // namespace Geometry
142 } // namespace Msp
143
144 #endif