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