1 #ifndef MSP_GEOMETRY_COMPOSITESHAPE_H_
2 #define MSP_GEOMETRY_COMPOSITESHAPE_H_
13 Common operations for shapes composed of other shapes.
15 template<typename T, unsigned D, typename O>
16 class CompositeShape: public Shape<T, D>
20 typedef std::vector<Shape<T, D> *> ShapeArray;
26 CompositeShape(const Shape<T, D> &, const Shape<T, D> &);
27 template<typename Iter>
28 void init_from_iter_range(const Iter &, const Iter &);
32 CompositeShape(const CompositeShape &);
33 CompositeShape &operator=(const CompositeShape &);
35 virtual ~CompositeShape();
37 virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
38 virtual bool contains(const LinAl::Vector<T, D> &) const;
39 virtual unsigned get_max_ray_intersections() const { return max_isect; }
40 virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
43 template<typename T, unsigned D, typename O>
44 inline CompositeShape<T, D, O>::CompositeShape(const Shape<T, D> &s1, const Shape<T, D> &s2)
47 shapes.push_back(s1.clone());
48 shapes.push_back(s2.clone());
52 template<typename T, unsigned D, typename O>
53 template<typename Iter>
54 inline void CompositeShape<T, D, O>::init_from_iter_range(const Iter &begin, const Iter &end)
57 throw std::invalid_argument("CompositeShape::init_from_iter_range");
59 for(Iter i=begin; i!=end; ++i)
60 shapes.push_back((*i)->clone());
64 template<typename T, unsigned D, typename O>
65 inline void CompositeShape<T, D, O>::init()
68 for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
69 max_isect += (*i)->get_max_ray_intersections();
72 template<typename T, unsigned D, typename O>
73 inline CompositeShape<T, D, O>::CompositeShape(const CompositeShape<T, D, O> &other):
75 max_isect(other.max_isect)
77 for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
81 template<typename T, unsigned D, typename O>
82 inline CompositeShape<T, D, O> &CompositeShape<T, D, O>::operator=(const CompositeShape<T, D, O> &other)
84 for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
87 shapes = other.shapes;
88 for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
91 max_isect = other.max_isect;
94 template<typename T, unsigned D, typename O>
95 inline CompositeShape<T, D, O>::~CompositeShape()
97 for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i)
101 template<typename T, unsigned D, typename O>
102 inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
104 BoundingBox<T, D> aabb;
105 for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
107 if(i==shapes.begin())
108 aabb = (*i)->get_axis_aligned_bounding_box();
110 aabb = Ops::combine_aabb(aabb, (*i)->get_axis_aligned_bounding_box());
115 template<typename T, unsigned D, typename O>
116 inline bool CompositeShape<T, D, O>::contains(const LinAl::Vector<T, D> &point) const
119 for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
121 inside = (*i)->contains(point);
122 if(Ops::shortcircuit(inside))
128 template<typename T, unsigned D, typename O>
129 inline unsigned CompositeShape<T, D, O>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
131 SurfacePoint<T, D> *buffer = points;
132 unsigned buf_size = size;
133 if(!points && !Ops::shortcircuit(true))
135 buffer = new SurfacePoint<T, D>[max_isect];
136 buf_size = max_isect;
139 int start_nesting = 0;
141 for(typename ShapeArray::const_iterator i=shapes.begin(); (n<buf_size && i!=shapes.end()); ++i)
144 unsigned count = (*i)->get_intersections(ray, buffer+base, buf_size-base);
145 bool start_inside = (*i)->contains(ray.get_start());
147 if(!count && !start_inside)
149 if(Ops::shortcircuit(false))
154 start_nesting += start_inside;
162 sort_points(buffer, base+count);
164 int nesting = start_nesting;
166 for(unsigned j=0; j<base+count; ++j)
168 if(Ops::shortcircuit(nesting+buffer[j].entry<2))
171 buffer[k] = buffer[j];
175 nesting += buffer[j].entry*2-1;
178 if(!k && Ops::shortcircuit(false))
183 if(i!=shapes.begin())
184 start_nesting = (start_nesting>!Ops::shortcircuit(true));
193 } // namespace Geometry