matrix.js 15 KB

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