]> git.tdb.fi Git - libs/math.git/blob - source/geometry/boundingbox.h
ac384ecd19760a5274f8a09bfa3a38adaeff3c81
[libs/math.git] / source / geometry / boundingbox.h
1 #ifndef MSP_GEOMETRY_BOUNDINGBOX_H_
2 #define MSP_GEOMETRY_BOUNDINGBOX_H_
3
4 #include <algorithm>
5 #include <stdexcept>
6 #include <msp/linal/vector.h>
7
8 namespace Msp {
9 namespace Geometry {
10
11 template<typename T, unsigned D>
12 class BoundingBox
13 {
14 private:
15         LinAl::Vector<T, D> min_pt;
16         LinAl::Vector<T, D> max_pt;
17         bool empty;
18         bool negated;
19
20 public:
21         BoundingBox();
22         BoundingBox(const LinAl::Vector<T, D> &, const LinAl::Vector<T, D> &);
23
24         static BoundingBox negate(const BoundingBox &);
25
26         const LinAl::Vector<T, D> &get_minimum_point() const { return min_pt; }
27         T get_minimum_coordinate(unsigned i) const { return min_pt[i]; }
28         const LinAl::Vector<T, D> &get_maximum_point() const { return max_pt; }
29         T get_maximum_coordinate(unsigned i) const { return max_pt[i]; }
30         bool is_empty() const { return empty && !negated; }
31         bool is_space() const { return empty && negated; }
32         bool is_negated() const { return negated; }
33 };
34
35 template<typename T, unsigned D>
36 inline BoundingBox<T, D>::BoundingBox():
37         empty(true),
38         negated(false)
39 { }
40
41 template<typename T, unsigned D>
42 inline BoundingBox<T, D>::BoundingBox(const LinAl::Vector<T, D> &n, const LinAl::Vector<T, D> &x):
43         min_pt(n),
44         max_pt(x),
45         empty(false),
46         negated(false)
47 {
48         for(unsigned i=0; i<D; ++i)
49                 if(min_pt[i]>max_pt[i])
50                         throw std::invalid_argument("BoundingBox::BoundingBox");
51 }
52
53 template<typename T, unsigned D>
54 inline BoundingBox<T, D> BoundingBox<T, D>::negate(const BoundingBox<T, D> &bb)
55 {
56         BoundingBox<T, D> result = bb;
57         result.negated = !bb.negated;
58         return result;
59 }
60
61 template<typename T, unsigned D>
62 inline BoundingBox<T, D> operator&(const BoundingBox<T, D> &bb1, const BoundingBox<T, D> &bb2)
63 {
64         if(bb1.is_empty() || bb2.is_empty())
65                 return BoundingBox<T, D>();
66
67         if(bb1.is_negated())
68         {
69                 if(bb2.is_negated())
70                         return ~((~bb1)|(~bb2));
71                 else
72                         return bb2&bb1;
73         }
74
75         LinAl::Vector<T, D> result_min;
76         LinAl::Vector<T, D> result_max;
77
78         if(bb2.is_negated())
79         {
80                 // This is effectively subtraction of (non-negated) bb2 from bb1
81                 int uncovered_axis = -1;
82                 for(unsigned i=0; i<D; ++i)
83                         if(bb1.get_minimum_coordinate(i)<bb2.get_minimum_coordinate(i) || bb1.get_maximum_coordinate(i)>bb2.get_maximum_coordinate(i))
84                         {
85                                 if(uncovered_axis!=-1)
86                                         return bb1;
87                                 uncovered_axis = i;
88                         }
89
90                 if(uncovered_axis==-1)
91                         return BoundingBox<T, D>();
92
93                 result_min = bb1.get_minimum_point();
94                 result_max = bb1.get_maximum_point();
95                 if(bb2.get_minimum_coordinate(uncovered_axis)<bb1.get_minimum_coordinate(uncovered_axis))
96                         result_min[uncovered_axis] = bb2.get_maximum_coordinate(uncovered_axis);
97                 else
98                         result_max[uncovered_axis] = bb2.get_minimum_coordinate(uncovered_axis);
99         }
100         else
101         {
102                 for(unsigned i=0; i<D; ++i)
103                 {
104                         result_min[i] = std::max(bb1.get_minimum_coordinate(i), bb2.get_minimum_coordinate(i));
105                         result_max[i] = std::min(bb1.get_maximum_coordinate(i), bb2.get_maximum_coordinate(i));
106                         if(result_min[i]>result_max[i])
107                                 return BoundingBox<T, D>();
108                 }
109         }
110
111         return BoundingBox<T, D>(result_min, result_max);
112 }
113
114 template<typename T, unsigned D>
115 inline BoundingBox<T, D> operator|(const BoundingBox<T, D> &bb1, const BoundingBox<T, D> &bb2)
116 {
117         if(bb1.is_empty())
118                 return bb2;
119         if(bb2.is_empty())
120                 return bb1;
121
122         if(bb1.is_negated())
123                 return ~((~bb1)&(~bb2));
124         else if(bb2.is_negated())
125                 return ~((~bb2)&(~bb1));
126
127         LinAl::Vector<T, D> result_min;
128         LinAl::Vector<T, D> result_max;
129         for(unsigned i=0; i<D; ++i)
130         {
131                 result_min[i] = std::min(bb1.get_minimum_coordinate(i), bb2.get_minimum_coordinate(i));
132                 result_max[i] = std::max(bb1.get_maximum_coordinate(i), bb2.get_maximum_coordinate(i));
133         }
134
135         return BoundingBox<T, D>(result_min, result_max);
136 }
137
138 template<typename T, unsigned D>
139 inline BoundingBox<T, D> operator~(const BoundingBox<T, D> &bb)
140 {
141         return BoundingBox<T, D>::negate(bb);
142 }
143
144 } // namespace Geometry
145 } // namespace Msp
146
147 #endif