Browse Source

Merge branch 'develop' into userstory2

Martin Edlund 5 years ago
parent
commit
2ff4f32409

+ 8 - 0
.appveyor.yml

@@ -0,0 +1,8 @@
+image:
+ - Visual Studio 2017
+ 
+install:
+ - "nuget install TestStack.White"
+ - "nuget install MSTest.TestAdapter"
+ - "nuget install MSTest.TestFramework"
+ - "nuget restore SketchAssistant/SketchAssistant.sln"

+ 0 - 6
.travis.yml

@@ -1,6 +0,0 @@
-language: csharp
-solution: "./SketchAssistant/SketchAssistant.sln"
-
-install:
-  - nuget restore "./SketchAssistant/SketchAssistant.sln"
-  - nuget install NUnit.ConsoleRunner -Version 3.9.0 -OutputDirectory testrunner

+ 13 - 0
Finished Userstories/userstory12.md

@@ -0,0 +1,13 @@
+# Userstory 12  
+ 
+|**ID**|12|  
+|-|-|
+|**Name**|Darstellen einer Zeichnung in der linken Picture Box|
+|**Beschreibung**|In der Linken picture box kann ein Bild angezeigt werden, was Line Elemente des Programms verwendet.|
+|**Akzeptanzkriterium**|Die Userstory ist akzeptiert, wenn das Programm ein Bild in bestehend aus den internen Line Elementen in der linken picture box darstellen kann.|
+|Geschätzter Aufwand (Story Points)|6|
+|Entwickler|Vincenz|
+|Umgesetzt in Iteration|3|
+|Tatsächlicher Aufwand (Std.)|8|
+|Velocity (Std./Story Point)|1.333|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory13.md

@@ -0,0 +1,13 @@
+# Userstory 13 
+ 
+|**ID**|13|  
+|-|-|
+|**Name**|Start und Endpunkt anzeigen|
+|**Beschreibung**|Beim Nachzeichnen kann der Start- & Endpunkt einer nachzuzeichnenden Linie angzeigt werden.|
+|**Akzeptanzkriterium**|Sofern auf der linken Seite eine nachzeichenbare Grafik dargestellt wird, kann der Start- und Endpunkt der ersten Linie der linken Grafik an der richtigen Stelle auf der rechten Seite angezeigt werden.|
+|Geschätzter Aufwand (Story Points)|2|
+|Entwickler|Martin|
+|Umgesetzt in Iteration|4|
+|Tatsächlicher Aufwand (Std.)|1|
+|Velocity (Std./Story Point)|0.5|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory17.md

@@ -0,0 +1,13 @@
+# Userstory 17  
+ 
+|**ID**|17|  
+|-|-|
+|**Name**|Nachzeichenmodus|
+|**Beschreibung**|Es gibt einen speziellen Modus zum Nachzeichnen von Bildern.|
+|**Akzeptanzkriterium**|Sobald ein Bild geladen wird, welches sich nachzeichenen lässt, wird der Nachzeichenmodus aktiviert. Ist der Nachzeichen Modus aktiviert, so werden Startpunkte für alle Linien auf der rechten Seite angezeigt. Fängt der Nutzer an einem Startpunkt an zu zeichnen, werden die anderen Startpunkte ausgeblendet und der Endpunkt der aktuellen Linie angezeigt. Zeichnet der Nutzer die Linie bis zum Endpunkt fertig, werden die verbleibenden Startpunkte angezeigt und der Nutzer kann eine neue Linie nachzeichnen. Wenn der Nutzer die Linie nicht zuende Zeichnet, muss sie von vorne begonnen werden.|
+|Geschätzter Aufwand (Story Points)|10|
+|Entwickler|Martin|
+|Umgesetzt in Iteration|4|
+|Tatsächlicher Aufwand (Std.)|11|
+|Velocity (Std./Story Point)|1.1|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory19.md

@@ -0,0 +1,13 @@
+# Userstory 19  
+ 
+|**ID**|19|  
+|-|-|
+|**Name**|Verbesserung der Struktur des Programms|
+|**Beschreibung**|Strukturierung des Programms zu einem Model-View-Controller Modell.|
+|**Akzeptanzkriterium**|Aufteilung der Form Datei in drei Klassen: Eine View Klasse, welche Aufgaben bezüglich Anzeigen im Form übernimmt. Eine Controller Klasse, welche Eingaben vom Form empfängt und verarbeitet. Sowie eine Model Klasse, welche den Status des Programms darstellt, und vom Controller manipuliert wird und selbst den View anpasst.|
+|Geschätzter Aufwand (Story Points)|20|
+|Entwickler|Martin Edlund|
+|Umgesetzt in Iteration|6|
+|Tatsächlicher Aufwand (Std.)|8,5|
+|Velocity (Std./Story Point)|0,425|
+|Bemerkungen|Keine|

+ 95 - 94
SketchAssistant/SketchAssistant.Tests/UnitTest1.cs

@@ -20,7 +20,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(1, 2), new Point(1, 2));
             Assert.AreEqual(1, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -34,7 +34,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(1, 2), new Point(6, 2));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -48,7 +48,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(6, 2), new Point(1, 2));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -62,7 +62,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(7, 5), new Point(7, 25));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -76,7 +76,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(7, 25), new Point(7, 5));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -90,7 +90,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(7, 5), new Point(27, 25));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -104,7 +104,7 @@ namespace Tests
             //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));
+            List<Point> actualResult = SketchAssistant.GeometryCalculator.BresenhamLineAlgorithm(new Point(27, 25), new Point(7, 5));
             Assert.AreEqual(expectedResult.Count, actualResult.Count);
             for (int i = 0; i < actualResult.Count; i++)
             {
@@ -205,11 +205,10 @@ namespace Tests
     [TestClass]
     public class ActionHistoryTests
     {
-        ToolStripStatusLabel testLabel = new ToolStripStatusLabel();
 
         private ActionHistory GetActionHistory()
         {
-            return new ActionHistory(testLabel);
+            return new ActionHistory();
         }
 
         [DataTestMethod]
@@ -267,107 +266,109 @@ namespace Tests
             Assert.AreEqual(true, testHistory.CanUndo());
             testHistory.MoveAction(true);
             Assert.AreEqual(true, testHistory.CanRedo());
-            testHistory.MoveAction(false);
+            var lastActionLabel = testHistory.MoveAction(false);
             Assert.AreEqual(actionType, testHistory.GetCurrentAction().GetActionType());
-            String currLabel = testLabel.Text;
-            Assert.AreEqual(currLabel, message);
+            Assert.AreEqual(message, lastActionLabel);
         }
     }
 
-    [TestClass]
-    public class FileImporterTests
+    /*
+[TestClass]
+public class FileImporterTests
+{
+    [DataTestMethod]
+    [DataRow(new int[] { 54, 43, 57, 11, 145, 34, 113, 299, 0 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
+    [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
+    [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 54, 43, 57, 11, 145, 34, 113, 199, 0 })]
+    public void ParseISADInputSuccessfulTest(int[] xCoordinates, int[] yCoordinates)
     {
-        [DataTestMethod]
-        [DataRow(new int[] { 54, 43, 57, 11, 145, 34, 113, 299, 0 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
-        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
-        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 54, 43, 57, 11, 145, 34, 113, 199, 0 })]
-        public void ParseISADInputSuccessfulTest(int[] xCoordinates, int[] yCoordinates)
-        {
-            Form1 program = new Form1();
-            FileImporter uut = new SketchAssistant.FileImporter();
+        Form1 program = new Form1();
+        FileImporter uut = new SketchAssistant.FileImporter();
 
-            List<String> file = new List<string>();
-            file.Add("drawing");
-            file.Add("300x200");
-            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
-            {
-                file.Add("line");
-                file.Add(xCoordinates[i] + ";" + yCoordinates[i]);
-                file.Add(xCoordinates[i + 1] + ";" + yCoordinates[i + 1]);
-                file.Add(xCoordinates[i + 2] + ";" + yCoordinates[i + 2]);
-                file.Add("endline");
-            }
-            file.Add("enddrawing");
+        List<String> file = new List<string>();
+        file.Add("drawing");
+        file.Add("300x200");
+        for (int i = 0; i < xCoordinates.Length - 2; i += 3)
+        {
+            file.Add("line");
+            file.Add(xCoordinates[i] + ";" + yCoordinates[i]);
+            file.Add(xCoordinates[i + 1] + ";" + yCoordinates[i + 1]);
+            file.Add(xCoordinates[i + 2] + ";" + yCoordinates[i + 2]);
+            file.Add("endline");
+        }
+        file.Add("enddrawing");
 
-            (int, int, List<Line>) values = uut.ParseISADInputForTesting(file.ToArray());
-            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
+        (int, int, List<Line>) values = uut.ParseISADInputForTesting(file.ToArray());
+        program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
 
-            Line[] drawing = GetLeftImage(program).ToArray();
+        Line[] drawing = GetLeftImage(program).ToArray();
 
-            Assert.AreEqual(xCoordinates.Length / 3, drawing.Length);
-            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
+        Assert.AreEqual(xCoordinates.Length / 3, drawing.Length);
+        for (int i = 0; i < xCoordinates.Length - 2; i += 3)
+        {
+            Point[] currentLine = drawing[i / 3].GetPoints().ToArray();
+            Assert.AreEqual(3, currentLine.Length);
+            for (int j = 0; j < 3; j++)
             {
-                Point[] currentLine = drawing[i / 3].GetPoints().ToArray();
-                Assert.AreEqual(3, currentLine.Length);
-                for (int j = 0; j < 3; j++)
-                {
-                    Assert.IsTrue(currentLine[j].X == xCoordinates[i + j] && currentLine[j].Y == yCoordinates[i + j]);
-                }
+                Assert.IsTrue(currentLine[j].X == xCoordinates[i + j] && currentLine[j].Y == yCoordinates[i + j]);
             }
         }
+    }
 
-        [DataTestMethod]
-        [DataRow(new String[] {})]
-        [DataRow(new String[] { "begindrawing", "300x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300;300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "30.5x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "beginline", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "500;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50x50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50", "100", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "line", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "stopline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline", "endrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline" })]
-        public void ParseISADInputExceptionTest(String[] file)
+    [DataTestMethod]
+    [DataRow(new String[] {})]
+    [DataRow(new String[] { "begindrawing", "300x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300;300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "30.5x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "line", "50;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "beginline", "50;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "500;50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50x50", "100;50", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50", "100", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "line", "endline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "stopline", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "enddrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline", "endrawing" })]
+    [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline" })]
+    public void ParseISADInputExceptionTest(String[] file)
+    {
+        bool exceptionThrown = false;
+        Form1 program = new Form1();
+        FileImporter uut = new SketchAssistant.FileImporter();
+        //check that left image initially is uninitialized
+        Assert.IsNull(GetLeftImage(program));
+        //initialize left image with a valid isad drawing
+        (int, int, List<Line>) values = uut.ParseISADInputForTesting(new string[] { "drawing", "300x205", "line", "40;40", "140;140", "endline", "enddrawing" });
+        program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
+        //save left image for later comparison
+        List<Line> oldLeftImage = GetLeftImage(program);
+        try
         {
-            bool exceptionThrown = false;
-            Form1 program = new Form1();
-            FileImporter uut = new SketchAssistant.FileImporter();
-            //check that left image initially is uninitialized
-            Assert.IsNull(GetLeftImage(program));
-            //initialize left image with a valid isad drawing
-            (int, int, List<Line>) values = uut.ParseISADInputForTesting(new string[] { "drawing", "300x205", "line", "40;40", "140;140", "endline", "enddrawing" });
-            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
-            //save left image for later comparison
-            List<Line> oldLeftImage = GetLeftImage(program);
-            try
-            {
-                //try to initialize the left image with an invalid isad drawing
-                (int, int, List<Line>) values1 = uut.ParseISADInputForTesting(file);
-                program.CreateCanvasAndSetPictureForTesting(values1.Item1, values1.Item2, values1.Item3);
-            }
-            catch(FileImporterException)
-            {
-                //save the occurence of an exception
-                exceptionThrown = true;
-            }
-            //check that an exception has been thrown
-            Assert.IsTrue(exceptionThrown);
-            //check that the left image has not been changed by the failed image import
-            Assert.AreEqual(oldLeftImage, GetLeftImage(program));
+            //try to initialize the left image with an invalid isad drawing
+            (int, int, List<Line>) values1 = uut.ParseISADInputForTesting(file);
+            program.CreateCanvasAndSetPictureForTesting(values1.Item1, values1.Item2, values1.Item3);
         }
-
-        /// <summary>
-        /// local helper method retrieving the left image from a Form1 instance
-        /// </summary>
-        /// <returns>the left image of the given Form1 instance</returns>
-        private List<Line> GetLeftImage(Form1 program)
+        catch(FileImporterException)
         {
-            //cast is save as long as Form1#GetAllVariables() is conform to its contract
-            return (List<Line>) program.GetAllVariables()[4];
+            //save the occurence of an exception
+            exceptionThrown = true;
         }
+        //check that an exception has been thrown
+        Assert.IsTrue(exceptionThrown);
+        //check that the left image has not been changed by the failed image import
+        Assert.AreEqual(oldLeftImage, GetLeftImage(program));
     }
+
+    /// <summary>
+    /// local helper method retrieving the left image from a Form1 instance
+    /// </summary>
+    /// <returns>the left image of the given Form1 instance</returns>
+    private List<Line> GetLeftImage(Form1 program)
+    {
+        //cast is save as long as Form1#GetAllVariables() is conform to its contract
+        return (List<Line>) program.GetAllVariables()[4];
+    }
+}
+*/
+
 }

+ 10 - 13
SketchAssistant/SketchAssistant/ActionHistory.cs

@@ -13,12 +13,9 @@ namespace SketchAssistant
         List<SketchAction> actionHistory;
         //The current position in the actionHistory
         Tuple<int, SketchAction> currentAction;
-        //The label in which the current action is displayed
-        ToolStripStatusLabel displayLabel;
 
-        public ActionHistory(ToolStripStatusLabel displayPosition)
+        public ActionHistory()
         {
-            displayLabel = displayPosition;
             actionHistory = new List<SketchAction>();
             currentAction = new Tuple<int, SketchAction>(-1, null);
             AddNewAction(new SketchAction(SketchAction.ActionType.Start, -1));
@@ -28,7 +25,8 @@ namespace SketchAssistant
         /// Adds a new action to the action history.
         /// </summary>
         /// <param name="newAction">The newly added action.</param>
-        public void AddNewAction(SketchAction newAction)
+        /// <returns>The message to be displayed</returns>
+        public String AddNewAction(SketchAction newAction)
         {
             //The current Action is before the last action taken, delete everything after the current action.
             if (currentAction.Item1 < actionHistory.Count - 1)
@@ -37,14 +35,15 @@ namespace SketchAssistant
             }
             actionHistory.Add(newAction);
             currentAction = new Tuple<int, SketchAction>(actionHistory.Count - 1, newAction);
-            UpdateStatusLabel();
+            return UpdateStatusLabel();
         }
 
         /// <summary>
         /// Changes the currentAction.
         /// </summary>
         /// <param name="moveBack">If True, moves the current action back one slot, if False, moves it forward.</param>
-        public void MoveAction(bool moveBack)
+        /// <returns>The message to be displayed</returns>
+        public String MoveAction(bool moveBack)
         {
             if(moveBack && CanUndo())
             {
@@ -54,7 +53,7 @@ namespace SketchAssistant
             {
                 currentAction = new Tuple<int, SketchAction>(currentAction.Item1 + 1, actionHistory[currentAction.Item1 + 1]);
             }
-            UpdateStatusLabel();
+            return UpdateStatusLabel();
         }
 
         /// <summary>
@@ -99,12 +98,10 @@ namespace SketchAssistant
         /// <summary>
         /// Updates the status label if there is one given.
         /// </summary>
-        private void UpdateStatusLabel()
+        /// <returns>The message to be displayed</returns>
+        private String UpdateStatusLabel()
         {
-            if (displayLabel != null)
-            {
-                displayLabel.Text = "Last Action: " + currentAction.Item2.GetActionInformation();
-            }
+            return "Last Action: " + currentAction.Item2.GetActionInformation();
         }
     }
 }

+ 0 - 4
SketchAssistant/SketchAssistant/FileImporter.cs

@@ -37,10 +37,6 @@ namespace SketchAssistant
         /// </summary>
         readonly int samplingRateBezier = 101;
 
-        public FileImporter()
-        {
-        }
-
         /// <summary>
         /// parses a drawing consisting of line objects, given as a file in the application specific .isad format
         /// </summary>

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

@@ -36,7 +36,6 @@ namespace SketchAssistant
             this.pictureBoxLeft = new System.Windows.Forms.PictureBox();
             this.menuStrip1 = new System.Windows.Forms.MenuStrip();
             this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
             this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
             this.examplePictureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
             this.toolStrip1 = new System.Windows.Forms.ToolStrip();
@@ -88,6 +87,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);
@@ -118,32 +118,24 @@ namespace SketchAssistant
             // fileToolStripMenuItem
             // 
             this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.loadToolStripMenuItem,
             this.importToolStripMenuItem});
             this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
             this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
             this.fileToolStripMenuItem.Text = "File";
             // 
-            // loadToolStripMenuItem
-            // 
-            this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
-            this.loadToolStripMenuItem.Text = "Load...";
-            this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
-            // 
             // importToolStripMenuItem
             // 
             this.importToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.examplePictureToolStripMenuItem,
             this.sVGDrawingToolStripMenuItem});
             this.importToolStripMenuItem.Name = "importToolStripMenuItem";
-            this.importToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.importToolStripMenuItem.Size = new System.Drawing.Size(119, 22);
             this.importToolStripMenuItem.Text = "Import...";
             // 
             // examplePictureToolStripMenuItem
             // 
             this.examplePictureToolStripMenuItem.Name = "examplePictureToolStripMenuItem";
-            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(158, 22);
             this.examplePictureToolStripMenuItem.Text = "Example picture";
             this.examplePictureToolStripMenuItem.Click += new System.EventHandler(this.examplePictureToolStripMenuItem_Click);
             // 
@@ -174,6 +166,7 @@ namespace SketchAssistant
             // drawButton
             // 
             this.drawButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.drawButton.Enabled = false;
             this.drawButton.Image = ((System.Drawing.Image)(resources.GetObject("drawButton.Image")));
             this.drawButton.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.drawButton.Name = "drawButton";
@@ -184,6 +177,7 @@ namespace SketchAssistant
             // deleteButton
             // 
             this.deleteButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.deleteButton.Enabled = false;
             this.deleteButton.Image = ((System.Drawing.Image)(resources.GetObject("deleteButton.Image")));
             this.deleteButton.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.deleteButton.Name = "deleteButton";
@@ -194,6 +188,7 @@ namespace SketchAssistant
             // undoButton
             // 
             this.undoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.undoButton.Enabled = false;
             this.undoButton.Image = ((System.Drawing.Image)(resources.GetObject("undoButton.Image")));
             this.undoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.undoButton.Name = "undoButton";
@@ -204,6 +199,7 @@ namespace SketchAssistant
             // redoButton
             // 
             this.redoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.redoButton.Enabled = false;
             this.redoButton.Image = ((System.Drawing.Image)(resources.GetObject("redoButton.Image")));
             this.redoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.redoButton.Name = "redoButton";
@@ -287,7 +283,6 @@ namespace SketchAssistant
         private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
         private System.Windows.Forms.MenuStrip menuStrip1;
         private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
-        private System.Windows.Forms.ToolStripMenuItem loadToolStripMenuItem;
         private System.Windows.Forms.ToolStrip toolStrip1;
         private System.Windows.Forms.StatusStrip statusStrip1;
         private System.Windows.Forms.ToolStripStatusLabel toolStripLoadStatus;

+ 143 - 464
SketchAssistant/SketchAssistant/Form1.cs

@@ -9,25 +9,29 @@ using System.Threading.Tasks;
 using System.Windows.Forms;
 using System.Text.RegularExpressions;
 
-
 // This is the code for your desktop app.
 // Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.
 
 namespace SketchAssistant
 {
-    public partial class Form1 : Form
+    public partial class Form1 : Form, MVP_View
     {
         public Form1()
         {
             InitializeComponent();
-            fileImporter = new FileImporter();
+            ProgramPresenter = new MVP_Presenter(this);
         }
 
         /**********************************/
         /*** CLASS VARIABLES START HERE ***/
         /**********************************/
 
-        //important: add new variables only at the end of the list to keep the order of definition consistent with the order in which they are returned by GetAllVariables()
+        public enum ButtonState
+        {
+            Enabled,
+            Disabled,
+            Active
+        }
 
         /// <summary>
         /// Different Program States
@@ -38,72 +42,23 @@ namespace SketchAssistant
             Draw,
             Delete
         }
-        /// <summary>
-        /// Current Program State
-        /// </summary>
-        private ProgramState currentState;
-        /// <summary>
-        /// instance of FileImporter to handle drawing imports
-        /// </summary>
-        private FileImporter fileImporter;
+
         /// <summary>
         /// Dialog to select a file.
         /// </summary>
         OpenFileDialog openFileDialog = new OpenFileDialog();
         /// <summary>
-        /// Image loaded on the left
-        /// </summary>
-        private Image leftImage = null;
-        /// <summary>
-        /// the graphic shown in the left window, represented as a list of polylines
-        /// </summary>
-        private List<Line> leftLineList;
-        /// <summary>
-        /// Image on the right
-        /// </summary>
-        Image rightImage = null;
-        /// <summary>
-        /// Current Line being Drawn
-        /// </summary>
-        List<Point> currentLine;
-        /// <summary>
         /// All Lines in the current session
         /// </summary>
-        List<Tuple<bool,Line>> rightLineList = new List<Tuple<bool, Line>>();
-        /// <summary>
-        /// Whether the Mouse is currently pressed in the rightPictureBox
-        /// </summary>
-        bool mousePressed = false;
-        /// <summary>
-        /// The Position of the Cursor in the right picture box
-        /// </summary>
-        Point currentCursorPosition;
-        /// <summary>
-        /// The Previous Cursor Position in the right picture box
-        /// </summary>
-        Point previousCursorPosition;
+        List<Tuple<bool, Line>> rightLineList = new List<Tuple<bool, Line>>();
         /// <summary>
         /// Queue for the cursorPositions
         /// </summary>
         Queue<Point> cursorPositions = new Queue<Point>();
         /// <summary>
-        /// The graphic representation of the right image
-        /// </summary>
-        Graphics rightGraph = null;
-        /// <summary>
-        /// Deletion Matrixes for checking postions of lines in the image
-        /// </summary>
-        bool[,] isFilledMatrix;
-        HashSet<int>[,] linesMatrix;
-        /// <summary>
-        /// Size of deletion area
+        /// The Presenter Component of the MVP-Model
         /// </summary>
-        uint deletionSize = 2;
-
-        /// <summary>
-        /// History of Actions
-        /// </summary>
-        ActionHistory historyOfActions;
+        MVP_Presenter ProgramPresenter;
 
         /******************************************/
         /*** FORM SPECIFIC FUNCTIONS START HERE ***/
@@ -111,54 +66,25 @@ namespace SketchAssistant
 
         private void Form1_Load(object sender, EventArgs e)
         {
-            currentState = ProgramState.Idle;
             this.DoubleBuffered = true;
-            historyOfActions = new ActionHistory(null);
-            UpdateButtonStatus();
         }
 
-        //Resize Function connected to the form resize event, will refresh the form when it is resized
+        /// <summary>
+        /// Resize Function connected to the form resize event, will refresh the form when it is resized
+        /// </summary>
         private void Form1_Resize(object sender, System.EventArgs e)
         {
+            ProgramPresenter.Resize(new Tuple<int, int>(pictureBoxLeft.Width, pictureBoxLeft.Height), 
+                new Tuple<int, int>(pictureBoxRight.Width, pictureBoxRight.Height));
             this.Refresh();
         }
-        
-        //Load button, will open an OpenFileDialog
-        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            openFileDialog.Filter = "Image|*.jpg;*.png;*.jpeg";
-            if(openFileDialog.ShowDialog() == DialogResult.OK)
-            {
-                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
-                leftImage = Image.FromFile(openFileDialog.FileName);
-                pictureBoxLeft.Image = leftImage;
-                //Refresh the left image box when the content is changed
-                this.Refresh();
-            }
-            UpdateButtonStatus();
-        }
 
         /// <summary>
         /// Import example picture button, will open an OpenFileDialog
         /// </summary>
         private void examplePictureToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            openFileDialog.Filter = "Interactive Sketch-Assistant Drawing|*.isad";
-            if (openFileDialog.ShowDialog() == DialogResult.OK)
-            {
-                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
-                try
-                {
-                    (int, int, List<Line>) values = fileImporter.ParseISADInputFile(openFileDialog.FileName);
-                    DrawEmptyCanvasLeft(values.Item1, values.Item2);
-                    BindAndDrawLeftImage(values.Item3);
-                    this.Refresh();
-                }
-                catch(FileImporterException ex)
-                {
-                    ShowInfoMessage(ex.ToString());
-                }
-            }
+            ProgramPresenter.ExamplePictureToolStripMenuItemClick();
         }
 
         /// <summary>
@@ -166,486 +92,239 @@ namespace SketchAssistant
         /// </summary>
         private void SVGDrawingToolStripMenuItem_Click(object sender, EventArgs e)
         {
-            openFileDialog.Filter = "Scalable Vector Graphics|*.svg";
-            if (openFileDialog.ShowDialog() == DialogResult.OK)
-            {
-                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
-                try
-                {
-                    (int, int, List<Line>) drawing = fileImporter.ParseSVGInputFile(openFileDialog.FileName, pictureBoxLeft.Width, pictureBoxLeft.Height);
-                    DrawEmptyCanvasLeft(drawing.Item1, drawing.Item2);
-                    BindAndDrawLeftImage(drawing.Item3);
-                    this.Refresh();
-                }
-                catch (FileImporterException ex)
-                {
-                    ShowInfoMessage(ex.ToString());
-                }
-                catch (Exception ex)
-                {
-                    ShowInfoMessage("exception occured while trying to parse svg file:\n\n" + ex.ToString() + "\n\n" + ex.StackTrace);
-                }
-            }
+            ProgramPresenter.SVGToolStripMenuItemClick();
         }
 
-        //Changes the state of the program to drawing
+        /// <summary>
+        /// Changes the state of the program to drawing
+        /// </summary>
         private void drawButton_Click(object sender, EventArgs e)
         {
-            if(rightImage != null)
-            {
-                if (currentState.Equals(ProgramState.Draw))
-                {
-                    ChangeState(ProgramState.Idle);
-                }
-                else
-                {
-                    ChangeState(ProgramState.Draw);
-                }
-            }
-            UpdateButtonStatus();
+            ProgramPresenter.ChangeState(true);
         }
 
-        //Changes the state of the program to deletion
+        /// <summary>
+        /// Changes the state of the program to deletion
+        /// </summary>
         private void deleteButton_Click(object sender, EventArgs e)
         {
-            if (rightImage != null)
-            {
-                if (currentState.Equals(ProgramState.Delete))
-                {
-                    ChangeState(ProgramState.Idle);
-                }
-                else
-                {
-                    ChangeState(ProgramState.Delete);
-                }
-            }
-            UpdateButtonStatus();
+            ProgramPresenter.ChangeState(false);
         }
 
-        //Undo an action
+        /// <summary>
+        /// Undo an Action.
+        /// </summary>
         private void undoButton_Click(object sender, EventArgs e)
         {
-            if (historyOfActions.CanUndo())
-            {
-                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
-                SketchAction.ActionType  undoAction = historyOfActions.GetCurrentAction().GetActionType();
-                switch (undoAction)
-                {
-                    case SketchAction.ActionType.Delete:
-                        //Deleted Lines need to be shown
-                        ChangeLines(affectedLines, true);
-                        break;
-                    case SketchAction.ActionType.Draw:
-                        //Drawn lines need to be hidden
-                        ChangeLines(affectedLines, false);
-                        break;
-                    default:
-                        break;
-                }
-            }
-            historyOfActions.MoveAction(true);
-            UpdateButtonStatus();
+            ProgramPresenter.Undo();
         }
 
-        //Redo an action
+        /// <summary>
+        /// Redo an Action.
+        /// </summary>
         private void redoButton_Click(object sender, EventArgs e)
         {
-            if (historyOfActions.CanRedo())
-            {
-                historyOfActions.MoveAction(false);
-                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
-                SketchAction.ActionType redoAction = historyOfActions.GetCurrentAction().GetActionType();
-                switch (redoAction)
-                {
-                    case SketchAction.ActionType.Delete:
-                        //Deleted Lines need to be redeleted
-                        ChangeLines(affectedLines, false);
-                        break;
-                    case SketchAction.ActionType.Draw:
-                        //Drawn lines need to be redrawn
-                        ChangeLines(affectedLines, true);
-                        break;
-                    default:
-                        break;
-                }
-            }
-            UpdateButtonStatus();
+            ProgramPresenter.Redo();
         }
 
-        //Detect Keyboard Shortcuts
+        /// <summary>
+        /// Detect Keyboard Shortcuts.
+        /// </summary>
         private void Form1_KeyDown(object sender, KeyEventArgs e)
         {
             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Z)
             {
-                undoButton_Click(sender, e);
+                ProgramPresenter.Undo();
             }
             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Y)
             {
-                redoButton_Click(sender, e);
+                ProgramPresenter.Redo();
             }
         }
 
-        //get current Mouse positon within the right picture box
-        private void pictureBoxRight_MouseMove(object sender, MouseEventArgs e)
+        /// <summary>
+        /// The Picture box is clicked.
+        /// </summary>
+        private void pictureBoxRight_Click(object sender, EventArgs e)
         {
-            currentCursorPosition = ConvertCoordinates(new Point(e.X, e.Y));
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Click);
         }
 
-        //hold left mouse button to draw.
+        /// <summary>
+        /// Get current Mouse positon within the right picture box.
+        /// </summary>
+        private void pictureBoxRight_MouseMove(object sender, MouseEventArgs e)
+        {
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, e);
+        }
+        
+        /// <summary>
+        /// Hold left mouse button to start drawing.
+        /// </summary>
         private void pictureBoxRight_MouseDown(object sender, MouseEventArgs e)
         {
-            mousePressed = true;
-            if (currentState.Equals(ProgramState.Draw))
-            {
-                currentLine = new List<Point>();
-            }
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down);
         }
-
-        //Lift left mouse button to stop drawing and add a new Line.
+        
+        /// <summary>
+        /// Lift left mouse button to stop drawing and add a new Line.
+        /// </summary>
         private void pictureBoxRight_MouseUp(object sender, MouseEventArgs e)
         {
-            mousePressed = false;
-            if (currentState.Equals(ProgramState.Draw) && currentLine.Count > 0)
-            {
-                Line newLine = new Line(currentLine, rightLineList.Count);
-                rightLineList.Add(new Tuple<bool, Line>(true, newLine));
-                newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
-                historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Draw, newLine.GetID()));
-            }
-            UpdateButtonStatus();
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up);
         }
-
-        //Button to create a new Canvas. Will create an empty image 
-        //which is the size of the left image, if there is one.
-        //If there is no image loaded the canvas will be the size of the right picture box
+        
+        /// <summary>
+        /// Button to create a new Canvas. Will create an empty image 
+        /// which is the size of the left image, if there is one.
+        /// If there is no image loaded the canvas will be the size of the right picture box
+        /// </summary>
         private void canvasButton_Click(object sender, EventArgs e)
         {
-            if (!historyOfActions.IsEmpty())
-            {
-                if (MessageBox.Show("You have unsaved changes, creating a new canvas will discard these.", 
-                    "Attention", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
-                {
-                    historyOfActions = new ActionHistory(lastActionTakenLabel);
-                    DrawEmptyCanvasRight();
-                    //The following lines cannot be in DrawEmptyCanvas()
-                    isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
-                    linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                    rightLineList = new List<Tuple<bool, Line>>();
-                }
-            }
-            else
-            {
-                historyOfActions = new ActionHistory(lastActionTakenLabel);
-                DrawEmptyCanvasRight();
-                //The following lines cannot be in DrawEmptyCanvas()
-                isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
-                linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                rightLineList = new List<Tuple<bool, Line>>();
-            }
-            UpdateButtonStatus();
+            ProgramPresenter.NewCanvas();
         }
 
-        //add a Point on every tick to the Drawpath
+        /// <summary>
+        /// Add a Point on every tick to the Drawpath.
+        /// Or detect lines for deletion on every tick
+        /// </summary>
         private void mouseTimer_Tick(object sender, EventArgs e)
         {
-            cursorPositions.Enqueue(currentCursorPosition);
-            previousCursorPosition = cursorPositions.Dequeue();
-            if (currentState.Equals(ProgramState.Draw) && mousePressed)
-            {
-                currentLine.Add(currentCursorPosition);
-                Line drawline = new Line(currentLine);
-                drawline.DrawLine(rightGraph);
-                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)
-                    {
-                        historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete));
-                        foreach (int lineID in linesToDelete)
-                        {
-                            rightLineList[lineID] = new Tuple<bool, Line>(false, rightLineList[lineID].Item2);
-                        }
-                        RepopulateDeletionMatrixes();
-                        RedrawRightImage();
-                    }
-                }
-            }
+            ProgramPresenter.Tick();
         }
 
-        /***********************************/
-        /*** HELPER FUNCTIONS START HERE ***/
-        /***********************************/
+        /*************************/
+        /*** PRESENTER -> VIEW ***/
+        /*************************/
 
         /// <summary>
-        /// Creates an empty Canvas
+        /// Enables the timer of the View, which will tick the Presenter.
         /// </summary>
-        private void DrawEmptyCanvasRight()
+        public void EnableTimer()
         {
-            if (leftImage == null)
-            {
-                rightImage = new Bitmap(pictureBoxRight.Width, pictureBoxRight.Height);
-                rightGraph = Graphics.FromImage(rightImage);
-                rightGraph.FillRectangle(Brushes.White, 0, 0, pictureBoxRight.Width + 10, pictureBoxRight.Height + 10);
-                pictureBoxRight.Image = rightImage;
-            }
-            else
-            {
-                rightImage = new Bitmap(leftImage.Width, leftImage.Height);
-                rightGraph = Graphics.FromImage(rightImage);
-                rightGraph.FillRectangle(Brushes.White, 0, 0, leftImage.Width + 10, leftImage.Height + 10);
-                pictureBoxRight.Image = rightImage;
-            }
-            this.Refresh();
-            pictureBoxRight.Refresh();
+            mouseTimer.Enabled = true;
         }
 
         /// <summary>
-        /// Creates an empty Canvas on the left
+        /// A function that opens a file dialog and returns the filename.
         /// </summary>
-        /// <param name="width"> width of the new canvas in pixels </param>
-        /// <param name="height"> height of the new canvas in pixels </param>
-        private void DrawEmptyCanvasLeft(int width, int height)
+        /// <param name="Filter">The filter that should be applied to the new Dialog.</param>
+        /// <returns>Returns the FileName and the SafeFileName if the user correctly selects a file, 
+        /// else returns a tuple with empty strigns</returns>
+        public Tuple<String, String> openNewDialog(String Filter)
         {
-            if (width == 0)
+            openFileDialog.Filter = Filter;
+            if (openFileDialog.ShowDialog() == DialogResult.OK)
             {
-                leftImage = new Bitmap(pictureBoxLeft.Width, pictureBoxLeft.Height);
+                return new Tuple<string, string>(openFileDialog.FileName, openFileDialog.SafeFileName);
             }
             else
             {
-                leftImage = new Bitmap(width, height);
+                return new Tuple<string, string>("", "");
             }
-            Graphics.FromImage(leftImage).FillRectangle(Brushes.White, 0, 0, pictureBoxLeft.Width + 10, pictureBoxLeft.Height + 10);
-            pictureBoxLeft.Image = leftImage;
-            
-            this.Refresh();
-            pictureBoxLeft.Refresh();
         }
 
         /// <summary>
-        /// Redraws all lines in lineList, for which their associated boolean value equals true.
+        /// Sets the contents of the load status indicator label.
         /// </summary>
-        private void RedrawRightImage()
+        /// <param name="message">The new contents</param>
+        public void SetToolStripLoadStatus(String message)
         {
-            DrawEmptyCanvasRight();
-            foreach (Tuple<bool, Line> lineBoolTuple in rightLineList)
-            {
-                if (lineBoolTuple.Item1)
-                {
-                    lineBoolTuple.Item2.DrawLine(rightGraph);
-                }
-            }
-            pictureBoxRight.Refresh();
+            toolStripLoadStatus.Text = message;
         }
 
         /// <summary>
-        /// Change the status of whether or not the lines are shown.
+        /// Sets the contents of the last action taken indicator label.
         /// </summary>
-        /// <param name="lines">The HashSet containing the affected Line IDs.</param>
-        /// <param name="shown">True if the lines should be shown, false if they should be hidden.</param>
-        private void ChangeLines(HashSet<int> lines, bool shown)
+        /// <param name="message">The new contents</param>
+        public void SetLastActionTakenText(String message)
         {
-            foreach (int lineId in lines)
-            {
-                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
-                {
-                    rightLineList[lineId] = new Tuple<bool, Line>(shown, rightLineList[lineId].Item2);
-                }
-            }
-            RedrawRightImage();
+            lastActionTakenLabel.Text = message;
         }
 
         /// <summary>
-        /// Updates the active status of buttons. Currently draw, delete, undo and redo button.
+        /// Changes the states of a tool strip button.
         /// </summary>
-        private void UpdateButtonStatus()
+        /// <param name="buttonName">The name of the button.</param>
+        /// <param name="state">The new state of the button.</param>
+        public void SetToolStripButtonStatus(String buttonName, ButtonState state)
         {
-            undoButton.Enabled = historyOfActions.CanUndo();
-            redoButton.Enabled = historyOfActions.CanRedo();
-            drawButton.Enabled = (rightImage != null);
-            deleteButton.Enabled = (rightImage != null);
-        }
-
-        /// <summary>
-        /// A helper function which handles tasks associated witch changing states, 
-        /// such as checking and unchecking buttons and changing the state.
-        /// </summary>
-        /// <param name="newState">The new state of the program</param>
-        private void ChangeState(ProgramState newState)
-        {
-            switch (currentState)
+            ToolStripButton buttonToChange;
+            switch (buttonName)
             {
-                case ProgramState.Draw:
-                    drawButton.CheckState = CheckState.Unchecked;
-                    mouseTimer.Enabled = false;
+                case "canvasButton":
+                    buttonToChange = canvasButton;
                     break;
-                case ProgramState.Delete:
-                    deleteButton.CheckState = CheckState.Unchecked;
-                    mouseTimer.Enabled = false;
+                case "drawButton":
+                    buttonToChange = drawButton;
                     break;
-                default:
+                case "deleteButton":
+                    buttonToChange = deleteButton;
                     break;
-            }
-            switch (newState)
-            {
-                case ProgramState.Draw:
-                    drawButton.CheckState = CheckState.Checked;
-                    mouseTimer.Enabled = true;
+                case "undoButton":
+                    buttonToChange = undoButton;
                     break;
-                case ProgramState.Delete:
-                    deleteButton.CheckState = CheckState.Checked;
-                    mouseTimer.Enabled = true;
+                case "redoButton":
+                    buttonToChange = redoButton;
                     break;
                 default:
-                    break;
+                    Console.WriteLine("Invalid Button was given to SetToolStripButton. \nMaybe you forgot to add a case?");
+                    return;
             }
-            currentState = newState;
-            pictureBoxRight.Refresh();
-        }
-
-        /// <summary>
-        /// A function that calculates the coordinates of a point on a zoomed in image.
-        /// </summary>
-        /// <param name="">The position of the mouse cursor</param>
-        /// <returns>The real coordinates of the mouse cursor on the image</returns>
-        private Point ConvertCoordinates(Point cursorPosition)
-        {
-            Point realCoordinates = new Point(5,3);
-            if(pictureBoxRight.Image == null)
-            {
-                return cursorPosition;
-            }
-
-            int widthImage = pictureBoxRight.Image.Width;
-            int heightImage = pictureBoxRight.Image.Height;
-            int widthBox = pictureBoxRight.Width;
-            int heightBox = pictureBoxRight.Height;
-
-            float imageRatio = (float)widthImage / (float)heightImage;
-            float containerRatio = (float)widthBox / (float)heightBox;
-
-            if (imageRatio >= containerRatio)
+            switch (state)
             {
-                //Image is wider than it is high
-                float zoomFactor = (float)widthImage / (float)widthBox;
-                float scaledHeight = heightImage / zoomFactor;
-                float filler = (heightBox - scaledHeight) / 2;
-                realCoordinates.X = (int)(cursorPosition.X * zoomFactor);
-                realCoordinates.Y = (int)((cursorPosition.Y - filler) * zoomFactor);
-            }
-            else
-            {
-                //Image is higher than it is wide
-                float zoomFactor = (float)heightImage / (float)heightBox;
-                float scaledWidth = widthImage / zoomFactor;
-                float filler = (widthBox - scaledWidth) / 2;
-                realCoordinates.X = (int)((cursorPosition.X - filler) * zoomFactor);
-                realCoordinates.Y = (int)(cursorPosition.Y * zoomFactor);
-            }
-            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 rightLineList)
-                {
-                    if (lineTuple.Item1)
-                    {
-                        lineTuple.Item2.PopulateMatrixes(isFilledMatrix, linesMatrix);
-                    }
-                }
+                case ButtonState.Active:
+                    buttonToChange.Checked = true;
+                    break;
+                case ButtonState.Disabled:
+                    buttonToChange.Checked = false;
+                    buttonToChange.Enabled = false;
+                    break;
+                case ButtonState.Enabled:
+                    buttonToChange.Checked = false;
+                    buttonToChange.Enabled = true;
+                    break;
             }
         }
 
         /// <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.
+        /// Displays an image in the left Picture box.
         /// </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)
+        /// <param name="img">The new image.</param>
+        public void DisplayInLeftPictureBox(Image img)
         {
-            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;
+            pictureBoxLeft.Image = img;
+            pictureBoxLeft.Refresh();
         }
 
         /// <summary>
-        /// binds the given picture to templatePicture and draws it
+        /// Displays an image in the right Picture box.
         /// </summary>
-        /// <param name="newTemplatePicture"> the new template picture, represented as a list of polylines </param>
-        /// <returns></returns>
-        private void BindAndDrawLeftImage(List<Line> newTemplatePicture)
+        /// <param name="img">The new image.</param>
+        public void DisplayInRightPictureBox(Image img)
         {
-            leftLineList = newTemplatePicture;
-            foreach(Line l in leftLineList)
-            {
-                l.DrawLine(Graphics.FromImage(leftImage));
-            }
+            pictureBoxRight.Image = img;
+            pictureBoxRight.Refresh();
         }
 
         /// <summary>
         /// shows the given info message in a popup and asks the user to aknowledge it
         /// </summary>
         /// <param name="message">the message to show</param>
-        private void ShowInfoMessage(String message)
+        public void ShowInfoMessage(String message)
         {
             MessageBox.Show(message);
         }
 
         /// <summary>
-        /// returns all instance variables in the order of their definition for testing
+        /// Shows a warning box with the given message (Yes/No Buttons)and returns true if the user aknowledges it.
         /// </summary>
-        /// <returns>all instance variables in the order of their definition</returns>
-        public Object[]/*(ProgramState, FileImporter, OpenFileDialog, Image, List<Line>, Image, List<Point>, List<Tuple<bool, Line>>, bool, Point, Point, Queue<Point>, Graphics, bool[,], HashSet<int>[,], uint, ActionHistory)*/ GetAllVariables()
+        /// <param name="message">The message of the warning.</param>
+        /// <returns>True if the user confirms (Yes), negative if he doesn't (No)</returns>
+        public bool ShowWarning(String message)
         {
-            return new Object[] { currentState, fileImporter, openFileDialog, leftImage, leftLineList, rightImage, currentLine, rightLineList, mousePressed, currentCursorPosition, previousCursorPosition, cursorPositions, rightGraph, isFilledMatrix, linesMatrix, deletionSize, historyOfActions };
+            return (MessageBox.Show(message, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes);
         }
 
-        /// <summary>
-        /// public method wrapper for testing purposes, invoking DrawEmptyCanvas(...) and BindAndDrawLeftImage(...)
-        /// </summary>
-        /// <param name="width">width of the parsed image</param>
-        /// <param name="height">height of the parsed image</param>
-        /// <param name="newImage">the parsed image</param>
-        public void CreateCanvasAndSetPictureForTesting(int width, int height, List<Line> newImage)
-        {
-            DrawEmptyCanvasLeft(width, height);
-            BindAndDrawLeftImage(newImage);
-        }
-
-
     }
 }

+ 204 - 0
SketchAssistant/SketchAssistant/GeometryCalculator.cs

@@ -0,0 +1,204 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    /// <summary>
+    /// A class that contains all algorithms related to geometry.
+    /// </summary>
+    public static class GeometryCalculator
+    {
+        /// <summary>
+        /// An implementation of the Bresenham Line Algorithm,
+        /// which calculates the points of a circle in a radius around a center point.
+        /// Implemented with the help of code examples on Wikipedia.
+        /// </summary>
+        /// <param name="center">The center of the circle.</param>
+        /// <param name="radius">The radius of the circle, 
+        /// when it is zero or less, only the midpoint is returned</param>
+        /// <returns>The HashSet containing all Points on the circle.</returns>
+        public static HashSet<Point> BresenhamCircleAlgorithm(Point center, int radius)
+        {
+            if(radius <= 0) { return new HashSet<Point> { center }; }
+
+            int x = radius - 1;
+            int y = 0;
+            int dx = 1;
+            int dy = 1;
+            int err = dx - (radius * 2);
+            HashSet<Point> returnSet = new HashSet<Point>();
+            
+            while (x >= y)
+            {
+                returnSet.Add(new Point(center.X + x, center.Y + y));
+                returnSet.Add(new Point(center.X + y, center.Y + x));
+                returnSet.Add(new Point(center.X - y, center.Y + x));
+                returnSet.Add(new Point(center.X - x, center.Y + y));
+                returnSet.Add(new Point(center.X - x, center.Y - y));
+                returnSet.Add(new Point(center.X - y, center.Y - x));
+                returnSet.Add(new Point(center.X + y, center.Y - x));
+                returnSet.Add(new Point(center.X + x, center.Y - y));
+
+                if (err <= 0)
+                {
+                    y++;
+                    err += dy;
+                    dy += 2;
+                }
+
+                if (err > 0)
+                {
+                    x--;
+                    dx += 2;
+                    err += dx - (radius * 2);
+                }
+            }
+            return returnSet;
+        }
+
+        /// <summary>
+        /// A simple algorithm that returns a filled circle with a radius and a center point.
+        /// </summary>
+        /// <param name="center">The center point of the alorithm </param>
+        /// <param name="radius">The radius of the circle, if its less or equal to 1 
+        /// only the center point is returned. </param>
+        /// <returns>All the points in or on the circle.</returns>
+        public static HashSet<Point> FilledCircleAlgorithm(Point center, int radius)
+        {
+            HashSet<Point> returnSet = new HashSet<Point> { center };
+            //Fill the circle
+            for (int x = 0; x < radius; x++)
+            {
+                for (int y = 0; y < radius; y++)
+                {
+                    //Check if point is on or in the circle
+                    if((x*x + y*y - radius * radius) <= 0)
+                    {
+                        returnSet.Add(new Point(center.X + x, center.Y + y));
+                        returnSet.Add(new Point(center.X - x, center.Y + y));
+                        returnSet.Add(new Point(center.X + x, center.Y - y));
+                        returnSet.Add(new Point(center.X - x, center.Y - y));
+                    }
+                }
+            }
+            return returnSet;
+        }
+
+        /// <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;
+        }
+    }
+}

+ 2 - 116
SketchAssistant/SketchAssistant/Line.cs

@@ -75,10 +75,9 @@ namespace SketchAssistant
         /// <returns>The given Graphics element with the additional line</returns>
         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]);
+                canvas.DrawLine(Pens.Black, 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); }
@@ -126,7 +125,7 @@ namespace SketchAssistant
                 for (int i = 0; i < linePoints.Count - 1; i++)
                 {
                     nullValue += linePoints[i + 1].X;
-                    List<Point> partialList = BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]);
+                    List<Point> partialList = GeometryCalculator.BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]);
                     tempList.AddRange(partialList);
                 }
                 Point nullPoint = new Point(nullValue, 0);
@@ -149,118 +148,5 @@ namespace SketchAssistant
                 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;
-        }
     }
 }

+ 568 - 0
SketchAssistant/SketchAssistant/MVP_Model.cs

@@ -0,0 +1,568 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    public class MVP_Model
+    {
+        /// <summary>
+        /// The Presenter of the MVP-Model.
+        /// </summary>
+        MVP_Presenter programPresenter;
+        /// <summary>
+        /// History of Actions
+        /// </summary>
+        ActionHistory historyOfActions;
+        /// <summary>
+        /// The assistant responsible for the redraw mode
+        /// </summary>
+        RedrawAssistant redrawAss;
+
+        /*******************/
+        /*** ENUMERATORS ***/
+        /*******************/
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        /// <summary>
+        /// If the program is in drawing mode.
+        /// </summary>
+        bool inDrawingMode;
+        /// <summary>
+        /// If the mouse is currently pressed or not.
+        /// </summary>
+        bool mousePressed;
+        /// <summary>
+        /// Size of deletion area
+        /// </summary>
+        int deletionRadius = 5;
+        /// <summary>
+        /// Size of areas marking endpoints of lines in the redraw mode.
+        /// </summary>
+        int markerRadius = 10;
+        /// <summary>
+        /// The Position of the Cursor in the right picture box
+        /// </summary>
+        Point currentCursorPosition;
+        /// <summary>
+        /// The Previous Cursor Position in the right picture box
+        /// </summary>
+        Point previousCursorPosition;
+        /// <summary>
+        /// Queue for the cursorPositions
+        /// </summary>
+        Queue<Point> cursorPositions = new Queue<Point>();
+        /// <summary>
+        /// Lookup Matrix for checking postions of lines in the image
+        /// </summary>
+        bool[,] isFilledMatrix;
+        /// <summary>
+        /// Lookup Matrix for getting line ids at a certain postions of the image
+        /// </summary>
+        HashSet<int>[,] linesMatrix;
+        /// <summary>
+        /// List of items which will be overlayed over the right canvas.
+        /// </summary>
+        List<Tuple<bool, HashSet<Point>>> overlayItems;
+        /// <summary>
+        /// Width of the LeftImageBox.
+        /// </summary>
+        public int leftImageBoxWidth;
+        /// <summary>
+        /// Height of the LeftImageBox.
+        /// </summary>
+        public int leftImageBoxHeight;
+        /// <summary>
+        /// Width of the RightImageBox.
+        /// </summary>
+        public int rightImageBoxWidth;
+        /// <summary>
+        /// Height of the RightImageBox.
+        /// </summary>
+        public int rightImageBoxHeight;
+
+        //Images
+        Image leftImage;
+
+        List<Line> leftLineList;
+
+        Image rightImageWithoutOverlay;
+
+        Image rightImageWithOverlay;
+
+        List<Tuple<bool, Line>> rightLineList;
+
+        List<Point> currentLine;
+
+
+
+        public MVP_Model(MVP_Presenter presenter)
+        {
+            programPresenter = presenter;
+            historyOfActions = new ActionHistory();
+            redrawAss = new RedrawAssistant();
+            rightLineList = new List<Tuple<bool, Line>>();
+            overlayItems = new List<Tuple<bool, HashSet<Point>>>();
+        }
+
+        /**************************/
+        /*** INTERNAL FUNCTIONS ***/
+        /**************************/
+
+        /// <summary>
+        /// A function that returns a white canvas for a given width and height.
+        /// </summary>
+        /// <param name="width">The width of the canvas in pixels</param>
+        /// <param name="height">The height of the canvas in pixels</param>
+        /// <returns>The new canvas</returns>
+        private Image GetEmptyCanvas(int width, int height)
+        {
+            Image image;
+            try
+            {
+                image = new Bitmap(width, height);
+            }
+            catch (ArgumentException e)
+            {
+                programPresenter.PassMessageToView("The requested canvas size caused an error: \n" 
+                    + e.ToString() + "\n The Canvas will be set to match your window.");
+                image = new Bitmap(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            Graphics graph = Graphics.FromImage(image);
+            graph.FillRectangle(Brushes.White, 0, 0, width + 10, height + 10);
+            return image;
+        }
+        
+
+        /// <summary>
+        /// Creates an empty Canvas on the left
+        /// </summary>
+        /// <param name="width"> width of the new canvas in pixels </param>
+        /// <param name="height"> height of the new canvas in pixels </param>
+        private void DrawEmptyCanvasLeft(int width, int height)
+        {
+            if (width == 0)
+            {
+                leftImage = GetEmptyCanvas(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            else
+            {
+                leftImage = GetEmptyCanvas(width, height);
+            }
+            programPresenter.UpdateLeftImage(leftImage);
+        }
+
+        /// <summary>
+        /// Redraws all lines in rightLineList, for which their associated boolean value equals true and calls RedrawRightOverlay.
+        /// </summary>
+        private void RedrawRightImage()
+        {
+            var workingCanvas = GetEmptyCanvas(rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height);
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            //Lines
+            foreach (Tuple<bool, Line> lineBoolTuple in rightLineList)
+            {
+                if (lineBoolTuple.Item1)
+                {
+                    lineBoolTuple.Item2.DrawLine(workingGraph);
+                }
+            }
+            //The Line being currently drawn
+            if (currentLine != null && currentLine.Count > 0 && inDrawingMode && mousePressed)
+            {
+                var currLine = new Line(currentLine);
+                currLine.DrawLine(workingGraph);
+            }
+            rightImageWithoutOverlay = workingCanvas;
+            //Redraw the Overlay if needed
+            if (leftImage != null)
+            {
+                RedrawRightOverlay();
+            }
+            else
+            {
+                programPresenter.UpdateRightImage(rightImageWithoutOverlay);
+            }
+        }
+
+        /// <summary>
+        /// Redraws all elements in the overlay items for which the respective boolean value is true.
+        /// </summary>
+        private void RedrawRightOverlay()
+        {
+            var workingCanvas = rightImageWithoutOverlay;
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            foreach (Tuple<bool, HashSet<Point>> tup in overlayItems)
+            {
+                if (tup.Item1)
+                {
+                    foreach (Point p in tup.Item2)
+                    {
+                        workingGraph.FillRectangle(Brushes.Green, p.X, p.Y, 1, 1);
+                    }
+                }
+            }
+            rightImageWithOverlay = workingCanvas;
+            programPresenter.UpdateRightImage(rightImageWithOverlay);
+        }
+        
+        /// <summary>
+        /// Change the status of whether or not the lines are shown.
+        /// </summary>
+        /// <param name="lines">The HashSet containing the affected Line IDs.</param>
+        /// <param name="shown">True if the lines should be shown, false if they should be hidden.</param>
+        private void ChangeLines(HashSet<int> lines, bool shown)
+        {
+            var changed = false;
+            foreach (int lineId in lines)
+            {
+                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
+                {
+                    rightLineList[lineId] = new Tuple<bool, Line>(shown, rightLineList[lineId].Item2);
+                    changed = true;
+                }
+            }
+            if (changed) { RedrawRightImage(); }
+        }
+        
+        /// <summary>
+        /// A function that populates the matrixes needed for deletion detection with line data.
+        /// </summary>
+        private void RepopulateDeletionMatrixes()
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                isFilledMatrix = new bool[rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height];
+                linesMatrix = new HashSet<int>[rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height];
+                foreach (Tuple<bool, Line> lineTuple in rightLineList)
+                {
+                    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, int range)
+        {
+            HashSet<int> returnSet = new HashSet<int>();
+
+            foreach (Point pnt in GeometryCalculator.FilledCircleAlgorithm(p, (int)range))
+            {
+                if (pnt.X >= 0 && pnt.Y >= 0 && pnt.X < rightImageWithoutOverlay.Width && pnt.Y < rightImageWithoutOverlay.Height)
+                {
+                    if (isFilledMatrix[pnt.X, pnt.Y])
+                    {
+                        returnSet.UnionWith(linesMatrix[pnt.X, pnt.Y]);
+                    }
+                }
+            }
+            return returnSet;
+        }
+
+        /*
+        /// <summary>
+        /// Will calculate the start and endpoints of the given line on the right canvas.
+        /// </summary>
+        /// <param name="line">The line.</param>
+        /// <param name="size">The size of the circle with which the endpoints of the line are marked.</param>
+        private Tuple<HashSet<Point>, HashSet<Point>> CalculateStartAndEnd(Line line, int size)
+        {
+            var circle0 = GeometryCalculator.FilledCircleAlgorithm(line.GetStartPoint(), size);
+            var circle1 = GeometryCalculator.FilledCircleAlgorithm(line.GetEndPoint(), size);
+            var currentLineEndings = new Tuple<HashSet<Point>, HashSet<Point>>(circle0, circle1);
+            return currentLineEndings;
+        }
+        */
+
+
+
+        /// <summary>
+        /// Tells the Presenter to Update the UI
+        /// </summary>
+        private void UpdateUI()
+        {
+            programPresenter.UpdateUIState(inDrawingMode, historyOfActions.CanUndo(), historyOfActions.CanRedo(), (rightImageWithoutOverlay != null));
+        }
+
+
+        /********************************************/
+        /*** FUNCTIONS TO INTERACT WITH PRESENTER ***/
+        /********************************************/
+
+        /// <summary>
+        /// Creates an empty Canvas
+        /// </summary>
+        public void DrawEmptyCanvasRight()
+        {
+            if (leftImage == null)
+            {
+                rightImageWithoutOverlay = GetEmptyCanvas(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            else
+            {
+                rightImageWithoutOverlay = GetEmptyCanvas(leftImage.Width, leftImage.Height);
+            }
+            RepopulateDeletionMatrixes();
+            rightImageWithOverlay = rightImageWithoutOverlay;
+            programPresenter.UpdateRightImage(rightImageWithOverlay);
+        }
+
+        /// <summary>
+        /// The function to set the left image.
+        /// </summary>
+        /// <param name="width">The width of the left image.</param>
+        /// <param name="height">The height of the left image.</param>
+        /// <param name="listOfLines">The List of Lines to be displayed in the left image.</param>
+        public void SetLeftLineList(int width, int height, List<Line> listOfLines)
+        {
+            var workingCanvas = GetEmptyCanvas(width,height);
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            leftLineList = listOfLines;
+            redrawAss = new RedrawAssistant(leftLineList);
+            overlayItems = redrawAss.Initialize(markerRadius);
+            //Lines
+            foreach (Line line in leftLineList)
+            {
+                line.DrawLine(workingGraph);
+            }
+            leftImage = workingCanvas;
+            programPresenter.UpdateLeftImage(leftImage);
+            //Set right image to same size as left image and delete linelist
+            DrawEmptyCanvasRight();
+            rightLineList = new List<Tuple<bool, Line>>();
+        }
+
+        /// <summary>
+        /// Will undo the last action taken, if the action history allows it.
+        /// </summary>
+        public void Undo()
+        {
+            if (historyOfActions.CanUndo())
+            {
+                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
+                SketchAction.ActionType undoAction = historyOfActions.GetCurrentAction().GetActionType();
+                switch (undoAction)
+                {
+                    case SketchAction.ActionType.Delete:
+                        //Deleted Lines need to be shown
+                        ChangeLines(affectedLines, true);
+                        break;
+                    case SketchAction.ActionType.Draw:
+                        //Drawn lines need to be hidden
+                        ChangeLines(affectedLines, false);
+                        break;
+                    default:
+                        break;
+                }
+                if(leftImage != null)
+                {
+                    //overlayItems = redrawAss.Tick(currentCursorPosition, rightLineList, -1, false);
+                }
+                RedrawRightImage();
+            }
+            RepopulateDeletionMatrixes();
+            programPresenter.PassLastActionTaken(historyOfActions.MoveAction(true));
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// Will redo the last action undone, if the action history allows it.
+        /// </summary>
+        public void Redo()
+        {
+            if (historyOfActions.CanRedo())
+            {
+                programPresenter.PassLastActionTaken(historyOfActions.MoveAction(false));
+                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
+                SketchAction.ActionType redoAction = historyOfActions.GetCurrentAction().GetActionType();
+                switch (redoAction)
+                {
+                    case SketchAction.ActionType.Delete:
+                        //Deleted Lines need to be redeleted
+                        ChangeLines(affectedLines, false);
+                        break;
+                    case SketchAction.ActionType.Draw:
+                        //Drawn lines need to be redrawn
+                        ChangeLines(affectedLines, true);
+                        break;
+                    default:
+                        break;
+                }
+                if (leftImage != null)
+                {
+                    //overlayItems = redrawAss.Tick(currentCursorPosition, rightLineList, -1, false);
+                }
+                RedrawRightImage();
+                RepopulateDeletionMatrixes();
+            }
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// The function called by the Presenter to change the drawing state of the program.
+        /// </summary>
+        /// <param name="nowDrawing">The new drawingstate of the program</param>
+        public void ChangeState(bool nowDrawing)
+        {
+            inDrawingMode = nowDrawing;
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// A method to get the dimensions of the right image.
+        /// </summary>
+        /// <returns>A tuple containing the width and height of the right image.</returns>
+        public Tuple<int, int> GetRightImageDimensions()
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                return new Tuple<int, int>(rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height);
+            }
+            else
+            {
+                return new Tuple<int, int>(0, 0);
+            }
+        }
+
+        /// <summary>
+        /// Updates the current cursor position of the model.
+        /// </summary>
+        /// <param name="p">The new cursor position</param>
+        public void SetCurrentCursorPosition(Point p)
+        {
+            currentCursorPosition = p;
+        }
+
+        /// <summary>
+        /// Start a new Line, when the Mouse is pressed down.
+        /// </summary>
+        public void MouseDown()
+        {
+            mousePressed = true;
+            if (inDrawingMode)
+            {
+                currentLine = new List<Point>();
+            }
+        }
+
+        /// <summary>
+        /// Finish the current Line, when the pressed Mouse is released.
+        /// </summary>
+        public void MouseUp()
+        {
+            mousePressed = false;
+            if (inDrawingMode && currentLine.Count > 0)
+            {
+                Line newLine = new Line(currentLine, rightLineList.Count);
+                rightLineList.Add(new Tuple<bool, Line>(true, newLine));
+                newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                programPresenter.PassLastActionTaken(historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Draw, newLine.GetID())));
+                if(leftImage != null)
+                {
+                    //Execute a RedrawAssistant tick with the currently finished Line
+                    //overlayItems = redrawAss.Tick(currentCursorPosition, rightLineList, newLine.GetID(), true);
+                }
+                RedrawRightImage();
+            }
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// Method to be called every tick. Updates the current Line, or checks for Lines to delete, depending on the drawing mode.
+        /// </summary>
+        public void Tick()
+        {
+            if (cursorPositions.Count > 0) { previousCursorPosition = cursorPositions.Dequeue(); }
+            else { previousCursorPosition = currentCursorPosition; }
+            cursorPositions.Enqueue(currentCursorPosition);
+            //Drawing
+            if (inDrawingMode && mousePressed)
+            {
+                var rightGraph = Graphics.FromImage(rightImageWithoutOverlay);
+                currentLine.Add(currentCursorPosition);
+                Line drawline = new Line(currentLine);
+                drawline.DrawLine(rightGraph);
+                RedrawRightOverlay();
+            }
+            //Deleting
+            if (!inDrawingMode && mousePressed)
+            {
+                List<Point> uncheckedPoints = GeometryCalculator.BresenhamLineAlgorithm(previousCursorPosition, currentCursorPosition);
+                foreach (Point currPoint in uncheckedPoints)
+                {
+                    HashSet<int> linesToDelete = CheckDeletionMatrixesAroundPoint(currPoint, deletionRadius);
+                    if (linesToDelete.Count > 0)
+                    {
+                        programPresenter.PassLastActionTaken(historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete)));
+                        foreach (int lineID in linesToDelete)
+                        {
+                            rightLineList[lineID] = new Tuple<bool, Line>(false, rightLineList[lineID].Item2);
+                        }
+                        RepopulateDeletionMatrixes();
+                        if(leftImage != null)
+                        {
+                            //Redraw overlay gets ticked
+                            //overlayItems = redrawAss.Tick(currentCursorPosition, rightLineList, -1, false);
+                        }
+                        RedrawRightImage();
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// A helper Function that updates the markerRadius & deletionRadius, considering the size of the canvas.
+        /// </summary>
+        public void UpdateSizes()
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                int widthImage = rightImageWithoutOverlay.Width;
+                int heightImage = rightImageWithoutOverlay.Height;
+                int widthBox = rightImageBoxWidth;
+                int heightBox = rightImageBoxHeight;
+
+                float imageRatio = (float)widthImage / (float)heightImage;
+                float containerRatio = (float)widthBox / (float)heightBox;
+                float zoomFactor = 0;
+                if (imageRatio >= containerRatio)
+                {
+                    //Image is wider than it is high
+                    zoomFactor = (float)widthImage / (float)widthBox;
+                }
+                else
+                {
+                    //Image is higher than it is wide
+                    zoomFactor = (float)heightImage / (float)heightBox;
+                }
+                markerRadius = (int)(10 * zoomFactor);
+                redrawAss.SetMarkerRadius(markerRadius);
+                deletionRadius = (int)(5 * zoomFactor);
+            }
+        }
+
+        /// <summary>
+        /// If there is unsaved progress.
+        /// </summary>
+        /// <returns>True if there is progress that has not been saved.</returns>
+        public bool HasUnsavedProgress()
+        {
+            return !historyOfActions.IsEmpty();
+        }
+    }
+}

+ 342 - 0
SketchAssistant/SketchAssistant/MVP_Presenter.cs

@@ -0,0 +1,342 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    public class MVP_Presenter
+    {
+        /// <summary>
+        /// The View of the MVP-Model, in this case Form1.
+        /// </summary>
+        MVP_View programView;
+        /// <summary>
+        /// The Model of the MVP-Model.
+        /// </summary>
+        MVP_Model programModel;
+
+        /*******************/
+        /*** ENUMERATORS ***/
+        /*******************/
+
+        public enum MouseAction
+        {
+            Click,
+            Down,
+            Up,
+            Move
+        }
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        /// <summary>
+        /// Instance of FileImporter to handle drawing imports.
+        /// </summary>
+        private FileImporter fileImporter;
+
+
+        public MVP_Presenter(MVP_View form)
+        {
+            programView = form;
+            programModel = new MVP_Model(this);
+            //Initialize Class Variables
+            fileImporter = new FileImporter();
+        }
+
+        /***********************************/
+        /*** FUNCTIONS VIEW -> PRESENTER ***/
+        /***********************************/
+
+        /// <summary>
+        /// Pass-trough function to update the appropriate information of the model, when the window is resized.
+        /// </summary>
+        /// <param name="leftPBS">The new size of the left picture box.</param>
+        /// <param name="rightPBS">The new size of the left picture box.</param>
+        public void Resize(Tuple<int, int> leftPBS,Tuple<int, int> rightPBS)
+        {
+            programModel.leftImageBoxWidth = leftPBS.Item1;
+            programModel.leftImageBoxHeight = leftPBS.Item2;
+            programModel.rightImageBoxWidth = rightPBS.Item1;
+            programModel.rightImageBoxHeight = rightPBS.Item2;
+            programModel.UpdateSizes();
+        }
+
+        /// <summary>
+        /// Display a new FileDialog to load a collection of lines.
+        /// </summary>
+        public void ExamplePictureToolStripMenuItemClick()
+        {
+            var okToContinue = true;
+            if (programModel.HasUnsavedProgress())
+            {
+                okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
+            }
+            if (okToContinue)
+            {
+                var fileNameTup = programView.openNewDialog("Interactive Sketch-Assistant Drawing|*.isad");
+                if (!fileNameTup.Item1.Equals("") && !fileNameTup.Item2.Equals(""))
+                {
+                    programView.SetToolStripLoadStatus(fileNameTup.Item2);
+                    (int, int, List<Line>) values = fileImporter.ParseISADInputFile(fileNameTup.Item1);
+                    programModel.SetLeftLineList(values.Item1, values.Item2, values.Item3);
+                    programModel.ChangeState(true);
+                    programView.EnableTimer();
+                }
+            }
+        }
+
+        public void SVGToolStripMenuItemClick()
+        {
+            var okToContinue = true;
+            if (programModel.HasUnsavedProgress())
+            {
+                okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
+            }
+            if (okToContinue)
+            {
+                var fileNameTup = programView.openNewDialog("Scalable Vector Graphics|*.svg");
+                if (!fileNameTup.Item1.Equals("") && !fileNameTup.Item2.Equals(""))
+                {
+                    programView.SetToolStripLoadStatus(fileNameTup.Item2);
+                    try
+                    {
+                        (int, int, List<Line>) values = fileImporter.ParseSVGInputFile(fileNameTup.Item1, programModel.leftImageBoxWidth, programModel.leftImageBoxHeight);
+                        programModel.SetLeftLineList(values.Item1, values.Item2, values.Item3);
+                        programModel.ChangeState(true);
+                        programView.EnableTimer();
+                    }
+                    catch (FileImporterException ex)
+                    {
+                        programView.ShowInfoMessage(ex.ToString());
+                    }
+                    catch (Exception ex)
+                    {
+                        programView.ShowInfoMessage("exception occured while trying to parse svg file:\n\n" + ex.ToString() + "\n\n" + ex.StackTrace);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough function to change the drawing state of the model.
+        /// </summary>
+        /// <param name="NowDrawing">Indicates if the program is in drawing (true) or deletion (false) mode.</param>
+        public void ChangeState(bool NowDrawing)
+        {
+            programModel.ChangeState(NowDrawing);
+        }
+
+        /// <summary>
+        /// Pass-trough function to undo an action.
+        /// </summary>
+        public void Undo()
+        {
+            programModel.Undo();
+        }
+
+        /// <summary>
+        /// Pass-trough function to redo an action.
+        /// </summary>
+        public void Redo()
+        {
+            programModel.Redo();
+        }
+
+        /// <summary>
+        /// Checks if there is unsaved progress, and promts the model to generate a new canvas if not.
+        /// </summary>
+        public void NewCanvas()
+        {
+            var okToContinue = true;
+            if (programModel.HasUnsavedProgress())
+            {
+                okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
+            }
+            if (okToContinue)
+            {
+                programModel.DrawEmptyCanvasRight();
+                programModel.ChangeState(true);
+                programView.EnableTimer();
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough function for ticking the model.
+        /// </summary>
+        public void Tick()
+        {
+            programModel.Tick();
+        }
+
+        /// <summary>
+        /// Pass-trough when the mouse is moved.
+        /// </summary>
+        /// <param name="mouseAction">The action which is sent by the View.</param>
+        /// <param name="e">The Mouse event arguments.</param>
+        public void MouseEvent(MouseAction mouseAction, MouseEventArgs e)
+        {
+            switch (mouseAction)
+            {
+                case MouseAction.Move:
+                    programModel.SetCurrentCursorPosition(ConvertCoordinates(new Point(e.X, e.Y)));
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough function that calls the correct Mouse event of the model, when the mouse is clicked.
+        /// </summary>
+        /// <param name="mouseAction">The action which is sent by the View.</param>
+        /// <param name="e">The Mouse event arguments.</param>
+        public void MouseEvent(MouseAction mouseAction)
+        {
+            switch (mouseAction)
+            {
+                case MouseAction.Click:
+                    programModel.MouseDown();
+                    programModel.Tick();
+                    programModel.MouseUp();
+                    break;
+                case MouseAction.Down:
+                    programModel.MouseDown();
+                    break;
+                case MouseAction.Up:
+                    programModel.MouseUp();
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        /************************************/
+        /*** FUNCTIONS MODEL -> PRESENTER ***/
+        /************************************/
+
+        /// <summary>
+        /// Called by the model when the state of the Program changes. 
+        /// Changes the look of the UI according to the current state of the model.
+        /// </summary>
+        /// <param name="inDrawingMode">If the model is in Drawing Mode</param>
+        /// <param name="canUndo">If actions in the model can be undone</param>
+        /// <param name="canRedo">If actions in the model can be redone</param>
+        /// <param name="imageLoaded">If an image is loaded in the model</param>
+        public void UpdateUIState(bool inDrawingMode, bool canUndo, bool canRedo, bool imageLoaded)
+        {
+            Dictionary<String, Form1.ButtonState> dict = new Dictionary<String, Form1.ButtonState> {
+                {"canvasButton", Form1.ButtonState.Enabled }, {"drawButton", Form1.ButtonState.Disabled}, {"deleteButton",Form1.ButtonState.Disabled },
+                {"undoButton", Form1.ButtonState.Disabled },{"redoButton",  Form1.ButtonState.Disabled}};
+
+            if (imageLoaded)
+            {
+                if (inDrawingMode)
+                {
+                    dict["drawButton"] = Form1.ButtonState.Active;
+                    dict["deleteButton"] = Form1.ButtonState.Enabled;
+                }
+                else
+                {
+                    dict["drawButton"] = Form1.ButtonState.Enabled;
+                    dict["deleteButton"] = Form1.ButtonState.Active;
+                }
+                if (canUndo){dict["undoButton"] = Form1.ButtonState.Enabled;}
+                if (canRedo){dict["redoButton"] = Form1.ButtonState.Enabled;}
+            }
+            foreach(KeyValuePair<String, Form1.ButtonState> entry in dict)
+            {
+                programView.SetToolStripButtonStatus(entry.Key, entry.Value);
+            }
+        }
+
+        /// <summary>
+        /// Is called by the model when the left image is changed.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        public void UpdateLeftImage(Image img)
+        {
+            programView.DisplayInLeftPictureBox(img);
+        }
+
+        /// <summary>
+        /// Is called by the model when the right image is changed.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        public void UpdateRightImage(Image img)
+        {
+            programView.DisplayInRightPictureBox(img);
+        }
+
+        /// <summary>
+        /// Pass-trough function to display an info message in the view.
+        /// </summary>
+        /// <param name="msg">The message.</param>
+        public void PassMessageToView(String msg)
+        {
+            programView.ShowInfoMessage(msg);
+        }
+
+        /// <summary>
+        /// Pass-trough function to update the display of the last action taken.
+        /// </summary>
+        /// <param name="msg">The new last action taken.</param>
+        public void PassLastActionTaken(String msg)
+        {
+            programView.SetLastActionTakenText(msg);
+        }
+
+        /*************************/
+        /*** HELPING FUNCTIONS ***/
+        /*************************/
+
+        /// <summary>
+        /// A function that calculates the coordinates of a point on a zoomed in image.
+        /// </summary>
+        /// <param name="">The position of the mouse cursor</param>
+        /// <returns>The real coordinates of the mouse cursor on the image</returns>
+        private Point ConvertCoordinates(Point cursorPosition)
+        {
+            var rightImageDimensions = programModel.GetRightImageDimensions();
+            Point realCoordinates = new Point(0, 0);
+
+            int widthImage = rightImageDimensions.Item1;
+            int heightImage = rightImageDimensions.Item2;
+            int widthBox = programModel.rightImageBoxWidth;
+            int heightBox = programModel.rightImageBoxHeight;
+
+            if (heightImage == 0 && widthImage == 0)
+            {
+                return cursorPosition;
+            }
+
+            float imageRatio = (float)widthImage / (float)heightImage;
+            float containerRatio = (float)widthBox / (float)heightBox;
+
+            if (imageRatio >= containerRatio)
+            {
+                //Image is wider than it is high
+                float zoomFactor = (float)widthImage / (float)widthBox;
+                float scaledHeight = heightImage / zoomFactor;
+                float filler = (heightBox - scaledHeight) / 2;
+                realCoordinates.X = (int)(cursorPosition.X * zoomFactor);
+                realCoordinates.Y = (int)((cursorPosition.Y - filler) * zoomFactor);
+            }
+            else
+            {
+                //Image is higher than it is wide
+                float zoomFactor = (float)heightImage / (float)heightBox;
+                float scaledWidth = widthImage / zoomFactor;
+                float filler = (widthBox - scaledWidth) / 2;
+                realCoordinates.X = (int)((cursorPosition.X - filler) * zoomFactor);
+                realCoordinates.Y = (int)(cursorPosition.Y * zoomFactor);
+            }
+            return realCoordinates;
+        }
+    }
+}

+ 71 - 0
SketchAssistant/SketchAssistant/MVP_View.cs

@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+
+
+namespace SketchAssistant
+{
+    public interface MVP_View
+    {
+
+        /// <summary>
+        /// Enables the timer of the View, which will tick the Presenter.
+        /// </summary>
+        void EnableTimer();
+
+        /// <summary>
+        /// A function that opens a file dialog and returns the filename.
+        /// </summary>
+        /// <param name="Filter">The filter that should be applied to the new Dialog.</param>
+        /// <returns>Returns the FileName and the SafeFileName if the user correctly selects a file, 
+        /// else returns a tuple with empty strigns</returns>
+        Tuple<String, String> openNewDialog(String Filter);
+
+        /// <summary>
+        /// Sets the contents of the load status indicator label.
+        /// </summary>
+        /// <param name="message">The new contents</param>
+        void SetToolStripLoadStatus(String message);
+
+        /// <summary>
+        /// Sets the contents of the last action taken indicator label.
+        /// </summary>
+        /// <param name="message">The new contents</param>
+        void SetLastActionTakenText(String message);
+
+        /// <summary>
+        /// Changes the states of a tool strip button.
+        /// </summary>
+        /// <param name="buttonName">The name of the button.</param>
+        /// <param name="state">The new state of the button.</param>
+        void SetToolStripButtonStatus(String buttonName, Form1.ButtonState state);
+
+        /// <summary>
+        /// Displays an image in the left Picture box.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        void DisplayInLeftPictureBox(Image img);
+
+        /// <summary>
+        /// Displays an image in the right Picture box.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        void DisplayInRightPictureBox(Image img);
+
+        /// <summary>
+        /// shows the given info message in a popup and asks the user to aknowledge it
+        /// </summary>
+        /// <param name="message">the message to show</param>
+        void ShowInfoMessage(String message);
+
+        /// <summary>
+        /// Shows a warning box with the given message (Yes/No Buttons)and returns true if the user aknowledges it.
+        /// </summary>
+        /// <param name="message">The message of the warning.</param>
+        /// <returns>True if the user confirms (Yes), negative if he doesn't (No)</returns>
+        bool ShowWarning(String message);
+    }
+}

+ 251 - 0
SketchAssistant/SketchAssistant/RedrawAssistant.cs

@@ -0,0 +1,251 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    public class RedrawAssistant
+    {
+        /// <summary>
+        /// The lines of the left image, with a boolean indicating if they have been redrawn
+        /// and an integer that is the same as the line id of the respective line in the right image.
+        /// </summary>
+        List<Tuple<Line, bool, int>> linesToRedraw;
+        /// <summary>
+        /// The Start and End points of all lines in linesToRedraw in the same order.
+        /// </summary>
+        List<Tuple<HashSet<Point>, HashSet<Point>>> startAndEndPoints;
+        /// <summary>
+        /// A Hashtable for quick lookup for a line id and its respective tuple in linesToRedraw
+        /// </summary>
+        Hashtable redrawnLineLookupTable;
+        /// <summary>
+        /// The position of the line currently being redrawn in the startAndEndPoints 
+        /// & linesToRedraw lists. -1 if no line is being redrawn.
+        /// </summary>
+        int lineBeingRedrawn;
+        /// <summary>
+        /// The id of the line being drawn on the right side. -1 if no line is being drawn.
+        /// </summary>
+        int currentLineID;
+        /// <summary>
+        /// Whether or not the user is currently redrawing a line.
+        /// </summary>
+        bool currentlyRedrawing;
+        /// <summary>
+        /// Whether or not the RedrawAssistant is active.
+        /// </summary>
+        bool isActive;
+        /// <summary>
+        /// The radius of the markers for redrawing.
+        /// </summary>
+        int markerRadius = 5;
+
+        /// <summary>
+        /// The Constructor for an inactive RedrawAssistant.
+        /// </summary>
+        public RedrawAssistant()
+        {
+            isActive = false;
+        }
+
+        /// <summary>
+        /// The constructor for an active RedrawAssistant
+        /// </summary>
+        /// <param name="redrawItem">The lines that shall be redrawn</param>
+        public RedrawAssistant(List<Line> redrawItem)
+        {
+            linesToRedraw = new List<Tuple<Line, bool, int>>();
+            startAndEndPoints = new List<Tuple<HashSet<Point>, HashSet<Point>>>();
+            isActive = true;
+            currentlyRedrawing = false;
+            lineBeingRedrawn = -1;
+            redrawnLineLookupTable = new Hashtable();
+            foreach (Line line in redrawItem)
+            {
+                linesToRedraw.Add(new Tuple<Line, bool, int>(line, false, -1));
+            }
+            SetMarkerRadius(5);
+        }
+
+        /// <summary>
+        /// Initialization function that returns the initial list of overlay points.
+        /// </summary>
+        /// <param name="mRad">The radius of the points.</param>
+        /// <returns>The list of overlay points.</returns>
+        public List<Tuple<bool, HashSet<Point>>> Initialize(int mRad)
+        {
+            if (isActive)
+            {
+                List<Tuple<bool, HashSet<Point>>> retList = new List<Tuple<bool, HashSet<Point>>>();
+                SetMarkerRadius(mRad);
+                foreach(Tuple<HashSet<Point>, HashSet<Point>> tup in startAndEndPoints)
+                {
+                    retList.Add(new Tuple<bool, HashSet<Point>>(false, tup.Item1));
+                    retList.Add(new Tuple<bool, HashSet<Point>>(false, tup.Item2));
+                }
+                return retList;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// The main functionality of the RedrawAssistant, which updates the Assistant according to the inputs given.
+        /// </summary>
+        /// <param name="currentPoint">The current position of the cursor, as a point</param>
+        /// <param name="rightLines">The lines on the right canvas</param>
+        /// <param name="currLineID">The id of the line currently being drawn.</param>
+        /// <param name="lineFinished">A boolean to indicate that the line is finished</param>
+        /// <param name="overlayItems">A list containing the overlay items and if they should be drawn.</param>
+        /// <returns>The updated List of overlay items, or the same list if no changes need to be done, 
+        /// along with a boolean indicating if something was changed</returns>
+        public Tuple<bool, List<Tuple<bool, HashSet<Point>>>> Tick(Point currentPoint, List<Tuple<bool, Line>> rightLines, int currLineID, bool lineFinished, 
+            List<Tuple<bool, HashSet<Point>>> overlayItems)
+        {
+            if (!isActive) { return new Tuple<bool, List<Tuple<bool, HashSet<Point>>>>(false, overlayItems); }
+
+            if (!currentlyRedrawing)
+            {
+
+            }
+            /*
+            Tuple<Line, bool, int> newLineTuple = null;
+            var returnAllStartPoints = true;
+            CheckForUndrawnLines(rightLines);
+            
+            // Checking if a startpoint is intersected
+            if (!currentlyRedrawing)
+            {
+                for (int i = 0; i < linesToRedraw.Count; i++)
+                {
+                    Tuple<Line, bool, int> tup = linesToRedraw[i];
+                    if (!tup.Item2)
+                    {
+                        if (startAndEndPoints[i].Item1.Contains(currentPoint))
+                        {
+                            currentlyRedrawing = true;
+                            lineBeingRedrawn = i;
+                            currentLineID = currLineID;
+                            returnList.Add(startAndEndPoints[i].Item1);
+                            returnList.Add(startAndEndPoints[i].Item2);
+                            returnAllStartPoints = false;
+                        }
+                    }
+                }
+            }
+            //Currently redrawing a line, but a line hasn't been finished drawing.
+            else if (!lineFinished)
+            {
+                returnList.Add(startAndEndPoints[lineBeingRedrawn].Item1);
+                returnList.Add(startAndEndPoints[lineBeingRedrawn].Item2);
+                returnAllStartPoints = false;
+            }
+            //Line is finished, check if it is in the correct endpoint
+            else if (currLineID == currentLineID && startAndEndPoints[lineBeingRedrawn].Item2.Contains(currentPoint))
+            {
+                newLineTuple = new Tuple<Line, bool, int>(linesToRedraw[lineBeingRedrawn].Item1, true, currLineID);
+                currentlyRedrawing = false;
+                lineBeingRedrawn = -1;
+                currentLineID = -1;
+            }
+            //Line is finished, but not in the correct endpoint
+            else
+            {
+                currentlyRedrawing = false;
+                lineBeingRedrawn = -1;
+                currentLineID = -1;
+            }
+
+            //Replace the changed line tuple in linesToRedraw
+            if(newLineTuple != null)
+            {
+                var newLine = newLineTuple.Item1;
+                for (int i = 0; i < linesToRedraw.Count; i++)
+                {
+                    var redrawLine = linesToRedraw[i].Item1;
+                    if (redrawLine.GetID() == newLine.GetID() 
+                        && redrawLine.GetStartPoint().Equals(newLine.GetStartPoint())
+                        && redrawLine.GetEndPoint().Equals(newLine.GetEndPoint()))
+                    {
+                        redrawnLineLookupTable.Add(currLineID, i);
+                        linesToRedraw[i] = newLineTuple;
+                    }
+                }
+            }
+
+            //Add all the startpoints to the list being returned
+            if (returnAllStartPoints)
+            {
+                for (int i = 0; i < linesToRedraw.Count; i++)
+                {
+                    if (!linesToRedraw[i].Item2)
+                    {
+                        returnList.Add(startAndEndPoints[i].Item1);
+                    }
+                }
+            }
+            return returnList;
+            */
+            return new Tuple<bool, List<Tuple<bool, HashSet<Point>>>>(false, overlayItems);
+        }
+
+        /// <summary>
+        /// A helping function which checks for lines where previously redrawn, but were removed from the image again.
+        /// </summary>
+        /// <param name="rightLines">The lines in the right image.</param>
+        private void CheckForUndrawnLines(List<Tuple<bool, Line>> rightLines)
+        {
+            for (int i = 0; i < rightLines.Count; i++)
+            {
+                if (redrawnLineLookupTable.ContainsKey(rightLines[i].Item2.GetID()))
+                {
+                    if (!rightLines[i].Item1)
+                    {
+                        int listPos = (int)redrawnLineLookupTable[rightLines[i].Item2.GetID()];
+                        var oldTup = linesToRedraw[listPos];
+                        linesToRedraw[listPos] = new Tuple<Line, bool, int>(oldTup.Item1, false, -1);
+                    }
+                    else
+                    {
+                        int listPos = (int)redrawnLineLookupTable[rightLines[i].Item2.GetID()];
+                        var oldTup = linesToRedraw[listPos];
+                        linesToRedraw[listPos] = new Tuple<Line, bool, int>(oldTup.Item1, true, rightLines[i].Item2.GetID());
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// A function to set the marker radius for the markers returned by the RedrawAssistant
+        /// </summary>
+        /// <param name="markerRad">The Radius of the markers.</param>
+        public void SetMarkerRadius(int markerRad)
+        {
+            markerRadius = markerRad;
+            if (isActive)
+            {
+                startAndEndPoints = new List<Tuple<HashSet<Point>, HashSet<Point>>>();
+                foreach (Tuple<Line, bool, int> tup in linesToRedraw)
+                {
+                    startAndEndPoints.Add(CalculateStartAndEnd(tup.Item1));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Will calculate the start and endpoints of the given line.
+        /// </summary>
+        /// <param name="line">The given line.</param>
+        private Tuple<HashSet<Point>, HashSet<Point>> CalculateStartAndEnd(Line line)
+        {
+            var circle0 = GeometryCalculator.FilledCircleAlgorithm(line.GetStartPoint(), markerRadius);
+            var circle1 = GeometryCalculator.FilledCircleAlgorithm(line.GetEndPoint(), markerRadius);
+            var currentLineEndings = new Tuple<HashSet<Point>, HashSet<Point>>(circle0, circle1);
+            return currentLineEndings;
+        }
+    }
+}

+ 5 - 0
SketchAssistant/SketchAssistant/SketchAssistant.csproj

@@ -69,8 +69,13 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="MVP_View.cs" />
+    <Compile Include="MVP_Presenter.cs" />
+    <Compile Include="MVP_Model.cs" />
+    <Compile Include="RedrawAssistant.cs" />
     <Compile Include="FileImporter.cs" />
     <Compile Include="FileImporterException.cs" />
+    <Compile Include="GeometryCalculator.cs" />
     <Compile Include="SketchAction.cs" />
     <Compile Include="ActionHistory.cs" />
     <Compile Include="Line.cs" />