/// <summary>
 /// Constructor for node model
 /// </summary>
 /// <param name="node1">The first of two nodes the line connects</param>
 /// <param name="node2">The second of two nodes that the line connects</param>
 /// <param name="color">The color of the line when drawn</param>
 public Line(Node node1, Node node2, Color color)
 {
     if (node1.X < node2.X || node1.X == node2.X && node1.Y < node2.Y)
     {
         this.node1 = node1;
         this.node2 = node2;
     }
     else
     {
         this.node1 = node2;
         this.node2 = node1;
     }
     lineColor = color;
 }
        /// <summary>
        /// Calculates the angle between two nodes
        /// </summary>
        /// <param name="nodeA">Base node, assumed to be lowest of both nodes</param>
        /// <param name="nodeB">Measured node, should be equal to or higher in height than base node</param>
        /// <returns>The angle, in degrees, between the two nodes; angle is on [0, 180] degrees</returns>
        private double AngleBetweenPoints(Node nodeA, Node nodeB)
        {
            int yPrime = nodeA.Y - nodeB.Y;
            int xPrime = nodeA.X - nodeB.X;

            double z = Math.Sqrt(xPrime * xPrime + yPrime * yPrime);

            double angle = (180 / Math.PI) * Math.Asin(yPrime / z);

            if (xPrime == 0)
            {
                return 90;
            }
            else if (xPrime > 0)
            {
                return 180 - angle;
            }
            else
            {
                return angle;
            }
        }
 /// <summary>
 /// Draws a single node on the graph
 /// </summary>
 /// <param name="node">The node to draw</param>
 private void DrawNode(Node node)
 {
     float halfRadius = radius / 2.0f;
     using (Graphics g = Graphics.FromImage(self))
     {
         g.FillRectangle(new SolidBrush(node.NodeColor), node.X - halfRadius, node.Y - halfRadius, 2 * radius, 2 * radius);
     }
 }
 /// <summary>
 /// Computes the cross product of three points
 /// </summary>
 /// <param name="p1">First node</param>
 /// <param name="p2">Second node</param>
 /// <param name="p3">Third node</param>
 /// <returns>Positive number if left turn, negative number if right turn, 0 if co-linear</returns>
 private int CrossProduct(Node p1, Node p2, Node p3)
 {
     return (p3.X - p1.X) * (p2.Y - p1.Y) - (p2.X - p1.X) * (p3.Y - p1.Y);
 }
        /// <summary>
        /// Determines if the line drawn from nodeA to nodeB split the other nodes such that all other nodes fall on one side
        /// </summary>
        /// <param name="nodes">List of nodes to check</param>
        /// <param name="nodeA">First node of potential hull line</param>
        /// <param name="nodeB">Second node of potential hull line</param>
        /// <returns>True if line from nodeA to nodeB belongs in the Convex Hull</returns>
        private bool ComputeStep(List<Node> nodes, Node nodeA, Node nodeB)
        {
            bool? IsLeftTurnExpected = null;

            foreach (Node nodeC in nodes)
            {
                if (nodeA == nodeC || nodeB == nodeC)
                {
                    continue;
                }

                int test = CrossProduct(nodeA, nodeB, nodeC);

                if (IsLeftTurnExpected == null)
                {
                    IsLeftTurnExpected = (test < 0);
                }

                if (test == 0)
                {
                    continue;
                }
                if (IsLeftTurnExpected == true && test > 0)
                {
                    return false;
                }
                else if (IsLeftTurnExpected == false && test < 0)
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Calculates and sorts a list of nodes by angel
        /// </summary>
        /// <param name="nodes">The nodes to sort</param>
        /// <param name="baseNode">The node to sort with respect to</param>
        /// <returns>A list of nodes sorted by angle from the base node counter-clockwise</returns>
        private List<Node> SortByAngle(List<Node> nodes, Node baseNode)
        {
            var nodeAngles = new Dictionary<Node, Double>();

            foreach (Node node in nodes)
            {
                if (node == baseNode)
                {
                    continue;
                }

                double angle = AngleBetweenPoints(baseNode, node);

                nodeAngles.Add(node, angle);
            }

            List<KeyValuePair<Node, Double>> nodeAngleList = nodeAngles.ToList();

            nodeAngleList.Sort(
                (firstPair, secondPair) =>
                {
                    return firstPair.Value.CompareTo(secondPair.Value);
                });

            List<Node> sortedNodes = new List<Node>();

            foreach (KeyValuePair<Node, Double> node in nodeAngleList)
            {
                sortedNodes.Add(node.Key);
            }

            return sortedNodes;
        }