/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

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