matrix.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.gfx3d.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.gfx3d.matrix"] = true;
  8. dojo.provide("dojox.gfx3d.matrix");
  9. // candidates for dojox.math:
  10. dojox.gfx3d.matrix._degToRad = function(degree){ return Math.PI * degree / 180; };
  11. dojox.gfx3d.matrix._radToDeg = function(radian){ return radian / Math.PI * 180; };
  12. dojox.gfx3d.matrix.Matrix3D = function(arg){
  13. // summary: a 3D matrix object
  14. // description: Normalizes a 3D matrix-like object. If arrays is passed,
  15. // all objects of the array are normalized and multiplied sequentially.
  16. // arg: Object
  17. // a 3D matrix-like object, a number, or an array of such objects
  18. if(arg){
  19. if(typeof arg == "number"){
  20. this.xx = this.yy = this.zz = arg;
  21. }else if(arg instanceof Array){
  22. if(arg.length > 0){
  23. var m = dojox.gfx3d.matrix.normalize(arg[0]);
  24. // combine matrices
  25. for(var i = 1; i < arg.length; ++i){
  26. var l = m;
  27. var r = dojox.gfx3d.matrix.normalize(arg[i]);
  28. m = new dojox.gfx3d.matrix.Matrix3D();
  29. m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx;
  30. m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy;
  31. m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz;
  32. m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx;
  33. m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy;
  34. m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz;
  35. m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx;
  36. m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy;
  37. m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz;
  38. m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx;
  39. m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy;
  40. m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz;
  41. }
  42. dojo.mixin(this, m);
  43. }
  44. }else{
  45. dojo.mixin(this, arg);
  46. }
  47. }
  48. };
  49. // the default (identity) matrix, which is used to fill in missing values
  50. dojo.extend(dojox.gfx3d.matrix.Matrix3D, {xx: 1, xy: 0, xz: 0, yx: 0, yy: 1, yz: 0, zx: 0, zy: 0, zz: 1, dx: 0, dy: 0, dz: 0});
  51. dojo.mixin(dojox.gfx3d.matrix, {
  52. // summary: class constants, and methods of dojox.gfx3d.matrix
  53. // matrix constants
  54. // identity: dojox.gfx3d.matrix.Matrix3D
  55. // an identity matrix constant: identity * (x, y, z) == (x, y, z)
  56. identity: new dojox.gfx3d.matrix.Matrix3D(),
  57. // matrix creators
  58. translate: function(a, b, c){
  59. // summary: forms a translation matrix
  60. // description: The resulting matrix is used to translate (move) points by specified offsets.
  61. // a: Number: an x coordinate value
  62. // b: Number: a y coordinate value
  63. // c: Number: a z coordinate value
  64. if(arguments.length > 1){
  65. return new dojox.gfx3d.matrix.Matrix3D({dx: a, dy: b, dz: c}); // dojox.gfx3d.matrix.Matrix3D
  66. }
  67. // branch
  68. // a: Object: a point-like object, which specifies offsets for 3 dimensions
  69. // b: null
  70. return new dojox.gfx3d.matrix.Matrix3D({dx: a.x, dy: a.y, dz: a.z}); // dojox.gfx3d.matrix.Matrix3D
  71. },
  72. scale: function(a, b, c){
  73. // summary: forms a scaling matrix
  74. // description: The resulting matrix is used to scale (magnify) points by specified offsets.
  75. // a: Number: a scaling factor used for the x coordinate
  76. // b: Number: a scaling factor used for the y coordinate
  77. // c: Number: a scaling factor used for the z coordinate
  78. if(arguments.length > 1){
  79. return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: b, zz: c}); // dojox.gfx3d.matrix.Matrix3D
  80. }
  81. if(typeof a == "number"){
  82. // branch
  83. // a: Number: a uniform scaling factor used for the all coordinates
  84. // b: null
  85. return new dojox.gfx3d.matrix.Matrix3D({xx: a, yy: a, zz: a}); // dojox.gfx3d.matrix.Matrix3D
  86. }
  87. // branch
  88. // a: Object: a point-like object, which specifies scale factors for 3 dimensions
  89. // b: null
  90. return new dojox.gfx3d.matrix.Matrix3D({xx: a.x, yy: a.y, zz: a.z}); // dojox.gfx3d.matrix.Matrix3D
  91. },
  92. rotateX: function(angle){
  93. // summary: forms a rotating matrix (about the x axis)
  94. // description: The resulting matrix is used to rotate points
  95. // around the origin of coordinates (0, 0) by specified angle.
  96. // angle: Number: an angle of rotation in radians (>0 for CW)
  97. var c = Math.cos(angle);
  98. var s = Math.sin(angle);
  99. return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
  100. },
  101. rotateXg: function(degree){
  102. // summary: forms a rotating matrix (about the x axis)
  103. // description: The resulting matrix is used to rotate points
  104. // around the origin of coordinates (0, 0) by specified degree.
  105. // See dojox.gfx3d.matrix.rotateX() for comparison.
  106. // degree: Number: an angle of rotation in degrees (>0 for CW)
  107. return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  108. },
  109. rotateY: function(angle){
  110. // summary: forms a rotating matrix (about the y axis)
  111. // description: The resulting matrix is used to rotate points
  112. // around the origin of coordinates (0, 0) by specified angle.
  113. // angle: Number: an angle of rotation in radians (>0 for CW)
  114. var c = Math.cos(angle);
  115. var s = Math.sin(angle);
  116. return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
  117. },
  118. rotateYg: function(degree){
  119. // summary: forms a rotating matrix (about the y axis)
  120. // description: The resulting matrix is used to rotate points
  121. // around the origin of coordinates (0, 0) by specified degree.
  122. // See dojox.gfx3d.matrix.rotateY() for comparison.
  123. // degree: Number: an angle of rotation in degrees (>0 for CW)
  124. return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  125. },
  126. rotateZ: function(angle){
  127. // summary: forms a rotating matrix (about the z axis)
  128. // description: The resulting matrix is used to rotate points
  129. // around the origin of coordinates (0, 0) by specified angle.
  130. // angle: Number: an angle of rotation in radians (>0 for CW)
  131. var c = Math.cos(angle);
  132. var s = Math.sin(angle);
  133. return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D
  134. },
  135. rotateZg: function(degree){
  136. // summary: forms a rotating matrix (about the z axis)
  137. // description: The resulting matrix is used to rotate points
  138. // around the origin of coordinates (0, 0) by specified degree.
  139. // See dojox.gfx3d.matrix.rotateZ() for comparison.
  140. // degree: Number: an angle of rotation in degrees (>0 for CW)
  141. return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  142. },
  143. // camera transformation
  144. cameraTranslate: function(a, b, c){
  145. // summary: forms a translation matrix
  146. // description: The resulting matrix is used to translate (move) points by specified offsets.
  147. // a: Number: an x coordinate value
  148. // b: Number: a y coordinate value
  149. // c: Number: a z coordinate value
  150. if(arguments.length > 1){
  151. return new dojox.gfx3d.matrix.Matrix3D({dx: -a, dy: -b, dz: -c}); // dojox.gfx3d.matrix.Matrix3D
  152. }
  153. // branch
  154. // a: Object: a point-like object, which specifies offsets for 3 dimensions
  155. // b: null
  156. return new dojox.gfx3d.matrix.Matrix3D({dx: -a.x, dy: -a.y, dz: -a.z}); // dojox.gfx3d.matrix.Matrix3D
  157. },
  158. cameraRotateX: function(angle){
  159. // summary: forms a rotating matrix (about the x axis) in cameraTransform manner
  160. // description: The resulting matrix is used to rotate points
  161. // around the origin of coordinates (0, 0) by specified angle.
  162. // angle: Number: an angle of rotation in radians (>0 for CW)
  163. var c = Math.cos(-angle);
  164. var s = Math.sin(-angle);
  165. return new dojox.gfx3d.matrix.Matrix3D({yy: c, yz: -s, zy: s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
  166. },
  167. cameraRotateXg: function(degree){
  168. // summary: forms a rotating matrix (about the x axis)in cameraTransform manner
  169. // description: The resulting matrix is used to rotate points
  170. // around the origin of coordinates (0, 0) by specified degree.
  171. // See dojox.gfx3d.matrix.rotateX() for comparison.
  172. // degree: Number: an angle of rotation in degrees (>0 for CW)
  173. return dojox.gfx3d.matrix.rotateX(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  174. },
  175. cameraRotateY: function(angle){
  176. // summary: forms a rotating matrix (about the y axis) in cameraTransform manner
  177. // description: The resulting matrix is used to rotate points
  178. // around the origin of coordinates (0, 0) by specified angle.
  179. // angle: Number: an angle of rotation in radians (>0 for CW)
  180. var c = Math.cos(-angle);
  181. var s = Math.sin(-angle);
  182. return new dojox.gfx3d.matrix.Matrix3D({xx: c, xz: s, zx: -s, zz: c}); // dojox.gfx3d.matrix.Matrix3D
  183. },
  184. cameraRotateYg: function(degree){
  185. // summary: forms a rotating matrix (about the y axis) in cameraTransform manner
  186. // description: The resulting matrix is used to rotate points
  187. // around the origin of coordinates (0, 0) by specified degree.
  188. // See dojox.gfx3d.matrix.rotateY() for comparison.
  189. // degree: Number: an angle of rotation in degrees (>0 for CW)
  190. return dojox.gfx3d.matrix.rotateY(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  191. },
  192. cameraRotateZ: function(angle){
  193. // summary: forms a rotating matrix (about the z axis) in cameraTransform manner
  194. // description: The resulting matrix is used to rotate points
  195. // around the origin of coordinates (0, 0) by specified angle.
  196. // angle: Number: an angle of rotation in radians (>0 for CW)
  197. var c = Math.cos(-angle);
  198. var s = Math.sin(-angle);
  199. return new dojox.gfx3d.matrix.Matrix3D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx3d.matrix.Matrix3D
  200. },
  201. cameraRotateZg: function(degree){
  202. // summary: forms a rotating matrix (about the z axis) in cameraTransform manner
  203. // description: The resulting matrix is used to rotate points
  204. // around the origin of coordinates (0, 0) by specified degree.
  205. // See dojox.gfx3d.matrix.rotateZ() for comparison.
  206. // degree: Number: an angle of rotation in degrees (>0 for CW)
  207. return dojox.gfx3d.matrix.rotateZ(dojox.gfx3d.matrix._degToRad(degree)); // dojox.gfx3d.matrix.Matrix3D
  208. },
  209. // ensure matrix 3D conformance
  210. normalize: function(matrix){
  211. // summary: converts an object to a matrix, if necessary
  212. // description: Converts any 3D matrix-like object or an array of
  213. // such objects to a valid dojox.gfx3d.matrix.Matrix3D object.
  214. // matrix: Object: an object, which is converted to a matrix, if necessary
  215. return (matrix instanceof dojox.gfx3d.matrix.Matrix3D) ? matrix : new dojox.gfx3d.matrix.Matrix3D(matrix); // dojox.gfx3d.matrix.Matrix3D
  216. },
  217. // common operations
  218. clone: function(matrix){
  219. // summary: creates a copy of a 3D matrix
  220. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix-like object to be cloned
  221. var obj = new dojox.gfx3d.matrix.Matrix3D();
  222. for(var i in matrix){
  223. if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
  224. }
  225. return obj; // dojox.gfx3d.matrix.Matrix3D
  226. },
  227. invert: function(matrix){
  228. // summary: inverts a 2D matrix
  229. // matrix: dojox.gfx.matrix.Matrix3D: a 2D matrix-like object to be inverted
  230. var m = dojox.gfx3d.matrix.normalize(matrix);
  231. var D = m.xx * m.yy * m.zz + m.xy * m.yz * m.zx + m.xz * m.yx * m.zy - m.xx * m.yz * m.zy - m.xy * m.yx * m.zz - m.xz * m.yy * m.zx;
  232. var M = new dojox.gfx3d.matrix.Matrix3D({
  233. xx: (m.yy * m.zz - m.yz * m.zy) / D,
  234. xy: (m.xz * m.zy - m.xy * m.zz) / D,
  235. xz: (m.xy * m.yz - m.xz * m.yy) / D,
  236. yx: (m.yz * m.zx - m.yx * m.zz) / D,
  237. yy: (m.xx * m.zz - m.xz * m.zx) / D,
  238. yz: (m.xz * m.yx - m.xx * m.yz) / D,
  239. zx: (m.yx * m.zy - m.yy * m.zx) / D,
  240. zy: (m.xy * m.zx - m.xx * m.zy) / D,
  241. zz: (m.xx * m.yy - m.xy * m.yx) / D,
  242. dx: -1 * (m.xy * m.yz * m.dz + m.xz * m.dy * m.zy + m.dx * m.yy * m.zz - m.xy * m.dy * m.zz - m.xz * m.yy * m.dz - m.dx * m.yz * m.zy) / D,
  243. dy: (m.xx * m.yz * m.dz + m.xz * m.dy * m.zx + m.dx * m.yx * m.zz - m.xx * m.dy * m.zz - m.xz * m.yx * m.dz - m.dx * m.yz * m.zx) / D,
  244. dz: -1 * (m.xx * m.yy * m.dz + m.xy * m.dy * m.zx + m.dx * m.yx * m.zy - m.xx * m.dy * m.zy - m.xy * m.yx * m.dz - m.dx * m.yy * m.zx) / D
  245. });
  246. return M; // dojox.gfx3d.matrix.Matrix3D
  247. },
  248. _multiplyPoint: function(m, x, y, z){
  249. // summary: applies a matrix to a point
  250. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  251. // x: Number: an x coordinate of a point
  252. // y: Number: a y coordinate of a point
  253. // z: Number: a z coordinate of a point
  254. return {x: m.xx * x + m.xy * y + m.xz * z + m.dx, y: m.yx * x + m.yy * y + m.yz * z + m.dy, z: m.zx * x + m.zy * y + m.zz * z + m.dz}; // Object
  255. },
  256. multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){
  257. // summary: applies a matrix to a point
  258. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  259. // a: Number: an x coordinate of a point
  260. // b: Number: a y coordinate of a point
  261. // c: Number: a z coordinate of a point
  262. var m = dojox.gfx3d.matrix.normalize(matrix);
  263. if(typeof a == "number" && typeof b == "number" && typeof c == "number"){
  264. return dojox.gfx3d.matrix._multiplyPoint(m, a, b, c); // Object
  265. }
  266. // branch
  267. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  268. // a: Object: a point
  269. // b: null
  270. // c: null
  271. return dojox.gfx3d.matrix._multiplyPoint(m, a.x, a.y, a.z); // Object
  272. },
  273. multiply: function(matrix){
  274. // summary: combines matrices by multiplying them sequentially in the given order
  275. // matrix: dojox.gfx3d.matrix.Matrix3D...: a 3D matrix-like object,
  276. // all subsequent arguments are matrix-like objects too
  277. var m = dojox.gfx3d.matrix.normalize(matrix);
  278. // combine matrices
  279. for(var i = 1; i < arguments.length; ++i){
  280. var l = m;
  281. var r = dojox.gfx3d.matrix.normalize(arguments[i]);
  282. m = new dojox.gfx3d.matrix.Matrix3D();
  283. m.xx = l.xx * r.xx + l.xy * r.yx + l.xz * r.zx;
  284. m.xy = l.xx * r.xy + l.xy * r.yy + l.xz * r.zy;
  285. m.xz = l.xx * r.xz + l.xy * r.yz + l.xz * r.zz;
  286. m.yx = l.yx * r.xx + l.yy * r.yx + l.yz * r.zx;
  287. m.yy = l.yx * r.xy + l.yy * r.yy + l.yz * r.zy;
  288. m.yz = l.yx * r.xz + l.yy * r.yz + l.yz * r.zz;
  289. m.zx = l.zx * r.xx + l.zy * r.yx + l.zz * r.zx;
  290. m.zy = l.zx * r.xy + l.zy * r.yy + l.zz * r.zy;
  291. m.zz = l.zx * r.xz + l.zy * r.yz + l.zz * r.zz;
  292. m.dx = l.xx * r.dx + l.xy * r.dy + l.xz * r.dz + l.dx;
  293. m.dy = l.yx * r.dx + l.yy * r.dy + l.yz * r.dz + l.dy;
  294. m.dz = l.zx * r.dx + l.zy * r.dy + l.zz * r.dz + l.dz;
  295. }
  296. return m; // dojox.gfx3d.matrix.Matrix3D
  297. },
  298. _project: function(m, x, y, z){
  299. // summary: applies a matrix to a point
  300. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  301. // x: Number: an x coordinate of a point
  302. // y: Number: a y coordinate of a point
  303. // z: Number: a z coordinate of a point
  304. return { // Object
  305. x: m.xx * x + m.xy * y + m.xz * z + m.dx,
  306. y: m.yx * x + m.yy * y + m.yz * z + m.dy,
  307. z: m.zx * x + m.zy * y + m.zz * z + m.dz};
  308. },
  309. project: function(matrix, /* Number||Point */ a, /* Number, optional */ b, /* Number, optional */ c){
  310. // summary: applies a matrix to a point
  311. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  312. // a: Number: an x coordinate of a point
  313. // b: Number: a y coordinate of a point
  314. // c: Number: a z coordinate of a point
  315. var m = dojox.gfx3d.matrix.normalize(matrix);
  316. if(typeof a == "number" && typeof b == "number" && typeof c == "number"){
  317. return dojox.gfx3d.matrix._project(m, a, b, c); // Object
  318. }
  319. // branch
  320. // matrix: dojox.gfx3d.matrix.Matrix3D: a 3D matrix object to be applied
  321. // a: Object: a point
  322. // b: null
  323. // c: null
  324. return dojox.gfx3d.matrix._project(m, a.x, a.y, a.z); // Object
  325. }
  326. });
  327. // propagate matrix up
  328. dojox.gfx3d.Matrix3D = dojox.gfx3d.matrix.Matrix3D;
  329. }