public Polygon Clone()
 {
     Polygon g = new Polygon();
     for (int k=0;k< contours.Count;k++) {
         g.AddContour(contours[k].Clone());
     }
     return g;
 }
        public Polygon ToPolygon()
        {
            // Check for empty result
            if ((closedPolygons.Count == 0 ||
                (closedPolygons.Count == 1 && closedPolygons[0].pointList.Count == 0)) &&
                (openPolygons.Count == 0 ||
                (openPolygons.Count == 1 && openPolygons[0].pointList.Count == 0))) {
                return null;
            }

            Polygon polygon = new Polygon ();
            foreach (PointChain pointChain in closedPolygons) {
                Contour c = new Contour ();
                c.AddRange (pointChain.pointList);
                polygon.AddContour (c);
            }
            FixOrientation(polygon);
            return polygon;
        }
 public void Compute(PolygonOp operation)
 {
     subject = ComputeInternal(operation);
 }
 //        public PolygonClipper(Region regionSubject, Region regionClipping) {
 //            // Setup subject and clipping polygons
 //            this.regionSubject = regionSubject;
 //            subject = new Polygon();
 //            Contour scont = new Contour();
 //            scont.AddRange(regionSubject.points);
 //            subject.AddContour(scont);
 //            SetClippingRegion(regionClipping);
 //        }
 //
 //        public void SetClippingRegion(Region regionClipping) {
 //            clipping = new Polygon();
 //            Contour ccont = new Contour();
 //            ccont.AddRange(regionClipping.points);
 //            clipping.AddContour(ccont);
 //        }
 public PolygonClipper(Polygon subject, Polygon clipping)
 {
     this.subject = subject;
     this.clipping = clipping;
 }
        /// <summary>
        /// Since polygons from countries and cells are not perfectly aligned in all cases, this method will take the largest contour and assume this is the resulting polygon
        /// (even if it's not closed...)
        /// </summary>
        public Polygon ToPolygonFromLargestLineStrip()
        {
            // Check for empty result
            if ((closedPolygons.Count == 0 ||
                 (closedPolygons.Count == 1 && closedPolygons[0].pointList.Count == 0)) &&
                (openPolygons.Count == 0 ||
             (openPolygons.Count == 1 && openPolygons[0].pointList.Count == 0))) {
                return null;
            }

            // Get the largest contour (open or closed)
            int maxPoints=-1;
            PointChain largestPointChain = null;
            foreach (PointChain pointChain in closedPolygons) {
                if (pointChain.pointList.Count>maxPoints) {
                    maxPoints = pointChain.pointList.Count;
                    largestPointChain = pointChain;
                }
            }
            foreach (PointChain pointChain in openPolygons) {
                if (pointChain.pointList.Count>maxPoints) {
                    maxPoints = pointChain.pointList.Count;
                    largestPointChain = pointChain;
                }
            }

            // ... and create a new polygon of that
            if (maxPoints<0) return null;
            Polygon polygon = new Polygon ();
            Contour c = new Contour ();
            c.AddRange (largestPointChain.pointList);
            polygon.AddContour (c);
            FixOrientation(polygon);
            return polygon;
        }
        // orientation2D_Polygon(): test the orientation of a simple 2D polygon
        //  Input:  Point* V = an array of n+1 vertex points with V[n]=V[0]
        //  Return: >0 for counterclockwise
        //          =0 for none (degenerate)
        //          <0 for clockwise
        //  Note: this algorithm is faster than computing the signed area.
        //  From http://geomalgorithms.com/a01-_area.html#orientation2D_Polygon()
        double[] Orientation(Polygon V)
        {
            // first find rightmost lowest vertex of the polygon
            double[] ou = new double[V.contours.Count];
            for(int j=0;j<V.contours.Count;j++) {
                Contour r = V.contours[j];
                int rmin = 0;
                double xmin = r.points[0].x;
                double ymin = r.points[0].y;
                for(int i=0;i<r.points.Count;i++) {
                    Point p = r.points[i];
                    if (p.y > ymin) {
                        continue;
                    } else if (p.y == ymin) { // just as low
                        if (p.x < xmin) { // and to left
                            continue;
                        }
                    }
                    rmin = i; // a new rightmost lowest vertex
                    xmin = p.x;
                    ymin = p.y;
                }

                // test orientation at the rmin vertex
                // ccw <=> the edge leaving V[rmin] is left of the entering edge
                if (rmin == 0 || rmin == r.points.Count-1) {
                    ou[j] = isLeft(r.points[r.points.Count-2], r.points[0], r.points[1]);
                } else {
                    ou[j] = isLeft(r.points[rmin-1], r.points[rmin], r.points[rmin+1]);
                }
            }
            return ou;
        }
 // Change the winding direction of the outer and inner
 // rings so the outer ring is counter-clockwise and
 // nesting rings alternate directions.
 void FixOrientation(Polygon g)
 {
     Polygon p = g; //.(geom.Polygon)
     double[] o = Orientation(p);
     for (int i=0;i<p.contours.Count;i++) {
         Contour inner = p.contours[i];
         int numInside = 0;
         for (int j=0;j<p.contours.Count;j++) {
             Contour outer = p.contours[j];
             if (i != j) {
                 if (PolyInPoly(outer, inner)) {
                     numInside++;
                 }
             }
         }
         if (numInside % 2 == 1 && o[i] > 0) {
             ReversePolygon(inner.points);
         } else if (numInside % 2 == 0 && o[i] < 0) {
             ReversePolygon(inner.points);
         }
     }
 }