/src/away3d/core/math/Vector3DUtils.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 231 lines · 155 code · 43 blank · 33 comment · 28 complexity · 7430ff9c27c4924719df33c8b70e79d9 MD5 · raw file

  1. package away3d.core.math
  2. {
  3. import flash.geom.*;
  4. /**
  5. * Vector3DUtils provides additional Vector3D math functions.
  6. */
  7. public class Vector3DUtils
  8. {
  9. private static const MathPI:Number = Math.PI;
  10. /**
  11. * Returns the angle in radians made between the 3d number obejct and the given <code>Vector3D</code> object.
  12. *
  13. * @param w The first 3d number object to use in the calculation.
  14. * @param q The first 3d number object to use in the calculation.
  15. * @return An angle in radians representing the angle between the two <code>Vector3D</code> objects.
  16. */
  17. public static function getAngle(w:Vector3D, q:Vector3D):Number
  18. {
  19. return Math.acos(w.dotProduct(q)/(w.length*q.length));
  20. }
  21. /**
  22. * Returns a <code>Vector3D</code> object with the euler angles represented by the 3x3 matrix rotation of the given <code>Matrix3D</code> object.
  23. *
  24. * @param m1 The 3d matrix object to use in the calculation.
  25. * @return A 3d vector representing the euler angles extracted from the 3d matrix.
  26. */
  27. public static function matrix2euler(m1:Matrix3D):Vector3D
  28. {
  29. var m2:Matrix3D = new Matrix3D();
  30. var result:Vector3D = new Vector3D();
  31. var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
  32. m1.copyRawDataTo(raw);
  33. // Extract the first angle, rotationX
  34. result.x = -Math.atan2(raw[uint(6)], raw[uint(10)]); // rot.x = Math<T>::atan2 (M[1][2], M[2][2]);
  35. // Remove the rotationX rotation from m2, so that the remaining
  36. // rotation, m2 is only around two axes, and gimbal lock cannot occur.
  37. m2.appendRotation(result.x*180/MathPI, new Vector3D(1, 0, 0));
  38. m2.append(m1);
  39. m2.copyRawDataTo(raw);
  40. // Extract the other two angles, rot.y and rot.z, from m2.
  41. var cy:Number = Math.sqrt(raw[uint(0)]*raw[uint(0)] + raw[uint(1)]*raw[uint(1)]); // T cy = Math<T>::sqrt (N[0][0]*N[0][0] + N[0][1]*N[0][1]);
  42. result.y = Math.atan2(-raw[uint(2)], cy); // rot.y = Math<T>::atan2 (-N[0][2], cy);
  43. result.z = Math.atan2(-raw[uint(4)], raw[uint(5)]); //rot.z = Math<T>::atan2 (-N[1][0], N[1][1]);
  44. // Fix angles
  45. if (Math.round(result.z/MathPI) == 1) {
  46. if (result.y > 0)
  47. result.y = -(result.y - MathPI);
  48. else
  49. result.y = -(result.y + MathPI);
  50. result.z -= MathPI;
  51. if (result.x > 0)
  52. result.x -= MathPI;
  53. else
  54. result.x += MathPI;
  55. } else if (Math.round(result.z/MathPI) == -1) {
  56. if (result.y > 0)
  57. result.y = -(result.y - MathPI);
  58. else
  59. result.y = -(result.y + MathPI);
  60. result.z += MathPI;
  61. if (result.x > 0)
  62. result.x -= MathPI;
  63. else
  64. result.x += MathPI;
  65. } else if (Math.round(result.x/MathPI) == 1) {
  66. if (result.y > 0)
  67. result.y = -(result.y - MathPI);
  68. else
  69. result.y = -(result.y + MathPI);
  70. result.x -= MathPI;
  71. if (result.z > 0)
  72. result.z -= MathPI;
  73. else
  74. result.z += MathPI;
  75. } else if (Math.round(result.x/MathPI) == -1) {
  76. if (result.y > 0)
  77. result.y = -(result.y - MathPI);
  78. else
  79. result.y = -(result.y + MathPI);
  80. result.x += MathPI;
  81. if (result.z > 0)
  82. result.z -= MathPI;
  83. else
  84. result.z += MathPI;
  85. }
  86. return result;
  87. }
  88. /**
  89. * Returns a <code>Vector3D</code> object containing the euler angles represented by the given <code>Quaternion</code> object.
  90. *
  91. * @param quaternion The quaternion object to use in the calculation.
  92. * @return A 3d vector representing the euler angles extracted from the quaternion.
  93. */
  94. public static function quaternion2euler(quarternion:Quaternion):Vector3D
  95. {
  96. var result:Vector3D = new Vector3D();
  97. var test:Number = quarternion.x*quarternion.y + quarternion.z*quarternion.w;
  98. if (test > 0.499) { // singularity at north pole
  99. result.x = 2*Math.atan2(quarternion.x, quarternion.w);
  100. result.y = Math.PI/2;
  101. result.z = 0;
  102. return result;
  103. }
  104. if (test < -0.499) { // singularity at south pole
  105. result.x = -2*Math.atan2(quarternion.x, quarternion.w);
  106. result.y = -Math.PI/2;
  107. result.z = 0;
  108. return result;
  109. }
  110. var sqx:Number = quarternion.x*quarternion.x;
  111. var sqy:Number = quarternion.y*quarternion.y;
  112. var sqz:Number = quarternion.z*quarternion.z;
  113. result.x = Math.atan2(2*quarternion.y*quarternion.w - 2*quarternion.x*quarternion.z, 1 - 2*sqy - 2*sqz);
  114. result.y = Math.asin(2*test);
  115. result.z = Math.atan2(2*quarternion.x*quarternion.w - 2*quarternion.y*quarternion.z, 1 - 2*sqx - 2*sqz);
  116. return result;
  117. }
  118. /**
  119. * Returns a <code>Vector3D</code> object containing the scale values represented by the given <code>Matrix3D</code> object.
  120. *
  121. * @param m The 3d matrix object to use in the calculation.
  122. * @return A 3d vector representing the axis scale values extracted from the 3d matrix.
  123. */
  124. public static function matrix2scale(m:Matrix3D):Vector3D
  125. {
  126. var result:Vector3D = new Vector3D();
  127. var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
  128. m.copyRawDataTo(raw);
  129. result.x = Math.sqrt(raw[uint(0)]*raw[uint(0)] + raw[uint(1)]*raw[uint(1)] + raw[uint(2)]*raw[uint(2)]);
  130. result.y = Math.sqrt(raw[uint(4)]*raw[uint(4)] + raw[uint(5)]*raw[uint(5)] + raw[uint(6)]*raw[uint(6)]);
  131. result.z = Math.sqrt(raw[uint(8)]*raw[uint(8)] + raw[uint(9)]*raw[uint(9)] + raw[uint(10)]*raw[uint(10)]);
  132. return result;
  133. }
  134. public static function rotatePoint(aPoint:Vector3D, rotation:Vector3D):Vector3D
  135. {
  136. if (rotation.x != 0 || rotation.y != 0 || rotation.z != 0) {
  137. var x1:Number;
  138. var y1:Number;
  139. var rad:Number = MathConsts.DEGREES_TO_RADIANS;
  140. var rotx:Number = rotation.x*rad;
  141. var roty:Number = rotation.y*rad;
  142. var rotz:Number = rotation.z*rad;
  143. var sinx:Number = Math.sin(rotx);
  144. var cosx:Number = Math.cos(rotx);
  145. var siny:Number = Math.sin(roty);
  146. var cosy:Number = Math.cos(roty);
  147. var sinz:Number = Math.sin(rotz);
  148. var cosz:Number = Math.cos(rotz);
  149. var x:Number = aPoint.x;
  150. var y:Number = aPoint.y;
  151. var z:Number = aPoint.z;
  152. y1 = y;
  153. y = y1*cosx + z* -sinx;
  154. z = y1*sinx + z*cosx;
  155. x1 = x;
  156. x = x1*cosy + z*siny;
  157. z = x1* -siny + z*cosy;
  158. x1 = x;
  159. x = x1*cosz + y* -sinz;
  160. y = x1*sinz + y*cosz;
  161. aPoint.x = x;
  162. aPoint.y = y;
  163. aPoint.z = z;
  164. }
  165. return aPoint;
  166. }
  167. public static function subdivide(startVal:Vector3D, endVal:Vector3D, numSegments:int):Vector.<Vector3D>
  168. {
  169. var points:Vector.<Vector3D> = new Vector.<Vector3D>();
  170. var numPoints:int = 0;
  171. var stepx:Number = (endVal.x - startVal.x)/numSegments;
  172. var stepy:Number = (endVal.y - startVal.y)/numSegments;
  173. var stepz:Number = (endVal.z - startVal.z)/numSegments;
  174. var step:int = 1;
  175. var scalestep:Vector3D;
  176. while (step < numSegments) {
  177. scalestep = new Vector3D();
  178. scalestep.x = startVal.x + (stepx*step);
  179. scalestep.y = startVal.y + (stepy*step);
  180. scalestep.z = startVal.z + (stepz*step);
  181. points[numPoints++] = scalestep;
  182. step++;
  183. }
  184. points[numPoints] = endVal;
  185. return points;
  186. }
  187. }
  188. }