Line.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Drawing;
  7. namespace SketchAssistant
  8. {
  9. public class Line
  10. {
  11. private List<Point> linePoints;
  12. private int identifier;
  13. private bool isTemporary;
  14. /// <summary>
  15. /// The constructor for lines which are only temporary.
  16. /// If you want nice lines use the other constructor.
  17. /// </summary>
  18. /// <param name="points">The points of the line</param>
  19. public Line(List<Point> points)
  20. {
  21. linePoints = new List<Point>(points);
  22. isTemporary = true;
  23. }
  24. /// <summary>
  25. /// The constructor for lines, which will be more resource efficient
  26. /// and have the ability to populate deletion matrixes.
  27. /// </summary>
  28. /// <param name="points">The points of the line</param>
  29. /// <param name="id">The identifier of the line</param>
  30. public Line(List<Point> points, int id)
  31. {
  32. linePoints = new List<Point>(points);
  33. identifier = id;
  34. CleanPoints();
  35. isTemporary = false;
  36. }
  37. public Point GetStartPoint()
  38. {
  39. return linePoints.First();
  40. }
  41. public Point GetEndPoint()
  42. {
  43. return linePoints.Last();
  44. }
  45. public List<Point> GetPoints()
  46. {
  47. return linePoints;
  48. }
  49. public int GetID()
  50. {
  51. return identifier;
  52. }
  53. /// <summary>
  54. /// A function that takes a Graphics element and returns it with
  55. /// the line drawn on it.
  56. /// </summary>
  57. /// <param name="canvas">The Graphics element on which the line shall be drawn</param>
  58. /// <returns>The given Graphics element with the additional line</returns>
  59. public Graphics DrawLine(Graphics canvas)
  60. {
  61. Pen thePen = new Pen(Color.Black);
  62. for(int i = 0; i < linePoints.Count - 1 ; i++)
  63. {
  64. canvas.DrawLine(thePen, linePoints[i], linePoints[i + 1]);
  65. }
  66. //If there is only one point
  67. if(linePoints.Count == 1){ canvas.FillRectangle(Brushes.Black, linePoints[0].X, linePoints[0].Y, 1, 1); }
  68. return canvas;
  69. }
  70. /// <summary>
  71. /// A function that will take to matrixes and populate the with the line data of this line object
  72. /// </summary>
  73. /// <param name="boolMatrix">The Matrix of booleans, in which is saved wether there is a line at this position.</param>
  74. /// <param name="listMatrix">The Matrix of Lists of integers, in which is saved which lines are at this position</param>
  75. public void PopulateMatrixes(bool[,] boolMatrix, HashSet<int>[,] listMatrix)
  76. {
  77. if(!isTemporary)
  78. {
  79. foreach (Point currPoint in linePoints)
  80. {
  81. if (currPoint.X >= 0 && currPoint.Y >= 0 &&
  82. currPoint.X < boolMatrix.GetLength(0) && currPoint.Y < boolMatrix.GetLength(1))
  83. {
  84. boolMatrix[currPoint.X, currPoint.Y] = true;
  85. if (listMatrix[currPoint.X, currPoint.Y] == null)
  86. {
  87. listMatrix[currPoint.X, currPoint.Y] = new HashSet<int>();
  88. }
  89. listMatrix[currPoint.X, currPoint.Y].Add(identifier);
  90. }
  91. }
  92. }
  93. }
  94. /// <summary>
  95. /// Removes duplicate points from the line object
  96. /// </summary>
  97. private void CleanPoints()
  98. {
  99. if (linePoints.Count > 1)
  100. {
  101. List<Point> newList = new List<Point>();
  102. List<Point> tempList = new List<Point>();
  103. //Since Point is non-nullable, we must ensure the nullPoints,
  104. //which we remove can not possibly be points of the original given line.
  105. int nullValue = linePoints[0].X + 1;
  106. //Fill the gaps between points
  107. for (int i = 0; i < linePoints.Count - 1; i++)
  108. {
  109. nullValue += linePoints[i + 1].X;
  110. List<Point> partialList = BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]);
  111. tempList.AddRange(partialList);
  112. }
  113. Point nullPoint = new Point(nullValue, 0);
  114. //Set duplicate points to the null point
  115. for (int i = 1; i < tempList.Count; i++)
  116. {
  117. if ((tempList[i].X == tempList[i - 1].X) && (tempList[i].Y == tempList[i - 1].Y))
  118. {
  119. tempList[i - 1] = nullPoint;
  120. }
  121. }
  122. //remove the null points
  123. foreach (Point tempPoint in tempList)
  124. {
  125. if (tempPoint.X != nullValue)
  126. {
  127. newList.Add(tempPoint);
  128. }
  129. }
  130. linePoints = new List<Point>(newList);
  131. }
  132. }
  133. /// <summary>
  134. /// An implementation of the Bresenham Line Algorithm,
  135. /// which calculates all points between two points in a straight line.
  136. /// Implemented using the pseudocode on Wikipedia.
  137. /// </summary>
  138. /// <param name="p0">The start point</param>
  139. /// <param name="p1">The end point</param>
  140. /// <returns>All points between p0 and p1 (including p0 and p1)</returns>
  141. public static List<Point> BresenhamLineAlgorithm(Point p0, Point p1)
  142. {
  143. int deltaX = p1.X - p0.X;
  144. int deltaY = p1.Y - p0.Y;
  145. List<Point> returnList;
  146. if (Math.Abs(deltaY) < Math.Abs(deltaX))
  147. {
  148. if(p0.X > p1.X)
  149. {
  150. returnList = GetLineLow(p1.X, p1.Y, p0.X, p0.Y);
  151. returnList.Reverse();
  152. }
  153. else
  154. {
  155. returnList = GetLineLow(p0.X, p0.Y, p1.X, p1.Y);
  156. }
  157. }
  158. else
  159. {
  160. if (p0.Y > p1.Y)
  161. {
  162. returnList = GetLineHigh(p1.X, p1.Y, p0.X, p0.Y);
  163. returnList.Reverse();
  164. }
  165. else
  166. {
  167. returnList = GetLineHigh(p0.X, p0.Y, p1.X, p1.Y);
  168. }
  169. }
  170. return returnList;
  171. }
  172. /// <summary>
  173. /// Helping function of the Bresenham Line algorithm,
  174. /// under the assumption that abs(deltaY) is smaller than abs(deltX)
  175. /// and x0 is smaller than x1
  176. /// </summary>
  177. /// <param name="x0">x value of point 0</param>
  178. /// <param name="y0">y value of point 0</param>
  179. /// <param name="x1">x value of point 1</param>
  180. /// <param name="y1">y value of point 1</param>
  181. /// <returns>All points on the line between the two points</returns>
  182. private static List<Point> GetLineLow(int x0, int y0, int x1, int y1)
  183. {
  184. List<Point> returnList = new List<Point>();
  185. int dx = x1 - x0;
  186. int dy = y1 - y0;
  187. int yi = 1;
  188. if(dy < 0)
  189. {
  190. yi = -1;
  191. dy = -dy;
  192. }
  193. int D = 2 * dy - dx;
  194. int y = y0;
  195. for (int x = x0; x <= x1; x++)
  196. {
  197. returnList.Add(new Point(x, y));
  198. if (D > 0)
  199. {
  200. y = y + yi;
  201. D = D - 2 * dx;
  202. }
  203. D = D + 2 * dy;
  204. }
  205. return returnList;
  206. }
  207. /// <summary>
  208. /// Helping function of the Bresenham Line algorithm,
  209. /// under the assumption that abs(deltaY) is larger or equal than abs(deltX)
  210. /// and y0 is smaller than y1
  211. /// </summary>
  212. /// <param name="x0">x value of point 0</param>
  213. /// <param name="y0">y value of point 0</param>
  214. /// <param name="x1">x value of point 1</param>
  215. /// <param name="y1">y value of point 1</param>
  216. /// <returns>All points on the line between the two points</returns>
  217. private static List<Point> GetLineHigh(int x0, int y0, int x1, int y1)
  218. {
  219. List<Point> returnList = new List<Point>();
  220. int dx = x1 - x0;
  221. int dy = y1 - y0;
  222. int xi = 1;
  223. if (dx < 0)
  224. {
  225. xi = -1;
  226. dx = -dx;
  227. }
  228. int D = 2 * dx - dy;
  229. int x = x0;
  230. for (int y = y0; y <= y1; y++)
  231. {
  232. returnList.Add(new Point(x, y));
  233. if (D > 0)
  234. {
  235. x = x + xi;
  236. D = D - 2 * dy;
  237. }
  238. D = D + 2 * dx;
  239. }
  240. return returnList;
  241. }
  242. }
  243. }