]> git.tdb.fi Git - libs/math.git/blob - source/geometry/compositeshape.h
846607689df582a8a9f0ae46ae79c75eb832ed81
[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         CompositeShape(const CompositeShape &);
26         CompositeShape &operator=(const CompositeShape &);
27         template<typename Iter>
28         void init_from_iter_range(const Iter &, const Iter &);
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 {
60         shapes.reserve(other.shapes.size());
61         for(typename ShapeArray::const_iterator i=other.shapes.begin(); i!=other.shapes.end(); ++i)
62                 shapes.push_back((*i)->clone());
63 }
64
65 template<typename T, unsigned D, typename O>
66 inline CompositeShape<T, D, O>::~CompositeShape()
67 {
68         for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
69                 delete *i;
70 }
71
72 template<typename T, unsigned D, typename O>
73 inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
74 {
75         BoundingBox<T, D> aabb;
76         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
77         {
78                 if(i==shapes.begin())
79                         aabb = (*i)->get_axis_aligned_bounding_box();
80                 else
81                         aabb = Ops::combine_aabb(aabb, (*i)->get_axis_aligned_bounding_box());
82         }
83         return aabb;
84 }
85
86 template<typename T, unsigned D, typename O>
87 inline bool CompositeShape<T, D, O>::contains(const LinAl::Vector<T, D> &point) const
88 {
89         bool inside = Ops::init_inside();
90         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
91         {
92                 inside = Ops::combine_inside(inside, (*i)->contains(point));
93                 if(Ops::is_inside_decided(inside))
94                         break;
95         }
96         return inside;
97 }
98
99 template<typename T, unsigned D, typename O>
100 inline unsigned CompositeShape<T, D, O>::get_max_ray_intersections() const
101 {
102         unsigned max_isect = 0;
103         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
104                 max_isect += (*i)->get_max_ray_intersections();
105         return max_isect;
106 }
107
108 template<typename T, unsigned D, typename O>
109 inline unsigned CompositeShape<T, D, O>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
110 {
111         unsigned n = 0;
112         for(typename ShapeArray::const_iterator i=shapes.begin(); (n<size && i!=shapes.end()); ++i)
113         {
114                 unsigned base = n;
115                 unsigned count = (*i)->get_intersections(ray, points+base, size-base);
116                 for(unsigned j=0; (n<size && j<count); ++j)
117                 {
118                         SurfacePoint<T, D> &pt = points[base+j];
119
120                         bool surface = Ops::init_surface();
121                         for(typename ShapeArray::const_iterator k=shapes.begin(); k!=shapes.end(); ++k)
122                                 if(k!=i)
123                                         surface = Ops::combine_surface(surface, (*k)->contains(pt.position));
124
125                         if(surface)
126                         {
127                                 if(points && base+j!=n)
128                                         points[n] = pt;
129
130                                 ++n;
131                         }
132                 }
133         }
134
135         sort_points(points, n);
136
137         return n;
138 }
139
140 } // namespace Geometry
141 } // namespace Msp
142
143 #endif