Path.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Xml.Serialization;
  5. using Microsoft.Xna.Framework;
  6. namespace FarseerPhysics.Common
  7. {
  8. //Contributed by Matthew Bettcher
  9. /// <summary>
  10. /// Path:
  11. /// Very similar to Vertices, but this
  12. /// class contains vectors describing
  13. /// control points on a Catmull-Rom
  14. /// curve.
  15. /// </summary>
  16. [XmlRoot("Path")]
  17. public class Path
  18. {
  19. /// <summary>
  20. /// All the points that makes up the curve
  21. /// </summary>
  22. [XmlElement("ControlPoints")]
  23. public List<Vector2> ControlPoints;
  24. private float _deltaT;
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="Path"/> class.
  27. /// </summary>
  28. public Path()
  29. {
  30. ControlPoints = new List<Vector2>();
  31. }
  32. /// <summary>
  33. /// Initializes a new instance of the <see cref="Path"/> class.
  34. /// </summary>
  35. /// <param name="vertices">The vertices to created the path from.</param>
  36. public Path(Vector2[] vertices)
  37. {
  38. ControlPoints = new List<Vector2>(vertices.Length);
  39. for (int i = 0; i < vertices.Length; i++)
  40. {
  41. Add(vertices[i]);
  42. }
  43. }
  44. /// <summary>
  45. /// Initializes a new instance of the <see cref="Path"/> class.
  46. /// </summary>
  47. /// <param name="vertices">The vertices to created the path from.</param>
  48. public Path(IList<Vector2> vertices)
  49. {
  50. ControlPoints = new List<Vector2>(vertices.Count);
  51. for (int i = 0; i < vertices.Count; i++)
  52. {
  53. Add(vertices[i]);
  54. }
  55. }
  56. /// <summary>
  57. /// True if the curve is closed.
  58. /// </summary>
  59. /// <value><c>true</c> if closed; otherwise, <c>false</c>.</value>
  60. [XmlElement("Closed")]
  61. public bool Closed { get; set; }
  62. /// <summary>
  63. /// Gets the next index of a controlpoint
  64. /// </summary>
  65. /// <param name="index">The index.</param>
  66. /// <returns></returns>
  67. public int NextIndex(int index)
  68. {
  69. if (index == ControlPoints.Count - 1)
  70. {
  71. return 0;
  72. }
  73. return index + 1;
  74. }
  75. /// <summary>
  76. /// Gets the previous index of a controlpoint
  77. /// </summary>
  78. /// <param name="index">The index.</param>
  79. /// <returns></returns>
  80. public int PreviousIndex(int index)
  81. {
  82. if (index == 0)
  83. {
  84. return ControlPoints.Count - 1;
  85. }
  86. return index - 1;
  87. }
  88. /// <summary>
  89. /// Translates the control points by the specified vector.
  90. /// </summary>
  91. /// <param name="vector">The vector.</param>
  92. public void Translate(ref Vector2 vector)
  93. {
  94. for (int i = 0; i < ControlPoints.Count; i++)
  95. ControlPoints[i] = Vector2.Add(ControlPoints[i], vector);
  96. }
  97. /// <summary>
  98. /// Scales the control points by the specified vector.
  99. /// </summary>
  100. /// <param name="value">The Value.</param>
  101. public void Scale(ref Vector2 value)
  102. {
  103. for (int i = 0; i < ControlPoints.Count; i++)
  104. ControlPoints[i] = Vector2.Multiply(ControlPoints[i], value);
  105. }
  106. /// <summary>
  107. /// Rotate the control points by the defined value in radians.
  108. /// </summary>
  109. /// <param name="value">The amount to rotate by in radians.</param>
  110. public void Rotate(float value)
  111. {
  112. Matrix rotationMatrix;
  113. Matrix.CreateRotationZ(value, out rotationMatrix);
  114. for (int i = 0; i < ControlPoints.Count; i++)
  115. ControlPoints[i] = Vector2.Transform(ControlPoints[i], rotationMatrix);
  116. }
  117. public override string ToString()
  118. {
  119. StringBuilder builder = new StringBuilder();
  120. for (int i = 0; i < ControlPoints.Count; i++)
  121. {
  122. builder.Append(ControlPoints[i].ToString());
  123. if (i < ControlPoints.Count - 1)
  124. {
  125. builder.Append(" ");
  126. }
  127. }
  128. return builder.ToString();
  129. }
  130. /// <summary>
  131. /// Returns a set of points defining the
  132. /// curve with the specifed number of divisions
  133. /// between each control point.
  134. /// </summary>
  135. /// <param name="divisions">Number of divisions between each control point.</param>
  136. /// <returns></returns>
  137. public Vertices GetVertices(int divisions)
  138. {
  139. Vertices verts = new Vertices();
  140. float timeStep = 1f / divisions;
  141. for (float i = 0; i < 1f; i += timeStep)
  142. {
  143. verts.Add(GetPosition(i));
  144. }
  145. return verts;
  146. }
  147. public Vector2 GetPosition(float time)
  148. {
  149. Vector2 temp;
  150. if (ControlPoints.Count < 2)
  151. throw new Exception("You need at least 2 control points to calculate a position.");
  152. if (Closed)
  153. {
  154. Add(ControlPoints[0]);
  155. _deltaT = 1f / (ControlPoints.Count - 1);
  156. int p = (int)(time / _deltaT);
  157. // use a circular indexing system
  158. int p0 = p - 1;
  159. if (p0 < 0) p0 = p0 + (ControlPoints.Count - 1);
  160. else if (p0 >= ControlPoints.Count - 1) p0 = p0 - (ControlPoints.Count - 1);
  161. int p1 = p;
  162. if (p1 < 0) p1 = p1 + (ControlPoints.Count - 1);
  163. else if (p1 >= ControlPoints.Count - 1) p1 = p1 - (ControlPoints.Count - 1);
  164. int p2 = p + 1;
  165. if (p2 < 0) p2 = p2 + (ControlPoints.Count - 1);
  166. else if (p2 >= ControlPoints.Count - 1) p2 = p2 - (ControlPoints.Count - 1);
  167. int p3 = p + 2;
  168. if (p3 < 0) p3 = p3 + (ControlPoints.Count - 1);
  169. else if (p3 >= ControlPoints.Count - 1) p3 = p3 - (ControlPoints.Count - 1);
  170. // relative time
  171. float lt = (time - _deltaT * p) / _deltaT;
  172. temp = Vector2.CatmullRom(ControlPoints[p0], ControlPoints[p1], ControlPoints[p2], ControlPoints[p3], lt);
  173. RemoveAt(ControlPoints.Count - 1);
  174. }
  175. else
  176. {
  177. int p = (int)(time / _deltaT);
  178. //
  179. int p0 = p - 1;
  180. if (p0 < 0) p0 = 0;
  181. else if (p0 >= ControlPoints.Count - 1) p0 = ControlPoints.Count - 1;
  182. int p1 = p;
  183. if (p1 < 0) p1 = 0;
  184. else if (p1 >= ControlPoints.Count - 1) p1 = ControlPoints.Count - 1;
  185. int p2 = p + 1;
  186. if (p2 < 0) p2 = 0;
  187. else if (p2 >= ControlPoints.Count - 1) p2 = ControlPoints.Count - 1;
  188. int p3 = p + 2;
  189. if (p3 < 0) p3 = 0;
  190. else if (p3 >= ControlPoints.Count - 1) p3 = ControlPoints.Count - 1;
  191. // relative time
  192. float lt = (time - _deltaT * p) / _deltaT;
  193. temp = Vector2.CatmullRom(ControlPoints[p0], ControlPoints[p1], ControlPoints[p2], ControlPoints[p3], lt);
  194. }
  195. return temp;
  196. }
  197. /// <summary>
  198. /// Gets the normal for the given time.
  199. /// </summary>
  200. /// <param name="time">The time</param>
  201. /// <returns>The normal.</returns>
  202. public Vector2 GetPositionNormal(float time)
  203. {
  204. float offsetTime = time + 0.0001f;
  205. Vector2 a = GetPosition(time);
  206. Vector2 b = GetPosition(offsetTime);
  207. Vector2 output, temp;
  208. Vector2.Subtract(ref a, ref b, out temp);
  209. #if (XBOX360 || WINDOWS_PHONE)
  210. output = new Vector2();
  211. #endif
  212. output.X = -temp.Y;
  213. output.Y = temp.X;
  214. Vector2.Normalize(ref output, out output);
  215. return output;
  216. }
  217. public void Add(Vector2 point)
  218. {
  219. ControlPoints.Add(point);
  220. _deltaT = 1f / (ControlPoints.Count - 1);
  221. }
  222. public void Remove(Vector2 point)
  223. {
  224. ControlPoints.Remove(point);
  225. _deltaT = 1f / (ControlPoints.Count - 1);
  226. }
  227. public void RemoveAt(int index)
  228. {
  229. ControlPoints.RemoveAt(index);
  230. _deltaT = 1f / (ControlPoints.Count - 1);
  231. }
  232. public float GetLength()
  233. {
  234. List<Vector2> verts = GetVertices(ControlPoints.Count * 25);
  235. float length = 0;
  236. for (int i = 1; i < verts.Count; i++)
  237. {
  238. length += Vector2.Distance(verts[i - 1], verts[i]);
  239. }
  240. if (Closed)
  241. length += Vector2.Distance(verts[ControlPoints.Count - 1], verts[0]);
  242. return length;
  243. }
  244. public List<Vector3> SubdivideEvenly(int divisions)
  245. {
  246. List<Vector3> verts = new List<Vector3>();
  247. float length = GetLength();
  248. float deltaLength = length / divisions + 0.001f;
  249. float t = 0.000f;
  250. // we always start at the first control point
  251. Vector2 start = ControlPoints[0];
  252. Vector2 end = GetPosition(t);
  253. // increment t until we are at half the distance
  254. while (deltaLength * 0.5f >= Vector2.Distance(start, end))
  255. {
  256. end = GetPosition(t);
  257. t += 0.0001f;
  258. if (t >= 1f)
  259. break;
  260. }
  261. start = end;
  262. // for each box
  263. for (int i = 1; i < divisions; i++)
  264. {
  265. Vector2 normal = GetPositionNormal(t);
  266. float angle = (float)Math.Atan2(normal.Y, normal.X);
  267. verts.Add(new Vector3(end, angle));
  268. // until we reach the correct distance down the curve
  269. while (deltaLength >= Vector2.Distance(start, end))
  270. {
  271. end = GetPosition(t);
  272. t += 0.00001f;
  273. if (t >= 1f)
  274. break;
  275. }
  276. if (t >= 1f)
  277. break;
  278. start = end;
  279. }
  280. return verts;
  281. }
  282. }
  283. }