예제 #1
0
 internal Polygon2(Ring2 <T> outerRing, RingSet2 <T> innerRings)
 {
     if (outerRing == null)
     {
         throw new ArgumentNullException();
     }
     this.OuterRing  = outerRing;
     this.InnerRings = innerRings;
 }
예제 #2
0
 public Polygon2 <T> ConstructPolygon(Ring2 <T> outerRing, Ring2 <T>[] innerRings)
 {
     if (outerRing != null && innerRings != null)
     {
         RingSet2 <T> rs = ConstructRingSet(innerRings);
         if (rs != null)
         {
             return(ConstructPolygon(outerRing, rs));
         }
     }
     return(null);
 }
예제 #3
0
 public int CompareTo(RingSet2 <T> other)
 {
     if (other == null)
     {
         return(1);
     }
     if (object.ReferenceEquals(this, other))
     {
         return(0);
     }
     if (object.ReferenceEquals(this.Rings, other.Rings))
     {
         return(0);
     }
     return(this.Envelope.CompareTo(other.Envelope));
 }
예제 #4
0
 public override Polygon2 <double> ConstructPolygon(Ring2 <double> outerRing, RingSet2 <double> innerRings)
 {
     if (outerRing == null)
     {
         return(null);
     }
     if (innerRings == null)
     {
         return(new Polygon2 <double>(outerRing));
     }
     if (PlanarGraphUtils.ValidPolygon(outerRing, innerRings))
     {
         return(new Polygon2 <double>(outerRing, innerRings));
     }
     return(null);
 }
예제 #5
0
 public Polygon2 <T> ConstructPolygon(Point2 <T>[] outerRing, Point2 <T>[][] innerRings)
 {
     if (outerRing != null && innerRings != null)
     {
         Ring2 <T> outer = ConstructRing(outerRing);
         if (outer != null)
         {
             RingSet2 <T> inner = ConstructRingSet(innerRings);
             if (inner != null)
             {
                 return(ConstructPolygon(outer, inner));
             }
         }
     }
     return(null);
 }
예제 #6
0
 public static Polygon2 <double> InvertExtent(PolygonSet2 <double> polys)
 {
     if (polys != null)
     {
         Ring2 <double>   outer  = polys.Factory.ConstructRing(polys.Envelope);
         Ring2 <double>[] inners = new Ring2 <double> [polys.Polygons.Length];
         for (int i = 0; i < inners.Length; i++)
         {
             inners[i] = polys.Polygons[i].OuterRing;
         }
         RingSet2 <double> innerSet = polys.Factory.ConstructRingSet(inners);
         if (innerSet == null)
         {
             return(null);
         }
         return(polys.Factory.ConstructPolygon(outer, innerSet));
     }
     return(null);
 }
예제 #7
0
 public override bool Equals(object obj)
 {
     if (object.ReferenceEquals(null, obj))
     {
         return(false);
     }
     if (object.ReferenceEquals(this, obj))
     {
         return(true);
     }
     if (obj is RingSet2 <T> )
     {
         RingSet2 <T> other = obj as RingSet2 <T>;
         if (other != null && this.Rings.Length == other.Rings.Length)
         {
             Ring2 <T> curUs;
             Ring2 <T> curThem;
             bool      match;
             for (int i = 0; i < this.Rings.Length; i++)
             {
                 match = false;
                 curUs = this.Rings[i];
                 for (int j = 0; j < other.Rings.Length; j++)
                 {
                     curThem = other.Rings[j];
                     if (curThem.Equals(curUs))
                     {
                         match = true;
                         break; //no point checking more
                     }
                 }
                 if (!match)
                 {
                     return(false); //didn't find a chain
                 }
             }
             return(true);
         }
     }
     return(false);
 }
예제 #8
0
 public bool Equals(RingSet2 <T> other)
 {
     if (other == null)
     {
         return(false);
     }
     if (object.ReferenceEquals(this, other))
     {
         return(true);
     }
     if (object.ReferenceEquals(this.Rings, other.Rings))
     {
         return(true);
     }
     if (this.Rings.Length == other.Rings.Length && this.VertexCount.Equals(other.VertexCount) && this.Envelope.Equals(other.Envelope))
     {
         Ring2 <T> us;
         Ring2 <T> them;
         bool      match = false;
         for (int i = 0; i < this.Rings.Length; i++)
         {
             us = this.Rings[i];
             for (int j = 0; j < other.Rings.Length; j++)
             {
                 them = other.Rings[j];
                 if (us.Equals(them))
                 {
                     match = true;
                     break;
                 }
             }
             if (!match)
             {
                 return(false);
             }
             match = false;
         }
         return(true);
     }
     return(false);
 }
예제 #9
0
        public static bool ValidPolygon(Ring2 <double> outer, RingSet2 <double> inner)
        {
            if (outer == null || inner == null)
            {
                return(false);
            }
            HashSet <Ring2 <double> > ringHash = new HashSet <Ring2 <double> >(); //check for the silly condition of multiple references to the same ring

            ringHash.Add(outer);

            Envelope2 <double> outerEnv = outer.Envelope;

            PlanarChainGraph <double> gr = new PlanarChainGraph <double>();

            foreach (Ring2 <double> r in inner.Rings)
            {
                if (!ringHash.Add(r))
                {
                    return(false);                                              //oops, duplicate reference
                }
                if (!Envelope2 <double> .EnvelopeContain(outerEnv, r.Envelope)) //all inner rings must be contained by outer ring, so the envelopes must overlap
                {
                    return(false);
                }
                gr.Add(r);
            }
            ringHash.Clear();
            ringHash = null;

            gr.Add(outer);

            SegmentGroup <double>        activeEdges = new SegmentGroup <double>();
            IEnumerator <Node <double> > points      = gr.GetEnumerator(); //walk through the points in xy sorted order

            Node <double> nd;
            LeakyResizableArray <Edge <double> > localEdges;

            int           localCt;
            int           activeCt = 0;
            Edge <double> localEdge;
            LineSegment2IntersectionResult <double> intersects;
            Point2 <double>      localStart;
            Point2 <double>      localEnd;
            Point2 <double>      activeStart;
            Point2 <double>      activeEnd;
            Point2 <double>      intPoint;
            SimpleGraph <object> touchingRings     = new SimpleGraph <object>();
            HashSet <object>     outerRingTouching = new HashSet <object>();

            //new point event in the moving front
            while (points.MoveNext())
            {
                nd         = points.Current;
                localEdges = nd.Edges; //edges connected to this point

                localCt = (int)localEdges.Count;

                //compute intersections with other edges in the scan area
                for (int i = 0; i < localCt; i++)
                {
                    localEdge  = localEdges.Data[i];
                    localStart = localEdge.Start.Point;
                    localEnd   = localEdge.End.Point;
                    activeCt   = activeEdges.Edges.Count;

                    foreach (Edge <double> activeEdge in activeEdges.Edges)
                    {
                        if (object.ReferenceEquals(localEdge, activeEdge) || object.ReferenceEquals(localEdge.Start.ParentShape, activeEdge.Start.ParentShape))
                        {
                            continue; //exiting edge || 2 edges on same ring
                        }
                        activeStart = activeEdge.Start.Point;
                        activeEnd   = activeEdge.End.Point;

                        intersects = SegmentUtils.ComputeIntersection(localStart, localEnd, activeStart, activeEnd);
                        if (intersects.IntersectionType != LineIntersectionType.NoIntersection)
                        {
                            if (intersects.IntersectionType == LineIntersectionType.CollinearIntersection)
                            {
                                return(false); // there's a full segment of intersection - must be between outer ring and an inner ring
                            }
                            //ok, we have an intersection that is a point between 2 different rings
                            intPoint = intersects.BasePoint;

                            if (object.ReferenceEquals(localEdge.Start.ParentShape, outer)) //localEdge is on the shell
                            {
                                if (PointUtilsDouble.PointsEqual(intPoint, activeStart))
                                {
                                    //only add the shell touching for segment intersection at segment start point - prevents recounting point
                                    if (!PointUtilsDouble.PointsEqual(intPoint, localEnd))
                                    {
                                        if (!outerRingTouching.Add(activeEdge.Start.ParentShape))
                                        {
                                            return(false); //same ring touches outer ring at multiple non-adjacent points
                                        }
                                    }
                                    if (!RingUtils.PointInteriorToRing(outer, activeEnd))
                                    {
                                        return(false); //ring is outside of shell or crosses shell at a vertex
                                    }
                                }
                                else if (PointUtilsDouble.PointsEqual(intPoint, activeEnd))
                                {
                                    //only add the shell touching for segment intersection at segment start point - prevents recounting point
                                    if (!PointUtilsDouble.PointsEqual(intPoint, localEnd))
                                    {
                                        if (!outerRingTouching.Add(activeEdge.Start.ParentShape))
                                        {
                                            return(false); //same ring touches outer ring at multiple non-adjacent points
                                        }
                                    }
                                    if (!RingUtils.PointInteriorToRing(outer, activeStart))
                                    {
                                        return(false); //ring is outside of shell or crosses shell at a vertex
                                    }
                                }
                                else
                                {
                                    return(false); //we have a mid-segment intersection between the outer ring and an inner ring
                                }
                            }
                            else if (object.ReferenceEquals(activeEdge.Start.ParentShape, outer)) //activeEdge is on the shell
                            {
                                if (PointUtilsDouble.PointsEqual(intPoint, localStart))
                                {
                                    //only add the shell touching for segment intersection at segment start point - prevents recounting point
                                    if (!PointUtilsDouble.PointsEqual(intPoint, activeEnd))
                                    {
                                        if (!outerRingTouching.Add(localEdge.Start.ParentShape))
                                        {
                                            return(false); //same ring touches outer ring at multiple non-adjacent points
                                        }
                                    }
                                    if (!RingUtils.PointInteriorToRing(outer, localEnd))
                                    {
                                        return(false); //ring is outside of shell or crosses shell at a vertex
                                    }
                                }
                                else if (PointUtilsDouble.PointsEqual(intPoint, localEnd))
                                {
                                    //only add the shell touching for segment intersection at segment start point - prevents recounting point
                                    if (!PointUtilsDouble.PointsEqual(intPoint, activeEnd))
                                    {
                                        if (!outerRingTouching.Add(localEdge.Start.ParentShape))
                                        {
                                            return(false); //same ring touches outer ring at multiple non-adjacent points
                                        }
                                    }
                                    if (!RingUtils.PointInteriorToRing(outer, localStart))
                                    {
                                        return(false); //ring is outside of shell or crosses shell at a vertex
                                    }
                                }
                                else
                                {
                                    return(false); //we have a mid-segment intersection between the outer ring and an inner ring
                                }
                            }
                            else //both are on inner rings
                            {
                                //since the ringset is valid, we just need to map the connectivity of rings
                                if (!touchingRings.Contains(localEdge.Start.ParentShape))
                                {
                                    touchingRings.AddNode(localEdge.Start.ParentShape);
                                }
                                if (!touchingRings.Contains(activeEdge.Start.ParentShape))
                                {
                                    touchingRings.AddNode(activeEdge.Start.ParentShape);
                                }
                                touchingRings.AddEdge(localEdge.Start.ParentShape, activeEdge.Start.ParentShape);
                            }
                        } //end !nointersection
                    }     //end foreach
                }         //end for

                //remove all exiting segments and add all starting segments
                //Action gets called exactly twice per edge -- once to add it, once to remove it
                for (int i = 0; i < localCt; i++)
                {
                    activeEdges.Action(localEdges.Data[i]);
                }
            }

            //we now know all the rings of the ringset are "legally" connected wrt the shell -- but --
            //inner rings may be adjacent to both the shell and other inner rings to form a "path" cutting the shell
            //any ring COULD be outside the shell -- we did already do the quick envelope check, so just do singular point-in-ring checks

            //shell cutting test (quick)
            object[] shellTouchers = outerRingTouching.ToArray();
            for (int i = shellTouchers.Length - 1; i > 0; i--)
            {
                object adjacentRingA = shellTouchers[i];
                if (touchingRings.Contains(adjacentRingA))
                {
                    for (int j = 0; j < i; j++)
                    {
                        object adjacentRingB = shellTouchers[j];
                        if (touchingRings.Contains(adjacentRingB))
                        {
                            if (HasPath(adjacentRingA, adjacentRingB, touchingRings))
                            {
                                return(false); //path exists between shell touching inner rings
                            }
                        }
                    }
                }
            }

            //ring inside shell testing
            foreach (Ring2 <double> innerR in inner.Rings)
            {
                if (!(RingUtils.PointInteriorToRing(outer, innerR.Points[0]) || RingUtils.PointInteriorToRing(outer, innerR.Points[1]))) //at least one of 2 adjacent points must be interior
                {
                    return(false);
                }
            }

            return(true);
        }
예제 #10
0
        public static Polygon2 <double> Simplify(double minSegmentLength, Polygon2 <double> poly)
        {
            if (poly == null)
            {
                return(null);
            }

            Ring2 <double> outer = RingUtils.Simplify(minSegmentLength, poly.OuterRing);

            if (outer == null)
            {
                return(null);
            }

            if (poly.HasHoles)
            {
                List <Ring2 <double> > inners = new List <Ring2 <double> >();
                Ring2 <double>         curInner;
                double distSum;
                double minDist = 3.0 * minSegmentLength;
                for (int i = 0; i < poly.InnerRings.Rings.Length; i++)
                {
                    curInner = poly.InnerRings.Rings[i];

                    //quick reject if the ring is "small"
                    distSum = 0;
                    for (uint j = 1; j < curInner.VertexCount; j++)
                    {
                        distSum += SegmentUtils.Length(curInner[j - 1], curInner[j]);
                        if (distSum >= minDist) //quick exit for big rings
                        {
                            break;
                        }
                    }
                    distSum += SegmentUtils.Length(curInner[curInner.VertexCount - 1], curInner[0]);
                    if (distSum <= minDist)
                    {
                        continue; //can't exist as a ring with that small a boundary
                    }
                    curInner = RingUtils.Simplify(minSegmentLength, curInner);
                    if (curInner != null)
                    {
                        inners.Add(curInner);
                    }
                }

                if (inners.Count < 1)
                {
                    return(outer); //no holes came through
                }
                RingSet2 <double> rs = poly.Factory.ConstructRingSet(inners);
                if (rs == null)
                {
                    return(null);
                }
                return(poly.Factory.ConstructPolygon(outer, rs));
            }
            else
            {
                return(outer);
            }
        }
예제 #11
0
 public abstract Polygon2 <T> ConstructPolygon(Ring2 <T> outerRing, RingSet2 <T> innerRings);