1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 /**
3  *	Contains AABB-related code.
4  *	\file		IceAABB.cpp
5  *	\author		Pierre Terdiman
6  *	\date		January, 29, 2000
7  */
8 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 
10 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 /**
12  *	AABB class.
13  *	\class		AABB
14  *	\author		Pierre Terdiman
15  *	\version	1.0
16  */
17 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 
19 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 // Precompiled Header
21 #include "Stdafx.h"
22 
23 using namespace IceMaths;
24 
25 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26 /**
27  *	Computes the sum of two AABBs.
28  *	\param		aabb	[in] the other AABB
29  *	\return		Self-Reference
30  */
31 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Add(const AABB & aabb)32 AABB& AABB::Add(const AABB& aabb)
33 {
34 	// Compute new min & max values
35 	Point Min;	GetMin(Min);
36 	Point Tmp;	aabb.GetMin(Tmp);
37 	Min.Min(Tmp);
38 
39 	Point Max;	GetMax(Max);
40 	aabb.GetMax(Tmp);
41 	Max.Max(Tmp);
42 
43 	// Update this
44 	SetMinMax(Min, Max);
45 	return *this;
46 }
47 
48 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
49 /**
50  *	Makes a cube from the AABB.
51  *	\param		cube	[out] the cube AABB
52  *	\return		cube edge length
53  */
54 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MakeCube(AABB & cube) const55 float AABB::MakeCube(AABB& cube) const
56 {
57 	Point Ext;	GetExtents(Ext);
58 	float Max = Ext.Max();
59 
60 	Point Cnt;	GetCenter(Cnt);
61 	cube.SetCenterExtents(Cnt, Point(Max, Max, Max));
62 	return Max;
63 }
64 
65 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
66 /**
67  *	Makes a sphere from the AABB.
68  *	\param		sphere	[out] sphere containing the AABB
69  */
70 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MakeSphere(Sphere & sphere) const71 void AABB::MakeSphere(Sphere& sphere) const
72 {
73 	GetExtents(sphere.mCenter);
74 	sphere.mRadius = sphere.mCenter.Magnitude() * 1.00001f;	// To make sure sphere::Contains(*this)	succeeds
75 	GetCenter(sphere.mCenter);
76 }
77 
78 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
79 /**
80  *	Checks a box is inside another box.
81  *	\param		box		[in] the other AABB
82  *	\return		true if current box is inside input box
83  */
84 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IsInside(const AABB & box) const85 bool AABB::IsInside(const AABB& box) const
86 {
87 	if(box.GetMin(0)>GetMin(0))	return false;
88 	if(box.GetMin(1)>GetMin(1))	return false;
89 	if(box.GetMin(2)>GetMin(2))	return false;
90 	if(box.GetMax(0)<GetMax(0))	return false;
91 	if(box.GetMax(1)<GetMax(1))	return false;
92 	if(box.GetMax(2)<GetMax(2))	return false;
93 	return true;
94 }
95 
96 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
97 /**
98  *	Computes the AABB planes.
99  *	\param		planes	[out] 6 planes surrounding the box
100  *	\return		true if success
101  */
102 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ComputePlanes(Plane * planes) const103 bool AABB::ComputePlanes(Plane* planes)	const
104 {
105 	// Checkings
106 	if(!planes)	return false;
107 
108 	Point Center, Extents;
109 	GetCenter(Center);
110 	GetExtents(Extents);
111 
112 	// Writes normals
113 	planes[0].n = Point(1.0f, 0.0f, 0.0f);
114 	planes[1].n = Point(-1.0f, 0.0f, 0.0f);
115 	planes[2].n = Point(0.0f, 1.0f, 0.0f);
116 	planes[3].n = Point(0.0f, -1.0f, 0.0f);
117 	planes[4].n = Point(0.0f, 0.0f, 1.0f);
118 	planes[5].n = Point(0.0f, 0.0f, -1.0f);
119 
120 	// Compute a point on each plane
121 	Point p0 = Point(Center.x+Extents.x, Center.y, Center.z);
122 	Point p1 = Point(Center.x-Extents.x, Center.y, Center.z);
123 	Point p2 = Point(Center.x, Center.y+Extents.y, Center.z);
124 	Point p3 = Point(Center.x, Center.y-Extents.y, Center.z);
125 	Point p4 = Point(Center.x, Center.y, Center.z+Extents.z);
126 	Point p5 = Point(Center.x, Center.y, Center.z-Extents.z);
127 
128 	// Compute d
129 	planes[0].d = -(planes[0].n|p0);
130 	planes[1].d = -(planes[1].n|p1);
131 	planes[2].d = -(planes[2].n|p2);
132 	planes[3].d = -(planes[3].n|p3);
133 	planes[4].d = -(planes[4].n|p4);
134 	planes[5].d = -(planes[5].n|p5);
135 
136 	return true;
137 }
138 
139 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
140 /**
141  *	Computes the aabb points.
142  *	\param		pts	[out] 8 box points
143  *	\return		true if success
144  */
145 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ComputePoints(Point * pts) const146 bool AABB::ComputePoints(Point* pts)	const
147 {
148 	// Checkings
149 	if(!pts)	return false;
150 
151 	// Get box corners
152 	Point min;	GetMin(min);
153 	Point max;	GetMax(max);
154 
155 	//     7+------+6			0 = ---
156 	//     /|     /|			1 = +--
157 	//    / |    / |			2 = ++-
158 	//   / 4+---/--+5			3 = -+-
159 	// 3+------+2 /    y   z	4 = --+
160 	//  | /    | /     |  /		5 = +-+
161 	//  |/     |/      |/		6 = +++
162 	// 0+------+1      *---x	7 = -++
163 
164 	// Generate 8 corners of the bbox
165 	pts[0] = Point(min.x, min.y, min.z);
166 	pts[1] = Point(max.x, min.y, min.z);
167 	pts[2] = Point(max.x, max.y, min.z);
168 	pts[3] = Point(min.x, max.y, min.z);
169 	pts[4] = Point(min.x, min.y, max.z);
170 	pts[5] = Point(max.x, min.y, max.z);
171 	pts[6] = Point(max.x, max.y, max.z);
172 	pts[7] = Point(min.x, max.y, max.z);
173 
174 	return true;
175 }
176 
177 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
178 /**
179  *	Gets vertex normals.
180  *	\param		pts	[out] 8 box points
181  *	\return		true if success
182  */
183 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GetVertexNormals() const184 const Point* AABB::GetVertexNormals()	const
185 {
186 	static const float VertexNormals[] =
187 	{
188 		-INVSQRT3,	-INVSQRT3,	-INVSQRT3,
189 		INVSQRT3,	-INVSQRT3,	-INVSQRT3,
190 		INVSQRT3,	INVSQRT3,	-INVSQRT3,
191 		-INVSQRT3,	INVSQRT3,	-INVSQRT3,
192 		-INVSQRT3,	-INVSQRT3,	INVSQRT3,
193 		INVSQRT3,	-INVSQRT3,	INVSQRT3,
194 		INVSQRT3,	INVSQRT3,	INVSQRT3,
195 		-INVSQRT3,	INVSQRT3,	INVSQRT3
196 	};
197 	return (const Point*)VertexNormals;
198 }
199 
200 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201 /**
202  *	Returns edges.
203  *	\return		24 indices (12 edges) indexing the list returned by ComputePoints()
204  */
205 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GetEdges() const206 const udword* AABB::GetEdges() const
207 {
208 	static const udword Indices[] = {
209 	0, 1,	1, 2,	2, 3,	3, 0,
210 	7, 6,	6, 5,	5, 4,	4, 7,
211 	1, 5,	6, 2,
212 	3, 7,	4, 0
213 	};
214 	return Indices;
215 }
216 
217 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
218 /**
219  *	Returns edge normals.
220  *	\return		edge normals in local space
221  */
222 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GetEdgeNormals() const223 const Point* AABB::GetEdgeNormals() const
224 {
225 	static const float EdgeNormals[] =
226 	{
227 		0,			-INVSQRT2,	-INVSQRT2,	// 0-1
228 		INVSQRT2,	0,			-INVSQRT2,	// 1-2
229 		0,			INVSQRT2,	-INVSQRT2,	// 2-3
230 		-INVSQRT2,	0,			-INVSQRT2,	// 3-0
231 
232 		0,			INVSQRT2,	INVSQRT2,	// 7-6
233 		INVSQRT2,	0,			INVSQRT2,	// 6-5
234 		0,			-INVSQRT2,	INVSQRT2,	// 5-4
235 		-INVSQRT2,	0,			INVSQRT2,	// 4-7
236 
237 		INVSQRT2,	-INVSQRT2,	0,			// 1-5
238 		INVSQRT2,	INVSQRT2,	0,			// 6-2
239 		-INVSQRT2,	INVSQRT2,	0,			// 3-7
240 		-INVSQRT2,	-INVSQRT2,	0			// 4-0
241 	};
242 	return (const Point*)EdgeNormals;
243 }
244 
245 // ===========================================================================
246 //  (C) 1996-98 Vienna University of Technology
247 // ===========================================================================
248 //  NAME:       bboxarea
249 //  TYPE:       c++ code
250 //  PROJECT:    Bounding Box Area
251 //  CONTENT:    Computes area of 2D projection of 3D oriented bounding box
252 //  VERSION:    1.0
253 // ===========================================================================
254 //  AUTHORS:    ds      Dieter Schmalstieg
255 //              ep      Erik Pojar
256 // ===========================================================================
257 //  HISTORY:
258 //
259 //  19-sep-99 15:23:03  ds      last modification
260 //  01-dec-98 15:23:03  ep      created
261 // ===========================================================================
262 
263 //----------------------------------------------------------------------------
264 // SAMPLE CODE STARTS HERE
265 //----------------------------------------------------------------------------
266 
267 // NOTE: This sample program requires OPEN INVENTOR!
268 
269 //indexlist: this table stores the 64 possible cases of classification of
270 //the eyepoint with respect to the 6 defining planes of the bbox (2^6=64)
271 //only 26 (3^3-1, where 1 is "inside" cube) of these cases are valid.
272 //the first 6 numbers in each row are the indices of the bbox vertices that
273 //form the outline of which we want to compute the area (counterclockwise
274 //ordering), the 7th entry means the number of vertices in the outline.
275 //there are 6 cases with a single face and and a 4-vertex outline, and
276 //20 cases with 2 or 3 faces and a 6-vertex outline. a value of 0 indicates
277 //an invalid case.
278 
279 
280 // Original list was made of 7 items, I added an 8th element:
281 // - to padd on a cache line
282 // - to repeat the first entry to avoid modulos
283 //
284 // I also replaced original ints with sbytes.
285 
286 static const sbyte gIndexList[64][8] =
287 {
288     {-1,-1,-1,-1,-1,-1,-1,   0}, // 0 inside
289     { 0, 4, 7, 3, 0,-1,-1,   4}, // 1 left
290     { 1, 2, 6, 5, 1,-1,-1,   4}, // 2 right
291     {-1,-1,-1,-1,-1,-1,-1,   0}, // 3 -
292     { 0, 1, 5, 4, 0,-1,-1,   4}, // 4 bottom
293     { 0, 1, 5, 4, 7, 3, 0,   6}, // 5 bottom, left
294     { 0, 1, 2, 6, 5, 4, 0,   6}, // 6 bottom, right
295     {-1,-1,-1,-1,-1,-1,-1,   0}, // 7 -
296     { 2, 3, 7, 6, 2,-1,-1,   4}, // 8 top
297     { 0, 4, 7, 6, 2, 3, 0,   6}, // 9 top, left
298     { 1, 2, 3, 7, 6, 5, 1,   6}, //10 top, right
299     {-1,-1,-1,-1,-1,-1,-1,   0}, //11 -
300     {-1,-1,-1,-1,-1,-1,-1,   0}, //12 -
301     {-1,-1,-1,-1,-1,-1,-1,   0}, //13 -
302     {-1,-1,-1,-1,-1,-1,-1,   0}, //14 -
303     {-1,-1,-1,-1,-1,-1,-1,   0}, //15 -
304     { 0, 3, 2, 1, 0,-1,-1,   4}, //16 front
305     { 0, 4, 7, 3, 2, 1, 0,   6}, //17 front, left
306     { 0, 3, 2, 6, 5, 1, 0,   6}, //18 front, right
307     {-1,-1,-1,-1,-1,-1,-1,   0}, //19 -
308     { 0, 3, 2, 1, 5, 4, 0,   6}, //20 front, bottom
309     { 1, 5, 4, 7, 3, 2, 1,   6}, //21 front, bottom, left
310     { 0, 3, 2, 6, 5, 4, 0,   6}, //22 front, bottom, right
311     {-1,-1,-1,-1,-1,-1,-1,   0}, //23 -
312     { 0, 3, 7, 6, 2, 1, 0,   6}, //24 front, top
313     { 0, 4, 7, 6, 2, 1, 0,   6}, //25 front, top, left
314     { 0, 3, 7, 6, 5, 1, 0,   6}, //26 front, top, right
315     {-1,-1,-1,-1,-1,-1,-1,   0}, //27 -
316     {-1,-1,-1,-1,-1,-1,-1,   0}, //28 -
317     {-1,-1,-1,-1,-1,-1,-1,   0}, //29 -
318     {-1,-1,-1,-1,-1,-1,-1,   0}, //30 -
319     {-1,-1,-1,-1,-1,-1,-1,   0}, //31 -
320     { 4, 5, 6, 7, 4,-1,-1,   4}, //32 back
321     { 0, 4, 5, 6, 7, 3, 0,   6}, //33 back, left
322     { 1, 2, 6, 7, 4, 5, 1,   6}, //34 back, right
323     {-1,-1,-1,-1,-1,-1,-1,   0}, //35 -
324     { 0, 1, 5, 6, 7, 4, 0,   6}, //36 back, bottom
325     { 0, 1, 5, 6, 7, 3, 0,   6}, //37 back, bottom, left
326     { 0, 1, 2, 6, 7, 4, 0,   6}, //38 back, bottom, right
327     {-1,-1,-1,-1,-1,-1,-1,   0}, //39 -
328     { 2, 3, 7, 4, 5, 6, 2,   6}, //40 back, top
329     { 0, 4, 5, 6, 2, 3, 0,   6}, //41 back, top, left
330     { 1, 2, 3, 7, 4, 5, 1,   6}, //42 back, top, right
331     {-1,-1,-1,-1,-1,-1,-1,   0}, //43 invalid
332     {-1,-1,-1,-1,-1,-1,-1,   0}, //44 invalid
333     {-1,-1,-1,-1,-1,-1,-1,   0}, //45 invalid
334     {-1,-1,-1,-1,-1,-1,-1,   0}, //46 invalid
335     {-1,-1,-1,-1,-1,-1,-1,   0}, //47 invalid
336     {-1,-1,-1,-1,-1,-1,-1,   0}, //48 invalid
337     {-1,-1,-1,-1,-1,-1,-1,   0}, //49 invalid
338     {-1,-1,-1,-1,-1,-1,-1,   0}, //50 invalid
339     {-1,-1,-1,-1,-1,-1,-1,   0}, //51 invalid
340     {-1,-1,-1,-1,-1,-1,-1,   0}, //52 invalid
341     {-1,-1,-1,-1,-1,-1,-1,   0}, //53 invalid
342     {-1,-1,-1,-1,-1,-1,-1,   0}, //54 invalid
343     {-1,-1,-1,-1,-1,-1,-1,   0}, //55 invalid
344     {-1,-1,-1,-1,-1,-1,-1,   0}, //56 invalid
345     {-1,-1,-1,-1,-1,-1,-1,   0}, //57 invalid
346     {-1,-1,-1,-1,-1,-1,-1,   0}, //58 invalid
347     {-1,-1,-1,-1,-1,-1,-1,   0}, //59 invalid
348     {-1,-1,-1,-1,-1,-1,-1,   0}, //60 invalid
349     {-1,-1,-1,-1,-1,-1,-1,   0}, //61 invalid
350     {-1,-1,-1,-1,-1,-1,-1,   0}, //62 invalid
351     {-1,-1,-1,-1,-1,-1,-1,   0}  //63 invalid
352 };
353 
ComputeOutline(const Point & local_eye,sdword & num) const354 const sbyte* AABB::ComputeOutline(const Point& local_eye, sdword& num)	const
355 {
356 	// Get box corners
357 	Point min;	GetMin(min);
358 	Point max;	GetMax(max);
359 
360 	// Compute 6-bit code to classify eye with respect to the 6 defining planes of the bbox
361 	int pos = ((local_eye.x < min.x) ?  1 : 0)	// 1 = left
362 			+ ((local_eye.x > max.x) ?  2 : 0)	// 2 = right
363 			+ ((local_eye.y < min.y) ?  4 : 0)	// 4 = bottom
364 			+ ((local_eye.y > max.y) ?  8 : 0)	// 8 = top
365 			+ ((local_eye.z < min.z) ? 16 : 0)	// 16 = front
366 			+ ((local_eye.z > max.z) ? 32 : 0);	// 32 = back
367 
368 	// Look up number of vertices in outline
369 	num = (sdword)gIndexList[pos][7];
370 	// Zero indicates invalid case
371 	if(!num) return null;
372 
373 	return &gIndexList[pos][0];
374 }
375 
376 // calculateBoxArea: computes the screen-projected 2D area of an oriented 3D bounding box
377 
378 //const Point&		eye,		//eye point (in bbox object coordinates)
379 //const AABB&			box,		//3d bbox
380 //const Matrix4x4&	mat,		//free transformation for bbox
381 //float width, float height, int& num)
ComputeBoxArea(const Point & eye,const Matrix4x4 & mat,float width,float height,sdword & num) const382 float AABB::ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num)	const
383 {
384 	const sbyte* Outline = ComputeOutline(eye, num);
385 	if(!Outline)	return -1.0f;
386 
387 	// Compute box vertices
388 	Point vertexBox[8], dst[8];
389 	ComputePoints(vertexBox);
390 
391 	// Transform all outline corners into 2D screen space
392 	for(sdword i=0;i<num;i++)
393 	{
394 		HPoint Projected;
395 		vertexBox[Outline[i]].ProjectToScreen(width, height, mat, Projected);
396 		dst[i] = Projected;
397 	}
398 
399 	float Sum = (dst[num-1][0] - dst[0][0]) * (dst[num-1][1] + dst[0][1]);
400 
401 	for(int i=0; i<num-1; i++)
402 		Sum += (dst[i][0] - dst[i+1][0]) * (dst[i][1] + dst[i+1][1]);
403 
404 	return Sum * 0.5f;	//return computed value corrected by 0.5
405 }
406