]> git.tdb.fi Git - libs/math.git/blob - source/geometry/hyperbox.h
Add more collision check functions for shapes
[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 template<typename T, unsigned D>
15 class HyperBox: public Shape<T, D>
16 {
17 private:
18         LinAl::Vector<T, D> dimensions;
19
20 public:
21         HyperBox();
22         explicit HyperBox(const LinAl::Vector<T, D> &);
23
24         virtual HyperBox *clone() const;
25
26         const LinAl::Vector<T, D> &get_dimensions() const { return dimensions; }
27         T get_dimension(unsigned) const;
28
29         virtual HyperBox<T, D> get_axis_aligned_bounding_box() const { return *this; }
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 { return 2; }
33         virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
34 };
35
36 template<typename T, unsigned D>
37 inline HyperBox<T, D>::HyperBox()
38 {
39         for(unsigned i=0; i<D; ++i)
40                 dimensions[i] = 1;
41 }
42
43 template<typename T, unsigned D>
44 inline HyperBox<T, D>::HyperBox(const LinAl::Vector<T, D> &d):
45         dimensions(d)
46 { }
47
48 template<typename T, unsigned D>
49 inline HyperBox<T, D> *HyperBox<T, D>::clone() const
50 {
51         return new HyperBox<T, D>(dimensions);
52 }
53
54 template<typename T, unsigned D>
55 inline T HyperBox<T, D>::get_dimension(unsigned i) const
56 {
57         return dimensions[i];
58 }
59
60 template<typename T, unsigned D>
61 inline bool HyperBox<T, D>::contains(const LinAl::Vector<T, D> &point) const
62 {
63         for(unsigned i=0; i<D; ++i)
64                 if(abs(point[i])>dimensions[i]/2)
65                         return false;
66         return true;
67 }
68
69 template<typename T, unsigned D>
70 inline bool HyperBox<T, D>::check_intersection(const Ray<T, D> &ray) const
71 {
72         return get_intersections(ray, 0, 1);
73 }
74
75 template<typename T, unsigned D>
76 inline unsigned HyperBox<T, D>::get_intersections(const Ray<T, D> &ray, SurfacePoint<T, D> *points, unsigned size) const
77 {
78         using std::abs;
79
80         LinAl::Vector<T, D> half_dim = dimensions/T(2);
81         unsigned n = 0;
82         T first_depth = T();
83         for(unsigned i=0; i<D; ++i)
84         {
85                 if(!ray.get_direction()[i])
86                         continue;
87
88                 for(int j=-1; j<=1; j+=2)
89                 {
90                         T x = (T(j)*half_dim[i]-ray.get_start()[i])/ray.get_direction()[i];
91                         if(x<0)
92                                 continue;
93
94                         LinAl::Vector<T, D> p = ray.get_start()+ray.get_direction()*x;
95
96                         bool inside = true;
97                         for(unsigned k=0; (inside && k<D); ++k)
98                                 inside = (k==i || abs(p[k])<=half_dim[k]);
99
100                         if(inside && n<size)
101                         {
102                                 if(points)
103                                 {
104                                         points[n].position = p;
105                                         points[n].normal = LinAl::Vector<T, D>();
106                                         points[n].normal[i] = j;
107                                         if(n==0)
108                                                 first_depth = x;
109                                         else if(n==1 && x<first_depth)
110                                                 std::swap(points[0], points[1]);
111                                 }
112
113                                 ++n;
114                                 if(n==size || n==2)
115                                         return n;
116                         }
117                 }
118         }
119
120         return n;
121 }
122
123 } // namespace Geometry
124 } // namespace Msp
125
126 #endif