xoreos  0.0.5
boundingbox.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include "glm/gtc/matrix_transform.hpp"
26 
27 #include "src/common/boundingbox.h"
28 #include "src/common/util.h"
29 #include "src/common/maths.h"
30 
31 namespace Common {
32 
34  clear();
35 }
36 
38 }
39 
41  _empty = true;
42  _absolute = true;
43 
44  // Set to boundaries
45  _coords[0][0] = FLT_MAX; _coords[0][1] = FLT_MAX; _coords[0][2] = FLT_MAX;
46  _coords[1][0] = FLT_MAX; _coords[1][1] = FLT_MAX; _coords[1][2] = -FLT_MAX;
47  _coords[2][0] = FLT_MAX; _coords[2][1] = -FLT_MAX; _coords[2][2] = FLT_MAX;
48  _coords[3][0] = FLT_MAX; _coords[3][1] = -FLT_MAX; _coords[3][2] = -FLT_MAX;
49  _coords[4][0] = -FLT_MAX; _coords[4][1] = FLT_MAX; _coords[4][2] = FLT_MAX;
50  _coords[5][0] = -FLT_MAX; _coords[5][1] = FLT_MAX; _coords[5][2] = -FLT_MAX;
51  _coords[6][0] = -FLT_MAX; _coords[6][1] = -FLT_MAX; _coords[6][2] = FLT_MAX;
52  _coords[7][0] = -FLT_MAX; _coords[7][1] = -FLT_MAX; _coords[7][2] = -FLT_MAX;
53 
54  _min[0] = 0.0f; _min[1] = 0.0f; _min[2] = 0.0f;
55  _max[0] = 0.0f; _max[1] = 0.0f; _max[2] = 0.0f;
56 
57  _origin = glm::mat4();
58 }
59 
60 bool BoundingBox::empty() const {
61  return _empty;
62 }
63 
64 const glm::mat4 &BoundingBox::getOrigin() const {
65  return _origin;
66 }
67 
68 void BoundingBox::getMin(float &x, float &y, float &z) const {
69  // Minimum, relative to the origin
70 
71  if (_absolute) {
72  x = _min[0]; y = _min[1]; z = _min[2];
73  return;
74  }
75 
76  glm::mat4 min = _origin;
77  min = glm::translate(min, glm::vec3(_min[0], _min[1], _min[2]));
78 
79  glm::mat4 max = _origin;
80  max = glm::translate(max, glm::vec3(_max[0], _max[1], _max[2]));
81 
82  x = MIN(min[3][0], max[3][0]);
83  y = MIN(min[3][1], max[3][1]);
84  z = MIN(min[3][2], max[3][2]);
85 }
86 
87 void BoundingBox::getMax(float &x, float &y, float &z) const {
88  // Maximum, relative to the origin
89 
90  if (_absolute) {
91  x = _max[0]; y = _max[1]; z = _max[2];
92  return;
93  }
94 
95  glm::mat4 min = _origin;
96  min = glm::translate(min, glm::vec3(_min[0], _min[1], _min[2]));
97 
98  glm::mat4 max = _origin;
99  max = glm::translate(max, glm::vec3(_max[0], _max[1], _max[2]));
100 
101  x = MAX(min[3][0], max[3][0]);
102  y = MAX(min[3][1], max[3][1]);
103  z = MAX(min[3][2], max[3][2]);
104 }
105 
106 float BoundingBox::getWidth() const {
107  return ABS(_max[0] - _min[0]);
108 }
109 
110 float BoundingBox::getHeight() const {
111  return ABS(_max[1] - _min[1]);
112 }
113 
114 float BoundingBox::getDepth() const {
115  return ABS(_max[2] - _min[2]);
116 }
117 
118 bool BoundingBox::isIn(float x, float y) const {
119  if (_empty)
120  return false;
121 
122  float minX, minY, minZ;
123  getMin(minX, minY, minZ);
124 
125  float maxX, maxY, maxZ;
126  getMax(maxX, maxY, maxZ);
127 
128  if ((x < minX) || (x > maxX))
129  return false;
130  if ((y < minY) || (y > maxY))
131  return false;
132 
133  return true;
134 }
135 
136 bool BoundingBox::isIn(float x, float y, float z) const {
137  if (_empty)
138  return false;
139 
140  float minX, minY, minZ;
141  getMin(minX, minY, minZ);
142 
143  float maxX, maxY, maxZ;
144  getMax(maxX, maxY, maxZ);
145 
146  if ((x < minX) || (x > maxX))
147  return false;
148  if ((y < minY) || (y > maxY))
149  return false;
150  if ((z < minZ) || (z > maxZ))
151  return false;
152 
153  return true;
154 }
155 
156 bool BoundingBox::getIntersection(float fDst1, float fDst2,
157  float x1, float y1, float z1,
158  float x2, float y2, float z2,
159  float &x, float &y, float &z) const {
160 
161  if ((fDst1 * fDst2) >= 0.0f)
162  return false;
163  if (fDst1 == fDst2)
164  return false;
165 
166  x = x1 + ((x2 - x1) * (-fDst1 / (fDst2 - fDst1)));
167  y = y1 + ((y2 - y1) * (-fDst1 / (fDst2 - fDst1)));
168  z = z1 + ((z2 - z1) * (-fDst1 / (fDst2 - fDst1)));
169 
170  return true;
171 }
172 
173 bool BoundingBox::inBox(float x, float y, float z, float minX, float minY, float minZ,
174  float maxX, float maxY, float maxZ, int axis) const {
175 
176  if (((axis == 1) && (z > minZ) && (z < maxZ) && (y > minY) && (y < maxY)) ||
177  ((axis == 2) && (z > minZ) && (z < maxZ) && (x > minX) && (x < maxX)) ||
178  ((axis == 3) && (x > minX) && (x < maxX) && (y > minY) && (y < maxY)))
179  return true;
180 
181  return false;
182 }
183 
184 bool BoundingBox::isIn(float x1, float y1, float z1, float x2, float y2, float z2) const {
185  if (_empty)
186  return false;
187 
188  float minX, minY, minZ;
189  getMin(minX, minY, minZ);
190 
191  float maxX, maxY, maxZ;
192  getMax(maxX, maxY, maxZ);
193 
194  if ((x2 < minX) && (x1 < minX)) return false;
195  if ((x2 > maxX) && (x1 > maxX)) return false;
196  if ((y2 < minY) && (y1 < minY)) return false;
197  if ((y2 > maxY) && (y1 > maxY)) return false;
198  if ((z2 < minZ) && (z1 < minZ)) return false;
199  if ((z2 > maxZ) && (z1 > maxZ)) return false;
200 
201  if ((x1 > minX) && (x1 < maxX) &&
202  (y1 > minY) && (y1 < maxY) &&
203  (z1 > minZ) && (z1 < maxZ))
204  return true;
205 
206  float x, y, z;
207 
208  if (getIntersection(x1 - minX, x2 - minX, x1, y1, z1, x2, y2, z2, x, y, z) &&
209  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 1))
210  return true;
211  if (getIntersection(y1 - minY, y2 - minY, x1, y1, z1, x2, y2, z2, x, y, z) &&
212  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 2))
213  return true;
214  if (getIntersection(z1 - minZ, z2 - minZ, x1, y1, z1, x2, y2, z2, x, y, z) &&
215  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 3))
216  return true;
217  if (getIntersection(x1 - maxX, x2 - maxX, x1, y1, z1, x2, y2, z2, x, y, z) &&
218  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 1))
219  return true;
220  if (getIntersection(y1 - maxY, y2 - maxY, x1, y1, z1, x2, y2, z2, x, y, z) &&
221  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 2))
222  return true;
223  if (getIntersection(z1 - maxZ, z2 - maxZ, x1, y1, z1, x2, y2, z2, x, y, z) &&
224  inBox(x, y, z, minX, minY, minZ, maxX, maxY, maxZ, 3))
225  return true;
226 
227  return false;
228 }
229 
230 void BoundingBox::add(float x, float y, float z) {
231  _coords[0][0] = MIN(_coords[0][0], x); _coords[0][1] = MIN(_coords[0][1], y); _coords[0][2] = MIN(_coords[0][2], z);
232  _coords[1][0] = MIN(_coords[1][0], x); _coords[1][1] = MIN(_coords[1][1], y); _coords[1][2] = MAX(_coords[1][2], z);
233  _coords[2][0] = MIN(_coords[2][0], x); _coords[2][1] = MAX(_coords[2][1], y); _coords[2][2] = MIN(_coords[2][2], z);
234  _coords[3][0] = MIN(_coords[3][0], x); _coords[3][1] = MAX(_coords[3][1], y); _coords[3][2] = MAX(_coords[3][2], z);
235  _coords[4][0] = MAX(_coords[4][0], x); _coords[4][1] = MIN(_coords[4][1], y); _coords[4][2] = MIN(_coords[4][2], z);
236  _coords[5][0] = MAX(_coords[5][0], x); _coords[5][1] = MIN(_coords[5][1], y); _coords[5][2] = MAX(_coords[5][2], z);
237  _coords[6][0] = MAX(_coords[6][0], x); _coords[6][1] = MAX(_coords[6][1], y); _coords[6][2] = MIN(_coords[6][2], z);
238  _coords[7][0] = MAX(_coords[7][0], x); _coords[7][1] = MAX(_coords[7][1], y); _coords[7][2] = MAX(_coords[7][2], z);
239 
240  for (int i = 0; i < 3; i++) {
241  float min = getCoordMin(i);
242  float max = getCoordMax(i);
243 
244  _min[i] = _empty ? min : MIN(_min[i], min);
245  _max[i] = _empty ? max : MAX(_max[i], max);
246  }
247 
248  _empty = false;
249 }
250 
251 void BoundingBox::add(const BoundingBox &box) {
252  if (box._empty)
253  // Don't add an empty bounding box :P
254  return;
255 
256  for (int i = 0; i < 8; i++)
257  add(box._coords[i][0], box._coords[i][1], box._coords[i][2]);
258 }
259 
260 void BoundingBox::translate(float x, float y, float z) {
261  _origin = glm::translate(_origin, glm::vec3(x, y, z));
262  _absolute = false;
263 }
264 
265 void BoundingBox::scale(float x, float y, float z) {
266  _origin = glm::scale(_origin, glm::vec3(x, y, z));
267  _absolute = false;
268 }
269 
270 void BoundingBox::rotate(float angle, float x, float y, float z) {
271  if (x == 0 && y == 0 && z == 0)
272  return;
273 
274  _origin = glm::rotate(_origin, Common::deg2rad(angle), glm::vec3(x, y, z));
275  _absolute = false;
276 }
277 
278 void BoundingBox::transform(const glm::mat4 &m) {
279  _origin *= m;
280  _absolute = false;
281 }
282 
283 inline float BoundingBox::getCoordMin(int i) const {
284  if (i == 0)
285  return MIN(MIN(MIN(_coords[0][0], _coords[1][0]), _coords[2][0]), _coords[3][0]);
286  if (i == 1)
287  return MIN(MIN(MIN(_coords[0][1], _coords[1][1]), _coords[4][1]), _coords[5][1]);
288  if (i == 2)
289  return MIN(MIN(MIN(_coords[0][2], _coords[2][2]), _coords[4][2]), _coords[6][2]);
290 
291  return 0.0f;
292 }
293 
294 inline float BoundingBox::getCoordMax(int i) const {
295  if (i == 0)
296  return MAX(MAX(MAX(_coords[4][0], _coords[5][0]), _coords[6][0]), _coords[7][0]);
297  if (i == 1)
298  return MAX(MAX(MAX(_coords[2][1], _coords[3][1]), _coords[6][1]), _coords[7][1]);
299  if (i == 2)
300  return MAX(MAX(MAX(_coords[1][2], _coords[3][2]), _coords[5][2]), _coords[7][2]);
301 
302  return 0.0f;
303 }
304 
306  if (_empty)
307  // Nothing to do
308  return;
309 
310  float coords[8][3];
311  for (int i = 0; i < 8; i++) {
312  glm::mat4 c = _origin;
313  c = glm::translate(c, glm::vec3(_coords[i][0], _coords[i][1], _coords[i][2]));
314 
315  coords[i][0] = c[3][0];
316  coords[i][1] = c[3][1];
317  coords[i][2] = c[3][2];
318  }
319 
320  clear();
321 
322  for (int i = 0; i < 8; i++)
323  add(coords[i][0], coords[i][1], coords[i][2]);
324 
325  _absolute = true;
326 }
327 
329  BoundingBox box = *this;
330 
331  box.absolutize();
332 
333  return box;
334 }
335 
336 } // End of namespace Common
T ABS(T x)
Definition: util.h:69
bool isIn(float x, float y) const
Definition: 2dafile.h:39
float getDepth() const
Get the depth of the bounding box.
Mathematical helpers.
void scale(float x, float y, float z)
A bounding box around 3D points.
Definition: boundingbox.h:33
bool empty() const
Definition: boundingbox.cpp:60
const glm::mat4 & getOrigin() const
Definition: boundingbox.cpp:64
float getHeight() const
Get the height of the bounding box.
void getMin(float &x, float &y, float &z) const
Definition: boundingbox.cpp:68
float getCoordMin(int i) const
Utility templates and functions.
void getMax(float &x, float &y, float &z) const
Definition: boundingbox.cpp:87
float getWidth() const
Get the width of the bounding box.
T MIN(T a, T b)
Definition: util.h:70
void transform(const glm::mat4 &m)
A bounding box.
float getCoordMax(int i) const
void absolutize()
Apply the origin transformations directly to the coordinates.
void rotate(float angle, float x, float y, float z)
float _coords[8][3]
Definition: boundingbox.h:78
bool inBox(float x, float y, float z, float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int axis) const
void add(float x, float y, float z)
BoundingBox getAbsolute() const
Return a copy with the origin transformations directly applied to the coordinates.
bool getIntersection(float fDst1, float fDst2, float x1, float y1, float z1, float x2, float y2, float z2, float &x, float &y, float &z) const
T MAX(T a, T b)
Definition: util.h:71
static float deg2rad(float deg)
Definition: maths.h:97
void translate(float x, float y, float z)
#define FLT_MAX
Definition: maths.h:47