1 #ifndef MSP_GEOMETRY_EXTRUDEDSHAPE_H_
2 #define MSP_GEOMETRY_EXTRUDEDSHAPE_H_
12 A shape embedded in space of dimension higher by one and extruded towards the
13 highest dimension. As an example, extruding a circle creates a cylinder. The
14 base shape's orientation is not changed.
16 template<typename T, unsigned D>
17 class ExtrudedShape: public Shape<T, D>
24 ExtrudedShape(const Shape<T, D-1> &, T);
25 ExtrudedShape(const ExtrudedShape &);
26 ExtrudedShape &operator=(const ExtrudedShape &);
27 virtual ~ExtrudedShape();
29 virtual ExtrudedShape *clone() const;
31 const Shape<T, D-1> &get_base() const { return *base; }
32 T get_length() const { return length; }
34 virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
35 virtual bool contains(const LinAl::Vector<T, D> &) const;
36 virtual unsigned get_max_ray_intersections() const;
37 virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
38 virtual Coverage get_coverage(const BoundingBox<T, D> &) const;
41 template<typename T, unsigned D>
42 inline ExtrudedShape<T, D>::ExtrudedShape(const Shape<T, D-1> &b, T l):
46 throw std::invalid_argument("ExtrudedShape::ExtrudedShape");
51 template<typename T, unsigned D>
52 inline ExtrudedShape<T, D>::ExtrudedShape(const ExtrudedShape<T, D> &other):
53 base(other.base.clone()),
57 template<typename T, unsigned D>
58 inline ExtrudedShape<T, D> &ExtrudedShape<T, D>::operator=(const ExtrudedShape<T, D> &other)
61 base = other.base.clone();
62 length = other.length;
65 template<typename T, unsigned D>
66 inline ExtrudedShape<T, D>::~ExtrudedShape()
71 template<typename T, unsigned D>
72 inline ExtrudedShape<T, D> *ExtrudedShape<T, D>::clone() const
74 return new ExtrudedShape<T, D>(*base, length);
77 template<typename T, unsigned D>
78 inline BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
80 BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box(detail);
81 T half_length = length/T(2);
82 return BoundingBox<T, D>(compose(base_bbox.get_minimum_point(), -half_length),
83 compose(base_bbox.get_maximum_point(), half_length));
86 template<typename T, unsigned D>
87 inline bool ExtrudedShape<T, D>::contains(const LinAl::Vector<T, D> &point) const
91 if(abs(point[D-1])>length/T(2))
94 return base->contains(point.template slice<D-1>(0));
97 template<typename T, unsigned D>
98 inline unsigned ExtrudedShape<T, D>::get_max_ray_intersections() const
100 return std::max(base->get_max_ray_intersections(), 2U);
103 template<typename T, unsigned D>
104 inline unsigned ExtrudedShape<T, D>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
109 T half_length = length/T(2);
110 const LinAl::Vector<T, D> &ray_start = ray.get_start();
111 const LinAl::Vector<T, D> &ray_direction = ray.get_direction();
112 LinAl::Vector<T, D-1> base_dir = ray_direction.template slice<D-1>(0);
114 /* If the ray does not degenerate to a point in the base space, it could
115 intersect the base shape. */
116 if(inner_product(base_dir, base_dir)!=T(0))
120 if(ray_direction[D-1]!=T(0))
122 offset = (half_length-ray_start[D-1])/ray_direction[D-1];
123 limit = (-half_length-ray_start[D-1])/ray_direction[D-1];
132 T distortion = base_dir.norm();
133 Ray<T, D-1> base_ray((ray_start+ray_direction*offset).template slice<D-1>(0),
134 base_dir, (limit-offset)*distortion);
136 SurfacePoint<T, D-1> *base_points = 0;
138 /* Shamelessly reuse the provided storage. Align to the end of the
139 array so processing can start from the first (nearest) point. */
140 base_points = reinterpret_cast<SurfacePoint<T, D-1> *>(points+size)-size;
142 unsigned count = base->get_intersections(base_ray, base_points, size);
143 for(unsigned i=0; (n<size && i<count); ++i)
147 T x = offset+base_points[i].distance/distortion;
148 points[n].position = ray_start+ray_direction*x;
149 points[n].normal = compose(base_points[i].normal, T(0));
150 points[n].distance = x;
151 points[n].entry = base_points[i].entry;
159 /* If the ray is not parallel to the base space, it may pass through the
161 if(n<size && ray_direction[D-1]!=T(0))
163 for(int i=-1; (n<size && i<=1); i+=2)
165 T x = (half_length*i-ray_start[D-1])/ray_direction[D-1];
166 if(!ray.check_limits(x))
169 LinAl::Vector<T, D> p = ray_start+ray_direction*x;
170 if(base->contains(p.template slice<D-1>(0)))
174 points[n].position = p;
175 points[n].normal = LinAl::Vector<T, D>();
176 points[n].normal[D-1] = i;
177 points[n].distance = x;
178 points[n].entry = (T(i)*ray_direction[D-1]<T(0));
185 sort_points(points, n);
191 template<typename T, unsigned D>
192 inline Coverage ExtrudedShape<T, D>::get_coverage(const BoundingBox<T, D> &bbox) const
194 T half_length = length/T(2);
195 if(bbox.get_maximum_coordinate(D-1)<-half_length || bbox.get_minimum_coordinate(D-1)>half_length)
198 BoundingBox<T, D-1> base_bbox(bbox.get_minimum_point().template slice<D-1>(0), bbox.get_maximum_point().template slice<D-1>(0));
199 Coverage coverage = base->get_coverage(base_bbox);
200 if(coverage==NO_COVERAGE)
203 if(bbox.get_minimum_coordinate(D-1)<-half_length || bbox.get_maximum_coordinate(D-1)>half_length)
204 return PARTIAL_COVERAGE;
209 } // namespace Geometry