Transform2D.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. using System;
  2. using System.Runtime.InteropServices;
  3. #if REAL_T_IS_DOUBLE
  4. using real_t = System.Double;
  5. #else
  6. using real_t = System.Single;
  7. #endif
  8. namespace Godot
  9. {
  10. [StructLayout(LayoutKind.Sequential)]
  11. public struct Transform2D : IEquatable<Transform2D>
  12. {
  13. public Vector2 x;
  14. public Vector2 y;
  15. public Vector2 o;
  16. public Vector2 Origin
  17. {
  18. get { return o; }
  19. }
  20. public real_t Rotation
  21. {
  22. get { return Mathf.Atan2(y.x, o.y); }
  23. }
  24. public Vector2 Scale
  25. {
  26. get { return new Vector2(x.Length(), y.Length()); }
  27. }
  28. public Vector2 this[int index]
  29. {
  30. get
  31. {
  32. switch (index)
  33. {
  34. case 0:
  35. return x;
  36. case 1:
  37. return y;
  38. case 2:
  39. return o;
  40. default:
  41. throw new IndexOutOfRangeException();
  42. }
  43. }
  44. set
  45. {
  46. switch (index)
  47. {
  48. case 0:
  49. x = value;
  50. return;
  51. case 1:
  52. y = value;
  53. return;
  54. case 2:
  55. o = value;
  56. return;
  57. default:
  58. throw new IndexOutOfRangeException();
  59. }
  60. }
  61. }
  62. public real_t this[int index, int axis]
  63. {
  64. get
  65. {
  66. switch (index)
  67. {
  68. case 0:
  69. return x[axis];
  70. case 1:
  71. return y[axis];
  72. default:
  73. throw new IndexOutOfRangeException();
  74. }
  75. }
  76. set
  77. {
  78. switch (index)
  79. {
  80. case 0:
  81. x[axis] = value;
  82. return;
  83. case 1:
  84. y[axis] = value;
  85. return;
  86. default:
  87. throw new IndexOutOfRangeException();
  88. }
  89. }
  90. }
  91. public Transform2D AffineInverse()
  92. {
  93. var inv = this;
  94. real_t det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
  95. if (det == 0)
  96. {
  97. return new Transform2D
  98. (
  99. float.NaN, float.NaN,
  100. float.NaN, float.NaN,
  101. float.NaN, float.NaN
  102. );
  103. }
  104. real_t idet = 1.0f / det;
  105. real_t temp = this[0, 0];
  106. this[0, 0] = this[1, 1];
  107. this[1, 1] = temp;
  108. this[0] *= new Vector2(idet, -idet);
  109. this[1] *= new Vector2(-idet, idet);
  110. this[2] = BasisXform(-this[2]);
  111. return inv;
  112. }
  113. public Vector2 BasisXform(Vector2 v)
  114. {
  115. return new Vector2(Tdotx(v), Tdoty(v));
  116. }
  117. public Vector2 BasisXformInv(Vector2 v)
  118. {
  119. return new Vector2(x.Dot(v), y.Dot(v));
  120. }
  121. public Transform2D InterpolateWith(Transform2D m, real_t c)
  122. {
  123. real_t r1 = Rotation;
  124. real_t r2 = m.Rotation;
  125. Vector2 s1 = Scale;
  126. Vector2 s2 = m.Scale;
  127. // Slerp rotation
  128. var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
  129. var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2));
  130. real_t dot = v1.Dot(v2);
  131. // Clamp dot to [-1, 1]
  132. dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot);
  133. Vector2 v;
  134. if (dot > 0.9995f)
  135. {
  136. // Linearly interpolate to avoid numerical precision issues
  137. v = v1.LinearInterpolate(v2, c).Normalized();
  138. }
  139. else
  140. {
  141. real_t angle = c * Mathf.Acos(dot);
  142. Vector2 v3 = (v2 - v1 * dot).Normalized();
  143. v = v1 * Mathf.Cos(angle) + v3 * Mathf.Sin(angle);
  144. }
  145. // Extract parameters
  146. Vector2 p1 = Origin;
  147. Vector2 p2 = m.Origin;
  148. // Construct matrix
  149. var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c));
  150. Vector2 scale = s1.LinearInterpolate(s2, c);
  151. res.x *= scale;
  152. res.y *= scale;
  153. return res;
  154. }
  155. public Transform2D Inverse()
  156. {
  157. var inv = this;
  158. // Swap
  159. real_t temp = inv.x.y;
  160. inv.x.y = inv.y.x;
  161. inv.y.x = temp;
  162. inv.o = inv.BasisXform(-inv.o);
  163. return inv;
  164. }
  165. public Transform2D Orthonormalized()
  166. {
  167. var on = this;
  168. Vector2 onX = on.x;
  169. Vector2 onY = on.y;
  170. onX.Normalize();
  171. onY = onY - onX * onX.Dot(onY);
  172. onY.Normalize();
  173. on.x = onX;
  174. on.y = onY;
  175. return on;
  176. }
  177. public Transform2D Rotated(real_t phi)
  178. {
  179. return this * new Transform2D(phi, new Vector2());
  180. }
  181. public Transform2D Scaled(Vector2 scale)
  182. {
  183. var copy = this;
  184. copy.x *= scale;
  185. copy.y *= scale;
  186. copy.o *= scale;
  187. return copy;
  188. }
  189. private real_t Tdotx(Vector2 with)
  190. {
  191. return this[0, 0] * with[0] + this[1, 0] * with[1];
  192. }
  193. private real_t Tdoty(Vector2 with)
  194. {
  195. return this[0, 1] * with[0] + this[1, 1] * with[1];
  196. }
  197. public Transform2D Translated(Vector2 offset)
  198. {
  199. var copy = this;
  200. copy.o += copy.BasisXform(offset);
  201. return copy;
  202. }
  203. public Vector2 Xform(Vector2 v)
  204. {
  205. return new Vector2(Tdotx(v), Tdoty(v)) + o;
  206. }
  207. public Vector2 XformInv(Vector2 v)
  208. {
  209. Vector2 vInv = v - o;
  210. return new Vector2(x.Dot(vInv), y.Dot(vInv));
  211. }
  212. // Constants
  213. private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
  214. private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
  215. private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero);
  216. public static Transform2D Identity { get { return _identity; } }
  217. public static Transform2D FlipX { get { return _flipX; } }
  218. public static Transform2D FlipY { get { return _flipY; } }
  219. // Constructors
  220. public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
  221. {
  222. x = xAxis;
  223. y = yAxis;
  224. o = origin;
  225. }
  226. public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy)
  227. {
  228. x = new Vector2(xx, xy);
  229. y = new Vector2(yx, yy);
  230. o = new Vector2(ox, oy);
  231. }
  232. public Transform2D(real_t rot, Vector2 pos)
  233. {
  234. real_t cr = Mathf.Cos(rot);
  235. real_t sr = Mathf.Sin(rot);
  236. x.x = cr;
  237. y.y = cr;
  238. x.y = -sr;
  239. y.x = sr;
  240. o = pos;
  241. }
  242. public static Transform2D operator *(Transform2D left, Transform2D right)
  243. {
  244. left.o = left.Xform(right.o);
  245. real_t x0, x1, y0, y1;
  246. x0 = left.Tdotx(right.x);
  247. x1 = left.Tdoty(right.x);
  248. y0 = left.Tdotx(right.y);
  249. y1 = left.Tdoty(right.y);
  250. left.x.x = x0;
  251. left.x.y = x1;
  252. left.y.x = y0;
  253. left.y.y = y1;
  254. return left;
  255. }
  256. public static bool operator ==(Transform2D left, Transform2D right)
  257. {
  258. return left.Equals(right);
  259. }
  260. public static bool operator !=(Transform2D left, Transform2D right)
  261. {
  262. return !left.Equals(right);
  263. }
  264. public override bool Equals(object obj)
  265. {
  266. if (obj is Transform2D)
  267. {
  268. return Equals((Transform2D)obj);
  269. }
  270. return false;
  271. }
  272. public bool Equals(Transform2D other)
  273. {
  274. return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
  275. }
  276. public override int GetHashCode()
  277. {
  278. return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
  279. }
  280. public override string ToString()
  281. {
  282. return String.Format("({0}, {1}, {2})", new object[]
  283. {
  284. x.ToString(),
  285. y.ToString(),
  286. o.ToString()
  287. });
  288. }
  289. public string ToString(string format)
  290. {
  291. return String.Format("({0}, {1}, {2})", new object[]
  292. {
  293. x.ToString(format),
  294. y.ToString(format),
  295. o.ToString(format)
  296. });
  297. }
  298. }
  299. }