PageRenderTime 506ms CodeModel.GetById 161ms app.highlight 103ms RepoModel.GetById 239ms app.codeStats 0ms

/src/away3d/tools/utils/Bounds.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 338 lines | 236 code | 52 blank | 50 comment | 49 complexity | 600ce59af040404ba596cd27c5f3e4af MD5 | raw file
  1package away3d.tools.utils
  2{
  3	import away3d.lights.LightBase;
  4	import flash.utils.Dictionary;
  5	
  6	import away3d.entities.Entity;
  7	
  8	import flash.geom.Matrix3D;
  9	
 10	import away3d.arcane;
 11	import away3d.containers.ObjectContainer3D;
 12	import away3d.entities.Mesh;
 13	
 14	import flash.geom.Vector3D;
 15	
 16	use namespace arcane;
 17	
 18	/**
 19	 * Helper Class to retrieve objects bounds <code>Bounds</code>
 20	 */
 21	
 22	public class Bounds
 23	{
 24		
 25		private static var _minX:Number;
 26		private static var _minY:Number;
 27		private static var _minZ:Number;
 28		private static var _maxX:Number;
 29		private static var _maxY:Number;
 30		private static var _maxZ:Number;
 31		private static var _defaultPosition:Vector3D = new Vector3D(0.0, 0.0, 0.0);
 32		private static var _containers:Dictionary;
 33		
 34		/**
 35		 * Calculate the bounds of a Mesh object
 36		 * @param mesh        Mesh. The Mesh to get the bounds from.
 37		 * Use the getters of this class to retrieve the results
 38		 */
 39		public static function getMeshBounds(mesh:Mesh):void
 40		{
 41			getObjectContainerBounds(mesh);
 42		}
 43		
 44		/**
 45		 * Calculate the bounds of an ObjectContainer3D object
 46		 * @param container        ObjectContainer3D. The ObjectContainer3D to get the bounds from.
 47		 * Use the getters of this class to retrieve the results
 48		 */
 49		public static function getObjectContainerBounds(container:ObjectContainer3D, worldBased:Boolean = true):void
 50		{
 51			reset();
 52			parseObjectContainerBounds(container);
 53			
 54			if (isInfinite(_minX) || isInfinite(_minY) || isInfinite(_minZ) ||
 55				isInfinite(_maxX) || isInfinite(_maxY) || isInfinite(_maxZ)) {
 56				return;
 57			}
 58			
 59			// Transform min/max values to the scene if required
 60			if (worldBased) {
 61				var b:Vector.<Number> = Vector.<Number>([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
 62				var c:Vector.<Number> = getBoundsCorners(_minX, _minY, _minZ, _maxX, _maxY, _maxZ);
 63				transformContainer(b, c, container.sceneTransform);
 64				_minX = b[0];
 65				_minY = b[1];
 66				_minZ = b[2];
 67				_maxX = b[3];
 68				_maxY = b[4];
 69				_maxZ = b[5];
 70			}
 71		}
 72		
 73		/**
 74		 * Calculate the bounds from a vector of number representing the vertices. &lt;x,y,z,x,y,z.....&gt;
 75		 * @param vertices        Vector.&lt;Number&gt;. The vertices to get the bounds from.
 76		 * Use the getters of this class to retrieve the results
 77		 */
 78		public static function getVerticesVectorBounds(vertices:Vector.<Number>):void
 79		{
 80			reset();
 81			var l:uint = vertices.length;
 82			if (l%3 != 0)
 83				return;
 84			
 85			var x:Number;
 86			var y:Number;
 87			var z:Number;
 88			
 89			for (var i:uint = 0; i < l; i += 3) {
 90				x = vertices[i];
 91				y = vertices[i + 1];
 92				z = vertices[i + 2];
 93				
 94				if (x < _minX)
 95					_minX = x;
 96				if (x > _maxX)
 97					_maxX = x;
 98				
 99				if (y < _minY)
100					_minY = y;
101				if (y > _maxY)
102					_maxY = y;
103				
104				if (z < _minZ)
105					_minZ = z;
106				if (z > _maxZ)
107					_maxZ = z;
108			}
109		}
110		
111		/**
112		 * @param outCenter        Vector3D. Optional Vector3D, if provided the same Vector3D is returned with the bounds center.
113		 * @return the center of the bound
114		 */
115		public static function getCenter(outCenter:Vector3D = null):Vector3D
116		{
117			var center:Vector3D = outCenter || new Vector3D();
118			center.x = _minX + (_maxX - _minX)*.5;
119			center.y = _minY + (_maxY - _minY)*.5;
120			center.z = _minZ + (_maxZ - _minZ)*.5;
121			
122			return center;
123		}
124		
125		/**
126		 * @return the smalest x value
127		 */
128		public static function get minX():Number
129		{
130			return _minX;
131		}
132		
133		/**
134		 * @return the smalest y value
135		 */
136		public static function get minY():Number
137		{
138			return _minY;
139		}
140		
141		/**
142		 * @return the smalest z value
143		 */
144		public static function get minZ():Number
145		{
146			return _minZ;
147		}
148		
149		/**
150		 * @return the biggest x value
151		 */
152		public static function get maxX():Number
153		{
154			return _maxX;
155		}
156		
157		/**
158		 * @return the biggest y value
159		 */
160		public static function get maxY():Number
161		{
162			return _maxY;
163		}
164		
165		/**
166		 * @return the biggest z value
167		 */
168		public static function get maxZ():Number
169		{
170			return _maxZ;
171		}
172		
173		/**
174		 * @return the width value from the bounds
175		 */
176		public static function get width():Number
177		{
178			return _maxX - _minX;
179		}
180		
181		/**
182		 * @return the height value from the bounds
183		 */
184		public static function get height():Number
185		{
186			return _maxY - _minY;
187		}
188		
189		/**
190		 * @return the depth value from the bounds
191		 */
192		public static function get depth():Number
193		{
194			return _maxZ - _minZ;
195		}
196		
197		private static function reset():void
198		{
199			_containers = new Dictionary();
200			_minX = _minY = _minZ = Infinity;
201			_maxX = _maxY = _maxZ = -Infinity;
202			_defaultPosition.x = 0.0;
203			_defaultPosition.y = 0.0;
204			_defaultPosition.z = 0.0;
205		}
206		
207		private static function parseObjectContainerBounds(obj:ObjectContainer3D, parentTransform:Matrix3D = null):void
208		{
209			if (!obj.visible)
210				return;
211			
212			var containerBounds:Vector.<Number> = _containers[obj] ||= Vector.<Number>([Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity]);
213			
214			var child:ObjectContainer3D;
215			var isEntity:Entity = obj as Entity;
216			var containerTransform:Matrix3D = new Matrix3D();
217			
218			if (isEntity && parentTransform) {
219				parseObjectBounds(obj, parentTransform);
220				
221				containerTransform = obj.transform.clone();
222				if (parentTransform)
223					containerTransform.append(parentTransform);
224			} else if (isEntity && !parentTransform) {
225				var mat:Matrix3D = obj.transform.clone();
226				mat.invert();
227				parseObjectBounds(obj, mat);
228			}
229			
230			for (var i:uint = 0; i < obj.numChildren; ++i) {
231				child = obj.getChildAt(i);
232				parseObjectContainerBounds(child, containerTransform);
233			}
234			
235			var parentBounds:Vector.<Number> = _containers[obj.parent];
236			if (!isEntity && parentTransform)
237				parseObjectBounds(obj, parentTransform, true);
238			
239			if (parentBounds) {
240				parentBounds[0] = Math.min(parentBounds[0], containerBounds[0]);
241				parentBounds[1] = Math.min(parentBounds[1], containerBounds[1]);
242				parentBounds[2] = Math.min(parentBounds[2], containerBounds[2]);
243				parentBounds[3] = Math.max(parentBounds[3], containerBounds[3]);
244				parentBounds[4] = Math.max(parentBounds[4], containerBounds[4]);
245				parentBounds[5] = Math.max(parentBounds[5], containerBounds[5]);
246			} else {
247				_minX = containerBounds[0];
248				_minY = containerBounds[1];
249				_minZ = containerBounds[2];
250				_maxX = containerBounds[3];
251				_maxY = containerBounds[4];
252				_maxZ = containerBounds[5];
253			}
254		}
255		
256		private static function isInfinite(value:Number):Boolean
257		{
258			return value == Number.POSITIVE_INFINITY || value == Number.NEGATIVE_INFINITY;
259		}
260		
261		private static function parseObjectBounds(oC:ObjectContainer3D, parentTransform:Matrix3D = null, resetBounds:Boolean = false):void
262		{
263			if (oC is LightBase) return; 
264			
265			var e:Entity = oC as Entity;
266			var corners:Vector.<Number>;
267			var mat:Matrix3D = oC.transform.clone();
268			var cB:Vector.<Number> = _containers[oC];
269			if (e) {
270				if (isInfinite(e.minX) || isInfinite(e.minY) || isInfinite(e.minZ) ||
271					isInfinite(e.maxX) || isInfinite(e.maxY) || isInfinite(e.maxZ)) {
272					return;
273				}
274				
275				corners = getBoundsCorners(e.minX, e.minY, e.minZ, e.maxX, e.maxY, e.maxZ);
276				if (parentTransform)
277					mat.append(parentTransform);
278			} else {
279				corners = getBoundsCorners(cB[0], cB[1], cB[2], cB[3], cB[4], cB[5]);
280				if (parentTransform)
281					mat.prepend(parentTransform);
282			}
283			
284			if (resetBounds) {
285				cB[0] = cB[1] = cB[2] = Infinity;
286				cB[3] = cB[4] = cB[5] = -Infinity;
287			}
288			
289			transformContainer(cB, corners, mat);
290		}
291		
292		private static function getBoundsCorners(minX:Number, minY:Number, minZ:Number, maxX:Number, maxY:Number, maxZ:Number):Vector.<Number>
293		{
294			return Vector.<Number>([
295				minX, minY, minZ,
296				minX, minY, maxZ,
297				minX, maxY, minZ,
298				minX, maxY, maxZ,
299				maxX, minY, minZ,
300				maxX, minY, maxZ,
301				maxX, maxY, minZ,
302				maxX, maxY, maxZ
303				]);
304		}
305		
306		private static function transformContainer(bounds:Vector.<Number>, corners:Vector.<Number>, matrix:Matrix3D):void
307		{
308			
309			matrix.transformVectors(corners, corners);
310			
311			var x:Number;
312			var y:Number;
313			var z:Number;
314			
315			var pCtr:int = 0;
316			while (pCtr < corners.length) {
317				x = corners[pCtr++];
318				y = corners[pCtr++];
319				z = corners[pCtr++];
320				
321				if (x < bounds[0])
322					bounds[0] = x;
323				if (x > bounds[3])
324					bounds[3] = x;
325				
326				if (y < bounds[1])
327					bounds[1] = y;
328				if (y > bounds[4])
329					bounds[4] = y;
330				
331				if (z < bounds[2])
332					bounds[2] = z;
333				if (z > bounds[5])
334					bounds[5] = z;
335			}
336		}
337	}
338}