Matrix.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //
  2. // System.Drawing.Drawing2D.Matrix.cs
  3. //
  4. // Author:
  5. // Stefan Maierhofer <[email protected]>
  6. //
  7. // (C) Ximian, Inc. http://www.ximian.com
  8. //
  9. using System;
  10. using System.Drawing;
  11. using System.Runtime.InteropServices;
  12. namespace System.Drawing.Drawing2D
  13. {
  14. public sealed class Matrix : MarshalByRefObject, IDisposable
  15. {
  16. // initialize to identity
  17. private float[] m = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
  18. // constructors
  19. public Matrix() { }
  20. /* TODO: depends on System.Drawing.Drawing2D.Rectangle
  21. public Matrix(Rectangle rect , Point[] plgpts)
  22. {
  23. // TODO
  24. }
  25. */
  26. /* TODO: depends on System.Drawing.Drawing2D.RectangleF
  27. public Matrix(RectangleF rect , PointF[] pa)
  28. {
  29. // TODO
  30. }
  31. */
  32. public Matrix(float m11, float m12,
  33. float m21, float m22,
  34. float dx, float dy)
  35. {
  36. m[0] = m11; m[1] = m12;
  37. m[2] = m21; m[3] = m22;
  38. m[4] = dx; m[5] = dy;
  39. }
  40. // properties
  41. public float[] Elements
  42. {
  43. get { return m; }
  44. }
  45. public bool IsIdentity
  46. {
  47. get
  48. {
  49. if ( (m[0] == 1.0f) && (m[1] == 0.0f) &&
  50. (m[2] == 0.0f) && (m[3] == 1.0f) &&
  51. (m[4] == 0.0f) && (m[5] == 0.0f) )
  52. return true;
  53. else
  54. return false;
  55. }
  56. }
  57. public bool IsInvertible
  58. {
  59. get
  60. {
  61. // matrix M is invertible if det(M) != 0
  62. float det = m[0] * m[3] - m[2] * m[1];
  63. if (det != 0.0f) return true;
  64. else return false;
  65. }
  66. }
  67. public float OffsetX
  68. {
  69. get { return m[4]; }
  70. }
  71. public float OffsetY
  72. {
  73. get { return m[5]; }
  74. }
  75. // methods
  76. public Matrix Clone()
  77. {
  78. return new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
  79. }
  80. public void Dispose() { }
  81. public override bool Equals(object obj)
  82. {
  83. if (obj is Matrix)
  84. {
  85. float[] a = ((Matrix)obj).Elements;
  86. if ( m[0] == a[0] && m[1] == a[1] &&
  87. m[2] == a[2] && m[3] == a[3] &&
  88. m[4] == a[4] && m[5] == a[5] )
  89. return true;
  90. else
  91. return false;
  92. }
  93. else
  94. {
  95. return false;
  96. }
  97. }
  98. ~Matrix() {}
  99. [StructLayout(LayoutKind.Explicit)]
  100. internal struct BitConverter
  101. {
  102. [FieldOffset(0)] public float f;
  103. [FieldOffset(0)] public int i;
  104. }
  105. public override int GetHashCode()
  106. {
  107. BitConverter b;
  108. // compiler is not smart
  109. b.i = 0;
  110. int h = 0;
  111. for (int i = 0; i < 6; i++)
  112. {
  113. b.f = m[i];
  114. h ^= b.i >> i;
  115. }
  116. return h;
  117. }
  118. public void Invert()
  119. {
  120. float det = m[0] * m[3] - m[2] * m[1];
  121. if (det != 0.0f) // if invertible
  122. {
  123. float[] r =
  124. {
  125. m[3] / det,
  126. -m[1] / det,
  127. -m[2] / det,
  128. m[0] / det,
  129. (-m[3] * m[4] + m[1] * m[5]) / det,
  130. (m[2] * m[4] - m[0] * m[5]) / det
  131. };
  132. m = r;
  133. }
  134. }
  135. public void Multiply(Matrix matrix)
  136. {
  137. Multiply(matrix, MatrixOrder.Prepend);
  138. }
  139. public void Multiply(Matrix matrix, MatrixOrder order)
  140. {
  141. switch (order)
  142. {
  143. case MatrixOrder.Prepend:
  144. // this = matrix * this
  145. float[] p = matrix.Elements;
  146. float[] r0 =
  147. {
  148. p[0] * m[0] + p[1] * m[2],
  149. p[0] * m[1] + p[1] * m[3],
  150. p[2] * m[0] + p[3] * m[2],
  151. p[2] * m[1] + p[3] * m[3],
  152. p[4] * m[0] + p[5] * m[2] + m[4],
  153. p[4] * m[1] + p[5] * m[3] + m[5]
  154. };
  155. m = r0;
  156. break;
  157. case MatrixOrder.Append:
  158. // this = this * matrix
  159. float[] a = matrix.Elements;
  160. float[] r1 =
  161. {
  162. m[0] * a[0] + m[1] * a[2],
  163. m[0] * a[1] + m[1] * a[3],
  164. m[2] * a[0] + m[3] * a[2],
  165. m[2] * a[1] + m[3] * a[3],
  166. m[4] * a[0] + m[5] * a[2] + a[4],
  167. m[4] * a[1] + m[5] * a[3] + a[5]
  168. };
  169. m = r1;
  170. break;
  171. }
  172. }
  173. public void Reset()
  174. {
  175. m[0] = 1.0f; m[1] = 0.0f;
  176. m[2] = 0.0f; m[3] = 1.0f;
  177. m[4] = 0.0f; m[5] = 0.0f;
  178. }
  179. public void Rotate(float angle)
  180. {
  181. Rotate(angle, MatrixOrder.Prepend);
  182. }
  183. public void Rotate(float angle, MatrixOrder order)
  184. {
  185. angle *= (float)(Math.PI / 180.0); // degrees to randians
  186. float cos = (float)Math.Cos(angle);
  187. float sin = (float)Math.Sin(angle);
  188. switch (order)
  189. {
  190. case MatrixOrder.Prepend:
  191. // this = rotation * this
  192. float[] r0 =
  193. {
  194. cos * m[0] + sin * m[2],
  195. cos * m[1] + sin * m[3],
  196. -sin * m[0] + cos * m[2],
  197. -sin * m[1] + cos * m[3],
  198. m[4],
  199. m[5]
  200. };
  201. m = r0;
  202. break;
  203. case MatrixOrder.Append:
  204. // this = this * rotation
  205. float[] r1 =
  206. {
  207. m[0] * cos + m[1] * -sin,
  208. m[0] * sin + m[1] * cos,
  209. m[2] * cos + m[3] * -sin,
  210. m[2] * sin + m[3] * cos,
  211. m[4] * cos + m[5] * -sin,
  212. m[4] * sin + m[5] * cos
  213. };
  214. m = r1;
  215. break;
  216. }
  217. }
  218. public void RotateAt(float angle, PointF point)
  219. {
  220. RotateAt(angle, point, MatrixOrder.Prepend);
  221. }
  222. public void RotateAt(float angle, PointF point, MatrixOrder order)
  223. {
  224. angle *= (float)(Math.PI / 180.0); // degrees to randians
  225. float cos = (float)Math.Cos(angle);
  226. float sin = (float)Math.Sin(angle);
  227. float e4 = -point.X * cos + point.Y * sin + point.X;
  228. float e5 = -point.X * sin - point.Y * cos + point.Y;
  229. switch (order)
  230. {
  231. case MatrixOrder.Prepend:
  232. // this = rotation * this
  233. float[] r0 =
  234. {
  235. cos * m[0] + sin * m[2],
  236. cos * m[1] + sin * m[3],
  237. -sin * m[0] + cos * m[2],
  238. -sin * m[1] + cos * m[3],
  239. e4 * m[0] + e5 * m[2] + m[4],
  240. e4 * m[1] + e5 * m[3] + m[5]
  241. };
  242. m = r0;
  243. break;
  244. case MatrixOrder.Append:
  245. // this = this * rotation
  246. float[] r1 =
  247. {
  248. m[0] * cos + m[1] * -sin,
  249. m[0] * sin + m[1] * cos,
  250. m[2] * cos + m[3] * -sin,
  251. m[2] * sin + m[3] * cos,
  252. m[4] * cos + m[5] * -sin + e4,
  253. m[4] * sin + m[5] * cos + e5
  254. };
  255. m = r1;
  256. break;
  257. }
  258. }
  259. public void Scale(float scaleX, float scaleY)
  260. {
  261. Scale(scaleX, scaleY, MatrixOrder.Prepend);
  262. }
  263. public void Scale(float scaleX, float scaleY, MatrixOrder order)
  264. {
  265. switch (order)
  266. {
  267. case MatrixOrder.Prepend:
  268. // this = scale * this
  269. m[0] *= scaleX; m[1] *= scaleX;
  270. m[2] *= scaleY; m[3] *= scaleY;
  271. break;
  272. case MatrixOrder.Append:
  273. // this = this * scale
  274. m[0] *= scaleX; m[1] *= scaleY;
  275. m[2] *= scaleX; m[3] *= scaleY;
  276. m[4] *= scaleX; m[5] *= scaleY;
  277. break;
  278. }
  279. }
  280. public void Shear(float shearX, float shearY)
  281. {
  282. Shear(shearX, shearY, MatrixOrder.Prepend);
  283. }
  284. // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
  285. //
  286. // assuming transformation matrix:
  287. //
  288. // (1 shearY 0)
  289. // (shearX 1 0)
  290. // (0 0 1)
  291. //
  292. public void Shear(float shearX, float shearY, MatrixOrder order)
  293. {
  294. switch (order)
  295. {
  296. case MatrixOrder.Prepend:
  297. // this = shear * this
  298. float[] r0 =
  299. {
  300. m[0] + shearY * m[2],
  301. m[1] + shearY * m[3],
  302. shearX * m[0] + m[2],
  303. shearX * m[1] + m[3],
  304. m[4],
  305. m[5]
  306. };
  307. m = r0;
  308. break;
  309. case MatrixOrder.Append:
  310. // this = this * shear
  311. float[] r1 =
  312. {
  313. m[0] + m[1] * shearX,
  314. m[0] * shearY + m[1],
  315. m[2] + m[3] * shearX,
  316. m[2] * shearY + m[3],
  317. m[4] + m[5] * shearX ,
  318. m[4] * shearY + m[5]
  319. };
  320. m = r1;
  321. break;
  322. }
  323. }
  324. public void TransformPoints(Point[] pts)
  325. {
  326. for (int i = 0; i < pts.Length; i++)
  327. {
  328. float x = (float)pts[i].X;
  329. float y = (float)pts[i].Y;
  330. pts[i].X = (int)(x * m[0] + y * m[2] + m[4]);
  331. pts[i].Y = (int)(x * m[1] + y * m[3] + m[5]);
  332. }
  333. }
  334. public void TransformPoints(PointF[] pts)
  335. {
  336. for (int i = 0; i < pts.Length; i++)
  337. {
  338. float x = pts[i].X;
  339. float y = pts[i].Y;
  340. pts[i].X = x * m[0] + y * m[2] + m[4];
  341. pts[i].Y = x * m[1] + y * m[3] + m[5];
  342. }
  343. }
  344. public void TransformVectors(Point[] pts)
  345. {
  346. for (int i = 0; i < pts.Length; i++)
  347. {
  348. float x = (float)pts[i].X;
  349. float y = (float)pts[i].Y;
  350. pts[i].X = (int)(x * m[0] + y * m[2]);
  351. pts[i].Y = (int)(x * m[1] + y * m[3]);
  352. }
  353. }
  354. public void TransformVectors(PointF[] pts)
  355. {
  356. for (int i = 0; i < pts.Length; i++)
  357. {
  358. float x = pts[i].X;
  359. float y = pts[i].Y;
  360. pts[i].X = x * m[0] + y * m[2];
  361. pts[i].Y = x * m[1] + y * m[3];
  362. }
  363. }
  364. public void Translate(float offsetX, float offsetY)
  365. {
  366. Translate(offsetX, offsetY, MatrixOrder.Prepend);
  367. }
  368. public void Translate(float offsetX, float offsetY, MatrixOrder order)
  369. {
  370. switch (order)
  371. {
  372. case MatrixOrder.Prepend:
  373. // this = translation * this
  374. m[4] = offsetX * m[0] + offsetY * m[2] + m[4];
  375. m[5] = offsetX * m[1] + offsetY * m[3] + m[5];
  376. break;
  377. case MatrixOrder.Append:
  378. // this = this * translation
  379. m[4] += offsetX;
  380. m[5] += offsetY;
  381. break;
  382. }
  383. }
  384. // LAMESPEC: quote from beta 2 sdk docs: "[To be supplied!]"
  385. // [MonoTODO]
  386. public void VectorTransformPoints(Point[] pts)
  387. {
  388. // TODO
  389. }
  390. // some simple test (TODO: remove)
  391. /*
  392. public static void Main()
  393. {
  394. PointF[] p = {new PointF(1.0f, 2.0f)};
  395. Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
  396. Matrix m = new Matrix();
  397. m.Translate(1.0f, 1.0f);
  398. m.Scale(2.0f, 2.0f);
  399. m.Rotate(180.0f);
  400. m.TransformPoints(p);
  401. Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
  402. m.Invert();
  403. m.TransformPoints(p);
  404. Console.WriteLine("(" + p[0].X + " " + p[0].Y + ")");
  405. Matrix a = new Matrix(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
  406. Matrix b = new Matrix(2.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f);
  407. Console.WriteLine("h(a) = " + a.GetHashCode());
  408. Console.WriteLine("h(b) = " + b.GetHashCode());
  409. }
  410. */
  411. }
  412. }