]> git.tdb.fi Git - libs/math.git/blob - source/geometry/hyperbox.h
Add basic description for all classes
[libs/math.git] / source / geometry / hyperbox.h
1 #ifndef MSP_GEOMETRY_HYPERBOX_H_
2 #define MSP_GEOMETRY_HYPERBOX_H_
3
4 #include <algorithm>
5 #include <cmath>
6 #include <msp/linal/vector.h>
7 #include "ray.h"
8 #include "shape.h"
9 #include "surfacepoint.h"
10
11 namespace Msp {
12 namespace Geometry {
13
14 /**
15 A shape bounded by planar faces at right angles to each other.  Two- and three-
16 dimensional cases are Rectangle and Box, respectively.
17 */
18 template<typename T, unsigned D>
19 class HyperBox: public Shape<T, D>
20 {
21 private:
22         LinAl::Vector<T, D> dimensions;
23
24 public:
25         HyperBox();
26         explicit HyperBox(const LinAl::Vector<T, D> &);
27
28         virtual HyperBox *clone() const;
29
30         const LinAl::Vector<T, D> &get_dimensions() const { return dimensions; }
31         T get_dimension(unsigned) const;
32
33         virtual HyperBox<T, D> get_axis_aligned_bounding_box() const { return *this; }
34         virtual bool contains(const LinAl::Vector<T, D> &) const;
35         virtual bool check_intersection(const Ray<T, D> &) const;
36         virtual unsigned get_max_ray_intersections() const { return 2; }
37         virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
38 };
39
40 template<typename T, unsigned D>
41 inline HyperBox<T, D>::HyperBox()
42 {
43         for(unsigned i=0; i<D; ++i)
44                 dimensions[i] = 1;
45 }
46
47 template<typename T, unsigned D>
48 inline HyperBox<T, D>::HyperBox(const LinAl::Vector<T, D> &d):
49         dimensions(d)
50 { }
51
52 template<typename T, unsigned D>
53 inline HyperBox<T, D> *HyperBox<T, D>::clone() const
54 {
55         return new HyperBox<T, D>(dimensions);
56 }
57
58 template<typename T, unsigned D>
59 inline T HyperBox<T, D>::get_dimension(unsigned i) const
60 {
61         return dimensions[i];
62 }
63
64 template<typename T, unsigned D>
65 inline bool HyperBox<T, D>::contains(const LinAl::Vector<T, D> &point) const
66 {
67         for(unsigned i=0; i<D; ++i)
68                 if(abs(point[i])>dimensions[i]/2)
69                         return false;
70         return true;
71 }
72
73 template<typename T, unsigned D>
74 inline bool HyperBox<T, D>::check_intersection(const Ray<T, D> &ray) const
75 {
76         return get_intersections(ray, 0, 1);
77 }
78
79 template<typename T, unsigned D>
80 inline unsigned HyperBox<T, D>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
81 {
82         using std::abs;
83
84         LinAl::Vector<T, D> half_dim = dimensions/T(2);
85         unsigned n = 0;
86         T first_depth = T();
87         for(unsigned i=0; i<D; ++i)
88         {
89                 if(!ray.get_direction()[i])
90                         continue;
91
92                 for(int j=-1; j<=1; j+=2)
93                 {
94                         T x = (T(j)*half_dim[i]-ray.get_start()[i])/ray.get_direction()[i];
95                         if(x<0)
96                                 continue;
97
98                         LinAl::Vector<T, D> p = ray.get_start()+ray.get_direction()*x;
99
100                         bool inside = true;
101                         for(unsigned k=0; (inside && k<D); ++k)
102                                 inside = (k==i || abs(p[k])<=half_dim[k]);
103
104                         if(inside && n<size)
105                         {
106                                 if(points)
107                                 {
108                                         points[n].position = p;
109                                         points[n].normal = LinAl::Vector<T, D>();
110                                         points[n].normal[i] = j;
111                                         if(n==0)
112                                                 first_depth = x;
113                                         else if(n==1 && x<first_depth)
114                                                 std::swap(points[0], points[1]);
115                                 }
116
117                                 ++n;
118                                 if(n==size || n==2)
119                                         return n;
120                         }
121                 }
122         }
123
124         return n;
125 }
126
127 } // namespace Geometry
128 } // namespace Msp
129
130 #endif