Martin Edlund 5 лет назад
Родитель
Сommit
929ba37648

+ 1 - 0
SketchAssistant/.gitignore

@@ -0,0 +1 @@
+/GeneratedReports/

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
SketchAssistant/SketchAssistantWPF/DebugData.cs


+ 64 - 16
SketchAssistant/SketchAssistantWPF/GeometryCalculator.cs

@@ -12,13 +12,58 @@ namespace SketchAssistantWPF
     /// </summary>
     public static class GeometryCalculator
     {
+        /// <summary>
+        /// Calculate the approximate similarity of two lines. 
+        /// Using three weighted parameters to calculate a value between 0 and 1 to indicate the similarity of the lines.
+        /// </summary>
+        /// <param name="l0">The first line.</param>
+        /// <param name="l1">The second line.</param>
+        /// <returns>The similarity of the two lines.</returns>
+        public static double CalculateSimilarity(InternalLine l0, InternalLine l1)
+        {
+            double CosSim = Math.Abs(CalculateAverageCosineSimilarity(l0, l1));
+            double LenSim = CalculateLengthSimilarity(l0, l1);
+            double AvDist = CalculateAverageDistance(l0, l1);
+            double DistSim = (50 - AvDist) / 50;
+            if (DistSim < 0) DistSim = 0;
+            if (CosSim < 0.5) CosSim = 0;
+            double output = (2 * CosSim + LenSim + DistSim) / 4;
+            System.Diagnostics.Debug.WriteLine("Results: CosSim: {0}, LenSim: {1}, AvDist {2}, DistSim: {3}. Total: {4}", 
+                CosSim, LenSim, AvDist, DistSim, output);
+            return output;
+        }
+
+        /// <summary>
+        /// The cosine similarity of two vectors.
+        /// </summary>
+        /// <param name="v0">The first vector</param>
+        /// <param name="v1">The second vector</param>
+        /// <returns>The cosine similarity</returns>
+        private static double CosineSimilarity(Vector v0, Vector v1)
+        {
+            return (v0.X * v1.X + v0.Y * v1.Y) / (Math.Sqrt(v0.X * v0.X + v0.Y * v0.Y) * Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y));
+        }
+
+        /// <summary>
+        /// An approximate calculation of the average cosine similarity 
+        /// of two lines, achieved by calculating the cosine similarity of subvectors.
+        /// </summary>
+        /// <param name="l0">The first line</param>
+        /// <param name="l1">The second line</param>
+        /// <returns>The approximate average cosine similarity of all subvectors</returns>
         public static double CalculateAverageCosineSimilarity(InternalLine l0, InternalLine l1)
         {
+            //check if one of the lines is a point, or both lines are points
+            if ((l0.isPoint && !l1.isPoint) || (l1.isPoint && !l0.isPoint)) return 0;
+            else if (l0.isPoint && l1.isPoint) return 1;
+
             List<Point> points0 = l0.GetPoints();
             List<Point> points1 = l1.GetPoints();
 
             if (points0.Count == points1.Count)
             {
+                //If the two lists have an equal amount of subvectors, 
+                //compare the nth subvectors from each list and average the value.
                 double sum = 0; int i = 0;
                 List<Point> shortL = points0; List<Point> longL = points1;
                 for (; i < shortL.Count - 1; i++)
@@ -32,12 +77,16 @@ namespace SketchAssistantWPF
             }
             else
             {
+                //Determine if the longer list is of similar length or contains significatly more items
                 List<Point> shortL = points0; List<Point> longL = points0;
                 if (points0.Count < points1.Count) { longL = points1; }
                 if (points0.Count > points1.Count) { shortL = points1;}
                 double dif = (longL.Count - 1) / (shortL.Count - 1);
                 if(dif > 1)
                 {
+                    //The longer list is significantly longer
+                    //Each element in the shorter list is compared to multiple 
+                    // elements in the longer list to make up the difference
                     double sum = 0; int adds = 0;
 
                     for (int i = 0; i < shortL.Count - 1; i++)
@@ -55,6 +104,8 @@ namespace SketchAssistantWPF
                 }
                 else
                 {
+                    //The longer list is almost the same length as the shorter list
+                    //The remaining items are simply skipped
                     double sum = 0; int i = 0;
                     for (; i < shortL.Count - 1; i++)
                     {
@@ -68,21 +119,17 @@ namespace SketchAssistantWPF
             }
         }
 
-        public static double CalculateSimilarity(InternalLine l0, InternalLine l1)
-        {
-            double CosSim = Math.Abs(CalculateAverageCosineSimilarity(l0, l1));
-            double LenSim = CalculateLengthSimilarity(l0, l1);
-            double AvDist = CalculateAverageDistance(l0, l1);
-            double DistSim = (50 - AvDist)/ 50;
-            if (DistSim < 0) DistSim = 0;
-
-            return (CosSim + LenSim + DistSim)/3;
-        }
-
+        /// <summary>
+        /// Calculate the similarity in length of two Lines.
+        /// </summary>
+        /// <param name="l0">The first line.</param>
+        /// <param name="l1">The second line.</param>
+        /// <returns>How similar the lines are in length.</returns>
         private static double CalculateLengthSimilarity(InternalLine l0, InternalLine l1)
         {
             double len0 = l0.GetLength(); double len1 = l1.GetLength();
             var dif = Math.Abs(len1 - len0);
+            if (dif == 0) return 1;
             double shorter;
             if (len1 > len0) shorter = len0;
             else shorter = len1;
@@ -90,6 +137,12 @@ namespace SketchAssistantWPF
             return (shorter - dif )/shorter;
         }
 
+        /// <summary>
+        /// Calculate the average distance between the ends of two lines.
+        /// </summary>
+        /// <param name="l0">The first line.</param>
+        /// <param name="l1">The second line.</param>
+        /// <returns>The shortest average distance between the ends of the lines.</returns>
         private static double CalculateAverageDistance(InternalLine l0, InternalLine l1)
         {
             List<Point> points0 = l0.GetPoints();
@@ -102,11 +155,6 @@ namespace SketchAssistantWPF
             else return (distfirstlast + distlastfirst) / 2;
         }
 
-        public static double CosineSimilarity(Vector v0, Vector v1)
-        {
-            return (v0.X * v1.X + v0.Y * v1.Y) / (Math.Sqrt(v0.X * v0.X + v0.Y * v0.Y) * Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y));
-        }
-
         /// <summary>
         /// A simple algorithm that returns a filled circle with a radius and a center point.
         /// </summary>

+ 2 - 2
SketchAssistant/SketchAssistantWPF/MainWindow.xaml.cs

@@ -112,7 +112,7 @@ namespace SketchAssistantWPF
         public void RightCanvas_StrokeCollection(object sender, InkCanvasStrokeCollectedEventArgs e)
         {
             strokeCollection.Add(e.Stroke);
-            System.Diagnostics.Debug.WriteLine(strokeCollection.Count);
+            //System.Diagnostics.Debug.WriteLine(strokeCollection.Count);
         }
 
         /// <summary>
@@ -172,7 +172,7 @@ namespace SketchAssistantWPF
                 ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up);
                 RightCanvas.Strokes.RemoveAt(0);
                 strokeCollection.RemoveAt(0);
-                System.Diagnostics.Debug.WriteLine(strokeCollection.Count);
+                //System.Diagnostics.Debug.WriteLine(strokeCollection.Count);
             }
             //System.Diagnostics.Debug.WriteLine("ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up);");
         }

+ 43 - 1
SketchAssistant/WhiteTests/UITest.cs

@@ -16,10 +16,11 @@ using System.Collections.Generic;
 using System.Text.RegularExpressions;
 using WindowsInput;
 using WindowsInput.Native;
+using System.Threading.Tasks;
 
 namespace WhiteTests
 {
-
+    
     [TestClass]
     public class UITest
     {
@@ -680,4 +681,45 @@ namespace WhiteTests
             }
         }
     }
+
+    [TestClass]
+    public class SimilarityCalculationTests
+    {
+        /// <summary>
+        /// The debug data element used to generate random lines.
+        /// </summary>
+        private DebugData DebugData = new DebugData();
+        
+        /// <summary>
+        /// Generates random lines and tests how similar they are. 
+        /// To test the similarity score always stays between 0 and 1.
+        /// </summary>
+        [TestMethod]
+        public void StaysWithinParameters()
+        {
+            Parallel.For(1,500,
+                i =>
+                {
+                    InternalLine l0 = DebugData.GetRandomLine(1, (uint) i);
+                    InternalLine l1 = DebugData.GetRandomLine(1, (uint)i);
+                    var sim = GeometryCalculator.CalculateSimilarity(l0, l1);
+                    Assert.IsTrue((sim >= 0));
+                    Assert.IsTrue((sim <= 1));
+                } );
+        }
+        
+        [TestMethod]
+        public void CorrectSimilarity()
+        {
+            Parallel.ForEach(DebugData.GetSimilarityTestData(),
+                tup =>
+                {
+                    InternalLine l0 = tup.Item1;
+                    InternalLine l1 = tup.Item2;
+                    var sim = GeometryCalculator.CalculateSimilarity(l0, l1);
+                    Assert.AreEqual(tup.Item3, sim, 0.00000001);
+                });
+        }
+
+    }
 }

Некоторые файлы не были показаны из-за большого количества измененных файлов