1 //------------------------------------------------------------------------
2 //  EPI Bounding Boxes
3 //------------------------------------------------------------------------
4 //
5 //  Copyright (c) 2003-2008  The EDGE Team.
6 //
7 //  This program 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 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program 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 //------------------------------------------------------------------------
18 
19 #ifndef __EPI_MATH_BBOX_H__
20 #define __EPI_MATH_BBOX_H__
21 
22 #include "math_vector.h"
23 
24 namespace epi
25 {
26 
27 class bbox2_c
28 {
29 	/* sealed, value semantics */
30 
31 friend class bbox3_c;
32 
33 private:
34 	vec2_c lo;
35 	vec2_c hi;
36 
37 public:
bbox2_c()38 	bbox2_c() : lo(), hi() { }
bbox2_c(const bbox2_c & rhs)39 	bbox2_c(const bbox2_c& rhs) : lo(rhs.lo), hi(rhs.hi) { }
40 
41 	explicit bbox2_c(const vec2_c& point);
42 	explicit bbox2_c(const vec2_c& p1, const vec2_c& p2);
43 	explicit bbox2_c(const vec2_c& p1, const vec2_c& p2, const vec2_c& p3);
44 
45 	/* ---- read-only operations ---- */
46 
47 	inline bool Contains(vec2_c point) const;
48 	// checks if the point lies inside the bounding box.
49 
50 	inline bool DoesIntersect(const bbox2_c& other) const;
51 	// checks if two bounding boxes intersect.  Returns false when only
52 	// touching, i.e. the intersected volume must be > 0.
53 
54 	/* ---- modifying operations ---- */
55 
56 	bbox2_c& operator= (const bbox2_c& rhs);
57 
58 	bbox2_c& operator+= (const vec2_c& offset);
59 	bbox2_c& operator-= (const vec2_c& offset);
60 	// move the whole bbox by the given offset.
61 
62 	inline bbox2_c& Insert(const vec2_c& point);
63 	// enlarge the bbox (if needed) to include the given point.
64 
65 	inline bbox2_c& Merge(const bbox2_c& other);
66 	// merge the other bbox with this one.
67 
68 	inline bbox2_c& Enlarge(float radius);
69 	// enlarge this bbox by moving each edge by radius.
70 };
71 
72 class bbox3_c
73 {
74 	/* sealed, value semantics */
75 
76 private:
77 	vec3_c lo;
78 	vec3_c hi;
79 
80 public:
bbox3_c()81 	bbox3_c() : lo(), hi() { }
bbox3_c(const bbox3_c & rhs)82 	bbox3_c(const bbox3_c& rhs) : lo(rhs.lo), hi(rhs.hi) { }
bbox3_c(const bbox2_c & rhs,float z1,float z2)83 	bbox3_c(const bbox2_c& rhs, float z1, float z2)
84 		: lo(rhs.lo, z1), hi(rhs.hi, z2) { }
85 
86 	explicit bbox3_c(const vec3_c& point);
87 	explicit bbox3_c(const vec3_c& p1, const vec3_c& p2);
88 	explicit bbox3_c(const vec3_c& p1, const vec3_c& p2, const vec3_c& p3);
89 
90 	/* ---- read-only operations ---- */
91 
92 	inline bool Contains(vec3_c point) const;
93 	// checks if the point lies inside the bounding box.
94 
95 	inline bool DoesIntersect(const bbox3_c& other) const;
96 	// checks if two bounding boxes intersect.  Returns false when only
97 	// touching, i.e. the intersected volume must be > 0.
98 
99 	enum
100 	{
101 		HIT_OUTSIDE = 0,  // fully outside the plane (back side)
102 		HIT_PARTIAL,      // intersects the plane
103 		HIT_INSIDE,       // fully inside the plane (front side)
104 	};
105 
106 	int IntersectPlane(vec3_c loc, vec3_c face) const;
107 	// check if this bounding box intersects the given plane,
108 	// returning one of the HIT_XXX values above.
109 	// NOTE: face vector must be unit length.
110 
111 	/* ---- modifying operations ---- */
112 
113 	bbox3_c& operator= (const bbox3_c& rhs);
114 
115 	bbox3_c& operator+= (const vec3_c& offset);
116 	bbox3_c& operator-= (const vec3_c& offset);
117 	// move the whole bbox by the given offset.
118 
119 	inline bbox3_c& Insert(const vec3_c& point);
120 	// enlarge the bbox (if needed) to include the given point.
121 
122 	inline bbox3_c& Merge(const bbox3_c& other);
123 	// merge the other bbox with this one.
124 
125 	inline bbox3_c& Enlarge(float radius);
126 	inline bbox3_c& Enlarge(float horiz_R, float vert_R);
127 	// enlarge this bbox by moving each edge by radius.
128 };
129 
130 
131 //------------------------------------------------------------------------
132 //    IMPLEMENTATION
133 //------------------------------------------------------------------------
134 
bbox2_c(const vec2_c & point)135 inline bbox2_c::bbox2_c(const vec2_c& point) : lo(point), hi(point)
136 { }
137 
bbox2_c(const vec2_c & p1,const vec2_c & p2)138 inline bbox2_c::bbox2_c(const vec2_c& p1, const vec2_c& p2) : lo(p1), hi(p1)
139 {
140 	Insert(p2);
141 }
142 
bbox2_c(const vec2_c & p1,const vec2_c & p2,const vec2_c & p3)143 inline bbox2_c::bbox2_c(const vec2_c& p1, const vec2_c& p2, const vec2_c& p3)
144 	: lo(p1), hi(p1)
145 {
146 	Insert(p2);
147 	Insert(p3);
148 }
149 
Contains(vec2_c point)150 inline bool bbox2_c::Contains(vec2_c point) const
151 {
152 	return (lo.x <= point.x && point.x <= hi.x &&
153 	        lo.y <= point.y && point.y <= hi.y);
154 }
155 
DoesIntersect(const bbox2_c & other)156 inline bool bbox2_c::DoesIntersect(const bbox2_c& other) const
157 {
158 	return (other.hi.x > lo.x && other.lo.x < hi.x &&
159 			other.hi.y > lo.y && other.lo.y < hi.y);
160 }
161 
162 inline bbox2_c& bbox2_c::operator= (const bbox2_c& rhs)
163 {
164 	// no need to check for self assignment
165 	lo = rhs.lo;
166 	hi = rhs.hi;
167 
168 	return *this;
169 }
170 
171 inline bbox2_c& bbox2_c::operator+= (const vec2_c& offset)
172 {
173 	lo += offset;
174 	hi += offset;
175 
176 	return *this;
177 }
178 
179 inline bbox2_c& bbox2_c::operator-= (const vec2_c& offset)
180 {
181 	lo -= offset;
182 	hi -= offset;
183 
184 	return *this;
185 }
186 
Insert(const vec2_c & point)187 inline bbox2_c& bbox2_c::Insert(const vec2_c& point)
188 {
189 	if (point.x < lo.x) lo.x = point.x;
190 	if (point.y < lo.y) lo.y = point.y;
191 	if (point.x > hi.x) hi.x = point.x;
192 	if (point.y > hi.y) hi.y = point.y;
193 
194 	return *this;
195 }
196 
Merge(const bbox2_c & other)197 inline bbox2_c& bbox2_c::Merge(const bbox2_c& other)
198 {
199 	Insert(other.lo);
200 	Insert(other.hi);
201 
202 	return *this;
203 }
204 
Enlarge(float radius)205 inline bbox2_c& bbox2_c::Enlarge(float radius)
206 {
207 	lo.x -= radius; lo.y -= radius;
208 	hi.x += radius; hi.y += radius;
209 
210 	return *this;
211 }
212 
213 //------------------------------------------------------------------------
214 
bbox3_c(const vec3_c & point)215 inline bbox3_c::bbox3_c(const vec3_c& point) : lo(point), hi(point)
216 { }
217 
bbox3_c(const vec3_c & p1,const vec3_c & p2)218 inline bbox3_c::bbox3_c(const vec3_c& p1, const vec3_c& p2) : lo(p1), hi(p1)
219 {
220 	Insert(p2);
221 }
222 
bbox3_c(const vec3_c & p1,const vec3_c & p2,const vec3_c & p3)223 inline bbox3_c::bbox3_c(const vec3_c& p1, const vec3_c& p2, const vec3_c& p3)
224 	: lo(p1), hi(p1)
225 {
226 	Insert(p2);
227 	Insert(p3);
228 }
229 
Contains(vec3_c point)230 inline bool bbox3_c::Contains(vec3_c point) const
231 {
232 	return (lo.x <= point.x && point.x <= hi.x &&
233 	        lo.y <= point.y && point.y <= hi.y &&
234 	        lo.z <= point.z && point.z <= hi.z);
235 }
236 
DoesIntersect(const bbox3_c & other)237 inline bool bbox3_c::DoesIntersect(const bbox3_c& other) const
238 {
239 	return (other.hi.x > lo.x && other.lo.x < hi.x &&
240 			other.hi.y > lo.y && other.lo.y < hi.y &&
241 			other.hi.z > lo.z && other.lo.z < hi.z);
242 }
243 
244 inline bbox3_c& bbox3_c::operator= (const bbox3_c& rhs)
245 {
246 	// no need to check for self assignment
247 	lo = rhs.lo;
248 	hi = rhs.hi;
249 
250 	return *this;
251 }
252 
253 inline bbox3_c& bbox3_c::operator+= (const vec3_c& offset)
254 {
255 	lo += offset;
256 	hi += offset;
257 
258 	return *this;
259 }
260 
261 inline bbox3_c& bbox3_c::operator-= (const vec3_c& offset)
262 {
263 	lo -= offset;
264 	hi -= offset;
265 
266 	return *this;
267 }
268 
Insert(const vec3_c & point)269 inline bbox3_c& bbox3_c::Insert(const vec3_c& point)
270 {
271 	if (point.x < lo.x) lo.x = point.x;
272 	if (point.y < lo.y) lo.y = point.y;
273 	if (point.z < lo.z) lo.z = point.z;
274 
275 	if (point.x > hi.x) hi.x = point.x;
276 	if (point.y > hi.y) hi.y = point.y;
277 	if (point.z > hi.z) hi.z = point.z;
278 
279 	return *this;
280 }
281 
Merge(const bbox3_c & other)282 inline bbox3_c& bbox3_c::Merge(const bbox3_c& other)
283 {
284 	Insert(other.lo);
285 	Insert(other.hi);
286 
287 	return *this;
288 }
289 
Enlarge(float radius)290 inline bbox3_c& bbox3_c::Enlarge(float radius)
291 {
292 	lo.x -= radius; lo.y -= radius; lo.z -= radius;
293 	hi.x += radius; hi.y += radius; hi.z += radius;
294 
295 	return *this;
296 }
297 
Enlarge(float horiz_R,float vert_R)298 inline bbox3_c& bbox3_c::Enlarge(float horiz_R, float vert_R)
299 {
300 	lo.x -= horiz_R; lo.y -= horiz_R;
301 	hi.x += horiz_R; hi.y += horiz_R;
302 
303 	lo.z -= vert_R;
304 	hi.z += vert_R;
305 
306 	return *this;
307 }
308 
309 }  // namespace epi
310 
311 #endif  /* __EPI_MATH_BBOX_H__ */
312 
313 //--- editor settings ---
314 // vi:ts=4:sw=4:noexpandtab
315