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