public void PrintFwd()
        {
            CDLL <T> node = this;

            do
            {
                node = node.next;
            } while (node != this);
        }
        public static IList <Vec> convexhull(IList <Point> pointList)
        {
            var pts = new XPoint[pointList.Count];
            int k   = 0;

            foreach (var point in pointList)
            {
                pts[k++] = new XPoint(point.X, point.Y);
            }

            // Sort XPoints lexicographically by increasing (x, y)
            int N = pts.Length;

            Polysort.Quicksort <XPoint>(pts);
            XPoint left = pts[0], right = pts[N - 1];
            // Partition into lower hull and upper hull
            CDLL <XPoint> lower = new CDLL <XPoint>(left), upper = new CDLL <XPoint>(left);

            for (int i = 0; i < N; i++)
            {
                double det = XPoint.Area2(left, right, pts[i]);
                if (det > 0)
                {
                    upper = upper.Append(new CDLL <XPoint>(pts[i]));
                }
                else if (det < 0)
                {
                    lower = lower.Prepend(new CDLL <XPoint>(pts[i]));
                }
            }
            lower = lower.Prepend(new CDLL <XPoint>(right));
            upper = upper.Append(new CDLL <XPoint>(right)).Next;
            // Eliminate XPoints not on the hull
            eliminate(lower);
            eliminate(upper);

            /* phil : Eliminating duplicates leaves holes in the hull
             * // Eliminate duplicate endXPoints
             * if (lower.Prev.val.Equals(upper.val))
             *  lower.Prev.Delete();
             * if (upper.Prev.val.Equals(lower.val))
             *  upper.Prev.Delete();
             */
            // Join the lower and upper hull
            XPoint[] res = new XPoint[lower.Size() + upper.Size()];
            lower.CopyInto(res, 0);
            upper.CopyInto(res, lower.Size());

            var result = new List <Vec>();

            foreach (var r in res)
            {
                result.Add(new Vec(r.x, r.y));
            }
            return(result);
        }
        public void CopyInto(T[] vals, int i)
        {
            CDLL <T> node = this;

            do
            {
                vals[i++] = node.val;   // still, implicit checkcasts at runtime
                node      = node.next;
            } while (node != this);
        }
        public int Size()
        {
            int      count = 0;
            CDLL <T> node  = this;

            do
            {
                count++;
                node = node.next;
            } while (node != this);
            return(count);
        }
        // Graham's scan
        private static void eliminate(CDLL <XPoint> start)
        {
            CDLL <XPoint> v = start, w = start.Prev;
            bool          fwd = false;

            while (v.Next != start || !fwd)
            {
                if (v.Next == w)
                {
                    fwd = true;
                }
                if (XPoint.Area2(v.val, v.Next.val, v.Next.Next.val) < 0) // right turn
                {
                    v = v.Next;
                }
                else
                {                                       // left turn or straight
                    v.Next.Delete();
                    v = v.Prev;
                }
            }
        }
 public CDLL <T> Append(CDLL <T> elt)
 {
     elt.prev = this; elt.next = next; next.prev = elt; next = elt;
     return(elt);
 }
 public CDLL <T> Prepend(CDLL <T> elt)
 {
     elt.next = this; elt.prev = prev; prev.next = elt; prev = elt;
     return(elt);
 }
 // Delete: adjust the remaining elements, make this one XPoint nowhere
 public void Delete()
 {
     next.prev = prev; prev.next = next;
     next      = prev = null;
 }
 // A new CDLL node is a one-element circular list
 public CDLL(T val)
 {
     this.val = val; next = prev = this;
 }