PageRenderTime 74ms CodeModel.GetById 43ms RepoModel.GetById 0ms app.codeStats 0ms

/WUW01/classes/Utils.cs

https://gitlab.com/asad2/sixthsense
C# | 391 lines | 288 code | 50 blank | 53 comment | 34 complexity | d15fb2cfcef5c1a305096cb57d320a89 MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Diagnostics;
  4. namespace WUW01
  5. {
  6. public class Utils
  7. {
  8. #region Constants
  9. private static readonly Random _rand = new Random();
  10. #endregion
  11. #region Lengths and Rects
  12. public static RectangleR FindBox(ArrayList points)
  13. {
  14. double minX = double.MaxValue;
  15. double maxX = double.MinValue;
  16. double minY = double.MaxValue;
  17. double maxY = double.MinValue;
  18. foreach (PointR p in points)
  19. {
  20. if (p.X < minX)
  21. minX = p.X;
  22. if (p.X > maxX)
  23. maxX = p.X;
  24. if (p.Y < minY)
  25. minY = p.Y;
  26. if (p.Y > maxY)
  27. maxY = p.Y;
  28. }
  29. return new RectangleR(minX, minY, maxX - minX, maxY - minY);
  30. }
  31. public static double Distance(PointR p1, PointR p2)
  32. {
  33. double dx = p2.X - p1.X;
  34. double dy = p2.Y - p1.Y;
  35. return Math.Sqrt(dx * dx + dy * dy);
  36. }
  37. // compute the centroid of the points given
  38. public static PointR Centroid(ArrayList points)
  39. {
  40. double xsum = 0.0;
  41. double ysum = 0.0;
  42. foreach (PointR p in points)
  43. {
  44. xsum += p.X;
  45. ysum += p.Y;
  46. }
  47. return new PointR(xsum / points.Count, ysum / points.Count);
  48. }
  49. public static double PathLength(ArrayList points)
  50. {
  51. double length = 0;
  52. for (int i = 1; i < points.Count; i++)
  53. {
  54. length += Distance((PointR) points[i - 1], (PointR) points[i]);
  55. }
  56. return length;
  57. }
  58. #endregion
  59. #region Angles and Rotations
  60. // determines the angle, in degrees, between two points. the angle is defined
  61. // by the circle centered on the start point with a radius to the end point,
  62. // where 0 degrees is straight right from start (+x-axis) and 90 degrees is
  63. // straight down (+y-axis).
  64. public static double AngleInDegrees(PointR start, PointR end, bool positiveOnly)
  65. {
  66. double radians = AngleInRadians(start, end, positiveOnly);
  67. return Rad2Deg(radians);
  68. }
  69. // determines the angle, in radians, between two points. the angle is defined
  70. // by the circle centered on the start point with a radius to the end point,
  71. // where 0 radians is straight right from start (+x-axis) and PI/2 radians is
  72. // straight down (+y-axis).
  73. public static double AngleInRadians(PointR start, PointR end, bool positiveOnly)
  74. {
  75. double radians = 0.0;
  76. if (start.X != end.X)
  77. {
  78. radians = Math.Atan2(end.Y - start.Y, end.X - start.X);
  79. }
  80. else // pure vertical movement
  81. {
  82. if (end.Y < start.Y)
  83. radians = -Math.PI / 2.0; // -90 degrees is straight up
  84. else if (end.Y > start.Y)
  85. radians = Math.PI / 2.0; // 90 degrees is straight down
  86. }
  87. if (positiveOnly && radians < 0.0)
  88. {
  89. radians += Math.PI * 2.0;
  90. }
  91. return radians;
  92. }
  93. public static double Rad2Deg(double rad)
  94. {
  95. return (rad * 180d / Math.PI);
  96. }
  97. public static double Deg2Rad(double deg)
  98. {
  99. return (deg * Math.PI / 180d);
  100. }
  101. // rotate the points by the given degrees about their centroid
  102. public static ArrayList RotateByDegrees(ArrayList points, double degrees)
  103. {
  104. double radians = Deg2Rad(degrees);
  105. return RotateByRadians(points, radians);
  106. }
  107. // rotate the points by the given radians about their centroid
  108. public static ArrayList RotateByRadians(ArrayList points, double radians)
  109. {
  110. ArrayList newPoints = new ArrayList(points.Count);
  111. PointR c = Centroid(points);
  112. double cos = Math.Cos(radians);
  113. double sin = Math.Sin(radians);
  114. double cx = c.X;
  115. double cy = c.Y;
  116. for (int i = 0; i < points.Count; i++)
  117. {
  118. PointR p = (PointR) points[i];
  119. double dx = p.X - cx;
  120. double dy = p.Y - cy;
  121. PointR q = PointR.Empty;
  122. q.X = dx * cos - dy * sin + cx;
  123. q.Y = dx * sin + dy * cos + cy;
  124. newPoints.Add(q);
  125. }
  126. return newPoints;
  127. }
  128. // Rotate a point 'p' around a point 'c' by the given radians.
  129. // Rotation (around the origin) amounts to a 2x2 matrix of the form:
  130. //
  131. // [ cos A -sin A ] [ p.x ]
  132. // [ sin A cos A ] [ p.y ]
  133. //
  134. // Note that the C# Math coordinate system has +x-axis stright right and
  135. // +y-axis straight down. Rotation is clockwise such that from +x-axis to
  136. // +y-axis is +90 degrees, from +x-axis to -x-axis is +180 degrees, and
  137. // from +x-axis to -y-axis is -90 degrees.
  138. public static PointR RotatePoint(PointR p, PointR c, double radians)
  139. {
  140. PointR q = PointR.Empty;
  141. q.X = (p.X - c.X) * Math.Cos(radians) - (p.Y - c.Y) * Math.Sin(radians) + c.X;
  142. q.Y = (p.X - c.X) * Math.Sin(radians) + (p.Y - c.Y) * Math.Cos(radians) + c.Y;
  143. return q;
  144. }
  145. #endregion
  146. #region Translations
  147. // translates the points so that the upper-left corner of their bounding box lies at 'toPt'
  148. public static ArrayList TranslateBBoxTo(ArrayList points, PointR toPt)
  149. {
  150. ArrayList newPoints = new ArrayList(points.Count);
  151. RectangleR r = Utils.FindBox(points);
  152. for (int i = 0; i < points.Count; i++)
  153. {
  154. PointR p = (PointR) points[i];
  155. p.X += (toPt.X - r.X);
  156. p.Y += (toPt.Y - r.Y);
  157. newPoints.Add(p);
  158. }
  159. return newPoints;
  160. }
  161. // translates the points so that their centroid lies at 'toPt'
  162. public static ArrayList TranslateCentroidTo(ArrayList points, PointR toPt)
  163. {
  164. ArrayList newPoints = new ArrayList(points.Count);
  165. PointR centroid = Centroid(points);
  166. for (int i = 0; i < points.Count; i++)
  167. {
  168. PointR p = (PointR) points[i];
  169. p.X += (toPt.X - centroid.X);
  170. p.Y += (toPt.Y - centroid.Y);
  171. newPoints.Add(p);
  172. }
  173. return newPoints;
  174. }
  175. // translates the points by the given delta amounts
  176. public static ArrayList TranslateBy(ArrayList points, SizeR sz)
  177. {
  178. ArrayList newPoints = new ArrayList(points.Count);
  179. for (int i = 0; i < points.Count; i++)
  180. {
  181. PointR p = (PointR) points[i];
  182. p.X += sz.Width;
  183. p.Y += sz.Height;
  184. newPoints.Add(p);
  185. }
  186. return newPoints;
  187. }
  188. #endregion
  189. #region Scaling
  190. // scales the points so that they form the size given. does not restore the
  191. // origin of the box.
  192. public static ArrayList ScaleTo(ArrayList points, SizeR sz)
  193. {
  194. ArrayList newPoints = new ArrayList(points.Count);
  195. RectangleR r = FindBox(points);
  196. for (int i = 0; i < points.Count; i++)
  197. {
  198. PointR p = (PointR) points[i];
  199. if (r.Width != 0d)
  200. p.X *= (sz.Width / r.Width);
  201. if (r.Height != 0d)
  202. p.Y *= (sz.Height / r.Height);
  203. newPoints.Add(p);
  204. }
  205. return newPoints;
  206. }
  207. // scales by the percentages contained in the 'sz' parameter. values of 1.0 would result in the
  208. // identity scale (that is, no change).
  209. public static ArrayList ScaleBy(ArrayList points, SizeR sz)
  210. {
  211. ArrayList newPoints = new ArrayList(points.Count);
  212. RectangleR r = FindBox(points);
  213. for (int i = 0; i < points.Count; i++)
  214. {
  215. PointR p = (PointR) points[i];
  216. p.X *= sz.Width;
  217. p.Y *= sz.Height;
  218. newPoints.Add(p);
  219. }
  220. return newPoints;
  221. }
  222. // scales the points so that the length of their longer side
  223. // matches the length of the longer side of the given box.
  224. // thus, both dimensions are warped proportionally, rather than
  225. // independently, like in the function ScaleTo.
  226. public static ArrayList ScaleToMax(ArrayList points, RectangleR box)
  227. {
  228. ArrayList newPoints = new ArrayList(points.Count);
  229. RectangleR r = FindBox(points);
  230. for (int i = 0; i < points.Count; i++)
  231. {
  232. PointR p = (PointR) points[i];
  233. p.X *= (box.MaxSide / r.MaxSide);
  234. p.Y *= (box.MaxSide / r.MaxSide);
  235. newPoints.Add(p);
  236. }
  237. return newPoints;
  238. }
  239. // scales the points so that the length of their shorter side
  240. // matches the length of the shorter side of the given box.
  241. // thus, both dimensions are warped proportionally, rather than
  242. // independently, like in the function ScaleTo.
  243. public static ArrayList ScaleToMin(ArrayList points, RectangleR box)
  244. {
  245. ArrayList newPoints = new ArrayList(points.Count);
  246. RectangleR r = FindBox(points);
  247. for (int i = 0; i < points.Count; i++)
  248. {
  249. PointR p = (PointR) points[i];
  250. p.X *= (box.MinSide / r.MinSide);
  251. p.Y *= (box.MinSide / r.MinSide);
  252. newPoints.Add(p);
  253. }
  254. return newPoints;
  255. }
  256. #endregion
  257. #region Path Sampling and Distance
  258. public static ArrayList Resample(ArrayList points, int n)
  259. {
  260. double I = PathLength(points) / (n - 1); // interval length
  261. double D = 0.0;
  262. ArrayList srcPts = new ArrayList(points);
  263. ArrayList dstPts = new ArrayList(n);
  264. dstPts.Add(srcPts[0]);
  265. for (int i = 1; i < srcPts.Count; i++)
  266. {
  267. PointR pt1 = (PointR) srcPts[i - 1];
  268. PointR pt2 = (PointR) srcPts[i];
  269. double d = Distance(pt1, pt2);
  270. if ((D + d) >= I)
  271. {
  272. double qx = pt1.X + ((I - D) / d) * (pt2.X - pt1.X);
  273. double qy = pt1.Y + ((I - D) / d) * (pt2.Y - pt1.Y);
  274. PointR q = new PointR(qx, qy);
  275. dstPts.Add(q); // append new point 'q'
  276. srcPts.Insert(i, q); // insert 'q' at position i in points s.t. 'q' will be the next i
  277. D = 0.0;
  278. }
  279. else
  280. {
  281. D += d;
  282. }
  283. }
  284. // somtimes we fall a rounding-error short of adding the last point, so add it if so
  285. if (dstPts.Count == n - 1)
  286. {
  287. dstPts.Add(srcPts[srcPts.Count - 1]);
  288. }
  289. return dstPts;
  290. }
  291. // computes the 'distance' between two point paths by summing their corresponding point distances.
  292. // assumes that each path has been resampled to the same number of points at the same distance apart.
  293. public static double PathDistance(ArrayList path1, ArrayList path2)
  294. {
  295. double distance = 0;
  296. for (int i = 0; i < path1.Count; i++)
  297. {
  298. distance += Distance((PointR) path1[i], (PointR) path2[i]);
  299. }
  300. return distance / path1.Count;
  301. }
  302. #endregion
  303. #region Random Numbers
  304. /// <summary>
  305. /// Gets a random number between low and high, inclusive.
  306. /// </summary>
  307. /// <param name="low"></param>
  308. /// <param name="high"></param>
  309. /// <returns></returns>
  310. public static int Random(int low, int high)
  311. {
  312. return _rand.Next(low, high + 1);
  313. }
  314. /// <summary>
  315. /// Gets multiple random numbers between low and high, inclusive. The
  316. /// numbers are guaranteed to be distinct.
  317. /// </summary>
  318. /// <param name="low"></param>
  319. /// <param name="high"></param>
  320. /// <param name="num"></param>
  321. /// <returns></returns>
  322. public static int[] Random(int low, int high, int num)
  323. {
  324. int[] array = new int[num];
  325. for (int i = 0; i < num; i++)
  326. {
  327. array[i] = _rand.Next(low, high + 1);
  328. for (int j = 0; j < i; j++)
  329. {
  330. if (array[i] == array[j])
  331. {
  332. i--; // redo i
  333. break;
  334. }
  335. }
  336. }
  337. return array;
  338. }
  339. #endregion
  340. }
  341. }