Line.cs 8.9 KB

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