Browse Source

Merge pull request #5 from m-edlund/userstory6

Userstory6
TiReischl 5 years ago
parent
commit
1612933d13

+ 13 - 0
Finished Userstories/userstory6.md

@@ -0,0 +1,13 @@
+# Userstory 6
+
+|**ID**|6|
+|-|-|
+|**Name**|Löschfunktionalität|
+|**Beschreibung**|Man kann einen Knopf in der UI drücken um in den Löschmodus zu kommen, und um wieder aus dem Löschmodus rauszukommen. Wenn man im Löschmodus ist, kann man auf einer Leinwand im rechten Bereich gezeichnete Elemente löschen indem man auf sie klickt.|
+|**Akzeptanzkriterium**|Der Knopf für den Löschmodus kann nur gedrückt werden, wenn im rechten Bereich eine Zeichennleinwand vorhanden ist. Wenn man den Knopf drückt ohne im Löschmodus zu sein, verändert sich der Knopf erkennbar und man kommt in den Löschmodus. Drückt man den Knopf, während man im Löschmodus ist, wird der Löschmodus beendet und der Knopf bekommt wieder sein urspüngliches Aussehen. Während man im Löschmodus ist, kann man auf der Leinwand im rechten Bereich Elemente löschen, wenn der Mauszeiger sie berührt während man die Maustaste gedrückt hält. Die Elemente die man löscht verschwinden. Drückt man den Löschknopf während man in einem anderen Modus ist (z.B. Zeichenmodus) wird der andere Modus beendet und man ist im Löschmodus.|
+|Geschätzter Aufwand (Story Points)|16|
+|Entwickler|Martin Edlund, Tim Reischl|
+|Umgesetzt in Iteration|3|
+|Tatsächlicher Aufwand (Std.)|14,5|
+|Velocity (Std./Story Point)|0,90625|
+|Bemerkungen|Keine|

+ 25 - 0
SketchAssistant/NUnitTestProject1/NUnitTestProject1.csproj

@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+
+    <ApplicationIcon />
+
+    <OutputType>Exe</OutputType>
+
+    <StartupObject />
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="nunit" Version="3.10.1" />
+    <PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\SketchAssistant\SketchAssistant.csproj" />
+  </ItemGroup>
+
+</Project>

+ 202 - 0
SketchAssistant/NUnitTestProject1/UnitTest1.cs

@@ -0,0 +1,202 @@
+using NUnit.Framework;
+using System.Drawing;
+using System;
+using System.Collections.Generic;
+using SketchAssistant;
+
+namespace Tests
+{
+    class LineTests
+    {
+        //========================//
+        //= Bresenham Line Tests =//
+        //========================//
+
+        [Test]
+        public void BresenhamLineTest1()
+        {
+            //Test point
+            List<Point> expectedResult = new List<Point>();
+            expectedResult.Add(new Point(1, 2));
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(1, 2), new Point(1, 2));
+            Assert.AreEqual(1, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest2()
+        {
+            //Test line going from left to right
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 1; i <= 6; i++) { expectedResult.Add(new Point(i, 2)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(1, 2), new Point(6, 2));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest3()
+        {
+            //Test line going from right to left
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 6; i >= 1; i--) { expectedResult.Add(new Point(i, 2)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(6, 2), new Point(1, 2));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest4()
+        {
+            //Test line going from top to bottom
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 5; i <= 25; i++) { expectedResult.Add(new Point(7, i)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 5), new Point(7, 25));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest5()
+        {
+            //Test line going from bottom to top
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 25; i >= 5; i--) { expectedResult.Add(new Point(7, i)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 25), new Point(7, 5));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest6()
+        {
+            //Test exactly diagonal line from top left to bottom right
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 5; i <= 25; i++) { expectedResult.Add(new Point(i + 2, i)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 5), new Point(27, 25));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        [Test]
+        public void BresenhamLineTest7()
+        {
+            //Test exactly diagonal line from bottom right to top left
+            List<Point> expectedResult = new List<Point>();
+            for (int i = 25; i >= 5; i--) { expectedResult.Add(new Point(i + 2, i)); }
+            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(27, 25), new Point(7, 5));
+            Assert.AreEqual(expectedResult.Count, actualResult.Count);
+            for (int i = 0; i < actualResult.Count; i++)
+            {
+                Assert.AreEqual(expectedResult[i], actualResult[i]);
+            }
+        }
+
+        //===========================//
+        //= Matrix Population Tests =//
+        //===========================//
+
+        [Test]
+        public void MatrixTest1()
+        {
+            //Populate Matrix for temporary Line
+            List<Point> thePoints = new List<Point>();
+            thePoints.Add(new Point(1, 1));
+            thePoints.Add(new Point(1, 2));
+            bool[,] testBoolMatrix = new bool[5, 5];
+            List<int>[,] testLineMatrix = new List<int>[5, 5];
+            bool[,] resultBoolMatrix = new bool[5, 5];
+            HashSet<int>[,] resultLineMatrix = new HashSet<int>[5, 5];
+            Line testLine = new Line(thePoints);
+            testLine.PopulateMatrixes(resultBoolMatrix, resultLineMatrix);
+            for (int i = 0; i < 5; i++)
+            {
+                for (int j = 0; j < 5; j++)
+                {
+                    Assert.AreEqual(testBoolMatrix[i, j], resultBoolMatrix[i, j]);
+                    Assert.AreEqual(testLineMatrix[i, j], resultLineMatrix[i, j]);
+                }
+            }
+        }
+
+        [Test]
+        public void MatrixTest2()
+        {
+            //Populate Matrix for non-temporary Line
+            List<Point> thePoints = new List<Point>();
+            thePoints.Add(new Point(1, 1));
+            thePoints.Add(new Point(3, 3));
+            bool[,] testBoolMatrix = new bool[5, 5];
+            HashSet<int>[,] testLineMatrix = new HashSet<int>[5, 5];
+            for (int i = 1; i <= 3; i++)
+            {
+                testBoolMatrix[i, i] = true;
+                HashSet<int> temp = new HashSet<int>();
+                temp.Add(5);
+                testLineMatrix[i, i] = temp;
+            }
+            bool[,] resultBoolMatrix = new bool[5, 5];
+            HashSet<int>[,] resultLineMatrix = new HashSet<int>[5, 5];
+            Line testLine = new Line(thePoints, 5);
+            testLine.PopulateMatrixes(resultBoolMatrix, resultLineMatrix);
+            for (int i = 0; i < 5; i++)
+            {
+                for (int j = 0; j < 5; j++)
+                {
+                    Assert.AreEqual(testBoolMatrix[i, j], resultBoolMatrix[i, j]);
+                    if (testLineMatrix[i, j] != null && resultLineMatrix[i, j] != null)
+                    {
+                        for (int k = 0; k < resultLineMatrix[i, j].Count; k++)
+                        {
+                            Assert.AreEqual(true, testLineMatrix[i, j].SetEquals(resultLineMatrix[i, j]));
+                        }
+                    }
+                }
+            }
+        }
+
+        //=========================//
+        //= Line Constructor Test =//
+        //=========================//
+
+        [Test]
+        public void ConstructorTest()
+        {
+            //Create non-temporary Line and check points
+            //reference Points
+            List<Point> comparisonPoints = new List<Point> {new Point(2,2), new Point(3, 1), new Point(4, 1), new Point(5, 1), new Point(6, 2),
+                new Point(7, 3), new Point(8, 4), new Point(9, 5), new Point(10, 6), new Point(11, 5), new Point(11, 4), new Point(11, 3),
+                new Point(10, 2), new Point(9, 1), new Point(8, 2), new Point(7, 3), new Point(6, 4), new Point(5, 5), new Point(4, 5),
+                new Point(3, 5), new Point(2, 5), new Point(1, 4)};
+            //test Points, with intermediate points missing & duplicate points
+            List<Point> testPoints = new List<Point> {new Point(2,2), new Point(3, 1), new Point(5, 1), new Point(5, 1), new Point(5, 1),
+                new Point(8, 4), new Point(10, 6), new Point(11, 5), new Point(11, 3), new Point(9, 1), new Point(9, 1), new Point(9, 1),
+                new Point(5, 5), new Point(2, 5), new Point(2, 5), new Point(1, 4) };
+            Line testLine = new Line(testPoints, 0);
+            List<Point> returnedPoints = testLine.GetPoints();
+            Assert.AreEqual(comparisonPoints.Count, returnedPoints.Count);
+            for (int i = 0; i < returnedPoints.Count; i++)
+            {
+                Assert.AreEqual(comparisonPoints[i], returnedPoints[i]);
+            }
+        }
+    }
+}

+ 6 - 0
SketchAssistant/SketchAssistant.sln

@@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.28010.2050
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchAssistant", "SketchAssistant\SketchAssistant.csproj", "{0336F628-A2F7-4170-8B2E-9277C23118D4}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NUnitTestProject1", "NUnitTestProject1\NUnitTestProject1.csproj", "{F94A09DE-004E-421A-A4BE-961AD5CEC809}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
 		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F94A09DE-004E-421A-A4BE-961AD5CEC809}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F94A09DE-004E-421A-A4BE-961AD5CEC809}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F94A09DE-004E-421A-A4BE-961AD5CEC809}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F94A09DE-004E-421A-A4BE-961AD5CEC809}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 21 - 7
SketchAssistant/SketchAssistant/Form1.Designer.cs

@@ -40,10 +40,11 @@ namespace SketchAssistant
             this.toolStrip1 = new System.Windows.Forms.ToolStrip();
             this.canvasButton = new System.Windows.Forms.ToolStripButton();
             this.drawButton = new System.Windows.Forms.ToolStripButton();
+            this.deleteButton = new System.Windows.Forms.ToolStripButton();
             this.statusStrip1 = new System.Windows.Forms.StatusStrip();
             this.toolStripLoadStatus = new System.Windows.Forms.ToolStripStatusLabel();
             this.backgroundWorker2 = new System.ComponentModel.BackgroundWorker();
-            this.drawTimer = new System.Windows.Forms.Timer(this.components);
+            this.mouseTimer = new System.Windows.Forms.Timer(this.components);
             this.tableLayoutPanel1.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.pictureBoxRight)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLeft)).BeginInit();
@@ -81,6 +82,7 @@ namespace SketchAssistant
             this.pictureBoxRight.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
             this.pictureBoxRight.TabIndex = 6;
             this.pictureBoxRight.TabStop = false;
+            this.pictureBoxRight.Click += new System.EventHandler(this.pictureBoxRight_Click);
             this.pictureBoxRight.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseDown);
             this.pictureBoxRight.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseMove);
             this.pictureBoxRight.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseUp);
@@ -119,7 +121,7 @@ namespace SketchAssistant
             // loadToolStripMenuItem
             // 
             this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.loadToolStripMenuItem.Size = new System.Drawing.Size(109, 22);
             this.loadToolStripMenuItem.Text = "Load...";
             this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
             // 
@@ -127,7 +129,8 @@ namespace SketchAssistant
             // 
             this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.canvasButton,
-            this.drawButton});
+            this.drawButton,
+            this.deleteButton});
             this.toolStrip1.Location = new System.Drawing.Point(0, 24);
             this.toolStrip1.Name = "toolStrip1";
             this.toolStrip1.Size = new System.Drawing.Size(696, 25);
@@ -154,6 +157,16 @@ namespace SketchAssistant
             this.drawButton.Text = "Draw";
             this.drawButton.Click += new System.EventHandler(this.drawButton_Click);
             // 
+            // deleteButton
+            // 
+            this.deleteButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.deleteButton.Image = ((System.Drawing.Image)(resources.GetObject("deleteButton.Image")));
+            this.deleteButton.ImageTransparentColor = System.Drawing.Color.Magenta;
+            this.deleteButton.Name = "deleteButton";
+            this.deleteButton.Size = new System.Drawing.Size(44, 22);
+            this.deleteButton.Text = "Delete";
+            this.deleteButton.Click += new System.EventHandler(this.deleteButton_Click);
+            // 
             // statusStrip1
             // 
             this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -170,10 +183,10 @@ namespace SketchAssistant
             this.toolStripLoadStatus.Size = new System.Drawing.Size(40, 17);
             this.toolStripLoadStatus.Text = "no file";
             // 
-            // drawTimer
+            // mouseTimer
             // 
-            this.drawTimer.Interval = 2;
-            this.drawTimer.Tick += new System.EventHandler(this.drawTimer_Tick);
+            this.mouseTimer.Interval = 1;
+            this.mouseTimer.Tick += new System.EventHandler(this.mouseTimer_Tick);
             // 
             // Form1
             // 
@@ -219,9 +232,10 @@ namespace SketchAssistant
         private System.ComponentModel.BackgroundWorker backgroundWorker2;
         private System.Windows.Forms.PictureBox pictureBoxRight;
         private System.Windows.Forms.PictureBox pictureBoxLeft;
-        private System.Windows.Forms.Timer drawTimer;
+        private System.Windows.Forms.Timer mouseTimer;
         private System.Windows.Forms.ToolStripButton canvasButton;
         private System.Windows.Forms.ToolStripButton drawButton;
+        private System.Windows.Forms.ToolStripButton deleteButton;
     }
 }
 

+ 134 - 8
SketchAssistant/SketchAssistant/Form1.cs

@@ -29,7 +29,8 @@ namespace SketchAssistant
         public enum ProgramState
         {
             Idle,
-            Draw
+            Draw,
+            Delete
         }
         //Current Program State
         private ProgramState currentState;
@@ -47,8 +48,17 @@ namespace SketchAssistant
         bool mousePressed = false;
         //The Position of the Cursor in the right picture box
         Point currentCursorPosition;
+        //The Previous Cursor Position in the right picture box
+        Point previousCursorPosition;
+        //Queue for the cursorPositions
+        Queue<Point> cursorPositions = new Queue<Point>();
         //The graphic representation of the right image
         Graphics graph = null;
+        //Deletion Matrixes for checking postions of lines in the image
+        bool[,] isFilledMatrix;
+        HashSet<int>[,] linesMatrix;
+        //Size of deletion area
+        uint deletionSize = 2;
 
         /******************************************/
         /*** FORM SPECIFIC FUNCTIONS START HERE ***/
@@ -80,7 +90,7 @@ namespace SketchAssistant
             }
         }
 
-        //Changes The State of the Program to drawing
+        //Changes the state of the program to drawing
         private void drawButton_Click(object sender, EventArgs e)
         {
             if(rightImage != null)
@@ -96,6 +106,22 @@ namespace SketchAssistant
             }
         }
 
+        //Changes the state of the program to deletion
+        private void deleteButton_Click(object sender, EventArgs e)
+        {
+            if (rightImage != null)
+            {
+                if (currentState.Equals(ProgramState.Delete))
+                {
+                    ChangeState(ProgramState.Idle);
+                }
+                else
+                {
+                    ChangeState(ProgramState.Delete);
+                }
+            }
+        }
+
         //get current Mouse positon within the right picture box
         private void pictureBoxRight_MouseMove(object sender, MouseEventArgs e)
         {
@@ -112,13 +138,28 @@ namespace SketchAssistant
             }
         }
 
-        //Lift left mouse button to stop drawing.
+        //when the picture box is clicked, add a point to the current line. Occurs f.ex. when using drawing tablets
+        private void pictureBoxRight_Click(object sender, EventArgs e)
+        {
+            if (currentState.Equals(ProgramState.Draw))
+            {
+                List<Point> singlePoint = new List<Point> { currentCursorPosition };
+                Line singlePointLine = new Line(singlePoint, lineList.Count);
+                singlePointLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                singlePointLine.DrawLine(graph);
+                pictureBoxRight.Image = rightImage;
+            }
+        }
+
+        //Lift left mouse button to stop drawing and add a new Line.
         private void pictureBoxRight_MouseUp(object sender, MouseEventArgs e)
         {
             mousePressed = false;
-            if (currentState.Equals(ProgramState.Draw))
+            if (currentState.Equals(ProgramState.Draw) && currentLine.Count > 0)
             {
-                lineList.Add(new Tuple<bool, Line>(true, new Line(currentLine)));
+                Line newLine = new Line(currentLine, lineList.Count);
+                lineList.Add(new Tuple<bool, Line>(true, newLine));
+                newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
             }
         }
 
@@ -128,11 +169,17 @@ namespace SketchAssistant
         private void canvasButton_Click(object sender, EventArgs e)
         {
             DrawEmptyCanvas();
+            //The following lines cannot be in DrawEmptyCanvas()
+            isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
+            linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
         }
 
         //add a Point on every tick to the Drawpath
-        private void drawTimer_Tick(object sender, EventArgs e)
+        private void mouseTimer_Tick(object sender, EventArgs e)
         {
+            cursorPositions.Enqueue(currentCursorPosition);
+            previousCursorPosition = cursorPositions.Dequeue();
+
             if (currentState.Equals(ProgramState.Draw) && mousePressed)
             {
                 currentLine.Add(currentCursorPosition);
@@ -140,6 +187,23 @@ namespace SketchAssistant
                 drawline.DrawLine(graph);
                 pictureBoxRight.Image = rightImage;
             }
+            if (currentState.Equals(ProgramState.Delete) && mousePressed)
+            {
+                List<Point> uncheckedPoints = Line.BresenhamLineAlgorithm(previousCursorPosition, currentCursorPosition);
+                foreach (Point currPoint in uncheckedPoints)
+                {
+                    HashSet<int> linesToDelete = CheckDeletionMatrixesAroundPoint(currPoint, deletionSize);
+                    if (linesToDelete.Count > 0)
+                    {
+                        foreach (int lineID in linesToDelete)
+                        {
+                            lineList[lineID] = new Tuple<bool, Line>(false, lineList[lineID].Item2);
+                        }
+                        RepopulateDeletionMatrixes();
+                        RedrawRightImage();
+                    }
+                }
+            }
         }
 
         /***********************************/
@@ -182,6 +246,7 @@ namespace SketchAssistant
                     lineBoolTuple.Item2.DrawLine(graph);
                 }
             }
+            pictureBoxRight.Refresh();
         }
 
         /// <summary>
@@ -195,7 +260,11 @@ namespace SketchAssistant
             {
                 case ProgramState.Draw:
                     drawButton.CheckState = CheckState.Unchecked;
-                    drawTimer.Enabled = false;
+                    mouseTimer.Enabled = false;
+                    break;
+                case ProgramState.Delete:
+                    deleteButton.CheckState = CheckState.Unchecked;
+                    mouseTimer.Enabled = false;
                     break;
                 default:
                     break;
@@ -204,7 +273,11 @@ namespace SketchAssistant
             {
                 case ProgramState.Draw:
                     drawButton.CheckState = CheckState.Checked;
-                    drawTimer.Enabled = true;
+                    mouseTimer.Enabled = true;
+                    break;
+                case ProgramState.Delete:
+                    deleteButton.CheckState = CheckState.Checked;
+                    mouseTimer.Enabled = true;
                     break;
                 default:
                     break;
@@ -254,5 +327,58 @@ namespace SketchAssistant
             }
             return realCoordinates;
         }
+
+        /// <summary>
+        /// A function that populates the matrixes needed for deletion detection with line data.
+        /// </summary>
+        private void RepopulateDeletionMatrixes()
+        {
+            if(rightImage != null)
+            {
+                isFilledMatrix = new bool[rightImage.Width,rightImage.Height];
+                linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
+                foreach(Tuple<bool,Line> lineTuple in lineList)
+                {
+                    if (lineTuple.Item1)
+                    {
+                        lineTuple.Item2.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// A function that checks the deletion matrixes at a certain point 
+        /// and returns all Line ids at that point and in a square around it in a certain range.
+        /// </summary>
+        /// <param name="p">The point around which to check.</param>
+        /// <param name="range">The range around the point. If range is 0, only the point is checked.</param>
+        /// <returns>A List of all lines.</returns>
+        private HashSet<int> CheckDeletionMatrixesAroundPoint(Point p, uint range)
+        {
+            HashSet<int> returnSet = new HashSet<int>();
+
+            if (p.X >= 0 && p.Y >= 0 && p.X < rightImage.Width && p.Y < rightImage.Height)
+            {
+                if (isFilledMatrix[p.X, p.Y])
+                {
+                    returnSet.UnionWith(linesMatrix[p.X, p.Y]);
+                }
+            }
+            for (int x_mod = (int)range*(-1); x_mod < range; x_mod++)
+            {
+                for (int y_mod = (int)range * (-1); y_mod < range; y_mod++)
+                {
+                    if (p.X + x_mod >= 0 && p.Y + y_mod >= 0 && p.X + x_mod < rightImage.Width && p.Y + y_mod < rightImage.Height)
+                    {
+                        if (isFilledMatrix[p.X + x_mod, p.Y + y_mod])
+                        {
+                            returnSet.UnionWith(linesMatrix[p.X + x_mod, p.Y + y_mod]);
+                        }
+                    }
+                }
+            }
+            return returnSet;
+        }
     }
 }

+ 16 - 1
SketchAssistant/SketchAssistant/Form1.resx

@@ -155,6 +155,21 @@
         mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
         kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
         TgDQASA1MVpwzwAAAABJRU5ErkJggg==
+</value>
+  </data>
+  <data name="deleteButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
+        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
+        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
+        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
+        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
+        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
+        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
+        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
+        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
+        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
 </value>
   </data>
   <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
@@ -163,7 +178,7 @@
   <metadata name="backgroundWorker2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>622, 17</value>
   </metadata>
-  <metadata name="drawTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+  <metadata name="mouseTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>786, 17</value>
   </metadata>
   <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

+ 208 - 2
SketchAssistant/SketchAssistant/Line.cs

@@ -7,13 +7,35 @@ using System.Drawing;
 
 namespace SketchAssistant
 {
-    class Line
+    public class Line
     {
         private List<Point> linePoints;
+        private int identifier;
+        private bool isTemporary;
 
+        /// <summary>
+        /// The constructor for lines which are only temporary.
+        /// If you want nice lines use the other constructor.
+        /// </summary>
+        /// <param name="points">The points of the line</param>
         public Line(List<Point> points)
         {
             linePoints = new List<Point>(points);
+            isTemporary = true;
+        }
+
+        /// <summary>
+        /// The constructor for lines, which will be more resource efficient 
+        /// and have the ability to populate deletion matrixes.
+        /// </summary>
+        /// <param name="points">The points of the line</param>
+        /// <param name="id">The identifier of the line</param>
+        public Line(List<Point> points, int id)
+        {
+            linePoints = new List<Point>(points);
+            identifier = id;
+            CleanPoints();
+            isTemporary = false;
         }
 
         public Point GetStartPoint()
@@ -26,6 +48,11 @@ namespace SketchAssistant
             return linePoints.Last();
         }
 
+        public List<Point> GetPoints()
+        {
+            return linePoints;
+        }
+
         /// <summary>
         /// A function that takes a Graphics element and returns it with
         /// the line drawn on it.
@@ -39,8 +66,187 @@ namespace SketchAssistant
             {
                 canvas.DrawLine(thePen, linePoints[i], linePoints[i + 1]);
             }
-            //canvas.DrawLine(thePen, linePoints[linePoints.Count-1], linePoints[linePoints.Count]);
+            //If there is only one point
+            if(linePoints.Count == 1){ canvas.FillRectangle(Brushes.Black, linePoints[0].X, linePoints[0].Y, 1, 1); }
             return canvas;
         }
+
+        /// <summary>
+        /// A function that will take to matrixes and populate the with the line data of this line object
+        /// </summary>
+        /// <param name="boolMatrix">The Matrix of booleans, in which is saved wether there is a line at this position.</param>
+        /// <param name="listMatrix">The Matrix of Lists of integers, in which is saved which lines are at this position</param>
+        public void PopulateMatrixes(bool[,] boolMatrix, HashSet<int>[,] 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<int>();
+                        }
+                        listMatrix[currPoint.X, currPoint.Y].Add(identifier);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Removes duplicate points from the line object
+        /// </summary>
+        private void CleanPoints()
+        {
+            if (linePoints.Count > 1)
+            {
+                List<Point> newList = new List<Point>();
+                List<Point> tempList = new List<Point>();
+                //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<Point> 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<Point>(newList);
+            }
+        }
+
+        /// <summary>
+        /// An implementation of the Bresenham Line Algorithm, 
+        /// which calculates all points between two points in a straight line.
+        /// Implemented using the pseudocode on Wikipedia.
+        /// </summary>
+        /// <param name="p0">The start point</param>
+        /// <param name="p1">The end point</param>
+        /// <returns>All points between p0 and p1 (including p0 and p1)</returns>
+        public static List<Point> BresenhamLineAlgorithm(Point p0, Point p1)
+        {
+            int deltaX = p1.X - p0.X;
+            int deltaY = p1.Y - p0.Y;
+            List<Point> 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;
+        }
+
+        /// <summary>
+        /// Helping function of the Bresenham Line algorithm,
+        /// under the assumption that abs(deltaY) is smaller than abs(deltX)
+        /// and x0 is smaller than x1
+        /// </summary>
+        /// <param name="x0">x value of point 0</param>
+        /// <param name="y0">y value of point 0</param>
+        /// <param name="x1">x value of point 1</param>
+        /// <param name="y1">y value of point 1</param>
+        /// <returns>All points on the line between the two points</returns>
+        private static List<Point> GetLineLow(int x0, int y0, int x1, int y1)
+        {
+            List<Point> returnList = new List<Point>();
+            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;
+        }
+
+        /// <summary>
+        /// 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
+        /// </summary>
+        /// <param name="x0">x value of point 0</param>
+        /// <param name="y0">y value of point 0</param>
+        /// <param name="x1">x value of point 1</param>
+        /// <param name="y1">y value of point 1</param>
+        /// <returns>All points on the line between the two points</returns>
+        private static List<Point> GetLineHigh(int x0, int y0, int x1, int y1)
+        {
+            List<Point> returnList = new List<Point>();
+            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;
+        }
     }
 }

+ 14 - 0
SketchAssistant/SketchAssistant/SketchAssistant.csproj

@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\NUnit3TestAdapter.3.11.2\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.11.2\build\net35\NUnit3TestAdapter.props')" />
+  <Import Project="..\packages\NUnit.3.11.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.11.0\build\NUnit.props')" />
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -26,6 +28,8 @@
     <IsWebBootstrapper>false</IsWebBootstrapper>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
@@ -47,6 +51,9 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="nunit.framework, Version=3.11.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
+      <HintPath>..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Xml.Linq" />
@@ -108,4 +115,11 @@
     </BootstrapperPackage>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\NUnit.3.11.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.11.0\build\NUnit.props'))" />
+    <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.11.2\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.11.2\build\net35\NUnit3TestAdapter.props'))" />
+  </Target>
 </Project>

+ 9 - 0
SketchAssistant/SketchAssistant/packages.config

@@ -1,5 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="NUnit" version="3.11.0" targetFramework="net461" />
+  <package id="NUnit.Console" version="3.9.0" targetFramework="net461" />
+  <package id="NUnit.ConsoleRunner" version="3.9.0" targetFramework="net461" />
+  <package id="NUnit.Extension.NUnitProjectLoader" version="3.6.0" targetFramework="net461" />
+  <package id="NUnit.Extension.NUnitV2Driver" version="3.7.0" targetFramework="net461" />
+  <package id="NUnit.Extension.NUnitV2ResultWriter" version="3.6.0" targetFramework="net461" />
+  <package id="NUnit.Extension.TeamCityEventListener" version="1.0.5" targetFramework="net461" />
+  <package id="NUnit.Extension.VSProjectLoader" version="3.8.0" targetFramework="net461" />
+  <package id="NUnit3TestAdapter" version="3.11.2" targetFramework="net461" />
   <package id="Svg" version="2.3.0" targetFramework="net461" />
   <package id="SvgNet" version="1.0.8" targetFramework="net461" />
 </packages>