]> git.tdb.fi Git - libs/math.git/blob - source/geometry/hyperbox.h
Record distance in SurfacePoint
[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         for(unsigned i=0; i<D; ++i)
87         {
88                 if(!ray.get_direction()[i])
89                         continue;
90
91                 for(int j=-1; j<=1; j+=2)
92                 {
93                         T x = (T(j)*half_dim[i]-ray.get_start()[i])/ray.get_direction()[i];
94                         if(x<0)
95                                 continue;
96
97                         LinAl::Vector<T, D> p = ray.get_start()+ray.get_direction()*x;
98
99                         bool inside = true;
100                         for(unsigned k=0; (inside && k<D); ++k)
101                                 inside = (k==i || abs(p[k])<=half_dim[k]);
102
103                         if(inside && n<size)
104                         {
105                                 if(points)
106                                 {
107                                         points[n].position = p;
108                                         points[n].normal = LinAl::Vector<T, D>();
109                                         points[n].normal[i] = j;
110                                         points[n].distance = x;
111
112                                         if(n==1 && x<points[0].distance)
113                                                 std::swap(points[0], points[1]);
114                                 }
115
116                                 ++n;
117                                 if(n==size || n==2)
118                                         return n;
119                         }
120                 }
121         }
122
123         return n;
124 }
125
126 } // namespace Geometry
127 } // namespace Msp
128
129 #endif