/src/away3d/extrusions/PathDuplicator.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 309 lines · 209 code · 52 blank · 48 comment · 29 complexity · 85cf64505cd1898ce97a50fd9f6b5300 MD5 · raw file

  1. package away3d.extrusions
  2. {
  3. import away3d.containers.ObjectContainer3D;
  4. import away3d.containers.Scene3D;
  5. import away3d.entities.Mesh;
  6. import away3d.paths.IPath;
  7. import flash.geom.Matrix3D;
  8. import flash.geom.Vector3D;
  9. [Deprecated]
  10. public class PathDuplicator
  11. {
  12. private var _transform:Matrix3D;
  13. private var _upAxis:Vector3D = new Vector3D(0, 1, 0);
  14. private var _path:IPath;
  15. private var _scene:Scene3D;
  16. private var _meshes:Vector.<Mesh>;
  17. private var _clones:Vector.<Mesh>;
  18. private var _repeat:uint;
  19. private var _alignToPath:Boolean;
  20. private var _randomRotationY:Boolean;
  21. private var _segmentSpread:Boolean = false;
  22. private var _mIndex:uint;
  23. private var _count:uint;
  24. private var _container:ObjectContainer3D;
  25. /**
  26. * Creates a new <code>PathDuplicator</code>
  27. * Class replicates and distribute one or more mesh(es) along a path. The offsets are defined by the position of the object. 0,0,0 would place the center of the mesh exactly on Path.
  28. *
  29. * @param path [optional] A Path object. The _path definition. either Cubic or Quadratic path
  30. * @param meshes [optional] Vector.&lt;Mesh&gt;. One or more meshes to repeat along the path.
  31. * @param scene [optional] Scene3D. The scene where to addchild the meshes if no ObjectContainer3D is provided.
  32. * @param repeat [optional] uint. How many times a mesh is cloned per PathSegment. Default is 1.
  33. * @param alignToPath [optional] Boolean. If the alignment of the clones must follow the path. Default is true.
  34. * @param segmentSpread [optional] Boolean. If more than one Mesh is passed, it defines if the clones alternate themselves per PathSegment or each repeat. Default is false.
  35. * @param container [optional] ObjectContainer3D. If an ObjectContainer3D is provided, the meshes are addChilded to it instead of directly into the scene. The container is NOT addChilded to the scene by default.
  36. * @param randomRotationY [optional] Boolean. If the clones must have a random rotationY added to them.
  37. *
  38. */
  39. function PathDuplicator(path:IPath = null, meshes:Vector.<Mesh> = null, scene:Scene3D = null, repeat:uint = 1, alignToPath:Boolean = true, segmentSpread:Boolean = true, container:ObjectContainer3D = null, randomRotationY:Boolean = false)
  40. {
  41. _path = path;
  42. _meshes = meshes;
  43. _scene = scene;
  44. _repeat = repeat;
  45. _alignToPath = alignToPath;
  46. _segmentSpread = segmentSpread;
  47. _randomRotationY = randomRotationY;
  48. _container = container;
  49. }
  50. /**
  51. * The up axis to which duplicated objects' Y axis will be oriented.
  52. */
  53. public function get upAxis():Vector3D
  54. {
  55. return _upAxis;
  56. }
  57. public function set upAxis(value:Vector3D):void
  58. {
  59. _upAxis = value;
  60. }
  61. /**
  62. * If a container is provided, the meshes are addChilded to it instead of directly into the scene. The container is NOT addChilded to the scene.
  63. */
  64. public function set container(cont:ObjectContainer3D):void
  65. {
  66. _container = cont;
  67. }
  68. public function get container():ObjectContainer3D
  69. {
  70. return _container;
  71. }
  72. /**
  73. * Defines the resolution between each PathSegments. Default 1, is also minimum.
  74. */
  75. public function set repeat(val:uint):void
  76. {
  77. _repeat = (val < 1)? 1 : val;
  78. }
  79. public function get repeat():uint
  80. {
  81. return _repeat;
  82. }
  83. /**
  84. * Defines if the profile point array should be orientated on path or not. Default true.
  85. */
  86. public function set alignToPath(b:Boolean):void
  87. {
  88. _alignToPath = b;
  89. }
  90. public function get alignToPath():Boolean
  91. {
  92. return _alignToPath;
  93. }
  94. /**
  95. * Defines if a clone gets a random rotationY to break visual repetitions, usefull in case of vegetation for instance.
  96. */
  97. public function set randomRotationY(b:Boolean):void
  98. {
  99. _randomRotationY = b;
  100. }
  101. public function get randomRotationY():Boolean
  102. {
  103. return _randomRotationY;
  104. }
  105. /**
  106. * returns a vector with all meshes cloned since last time build method was called. Returns null if build hasn't be called yet.
  107. * Another option to retreive the generated meshes is to pass an ObjectContainer3D to the class
  108. */
  109. public function get clones():Vector.<Mesh>
  110. {
  111. return _clones;
  112. }
  113. /**
  114. * Sets and defines the Path object. See extrusions.utils package. Required for this class.
  115. */
  116. public function set path(p:IPath):void
  117. {
  118. _path = p;
  119. }
  120. public function get path():IPath
  121. {
  122. return _path;
  123. }
  124. /**
  125. * Defines an optional Vector.&lt;Mesh&gt;. One or more meshes to repeat along the path.
  126. * When the last in the vector is reached, the first in the array will be used, this process go on and on until the last segment.
  127. *
  128. * @param ms A Vector.<Mesh>. One or more meshes to repeat along the path. Required for this class.
  129. */
  130. public function set meshes(ms:Vector.<Mesh>):void
  131. {
  132. _meshes = ms;
  133. }
  134. public function get meshes():Vector.<Mesh>
  135. {
  136. return _meshes;
  137. }
  138. public function clearData(destroyCachedMeshes:Boolean):void
  139. {
  140. if (destroyCachedMeshes) {
  141. var i:uint = 0;
  142. if (meshes) {
  143. for (i = 0; i < meshes.length; ++i)
  144. meshes[i] = null;
  145. }
  146. if (_clones) {
  147. for (i; i < _clones.length; ++i)
  148. _clones[i] = null;
  149. }
  150. }
  151. _meshes = _clones = null;
  152. }
  153. /**
  154. * defines if the meshes[index] is repeated per segments or duplicated after each others. default = false.
  155. */
  156. public function set segmentSpread(b:Boolean):void
  157. {
  158. _segmentSpread = b;
  159. }
  160. public function get segmentSpread():Boolean
  161. {
  162. return _segmentSpread;
  163. }
  164. /**
  165. * Triggers the generation
  166. */
  167. public function build():void
  168. {
  169. if (!_path || !_meshes || meshes.length == 0)
  170. throw new Error("PathDuplicator error: Missing Path or Meshes data.");
  171. if (!_scene && !_container)
  172. throw new Error("PathDuplicator error: Missing Scene3D or ObjectContainer3D.");
  173. _mIndex = _meshes.length - 1;
  174. _count = 0;
  175. _clones = new Vector.<Mesh>();
  176. var segments:Vector.<Vector.<Vector3D>> = _path.getPointsOnCurvePerSegment(_repeat);
  177. var tmppt:Vector3D = new Vector3D();
  178. var i:uint;
  179. var j:uint;
  180. var nextpt:Vector3D;
  181. var m:Mesh;
  182. var tPosi:Vector3D;
  183. for (i = 0; i < segments.length; ++i) {
  184. if (!_segmentSpread)
  185. _mIndex = (_mIndex + 1 != _meshes.length)? _mIndex + 1 : 0;
  186. for (j = 0; j < segments[i].length; ++j) {
  187. if (_segmentSpread)
  188. _mIndex = (_mIndex + 1 != _meshes.length)? _mIndex + 1 : 0;
  189. m = _meshes[_mIndex];
  190. tPosi = m.position;
  191. if (_alignToPath) {
  192. _transform = new Matrix3D();
  193. if (i == segments.length - 1 && j == segments[i].length - 1) {
  194. nextpt = segments[i][j - 1];
  195. orientateAt(segments[i][j], nextpt);
  196. } else {
  197. nextpt = (j < segments[i].length - 1)? segments[i][j + 1] : segments[i + 1][0];
  198. orientateAt(nextpt, segments[i][j]);
  199. }
  200. }
  201. if (_alignToPath) {
  202. tmppt.x = tPosi.x*_transform.rawData[0] + tPosi.y*_transform.rawData[4] + tPosi.z*_transform.rawData[8] + _transform.rawData[12];
  203. tmppt.y = tPosi.x*_transform.rawData[1] + tPosi.y*_transform.rawData[5] + tPosi.z*_transform.rawData[9] + _transform.rawData[13];
  204. tmppt.z = tPosi.x*_transform.rawData[2] + tPosi.y*_transform.rawData[6] + tPosi.z*_transform.rawData[10] + _transform.rawData[14];
  205. tmppt.x += segments[i][j].x;
  206. tmppt.y += segments[i][j].y;
  207. tmppt.z += segments[i][j].z;
  208. } else
  209. tmppt = new Vector3D(tPosi.x + segments[i][j].x, tPosi.y + segments[i][j].y, tPosi.z + segments[i][j].z);
  210. generate(m, tmppt);
  211. }
  212. }
  213. segments = null;
  214. }
  215. private function orientateAt(target:Vector3D, position:Vector3D):void
  216. {
  217. var xAxis:Vector3D;
  218. var yAxis:Vector3D;
  219. var zAxis:Vector3D = target.subtract(position);
  220. zAxis.normalize();
  221. if (zAxis.length > 0.1) {
  222. xAxis = _upAxis.crossProduct(zAxis);
  223. xAxis.normalize();
  224. yAxis = xAxis.crossProduct(zAxis);
  225. yAxis.normalize();
  226. var rawData:Vector.<Number> = _transform.rawData;
  227. rawData[0] = xAxis.x;
  228. rawData[1] = xAxis.y;
  229. rawData[2] = xAxis.z;
  230. rawData[4] = -yAxis.x;
  231. rawData[5] = -yAxis.y;
  232. rawData[6] = -yAxis.z;
  233. rawData[8] = zAxis.x;
  234. rawData[9] = zAxis.y;
  235. rawData[10] = zAxis.z;
  236. _transform.rawData = rawData;
  237. }
  238. }
  239. private function generate(m:Mesh, position:Vector3D):void
  240. {
  241. var clone:Mesh = m.clone() as Mesh;
  242. if (_alignToPath)
  243. clone.transform = _transform;
  244. else
  245. clone.position = position;
  246. clone.name = (m.name != null)? m.name + "_" + _count : "clone_" + _count;
  247. _count++;
  248. if (_randomRotationY)
  249. clone.rotationY = Math.random()*360;
  250. if (_container)
  251. _container.addChild(clone);
  252. else
  253. _scene.addChild(clone);
  254. _clones.push(clone);
  255. }
  256. }
  257. }