/// <summary>
            /// Calculates the similarity between this point and either 1 or 2 previous points representing a line segment
            /// This function decides how appropriately this point would fit into a path joining 'point'
            /// Comparison factors include: thickness of this valley compared to the last, valley colour, relative directions of the valleys
            /// </summary>
            /// <param name="point">Point to compare with</param>
            /// <param name="previousPoint">Point prior to 'point', if applicable</param>
            /// <returns>A floating-point similarity value between 0 and 1 where 1 is virtually identical</returns>
            public SimilarityPack CalculateSimilarity(EdgePoint point, EdgePoint previousPoint = null)
            {
                SimilarityPack similarity = new SimilarityPack()
                {
                    Colour    = ImageMath.PixelDifference(ColourUnderPoint, point.ColourUnderPoint),
                    Direction = 1.0f,
                    Length    = 1.0f,
                    Width     = 1.0f,
                    Distance  = 1.0f,
                };

                if (previousPoint != null)
                {
                    Vector2 previousVector = new Vector2(point.X - previousPoint.X, point.Y - previousPoint.Y);
                    Vector2 currentVector  = new Vector2(X - point.X, Y - point.Y);

                    if (previousVector.LengthSquared() > 0 && currentVector.LengthSquared() > 0)
                    {
                        // Direction similarity: Use the dot product of the normalised segment vectors
                        similarity.Direction = Vector2.Dot(previousVector / previousVector.Length(), currentVector / currentVector.Length());

                        // Length similarity: Use the smaller length divided by the bigger length.....?
                        similarity.Length = previousVector.Length() / currentVector.Length();

                        if (similarity.Length > 1.0f)
                        {
                            similarity.Length = 1.0f / similarity.Length; // swap the division operands lazily
                        }
                    }
                }

                if (point.LastPoint != null && LastPoint != null)
                {
                    // Width similarity: Use the smaller width divided by the bigger width?
                    similarity.Width = Vector2.Distance(new Vector2(X, Y), new Vector2(LastPoint.X, LastPoint.Y)) /
                                       Vector2.Distance(new Vector2(point.X, point.Y), new Vector2(point.LastPoint.X, point.LastPoint.Y));

                    if (similarity.Width > 1.0f)
                    {
                        similarity.Width = 1.0f / similarity.Width;
                    }
                }

                if (previousPoint == null)
                {
                    float distanceToPoint = Vector2.Distance(new Vector2(X, Y), new Vector2(point.X, point.Y));
                    similarity.Distance = distanceToPoint > 0 ? 1.0f / distanceToPoint : 1.0f;
                }

                return(similarity);
            }
        private void ConnectEdgePoints(IEnumerable <EdgePoint>[] gridLines, List <Highlighter> highlighters)
        {
            // We want to join lines of similar edge lengths together. If we're coming from the tips of the fingers, we're fine increasing the width over time
            // If we're coming from the opposite, we're fine decreasing the width
            // Basically, we want to track whether the width increases or decreases as we go along
            List <EdgePoint> finalEdgeList = new List <EdgePoint>();

            for (int i = Input.LastClickPosition.X / gridInterval; i < gridLines.Count(); ++i)
            {
                EdgePoint      mostSimilarPoint  = null;
                SimilarityPack highestSimilarity = new SimilarityPack();

                foreach (EdgePoint p in gridLines[i])
                {
                    SimilarityPack similarity;

                    if (finalEdgeList.Count == 0)
                    {
                        similarity          = new SimilarityPack();
                        similarity.Distance = 1.0f / ((p.X - Input.LastClickPosition.X) * (p.X - Input.LastClickPosition.X) + (p.Y - Input.LastClickPosition.Y) * (p.Y - Input.LastClickPosition.Y));
                    }
                    else if (finalEdgeList.Count == 1)
                    {
                        similarity = p.CalculateSimilarity(finalEdgeList[0], null);
                    }
                    else
                    {
                        similarity = p.CalculateSimilarity(finalEdgeList[finalEdgeList.Count - 1], finalEdgeList[finalEdgeList.Count - 2]);
                    }

                    if (similarity.OverallSimilarity >= highestSimilarity.OverallSimilarity)
                    {
                        mostSimilarPoint  = p;
                        highestSimilarity = similarity;
                    }
                }

                finalEdgeList.Add(mostSimilarPoint);
                DebugInfo += highestSimilarity.Info + "\r\n";
            }

            for (int i = 1; i < finalEdgeList.Count; ++i)
            {
                highlighters.Add(new EdgeHighlighter(new Point(finalEdgeList[i - 1].X, finalEdgeList[i - 1].Y), new Point(finalEdgeList[i].X, finalEdgeList[i].Y))
                {
                    Pen = new Pen(Color.Green, 1.0f)
                });
            }
        }