/// <summary> /// Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. /// The innermost enclosing ring is the <i>smallest</i> enclosing ring. /// The algorithm used depends on the fact that: /// ring A contains ring B iff envelope(ring A) contains envelope(ring B). /// This routine is only safe to use if the chosen point of the hole /// is known to be properly contained in a shell /// (which is guaranteed to be the case if the hole does not touch its shell). /// </summary> /// <param name="testEr"></param> /// <param name="shellList"></param> /// <returns>Containing EdgeRing, if there is one, OR /// null if no containing EdgeRing is found.</returns> private static EdgeRing FindEdgeRingContaining(EdgeRing testEr, IEnumerable shellList) { ILinearRing teString = testEr.LinearRing; IEnvelope testEnv = teString.EnvelopeInternal; Coordinate testPt = teString.Coordinates[0]; EdgeRing minShell = null; IEnvelope minEnv = null; for (IEnumerator it = shellList.GetEnumerator(); it.MoveNext();) { EdgeRing tryShell = (EdgeRing)it.Current; ILinearRing tryRing = tryShell.LinearRing; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.LinearRing.EnvelopeInternal; } bool isContained = false; if (tryEnv.Contains(testEnv) && CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)) { isContained = true; } // check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryShell; } } } return(minShell); }
/// <summary> /// This routine checks to see if a shell is properly contained in a hole. /// It assumes that the edges of the shell and hole do not /// properly intersect. /// </summary> /// <param name="shell"></param> /// <param name="hole"></param> /// <param name="graph"></param> /// <returns> /// <c>null</c> if the shell is properly contained, or /// a Coordinate which is not inside the hole if it is not. /// </returns> private static Coordinate CheckShellInsideHole(LinearRing shell, LinearRing hole, GeometryGraph graph) { IList <Coordinate> shellPts = shell.Coordinates; IList <Coordinate> holePts = hole.Coordinates; // TODO: improve performance of this - by sorting pointlists? Coordinate shellPt = FindPointNotNode(shellPts, hole, graph); // if point is on shell but not hole, check that the shell is inside the hole if (shellPt != null) { bool insideHole = CgAlgorithms.IsPointInRing(shellPt, holePts); if (!insideHole) { return(shellPt); } } Coordinate holePt = FindPointNotNode(holePts, shell, graph); // if point is on hole but not shell, check that the hole is outside the shell if (holePt != null) { bool insideShell = CgAlgorithms.IsPointInRing(holePt, shellPts); return(insideShell ? holePt : null); } throw new ShellHoleIdentityException(); }
/// <summary> /// /// </summary> /// <returns></returns> public virtual bool IsNonNested() { for (int i = 0; i < _rings.Count; i++) { LinearRing innerRing = (LinearRing)_rings[i]; IList <Coordinate> innerRingPts = innerRing.Coordinates; for (int j = 0; j < _rings.Count; j++) { LinearRing searchRing = (LinearRing)_rings[j]; IList <Coordinate> searchRingPts = searchRing.Coordinates; if (innerRing == searchRing) { continue; } if (!innerRing.EnvelopeInternal.Intersects(searchRing.EnvelopeInternal)) { continue; } Coordinate innerRingPt = IsValidOp.FindPointNotNode(innerRingPts, searchRing, _graph); Assert.IsTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring"); bool isInside = CgAlgorithms.IsPointInRing(innerRingPt, searchRingPts); if (isInside) { _nestedPt = innerRingPt; return(false); } } } return(true); }
/// <summary> /// Check if a shell is incorrectly nested within a polygon. This is the case /// if the shell is inside the polygon shell, but not inside a polygon hole. /// (If the shell is inside a polygon hole, the nesting is valid.) /// The algorithm used relies on the fact that the rings must be properly contained. /// E.g. they cannot partially overlap (this has been previously checked by /// <c>CheckRelateConsistency</c>). /// </summary> private void CheckShellNotNested(LinearRing shell, Polygon p, GeometryGraph graph) { IList <Coordinate> shellPts = shell.Coordinates; // test if shell is inside polygon shell LinearRing polyShell = (LinearRing)p.ExteriorRing; IList <Coordinate> polyPts = polyShell.Coordinates; Coordinate shellPt = FindPointNotNode(shellPts, polyShell, graph); // if no point could be found, we can assume that the shell is outside the polygon if (shellPt == null) { return; } bool insidePolyShell = CgAlgorithms.IsPointInRing(shellPt, polyPts); if (!insidePolyShell) { return; } // if no holes, this is an error! if (p.NumHoles <= 0) { _validErr = new TopologyValidationError(TopologyValidationErrorType.NestedShells, shellPt); return; } /* * Check if the shell is inside one of the holes. * This is the case if one of the calls to checkShellInsideHole * returns a null coordinate. * Otherwise, the shell is not properly contained in a hole, which is an error. */ Coordinate badNestedPt = null; for (int i = 0; i < p.NumHoles; i++) { LinearRing hole = (LinearRing)p.GetInteriorRingN(i); badNestedPt = CheckShellInsideHole(shell, hole, graph); if (badNestedPt == null) { return; } } _validErr = new TopologyValidationError(TopologyValidationErrorType.NestedShells, badNestedPt); }
/// <summary> /// /// </summary> /// <param name="innerRing"></param> /// <param name="searchRing"></param> /// <returns></returns> private bool IsInside(ILinearRing innerRing, ILinearRing searchRing) { IList <Coordinate> innerRingPts = innerRing.Coordinates; IList <Coordinate> searchRingPts = searchRing.Coordinates; if (!innerRing.EnvelopeInternal.Intersects(searchRing.EnvelopeInternal)) { return(false); } Coordinate innerRingPt = IsValidOp.FindPointNotNode(innerRingPts, searchRing, _graph); Assert.IsTrue(innerRingPt != null, "Unable to find a ring point not a node of the search ring"); bool isInside = CgAlgorithms.IsPointInRing(innerRingPt, searchRingPts); if (isInside) { _nestedPt = new Coordinate(innerRingPt); return(true); } return(false); }
/// <summary> /// Find the innermost enclosing shell EdgeRing containing the argument EdgeRing, if any. /// The innermost enclosing ring is the <i>smallest</i> enclosing ring. /// The algorithm used depends on the fact that: /// ring A contains ring B iff envelope(ring A) contains envelope(ring B). /// This routine is only safe to use if the chosen point of the hole /// is known to be properly contained in a shell /// (which is guaranteed to be the case if the hole does not touch its shell). /// </summary> /// <param name="testEr">The EdgeRing to test.</param> /// <param name="shellList">The list of shells to test.</param> /// <returns>Containing EdgeRing, if there is one, OR /// null if no containing EdgeRing is found.</returns> public static EdgeRing FindEdgeRingContaining(EdgeRing testEr, IList shellList) { ILinearRing teString = testEr.Ring; IEnvelope testEnv = teString.EnvelopeInternal; EdgeRing minShell = null; IEnvelope minEnv = null; for (IEnumerator it = shellList.GetEnumerator(); it.MoveNext();) { EdgeRing tryShell = (EdgeRing)it.Current; ILinearRing tryRing = tryShell.Ring; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.Ring.EnvelopeInternal; } bool isContained = false; // the hole envelope cannot equal the shell envelope if (tryEnv.Equals(testEnv)) { continue; } Coordinate testPt = PtNotInList(teString.Coordinates, tryRing.Coordinates); if (tryEnv.Contains(testEnv) && CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)) { isContained = true; } // check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryShell; } } } return(minShell); }
/// <summary> /// This method will cause the ring to be computed. /// It will also check any holes, if they have been assigned. /// </summary> /// <param name="p"></param> public virtual bool ContainsPoint(Coordinate p) { ILinearRing shell = LinearRing; IEnvelope env = shell.EnvelopeInternal; if (!env.Contains(p)) { return(false); } if (!CgAlgorithms.IsPointInRing(p, shell.Coordinates)) { return(false); } for (IEnumerator i = _holes.GetEnumerator(); i.MoveNext();) { EdgeRing hole = (EdgeRing)i.Current; if (hole.ContainsPoint(p)) { return(false); } } return(true); }
private void ReadPolygonShape(Shape shape) { _envelope = shape.Range.Extent.ToEnvelope(); List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (PartRange part in shape.Range.Parts) { List <Coordinate> coords = new List <Coordinate>(); int i = part.StartIndex; foreach (Vertex d in part) { Coordinate c = new Coordinate(d.X, d.Y); if (shape.M != null && shape.M.Length > 0) { c.M = shape.M[i]; } if (shape.Z != null && shape.Z.Length > 0) { c.Z = shape.Z[i]; } i++; coords.Add(c); } LinearRing ring = new LinearRing(coords); if (shape.Range.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } //if (part.IsHole()) //{ // holes.Add(ring); //} //else //{ // shells.Add(ring); //} } } if (shells.Count == 0 && holes.Count > 0) { shells = holes; holes = new List <ILinearRing>(); } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes for (int i = 0; i < holes.Count; i++) { ILinearRing testRing = holes[i]; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } bool isContained = false; if (tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates)))) { isContained = true; } // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(holes[i]); } } } var polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = new Polygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { _basicGeometry = polygons[0]; } else { // It's a multi part _basicGeometry = new MultiPolygon(polygons); } }
/// <summary> /// Creates a Polygon or MultiPolygon from this Polygon shape. /// </summary> /// <param name="factory">The IGeometryFactory to use to create the new IGeometry.</param> /// <returns>The IPolygon or IMultiPolygon created from this shape.</returns> protected IGeometry FromPolygon(IGeometryFactory factory) { if (factory == null) { factory = Geometry.DefaultFactory; } List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (PartRange part in _shapeRange.Parts) { List <Coordinate> coords = new List <Coordinate>(); int i = part.StartIndex; foreach (Vertex d in part) { Coordinate c = new Coordinate(d.X, d.Y); if (M != null && M.Length > 0) { c.M = M[i]; } if (Z != null && Z.Length > 0) { c.Z = Z[i]; } i++; coords.Add(c); } ILinearRing ring = factory.CreateLinearRing(coords); if (_shapeRange.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } } } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes foreach (ILinearRing t in holes) { ILinearRing testRing = t; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; ILinearRing tryRing; for (int j = 0; j < shells.Count; j++) { tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } bool isContained = false; if (tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates)))) { isContained = true; } // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(t); } } } IPolygon[] polygons = new Polygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(factory.CreateMultiPolygon(polygons)); }
/// <summary> /// Creates a Polygon or MultiPolygon from this Polygon shape. /// </summary> /// <param name="factory">The IGeometryFactory to use to create the new IGeometry.</param> /// <returns>The IPolygon or IMultiPolygon created from this shape.</returns> protected IGeometry FromPolygon(IGeometryFactory factory) { if (factory == null) { factory = Geometry.DefaultFactory; } List <ILinearRing> shells = new List <ILinearRing>(); List <ILinearRing> holes = new List <ILinearRing>(); foreach (var part in _shapeRange.Parts) { var coords = GetCoordinates(part); var ring = factory.CreateLinearRing(coords); if (_shapeRange.Parts.Count == 1) { shells.Add(ring); } else { if (CgAlgorithms.IsCounterClockwise(ring.Coordinates)) { holes.Add(ring); } else { shells.Add(ring); } } } //// Now we have a list of all shells and all holes List <ILinearRing>[] holesForShells = new List <ILinearRing> [shells.Count]; for (int i = 0; i < shells.Count; i++) { holesForShells[i] = new List <ILinearRing>(); } // Find holes foreach (ILinearRing t in holes) { ILinearRing testRing = t; ILinearRing minShell = null; IEnvelope minEnv = null; IEnvelope testEnv = testRing.EnvelopeInternal; Coordinate testPt = testRing.Coordinates[0]; for (int j = 0; j < shells.Count; j++) { ILinearRing tryRing = shells[j]; IEnvelope tryEnv = tryRing.EnvelopeInternal; if (minShell != null) { minEnv = minShell.EnvelopeInternal; } var isContained = tryEnv.Contains(testEnv) && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates) || (PointInList(testPt, tryRing.Coordinates))); // Check if this new containing ring is smaller than the current minimum ring if (isContained) { if (minShell == null || minEnv.Contains(tryEnv)) { minShell = tryRing; } holesForShells[j].Add(t); } } } var polygons = new IPolygon[shells.Count]; for (int i = 0; i < shells.Count; i++) { polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray()); } if (polygons.Length == 1) { return(polygons[0]); } // It's a multi part return(factory.CreateMultiPolygon(polygons)); }