2
0

Matrix.cs 14 KB

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