Transform.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. using System;
  2. namespace PaintDotNet.Data.SurfacePlot
  3. {
  4. public class Transform
  5. {
  6. // direction of z // zOrientation = -1 means z is pointing out of the screen
  7. private int zOrientation = -1; // zOrientation = 1 means z is pointing into the screen
  8. private double angleX = 0; // angle for X-rotation
  9. private double angleY = 0;
  10. private double angleZ = 0; // angle for Z-rotation
  11. // public double angleX = 0; // angle for X-rotation
  12. // public double angleY = 0;
  13. // public double angleZ = 0; // angle for Z-rotation
  14. private double xs = 256;
  15. private double ys = 256;
  16. private double cosZ; // = (double)Math.cos(angleB),
  17. private double sinZ; // = (double)Math.sin(angleB);
  18. private double cosX; // = (double)Math.cos(angleR);
  19. private double sinX; // = (double)Math.sin(angleR);
  20. private double cosY;
  21. private double sinY;
  22. private double scale = 1;
  23. private double zAspect = 1;
  24. double[,] m = new double[4, 4];
  25. double[,] m_ = new double[4, 4];
  26. double[,] mX = new double[4, 4];
  27. double[,] mY = new double[4, 4];
  28. double[,] mZ = new double[4, 4];
  29. double[,] mP = new double[4, 4];
  30. double[,] m_Z = new double[4, 4];
  31. double[,] m_YZ = new double[4, 4];
  32. double[,] m_XYZ = new double[4, 4];
  33. double[,] m_PXYZ = new double[4, 4];
  34. double[,] m_XYZInv = new double[4, 4];
  35. public double xO;
  36. public double yO;
  37. public double zO;
  38. public double a00, a01, a02, a03; // coefficients of the transformation
  39. public double a10, a11, a12, a13;
  40. public double a20, a21, a22, a23;
  41. //double a30, a31, a32, a33;
  42. public double ai00, ai01, ai02, ai03; // coefficients of the inverse transformation
  43. public double ai10, ai11, ai12, ai13;
  44. public double ai20, ai21, ai22, ai23;
  45. //double ai30, ai31, ai32, ai33;
  46. public double y, x, z; // volume coordinates
  47. public int[] xyz;
  48. public double X, Y, Z; // screen coordinates
  49. private double perspective = 0;
  50. private double maxDistance = 256;
  51. public Transform(int width, int height)
  52. {
  53. xs = (double)(width / 2 + 0.5);
  54. ys = (double)(height / 2 + 0.5);
  55. initializeTransformation();
  56. }
  57. public void transform(SurfacePlotData plotItem)
  58. {
  59. y = plotItem.y;
  60. x = plotItem.x;
  61. z = plotItem.z;
  62. xyzPos();
  63. }
  64. public void transform(Text3D textItem)
  65. {
  66. x = textItem.x;
  67. y = textItem.y;
  68. z = textItem.z;
  69. xyzPos();
  70. }
  71. public void transform(double x_, double y_, double z_)
  72. {
  73. x = x_;
  74. y = y_;
  75. z = z_;
  76. xyzPos_noShift();
  77. }
  78. public void transform(Point3D pt)
  79. {
  80. x = pt.x;
  81. y = pt.y;
  82. z = pt.z;
  83. xyzPos();
  84. }
  85. public void setScale(double scale)
  86. {
  87. this.scale = scale;
  88. initializeTransformation();
  89. }
  90. public void setZOrientation(int zOrientation)
  91. {
  92. if (zOrientation <= 0)
  93. this.zOrientation = -1;
  94. else
  95. this.zOrientation = 1;
  96. initializeTransformation();
  97. }
  98. public void setZAspectRatio(double zAspectRatio)
  99. {
  100. this.zAspect = zAspectRatio;
  101. initializeTransformation();
  102. }
  103. public void setRotationZ(double angleZ)
  104. {
  105. this.angleZ = angleZ;
  106. initializeTransformation();
  107. }
  108. public void setRotationY(double angleY)
  109. {
  110. this.angleY = angleY;
  111. initializeTransformation();
  112. }
  113. public void setRotationX(double angleX)
  114. {
  115. this.angleX = angleX;
  116. initializeTransformation();
  117. }
  118. public void setRotationXYZ(double angleX, double angleY, double angleZ)
  119. {
  120. this.angleX = angleX;
  121. this.angleY = angleY;
  122. this.angleZ = angleZ;
  123. initializeTransformation();
  124. }
  125. public void setRotationXZ(double angleX, double angleZ)
  126. {
  127. this.angleX = angleX;
  128. this.angleZ = angleZ;
  129. initializeTransformation();
  130. }
  131. public double getRotationX()
  132. {
  133. return angleX;
  134. }
  135. public double getRotationY()
  136. {
  137. return angleY;
  138. }
  139. public double getRotationZ()
  140. {
  141. return angleZ;
  142. }
  143. public void changeRotationXZ(double dx, double dz)
  144. {
  145. angleX += dx;
  146. angleZ += dz;
  147. initializeTransformation();
  148. }
  149. public void changeRotationXYZ(double dx, double dy, double dz)
  150. {
  151. angleX += dx;
  152. angleY += dy;
  153. angleZ += dz;
  154. initializeTransformation();
  155. }
  156. public void setOffsets(double xOff, double yOff, double zOff)
  157. {
  158. xO = -xOff;
  159. yO = -yOff;
  160. zO = -zOff;
  161. initializeTransformation();
  162. }
  163. private void initializeTransformation()
  164. {
  165. // calculate new cos and sins
  166. cosX = (double)Math.Cos(angleX);
  167. sinX = (double)Math.Sin(angleX);
  168. cosY = (double)Math.Cos(angleY);
  169. sinY = (double)Math.Sin(angleY);
  170. cosZ = (double)Math.Cos(angleZ);
  171. sinZ = (double)Math.Sin(angleZ);
  172. double s = 1; //scale;
  173. // translation & scale
  174. m[0, 0] = s; m[0, 1] = 0; m[0, 2] = 0; m[0, 3] = s * xO;
  175. m[1, 0] = 0; m[1, 1] = s; m[1, 2] = 0; m[1, 3] = s * yO;
  176. m[2, 0] = 0; m[2, 1] = 0; m[2, 2] = s * zOrientation * zAspect; m[2, 3] = s * zOrientation * zAspect * zO;
  177. m[3, 0] = 0; m[3, 1] = 0; m[3, 2] = 0; m[3, 3] = 1;
  178. // z rotation
  179. mZ[0, 0] = cosZ; mZ[0, 1] = sinZ; mZ[0, 2] = 0; mZ[0, 3] = 0;
  180. mZ[1, 0] = -sinZ; mZ[1, 1] = cosZ; mZ[1, 2] = 0; mZ[1, 3] = 0;
  181. mZ[2, 0] = 0; mZ[2, 1] = 0; mZ[2, 2] = 1; mZ[2, 3] = 0;
  182. mZ[3, 0] = 0; mZ[3, 1] = 0; mZ[3, 2] = 0; mZ[3, 3] = 1;
  183. // y rotation
  184. mY[0, 0] = cosY; mY[0, 1] = 0; mY[0, 2] = -sinY; mY[0, 3] = 0;
  185. mY[1, 0] = 0; mY[1, 1] = 1; mY[1, 2] = 0; mY[1, 3] = 0;
  186. mY[2, 0] = sinY; mY[2, 1] = 0; mY[2, 2] = cosY; mY[2, 3] = 0;
  187. mY[3, 0] = 0; mY[3, 1] = 0; mY[3, 2] = 0; mY[3, 3] = 1;
  188. // x rotation
  189. mX[0, 0] = 1; mX[0, 1] = 0; mX[0, 2] = 0; mX[0, 3] = 0;
  190. mX[1, 0] = 0; mX[1, 1] = cosX; mX[1, 2] = sinX; mX[1, 3] = 0;
  191. mX[2, 0] = 0; mX[2, 1] = -sinX; mX[2, 2] = cosX; mX[2, 3] = 0;
  192. mX[3, 0] = 0; mX[3, 1] = 0; mX[3, 2] = 0; mX[3, 3] = 1;
  193. matProd(m_Z, mZ, m);
  194. matProd(m_YZ, mY, m_Z);
  195. matProd(m_XYZ, mX, m_YZ);
  196. a00 = m_XYZ[0, 0];
  197. a01 = m_XYZ[0, 1];
  198. a02 = m_XYZ[0, 2];
  199. a03 = m_XYZ[0, 3];
  200. a10 = m_XYZ[1, 0];
  201. a11 = m_XYZ[1, 1];
  202. a12 = m_XYZ[1, 2];
  203. a13 = m_XYZ[1, 3];
  204. a20 = m_XYZ[2, 0];
  205. a21 = m_XYZ[2, 1];
  206. a22 = m_XYZ[2, 2];
  207. a23 = m_XYZ[2, 3];
  208. matInv4(m_XYZInv, m_XYZ);
  209. ai00 = m_XYZInv[0, 0];
  210. ai01 = m_XYZInv[0, 1];
  211. ai02 = m_XYZInv[0, 2];
  212. ai03 = m_XYZInv[0, 3];
  213. ai10 = m_XYZInv[1, 0];
  214. ai11 = m_XYZInv[1, 1];
  215. ai12 = m_XYZInv[1, 2];
  216. ai13 = m_XYZInv[1, 3];
  217. ai20 = m_XYZInv[2, 0];
  218. ai21 = m_XYZInv[2, 1];
  219. ai22 = m_XYZInv[2, 2];
  220. ai23 = m_XYZInv[2, 3];
  221. }
  222. public void rotateTransformation(double angle_X, double angle_Y, double angle_Z)
  223. {
  224. cosX = (double)Math.Cos(angle_X);
  225. sinX = (double)Math.Sin(angle_X);
  226. cosY = (double)Math.Cos(angle_Y);
  227. sinY = (double)Math.Sin(angle_Y);
  228. cosZ = (double)Math.Cos(angle_Z);
  229. sinZ = (double)Math.Sin(angle_Z);
  230. m_[0, 0] = m_XYZ[0, 0]; m_[0, 1] = m_XYZ[0, 1]; m_[0, 2] = m_XYZ[0, 2]; m_[0, 3] = m_XYZ[0, 3];
  231. m_[1, 0] = m_XYZ[1, 0]; m_[1, 1] = m_XYZ[1, 1]; m_[1, 2] = m_XYZ[1, 2]; m_[1, 3] = m_XYZ[1, 3];
  232. m_[2, 0] = m_XYZ[2, 0]; m_[2, 1] = m_XYZ[2, 1]; m_[2, 2] = m_XYZ[2, 2]; m_[2, 3] = m_XYZ[2, 3];
  233. m_[3, 0] = m_XYZ[3, 0]; m_[3, 1] = m_XYZ[3, 1]; m_[3, 2] = m_XYZ[3, 2]; m_[3, 3] = m_XYZ[3, 3];
  234. // z rotation
  235. mZ[0, 0] = cosZ; mZ[0, 1] = sinZ; mZ[0, 2] = 0; mZ[0, 3] = 0;
  236. mZ[1, 0] = -sinZ; mZ[1, 1] = cosZ; mZ[1, 2] = 0; mZ[1, 3] = 0;
  237. mZ[2, 0] = 0; mZ[2, 1] = 0; mZ[2, 2] = 1; mZ[2, 3] = 0;
  238. mZ[3, 0] = 0; mZ[3, 1] = 0; mZ[3, 2] = 0; mZ[3, 3] = 1;
  239. // y rotation
  240. mY[0, 0] = cosY; mY[0, 1] = 0; mY[0, 2] = -sinY; mY[0, 3] = 0;
  241. mY[1, 0] = 0; mY[1, 1] = 1; mY[1, 2] = 0; mY[1, 3] = 0;
  242. mY[2, 0] = sinY; mY[2, 1] = 0; mY[2, 2] = cosY; mY[2, 3] = 0;
  243. mY[3, 0] = 0; mY[3, 1] = 0; mY[3, 2] = 0; mY[3, 3] = 1;
  244. // x rotation
  245. mX[0, 0] = 1; mX[0, 1] = 0; mX[0, 2] = 0; mX[0, 3] = 0;
  246. mX[1, 0] = 0; mX[1, 1] = cosX; mX[1, 2] = sinX; mX[1, 3] = 0;
  247. mX[2, 0] = 0; mX[2, 1] = -sinX; mX[2, 2] = cosX; mX[2, 3] = 0;
  248. mX[3, 0] = 0; mX[3, 1] = 0; mX[3, 2] = 0; mX[3, 3] = 1;
  249. //matProd(m_Z, mZ, m);
  250. matProd(m_YZ, mY, mZ);
  251. matProd(m_Z, mX, m_YZ);
  252. matProd(m_XYZ, m_Z, m_);
  253. a00 = m_XYZ[0, 0];
  254. a01 = m_XYZ[0, 1];
  255. a02 = m_XYZ[0, 2];
  256. a03 = m_XYZ[0, 3];
  257. a10 = m_XYZ[1, 0];
  258. a11 = m_XYZ[1, 1];
  259. a12 = m_XYZ[1, 2];
  260. a13 = m_XYZ[1, 3];
  261. a20 = m_XYZ[2, 0];
  262. a21 = m_XYZ[2, 1];
  263. a22 = m_XYZ[2, 2];
  264. a23 = m_XYZ[2, 3];
  265. matInv4(m_XYZInv, m_XYZ);
  266. ai00 = m_XYZInv[0, 0];
  267. ai01 = m_XYZInv[0, 1];
  268. ai02 = m_XYZInv[0, 2];
  269. ai03 = m_XYZInv[0, 3];
  270. ai10 = m_XYZInv[1, 0];
  271. ai11 = m_XYZInv[1, 1];
  272. ai12 = m_XYZInv[1, 2];
  273. ai13 = m_XYZInv[1, 3];
  274. ai20 = m_XYZInv[2, 0];
  275. ai21 = m_XYZInv[2, 1];
  276. ai22 = m_XYZInv[2, 2];
  277. ai23 = m_XYZInv[2, 3];
  278. }
  279. private void xyzPos()
  280. {
  281. X = a00 * x + a01 * y + a02 * z + a03;
  282. Y = a10 * x + a11 * y + a12 * z + a13;
  283. Z = a20 * x + a21 * y + a22 * z + a23;
  284. double sz = scale * maxDistance / (maxDistance + perspective * Z);
  285. X = sz * X + xs;
  286. Y = sz * Y + ys;
  287. }
  288. private void xyzPos_noShift()
  289. {
  290. X = a00 * x + a01 * y + a02 * z + a03;
  291. Y = a10 * x + a11 * y + a12 * z + a13;
  292. Z = a20 * x + a21 * y + a22 * z + a23;
  293. }
  294. private void invxyzPos()
  295. {
  296. double sz = (maxDistance + perspective * Z) / (scale * maxDistance);
  297. X = (X - xs) * sz;
  298. Y = (Y - ys) * sz;
  299. x = ai00 * X + ai01 * Y + ai02 * Z + ai03;
  300. y = ai10 * X + ai11 * Y + ai12 * Z + ai13;
  301. z = ai20 * X + ai21 * Y + ai22 * Z + ai23;
  302. }
  303. public void matInv4(double[,] z, double[,] u)
  304. {
  305. int i, j, n;
  306. int[] ii = new int[4];
  307. double f;
  308. double[,] w = new double[4, 4];
  309. n = 4;
  310. matCopy4(w, u);
  311. matUnit4(z);
  312. for (i = 0; i < n; i++)
  313. {
  314. ii[i] = matge4(w, i);
  315. matXr4(w, i, ii[i]);
  316. for (j = 0; j < n; j++)
  317. {
  318. if (i == j) continue;
  319. f = -w[i, j] / w[i, i];
  320. matAc4(w, j, j, f, i);
  321. matAc4(z, j, j, f, i);
  322. }
  323. }
  324. for (i = 0; i < n; i++)
  325. matMc4(z, 1.0f / w[i, i], i);
  326. for (i = 0; i < n; i++)
  327. {
  328. j = n - i - 1;
  329. matXc4(z, j, ii[j]);
  330. }
  331. }
  332. /* greatest element in the nth column of 4x4 matrix */
  333. public int matge4(double[,] p, int n)
  334. {
  335. double g, h;
  336. int m;
  337. m = n;
  338. g = p[n, n];
  339. g = (g < 0.0 ? -g : g);
  340. for (int i = n; i < 4; i++)
  341. {
  342. h = p[i, n];
  343. h = (h < 0.0 ? -h : h);
  344. if (h < g) continue;
  345. g = h; m = i;
  346. }
  347. return m;
  348. }
  349. /* copy 4x4 matrix */
  350. void matCopy4(double[,] z, double[,] x)
  351. {
  352. int i, j;
  353. for (i = 0; i < 4; i++)
  354. for (j = 0; j < 4; j++)
  355. z[i, j] = x[i, j];
  356. }
  357. /* 4x4 unit matrix */
  358. public void matUnit4(double[,] z)
  359. {
  360. for (int i = 0; i < 4; i++)
  361. {
  362. for (int j = 0; j < 4; j++)
  363. z[i, j] = 0.0f;
  364. z[i, i] = 1.0f;
  365. }
  366. }
  367. /* exchange ith and jth columns of a 4x4 matrix */
  368. public void matXc4(double[,] z, int i, int j)
  369. {
  370. double t;
  371. if (i == j)
  372. return;
  373. for (int k = 0; k < 4; k++)
  374. {
  375. t = z[k, i];
  376. z[k, i] = z[k, j];
  377. z[k, j] = t;
  378. }
  379. }
  380. /* exchange ith and jth rows of a 4x4 matrix */
  381. public void matXr4(double[,] z, int i, int j)
  382. {
  383. double t;
  384. if (i == j)
  385. return;
  386. for (int k = 0; k < 4; k++)
  387. {
  388. t = z[i, k];
  389. z[i, k] = z[j, k];
  390. z[j, k] = t;
  391. }
  392. }
  393. /* extract nth column from 4x4 matrix */
  394. public void matXtc4(double[] p, double[,] z, int n)
  395. {
  396. int i;
  397. for (i = 0; i < 4; i++)
  398. p[i] = z[i, n];
  399. }
  400. /* augment column of a 4x4 matrix */
  401. public void matAc4(double[,] z, int i, int j, double f, int k)
  402. {
  403. int l;
  404. for (l = 0; l < 4; l++)
  405. z[l, i] = z[l, j] + f * z[l, k];
  406. }
  407. /* multiply ith column of 4x4 matrix by a factor */
  408. public void matMc4(double[,] z, double f, int i)
  409. {
  410. int j;
  411. for (j = 0; j < 4; j++)
  412. z[j, i] *= f;
  413. }
  414. public void matProd(double[,] z, double[,] u, double[,] v)
  415. {
  416. int i, j, k;
  417. for (i = 0; i < 4; i++)
  418. for (j = 0; j < 4; j++)
  419. {
  420. z[i, j] = 0.0f;
  421. for (k = 0; k < 4; k++)
  422. z[i, j] += u[i, k] * v[k, j];
  423. }
  424. }
  425. public void xyzPos(int[] xyz)
  426. {
  427. x = xyz[0];
  428. y = xyz[1];
  429. z = xyz[2];
  430. xyzPos();
  431. }
  432. public double getScalarProduct()
  433. {
  434. return cosZ * x + sinZ * y;
  435. //return -cosZ*y - sinZ*x;
  436. }
  437. public void invxyzPosf(int[] XYZ)
  438. {
  439. X = XYZ[0];
  440. Y = XYZ[1];
  441. Z = XYZ[2];
  442. invxyzPos();
  443. }
  444. public void invxyzPosf(double[] XYZ)
  445. {
  446. X = XYZ[0];
  447. Y = XYZ[1];
  448. Z = XYZ[2];
  449. invxyzPos();
  450. }
  451. public double getScale()
  452. {
  453. return scale;
  454. }
  455. public double getZAspectRatio()
  456. {
  457. return zAspect;
  458. }
  459. public int getZOrientation()
  460. {
  461. return zOrientation;
  462. }
  463. public void setPerspective(double perspective)
  464. {
  465. this.perspective = perspective;
  466. }
  467. public void setMaxDistance(double maxDistance)
  468. {
  469. this.maxDistance = maxDistance;
  470. }
  471. public double getPerspective()
  472. {
  473. return perspective;
  474. }
  475. public double getMaxDistance()
  476. {
  477. return maxDistance;
  478. }
  479. }
  480. }