// key difference between a static and a non-static method is that static method belongs to a class while non-static method belongs to the instance
                        public static double angle_between(edge_store with_edge, edge_store the_edge)
            {
                double v1_x, v1_y;
                double v2_x, v2_y;
                double normalzie;

                // vector with edge
                v1_x      = with_edge.end_pt.x - with_edge.start_pt.x;
                v1_y      = with_edge.end_pt.y - with_edge.start_pt.y;
                normalzie = Math.Sqrt(Math.Pow(v1_x, 2) + Math.Pow(v1_y, 2));

                v1_x = v1_x / normalzie;
                v1_y = v1_y / normalzie;

                // vector the edge
                v2_x      = the_edge.end_pt.x - the_edge.start_pt.x;
                v2_y      = the_edge.end_pt.y - the_edge.start_pt.y;
                normalzie = Math.Sqrt(Math.Pow(v2_x, 2) + Math.Pow(v2_y, 2));

                v2_x = v2_x / normalzie;
                v2_y = v2_y / normalzie;

                // sin and cos of the two vectors
                double sin = (v1_x * v2_y) - (v2_x * v1_y);
                double cos = (v1_x * v2_x) + (v1_y * v2_y);

                double angle = (Math.Atan2(sin, cos) / Math.PI) * 180f;

                if (angle <= 0) // there is no zero degree (zero degree = 360 degree) to avoid the vertical line mismatch
                {
                    angle += 360f;
                }

                return(angle);
            }
            public edge_store find_intial_baseLR(List <point_store> left, List <point_store> right)
            {
                point_store left_end = left[left.Count - 1];               // left end // Colinear error fixed
                                point_store right_end = right[0];          // right end

                edge_store left_bot_edge  = left_end.cw_vertical_edge(0);  // First Vertical edge at clock wise direction at this point
                edge_store right_bot_edge = right_end.cc_vertical_edge(0); // First Vertical edge at counter clock wise direction at this point

                while (true)
                {
                                                                              // Select the bottom most end by comparing the orientation with the other
                        if (leftof(right_end, left_bot_edge) == true)         // check the right_end point and orientation of the left edge
                    {
                        left_end      = left_bot_edge.the_other_pt(left_end); // Find the next point (whihc is the endpoint of the left edge)
                        left_bot_edge = left_end.cw_vertical_edge(0);
                    }
                    else if (rightof(left_end, right_bot_edge) == true)          // check the left_end point and orientation of the right edge
                    {
                        right_end      = right_bot_edge.the_other_pt(right_end); // Find the next point (which is the endpoint of the right edge)
                        right_bot_edge = right_end.cc_vertical_edge(0);
                    }
                    else
                    {
                        break;
                    }
                }

                add_edge(left_end, right_end);                          // Add the base LR edge
                                return(edge_list[edge_list.Count - 1]); // return the last add item (which is the baseLR edge)

                           
            }
            private void add_to_local_list(edge_store e, triangle_store t)
            {
                //____________________________________________________________________________________________________________________________________________________________________
                // !! Addition on main list here
                //Form1.planar_object_store.point2d spt = local_input_points.Find(obj => obj.Equals(new Form1.planar_object_store.point2d(e.start_pt.pt_id, e.start_pt.x, e.start_pt.y)));
                //Form1.planar_object_store.point2d ept = local_input_points.Find(obj => obj.Equals(new Form1.planar_object_store.point2d(-1, e.end_pt.x, e.end_pt.y)));
                Form1.planar_object_store.edge2d temp_edge = new Form1.planar_object_store.edge2d(e.edge_id, e.start_pt.get_parent_data_type, e.end_pt.get_parent_data_type);
                local_output_edges.Add(temp_edge);

                if (t != null)
                {
                    Form1.planar_object_store.face2d temp_face = new Form1.planar_object_store.face2d(t.tri_id, t.p1.get_parent_data_type, t.p2.get_parent_data_type, t.p3.get_parent_data_type);
                    local_output_triangle.Add(temp_face);
                }

                                // #################################################################
                                Form1.planar_object_store.instance_tracker temp_edge_tracker = new Form1.planar_object_store.instance_tracker();

                temp_edge_tracker.edge_list = new List <Form1.planar_object_store.edge2d>();
                temp_edge_tracker.edge_list.AddRange(local_output_edges);
                temp_edge_tracker.face_list = new List <Form1.planar_object_store.face2d>();
                temp_edge_tracker.face_list.AddRange(local_output_triangle);
                local_history_tracker.Add(temp_edge_tracker);
                                // #################################################################
            }
 public bool Equals_without_orientation(edge_store other)
 {
     if ((other.Equals(this) == true) || (other.Equals(this.sym) == true))
     {
         return(true);
     }
     return(false);
 }
 public bool Equals(edge_store other)
 {
     if (other.start_pt.Equals(this._start_pt) == true && other.end_pt.Equals(this._end_pt) == true)
     {
         return(true);
     }
     return(false);
 }
            private void add_to_local_edge_list(edge_store e)
            {
                //____________________________________________________________________________________________________________________________________________________________________
                // !! Addition on main list here
                Form1.planar_object_store.edge2d temp_edge = new Form1.planar_object_store.edge2d(e.edge_id, e.start_pt.get_parent_data_type, e.end_pt.get_parent_data_type);

                local_output_edges.Add(temp_edge);
            }
                public void delete_edge(edge_store edge_to_delete)
                {
                    int edge_index = this._connected_edge_list.FindIndex(obj => obj.Equals(edge_to_delete));

                    if (edge_index != -1)
                    {
                        this._connected_edge_list.RemoveAt(edge_index);
                    }
                }
            private void remove_from_local_edge_list(edge_store e)
            {
                //____________________________________________________________________________________________________________________________________________________________________
                // !! Addition on main list here
                Form1.planar_object_store.edge2d temp_edge = new Form1.planar_object_store.edge2d(e.edge_id, e.start_pt.get_parent_data_type, e.end_pt.get_parent_data_type);
                int temp_id = local_output_edges.FindLastIndex(obj => obj.edge_id == e.edge_id);

                local_output_edges.RemoveAt(temp_id);
                //local_output_edges.Remove(temp_edge);
            }
            public void delaunay_divide_n_conquer(List <point_store> left_list, List <point_store> right_list)
            {
                                // main divide and conquer recursive function

                                // Left
                                if (left_list.Count > 3)
                {
                    int half_length = Convert.ToInt32(Math.Ceiling(left_list.Count / 2.0f));
                    List <point_store> left_left_list = left_list.GetRange(0, half_length);                                                  // extract the left list
                                        List <point_store> left_right_list = left_list.GetRange(half_length, left_list.Count - half_length); // extract the right list
                                                                                                                                             // delaunay divide and conquer
                    delaunay_divide_n_conquer(left_left_list, left_right_list);
                }
                else
                {
                    if (left_list.Count == 3)
                    {
                        add_triangle(left_list[0], left_list[1], left_list[2]);
                    }
                    else // pts.count == 2
                    {
                                            {
                            add_edge(left_list[0], left_list[1]);
                        }
                    }
                }

                                // Right
                                if (right_list.Count > 3)
                {
                    int half_length = Convert.ToInt32(Math.Ceiling(right_list.Count / 2.0f));
                    List <point_store> right_left_list = right_list.GetRange(0, half_length);                                                   // extract the left list
                                        List <point_store> right_right_list = right_list.GetRange(half_length, right_list.Count - half_length); // extract the right list
                                                                                                                                                // delaunay divide and conquer
                    delaunay_divide_n_conquer(right_left_list, right_right_list);
                }
                else
                {
                    if (right_list.Count == 3)
                    {
                        add_triangle(right_list[0], right_list[1], right_list[2]);
                    }
                    else // pts.count == 2
                    {
                                            {
                            add_edge(right_list[0], right_list[1]);
                        }
                    }
                }

                edge_store baseLR = find_intial_baseLR(left_list, right_list);

                //Link LR edges
                Merge_LRedges(baseLR);
            }
 public bool contains_edge(edge_store the_edge)
 {
     // find whether the edge belongs to the triangle
     if (the_edge.Equals_without_orientation(this._e1) == true ||
         the_edge.Equals_without_orientation(this._e2) == true ||
         the_edge.Equals_without_orientation(this._e3) == true)
     {
         return(true);
     }
     return(false);
 }
 public bool equal_edge(edge_store other_e)
 {
     if (other_e.Equals(this.e1) == true || other_e.Equals(this.e2) == true || other_e.Equals(this.e3) == true)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
                private edge_store get_edge_away_from_this_pt(edge_store the_edge)
                {
                    // This function returns the edge oriented from this point
                    point_store this_pt = new point_store(this._pt_id, this._x, this._y, this.store_parent_data);

                    if (the_edge.start_pt.Equals(this_pt) == false)
                    {
                        return(new edge_store(the_edge.edge_id, this_pt, the_edge.the_other_pt(this_pt)));
                    }
                    else
                    {
                        return(the_edge);
                    }
                }
            private void add_edge(point_store p1, point_store p2)
            {
                int        edge_id = get_unique_edge_id();
                edge_store e       = new edge_store(edge_id, p1, p2);

                // Update the points p1 & p2 -> edge id lists
                // Note points are never removed from the list so indexing is easier (pt_id remains the same)
                pt_list[p1.pt_id].add_sorted_edge(e);
                pt_list[p2.pt_id].add_sorted_edge(e);

                edge_list.Add(e); // Add the edge e to the list

                add_to_local_list(e, null);
            }
            private void delete_from_local_list(edge_store e, int t1_id, int t2_id)
            {
                Form1.planar_object_store.edge2d temp_edge, temp_edge_sym;
                int rem_index;

                // edge e
                // !! removal on main list here
                temp_edge     = new Form1.planar_object_store.edge2d(e.edge_id, e.start_pt.get_parent_data_type, e.end_pt.get_parent_data_type);
                temp_edge_sym = new Form1.planar_object_store.edge2d(e.edge_id, e.end_pt.get_parent_data_type, e.start_pt.get_parent_data_type);

                rem_index = local_output_edges.FindIndex(obj => obj.Equals(temp_edge) || obj.Equals(temp_edge_sym));

                if (rem_index != -1)
                {
                    local_output_edges.RemoveAt(rem_index); // !! Deletion on main list here

                    if (t1_id != -1 || t2_id != -1)         // Check whether triangle need to be removed
                    {
                        if (t1_id < t2_id)                  // swap to remove in order
                        {
                            int temp = t1_id;
                            t1_id = t2_id;
                            t2_id = temp;
                        }

                        if (t1_id != -1)
                        {
                            int t1_index = local_output_triangle.FindIndex(obj => obj.face_id == triangle_list[t1_id].tri_id);
                            local_output_triangle.RemoveAt(t1_index);
                        }

                        if (t2_id != -1)
                        {
                            int t2_index = local_output_triangle.FindIndex(obj => obj.face_id == triangle_list[t2_id].tri_id);
                            local_output_triangle.RemoveAt(t2_index);
                        }
                    }


                    // #################################################################
                    Form1.planar_object_store.instance_tracker temp_edge_tracker = new Form1.planar_object_store.instance_tracker();
                    temp_edge_tracker.edge_list = new List <Form1.planar_object_store.edge2d>();
                    temp_edge_tracker.edge_list.AddRange(local_output_edges);
                    temp_edge_tracker.face_list = new List <Form1.planar_object_store.face2d>();
                    temp_edge_tracker.face_list.AddRange(local_output_triangle);
                    local_history_tracker.Add(temp_edge_tracker);
                    // #################################################################
                }
            }
                public edge_store cw_vertical_edge(edge_store with_edge) // clockwise vertical edge
                {
                    int index_of_next = this._connected_edge_list.FindIndex(obj => obj.edge_id == with_edge.edge_id);

                    if (index_of_next == -1)                                 // object not found
                    {
                        return(null);                                        // this should never happen
                    }
                    index_of_next--;                                         // next clockwise edge in the list
                    if (index_of_next == -1)                                 // check if the index reached begining
                    {
                        index_of_next = this._connected_edge_list.Count - 1; //cycle back to end (reverse)
                    }
                    return(cc_vertical_edge(index_of_next));                 //0,1,2,.....
                }
                public edge_store cc_vertical_edge(edge_store with_edge) //counter clockwise vertical edge
                {
                    int index_of_next = this._connected_edge_list.FindIndex(obj => obj.edge_id == with_edge.edge_id);

                    if (index_of_next == -1)                              // object not found
                    {
                        return(null);                                     // this should never happen
                    }
                    index_of_next++;                                      // next counter clockwise edge in the list
                    if (index_of_next == this._connected_edge_list.Count) // check if the index reached end
                    {
                        index_of_next = 0;                                //cycle back to zero
                    }
                    return(cc_vertical_edge(index_of_next));              //0,1,2,.....
                }
 public triangle_store(int i_tri_id, point_store i_p1, point_store i_p2, point_store i_p3, edge_store i_e1, edge_store i_e2, edge_store i_e3)
 {
     // Constructor
     // set id
     this._tri_id = i_tri_id;
     // set points
     this._pt1 = i_p1;
     this._pt2 = i_p2;
     this._pt3 = i_p3;
     // set edges
     this._e1 = i_e1;
     this._e2 = i_e2;
     this._e3 = i_e3;
     // set the mid point
     this._mid_pt = new point_store(-1, (this._pt1.x + this._pt2.x + this._pt3.x) / 3.0f, (this._pt1.y + this._pt2.y + this._pt3.y) / 3.0f, null);
 }
 public point_store get_other_pt(edge_store the_edge)
 {
     // Returns the third vertex of this triangle which is not part of the given edge
     if (the_edge.Equals_without_orientation(this.e1) == true)
     {
         return(this.e2.find_common_pt(this.e3));
     }
     else if (the_edge.Equals_without_orientation(this.e2) == true)
     {
         return(this.e3.find_common_pt(this.e1));
     }
     else if (the_edge.Equals_without_orientation(this.e3) == true)
     {
         return(this.e1.find_common_pt(this.e2));
     }
     return(null);
 }
                public void add_sorted_edge(edge_store edge_to_add)
                {
                    // Add the edges as counter clock wise to the sorted list
                    //     this_pt
                    //      |\    
                    //      | \ 
                    //      |  \ 
                    //      |   \
                    //      |    \
                    //      |     \
                    //      V      V
                    //  vertical   edge_0
                    //____________________________________________________________________________________

                    edge_to_add = get_edge_away_from_this_pt(edge_to_add); // Always add edge away from this point

                    if (this._connected_edge_list.Count == 0)
                    {
                        this._connected_edge_list.Add(edge_to_add);
                        return;
                    }

                    if (new edge_angle_comparer_vertical().Compare(this._connected_edge_list[this._connected_edge_list.Count - 1], edge_to_add) <= 0) // Equal to zero should not occur
                    {
                        this._connected_edge_list.Add(edge_to_add);
                        return;
                    }

                    if (new edge_angle_comparer_vertical().Compare(this._connected_edge_list[0], edge_to_add) >= 0) // Equal to zero should not occur
                    {
                        this._connected_edge_list.Insert(0, edge_to_add);                                           // Insert at zero because all the other angles are higher
                        return;
                    }

                    // Uses a binary search algorithm to locate a specific element in the sorted List<edge_store>
                    int index = this._connected_edge_list.BinarySearch(edge_to_add, new edge_angle_comparer_vertical());

                    if (index < 0)
                    {
                        index = ~index; // Bitwise Complement operator is represented by ~.It is a unary operator, i.e.operates on only one operand.The ~ operator inverts each bits i.e.changes 1 to 0 and 0 to 1.
                    }
                    this._connected_edge_list.Insert(index, edge_to_add);
                }
 public point_store find_common_pt(edge_store other_edge)
 {
     // Returns the common point of this edge and the other edges
     if (this.start_pt.Equals(other_edge.start_pt))
     {
         return(this.start_pt);
     }
     else if (this.start_pt.Equals(other_edge.end_pt))
     {
         return(this.start_pt);
     }
     else if (this.end_pt.Equals(other_edge.start_pt))
     {
         return(this.end_pt);
     }
     else if (this.end_pt.Equals(other_edge.end_pt))
     {
         return(this.end_pt);
     }
     return(null);
 }
 public bool commutative_equal(edge_store other) // commutative equals check edges with same two points but different orientation
                
 {
     return((this._start_pt.Equals(other.start_pt) && this._end_pt.Equals(other.end_pt)) ||
            (this._end_pt.Equals(other.start_pt) && this._start_pt.Equals(other.end_pt)));
 }
 public bool Equals(edge_store other) // orientation is important
                
 {
     return(this._start_pt.Equals(other.start_pt) && this._end_pt.Equals(other.end_pt));
 }
 private bool rightof(point_store x, edge_store e)
 {
     return(ccw(x, e.end_pt, e.start_pt));
 }
            public void Merge_LRedges(edge_store baseLRedge)
            {
                edge_store baseLRedge_sym = new edge_store(baseLRedge.edge_id, baseLRedge.end_pt, baseLRedge.start_pt); // symmetry of baseLRedge
                edge_store lcand          = baseLRedge.start_pt.cc_vertical_edge(baseLRedge);                           // left candidate
                edge_store rcand          = baseLRedge.end_pt.cw_vertical_edge(baseLRedge_sym);                         // rigth candidate

                // Left side Remove operation
                if (leftof(lcand.end_pt, baseLRedge) == true)                            // if the left candidate end point is not leftof baseLRedge then top is reached with baseLRedge and the end point of leftcandidate will not lie inCircle
                {
                    edge_store lcand_next = baseLRedge.start_pt.cc_vertical_edge(lcand); // find the next candidate by counter clockwise cycle at baseLRedge start point with the current left candidate as qualifier
                    while (incircle(baseLRedge.start_pt, baseLRedge.end_pt, lcand.end_pt, lcand_next.end_pt) == true)
                    {
                        edge_store new_lcand = baseLRedge.start_pt.cc_vertical_edge(lcand); // find the next candidate by counter clockwise cycle at baseLRedge start point with the current left candidate as qualifier
                        remove_edge(lcand.edge_id);
                        lcand      = new_lcand;
                        lcand_next = baseLRedge.start_pt.cc_vertical_edge(lcand);
                    }
                }

                // Right side Remove operation
                if (rightof(rcand.end_pt, baseLRedge_sym) == true)                     // if the right candidate end point is not rightof baseLRedge_sym then top is reached with baseLRedge and the end point of rightcandidate will not lie inCircle
                {
                    edge_store rcand_next = baseLRedge.end_pt.cw_vertical_edge(rcand); // find the next candidate by clockwise cycle at baseLRedge end point with the current right candidate as qualifier
                    while (incircle(baseLRedge_sym.end_pt, baseLRedge_sym.start_pt, rcand.end_pt, rcand_next.end_pt) == true)
                    {
                        edge_store new_rcand = baseLRedge.end_pt.cw_vertical_edge(rcand); // find the next candidate by clockwise cycle at baseLRedge end point with the current right candidate as qualifier
                        remove_edge(rcand.edge_id);
                        rcand      = new_rcand;
                        rcand_next = baseLRedge.end_pt.cw_vertical_edge(rcand);
                    }
                }


                bool lvalid, rvalid;

                lvalid = leftof(lcand.end_pt, baseLRedge);      // validity of left candidate
                rvalid = rightof(rcand.end_pt, baseLRedge_sym); // validity of right candidate

                // The next cross edge is to be connected to either lcand.end_pt or rcand.end_pt
                if (lvalid == true && rvalid == true)                                                         // both are valid, then choose the correct end with in-circle test
                {
                    if (incircle(baseLRedge.start_pt, baseLRedge.end_pt, lcand.end_pt, rcand.end_pt) == true) //right candidate end point lies inside in circle formed by left candidate
                    {
                        add_edge_with_triangle(baseLRedge.start_pt, rcand.end_pt);                            // so form the edge with right candidate end point
                    }
                    else // left candidate end point in cicle doesn't enclose right candidate end point
                    {
                        add_edge_with_triangle(lcand.end_pt, baseLRedge_sym.start_pt); // so form the edge with left candidate end point
                    }
                }
                else if (lvalid == true)
                {
                    add_edge_with_triangle(lcand.end_pt, baseLRedge_sym.start_pt);// Add cross edge base1 from lcand.end_pt to baseLRedge_sym.start_pt
                }
                else if (rvalid == true)
                {
                    add_edge_with_triangle(baseLRedge.start_pt, rcand.end_pt);// Add cross edge basel frombaseLRedge.start_pt to rcand.end_pt
                }
                else
                {
                    // both lcand and rcand are making obtuse angle with baseLRedge, then baseLRedge is the upper common tangent
                    return; // end of recursion
                }


                edge_store new_baseLRedge = edge_list[edge_list.Count - 1]; // new baseLRedge is the last created edge

                Merge_LRedges(new_baseLRedge);                              // Recursion here
            }
 private static bool leftof(point_store x, edge_store e)
 {
     return(ccw(x, e.start_pt, e.end_pt));
 }
            private void add_edge_with_triangle(point_store p1, point_store p2)
            {
                int        edge_id = get_unique_edge_id();
                edge_store e       = new edge_store(edge_id, p1, p2);

                // Update the points p1 & p2 -> edge id lists
                // Note points are never removed from the list so indexing is easier (pt_id remains the same)
                pt_list[p1.pt_id].add_sorted_edge(e);
                pt_list[p2.pt_id].add_sorted_edge(e);

                // Now find the other two edges connected to this edge forming a triangle
                bool       is_triangle_found = false;
                edge_store second_edge, third_edge;

                // clockwise search
                second_edge = e.end_pt.cc_vertical_edge(e);
                third_edge  = second_edge.end_pt.cc_vertical_edge(second_edge);

                if (third_edge.end_pt.Equals(e.start_pt) == true)
                {
                    is_triangle_found = true;
                }
                else
                {
                    // counter clockwise search
                    second_edge = e.end_pt.cw_vertical_edge(e);
                    third_edge  = second_edge.end_pt.cw_vertical_edge(second_edge);

                    if (third_edge.end_pt.Equals(e.start_pt) == true)
                    {
                        is_triangle_found = true;
                    }
                }
                edge_list.Add(e);              // Add the edge e to the list

                if (is_triangle_found == true) // must found otherwise something went wrong
                {
                    int tri_id = get_unique_triangle_id();

                    int second_edge_index, third_edge_index;

                    second_edge_index = edge_list.FindIndex(obj => obj.edge_id == second_edge.edge_id);
                    third_edge_index  = edge_list.FindIndex(obj => obj.edge_id == third_edge.edge_id);

                    edge_list[second_edge_index].add_triangle_id(tri_id); // got lazy.. need to develop more efficient method
                    edge_list[third_edge_index].add_triangle_id(tri_id);  // got lazy.. need to develop more efficient method

                    // Update the edge triangle id
                    edge_list[edge_list.Count - 1].add_triangle_id(tri_id);

                    //Add the triangle
                    triangle_list.Add(new triangle_store(tri_id, e.start_pt, e.end_pt, second_edge.the_other_pt(e.end_pt)));

                    triangle_list[triangle_list.Count - 1].e1 = edge_list[third_edge_index];
                    triangle_list[triangle_list.Count - 1].e2 = edge_list[second_edge_index];
                    triangle_list[triangle_list.Count - 1].e3 = edge_list[edge_list.Count - 1];
                }


                add_to_local_list(e, is_triangle_found == true ? triangle_list[triangle_list.Count - 1] : null);
            }