]> git.tdb.fi Git - libs/math.git/blob - source/geometry/compositeshape.h
Properly sort intersection points for complex shapes
[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 bool check_intersection(const Ray<T, D> &) const;
32         virtual unsigned get_max_ray_intersections() const;
33         virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
34 };
35
36 template<typename T, unsigned D, typename O>
37 inline CompositeShape<T, D, O>::CompositeShape(const Shape<T, D> &s1, const Shape<T, D> &s2)
38 {
39         shapes.reserve(2);
40         shapes.push_back(s1.clone());
41         shapes.push_back(s2.clone());
42 }
43
44 template<typename T, unsigned D, typename O>
45 inline CompositeShape<T, D, O>::CompositeShape(const ShapeArray &s)
46 {
47         if(s.empty())
48                 throw std::invalid_argument("CompositeShape::CompositeShape");
49
50         shapes.reserve(s.size());
51         for(typename ShapeArray::const_iterator i=s.begin(); i!=s.end(); ++i)
52                 shapes.push_back((*i)->clone());
53 }
54
55 template<typename T, unsigned D, typename O>
56 inline CompositeShape<T, D, O>::~CompositeShape()
57 {
58         for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
59                 delete *i;
60 }
61
62 template<typename T, unsigned D, typename O>
63 inline HyperBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
64 {
65         HyperBox<T, D> aabb;
66         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
67         {
68                 if(i==shapes.begin())
69                         aabb = (*i)->get_axis_aligned_bounding_box();
70                 else
71                         aabb = Ops::combine_aabb(aabb, (*i)->get_axis_aligned_bounding_box());
72         }
73         return aabb;
74 }
75
76 template<typename T, unsigned D, typename O>
77 inline bool CompositeShape<T, D, O>::contains(const LinAl::Vector<T, D> &point) const
78 {
79         bool inside = Ops::init_inside();
80         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
81         {
82                 inside = Ops::combine_inside(inside, (*i)->contains(point));
83                 if(Ops::is_inside_decided(inside))
84                         break;
85         }
86         return inside;
87 }
88
89 template<typename T, unsigned D, typename O>
90 inline bool CompositeShape<T, D, O>::check_intersection(const Ray<T, D> &ray) const
91 {
92         return get_intersections(ray, 0, 1);
93 }
94
95 template<typename T, unsigned D, typename O>
96 inline unsigned CompositeShape<T, D, O>::get_max_ray_intersections() const
97 {
98         unsigned max_isect = 0;
99         for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
100                 max_isect += (*i)->get_max_ray_intersections();
101         return max_isect;
102 }
103
104 template<typename T, unsigned D, typename O>
105 inline unsigned CompositeShape<T, D, O>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
106 {
107         unsigned n = 0;
108         for(typename ShapeArray::const_iterator i=shapes.begin(); (n<size && i!=shapes.end()); ++i)
109         {
110                 unsigned base = n;
111                 unsigned count = (*i)->get_intersections(ray, points+base, size-base);
112                 for(unsigned j=0; (n<size && j<count); ++j)
113                 {
114                         SurfacePoint<T, D> &pt = points[base+j];
115
116                         bool surface = Ops::init_surface();
117                         for(typename ShapeArray::const_iterator k=shapes.begin(); k!=shapes.end(); ++k)
118                                 if(k!=i)
119                                         surface = Ops::combine_surface(surface, (*k)->contains(pt.position));
120
121                         if(surface)
122                         {
123                                 if(points && base+j!=n)
124                                         points[n] = pt;
125
126                                 ++n;
127                         }
128                 }
129         }
130
131         sort_points(points, n);
132
133         return n;
134 }
135
136 } // namespace Geometry
137 } // namespace Msp
138
139 #endif