using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; namespace SketchAssistant { public class Line { private List linePoints; private int identifier; private bool isTemporary; /// /// The constructor for lines which are only temporary. /// If you want nice lines use the other constructor. /// /// The points of the line public Line(List points) { linePoints = new List(points); isTemporary = true; } /// /// The constructor for lines, which will be more resource efficient /// and have the ability to populate deletion matrixes. /// /// The points of the line /// The identifier of the line public Line(List points, int id) { linePoints = new List(points); identifier = id; CleanPoints(); isTemporary = false; } public Point GetStartPoint() { return linePoints.First(); } public Point GetEndPoint() { return linePoints.Last(); } public List GetPoints() { return linePoints; } public int GetID() { return identifier; } /// /// A function that takes a Graphics element and returns it with /// the line drawn on it. /// /// The Graphics element on which the line shall be drawn /// The given Graphics element with the additional line public Graphics DrawLine(Graphics canvas) { Pen thePen = new Pen(Color.Black); for(int i = 0; i < linePoints.Count - 1 ; i++) { canvas.DrawLine(thePen, linePoints[i], linePoints[i + 1]); } //If there is only one point if(linePoints.Count == 1){ canvas.FillRectangle(Brushes.Black, linePoints[0].X, linePoints[0].Y, 1, 1); } return canvas; } /// /// A function that will take to matrixes and populate the with the line data of this line object /// /// The Matrix of booleans, in which is saved wether there is a line at this position. /// The Matrix of Lists of integers, in which is saved which lines are at this position public void PopulateMatrixes(bool[,] boolMatrix, HashSet[,] listMatrix) { if(!isTemporary) { foreach (Point currPoint in linePoints) { if (currPoint.X >= 0 && currPoint.Y >= 0 && currPoint.X < boolMatrix.GetLength(0) && currPoint.Y < boolMatrix.GetLength(1)) { boolMatrix[currPoint.X, currPoint.Y] = true; if (listMatrix[currPoint.X, currPoint.Y] == null) { listMatrix[currPoint.X, currPoint.Y] = new HashSet(); } listMatrix[currPoint.X, currPoint.Y].Add(identifier); } } } } /// /// Removes duplicate points from the line object /// private void CleanPoints() { if (linePoints.Count > 1) { List newList = new List(); List tempList = new List(); //Since Point is non-nullable, we must ensure the nullPoints, //which we remove can not possibly be points of the original given line. int nullValue = linePoints[0].X + 1; //Fill the gaps between points for (int i = 0; i < linePoints.Count - 1; i++) { nullValue += linePoints[i + 1].X; List partialList = BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]); tempList.AddRange(partialList); } Point nullPoint = new Point(nullValue, 0); //Set duplicate points to the null point for (int i = 1; i < tempList.Count; i++) { if ((tempList[i].X == tempList[i - 1].X) && (tempList[i].Y == tempList[i - 1].Y)) { tempList[i - 1] = nullPoint; } } //remove the null points foreach (Point tempPoint in tempList) { if (tempPoint.X != nullValue) { newList.Add(tempPoint); } } linePoints = new List(newList); } } /// /// An implementation of the Bresenham Line Algorithm, /// which calculates all points between two points in a straight line. /// Implemented using the pseudocode on Wikipedia. /// /// The start point /// The end point /// All points between p0 and p1 (including p0 and p1) public static List BresenhamLineAlgorithm(Point p0, Point p1) { int deltaX = p1.X - p0.X; int deltaY = p1.Y - p0.Y; List returnList; if (Math.Abs(deltaY) < Math.Abs(deltaX)) { if(p0.X > p1.X) { returnList = GetLineLow(p1.X, p1.Y, p0.X, p0.Y); returnList.Reverse(); } else { returnList = GetLineLow(p0.X, p0.Y, p1.X, p1.Y); } } else { if (p0.Y > p1.Y) { returnList = GetLineHigh(p1.X, p1.Y, p0.X, p0.Y); returnList.Reverse(); } else { returnList = GetLineHigh(p0.X, p0.Y, p1.X, p1.Y); } } return returnList; } /// /// Helping function of the Bresenham Line algorithm, /// under the assumption that abs(deltaY) is smaller than abs(deltX) /// and x0 is smaller than x1 /// /// x value of point 0 /// y value of point 0 /// x value of point 1 /// y value of point 1 /// All points on the line between the two points private static List GetLineLow(int x0, int y0, int x1, int y1) { List returnList = new List(); int dx = x1 - x0; int dy = y1 - y0; int yi = 1; if(dy < 0) { yi = -1; dy = -dy; } int D = 2 * dy - dx; int y = y0; for (int x = x0; x <= x1; x++) { returnList.Add(new Point(x, y)); if (D > 0) { y = y + yi; D = D - 2 * dx; } D = D + 2 * dy; } return returnList; } /// /// Helping function of the Bresenham Line algorithm, /// under the assumption that abs(deltaY) is larger or equal than abs(deltX) /// and y0 is smaller than y1 /// /// x value of point 0 /// y value of point 0 /// x value of point 1 /// y value of point 1 /// All points on the line between the two points private static List GetLineHigh(int x0, int y0, int x1, int y1) { List returnList = new List(); int dx = x1 - x0; int dy = y1 - y0; int xi = 1; if (dx < 0) { xi = -1; dx = -dx; } int D = 2 * dx - dy; int x = x0; for (int y = y0; y <= y1; y++) { returnList.Add(new Point(x, y)); if (D > 0) { x = x + xi; D = D - 2 * dy; } D = D + 2 * dx; } return returnList; } } }