internal Polygon2(Ring2 <T> outerRing, RingSet2 <T> innerRings) { if (outerRing == null) { throw new ArgumentNullException(); } this.OuterRing = outerRing; this.InnerRings = innerRings; }
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); }
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)); }
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); }
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); }
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); }
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); }
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); }
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); }
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); } }
public abstract Polygon2 <T> ConstructPolygon(Ring2 <T> outerRing, RingSet2 <T> innerRings);