/// <summary> /// Tests that each hole is inside the polygon shell. /// This routine assumes that the holes have previously been tested /// to ensure that all vertices lie on the shell or inside it. /// A simple test of a single point in the hole can be used, /// provide the point is chosen such that it does not lie on the /// boundary of the shell. /// </summary> /// <param name="p">The polygon to be tested for hole inclusion.</param> /// <param name="graph">A GeometryGraph incorporating the polygon.</param> private void CheckHolesInShell(IPolygon p, GeometryGraph graph) { var shell = p.Shell; //IPointInRing pir = new MCPointInRing(shell); var pir = new IndexedPointInAreaLocator(shell); for (int i = 0; i < p.NumInteriorRings; i++) { var hole = p.Holes[i]; var holePt = FindPointNotNode(hole.Coordinates, shell, graph); /* * If no non-node hole vertex can be found, the hole must * split the polygon into disconnected interiors. * This will be caught by a subsequent check. */ if (holePt == null) { return; } var outside = Location.Exterior == pir.Locate(holePt); if (outside) { _validErr = new TopologyValidationError(TopologyValidationErrors.HoleOutsideShell, holePt); return; } } }
/// <summary> /// /// </summary> /// <param name="ring"></param> private void CheckClosedRing(ILinearRing ring) { if (!ring.IsClosed) { _validErr = new TopologyValidationError(TopologyValidationErrors.RingNotClosed, ring.GetCoordinateN(0)); } }
/// <summary> /// /// </summary> /// <param name="graph"></param> private void CheckTooFewPoints(GeometryGraph graph) { if (graph.HasTooFewPoints) { _validErr = new TopologyValidationError(TopologyValidationErrors.TooFewPoints, graph.InvalidPoint); return; } }
/// <summary> /// /// </summary> /// <param name="graph"></param> private void CheckConnectedInteriors(GeometryGraph graph) { ConnectedInteriorTester cit = new ConnectedInteriorTester(graph); if (!cit.IsInteriorsConnected()) { _validErr = new TopologyValidationError(TopologyValidationErrors.DisconnectedInteriors, cit.Coordinate); } }
/// <summary> /// /// </summary> /// <param name="coords"></param> private void CheckInvalidCoordinates(Coordinate[] coords) { foreach (Coordinate c in coords) { if (!IsValidCoordinate(c)) { _validErr = new TopologyValidationError(TopologyValidationErrors.InvalidCoordinate, c); return; } } }
/// <summary> /// Tests that no hole is nested inside another hole. /// This routine assumes that the holes are disjoint. /// To ensure this, holes have previously been tested /// to ensure that: /// They do not partially overlap /// (checked by <c>checkRelateConsistency</c>). /// They are not identical /// (checked by <c>checkRelateConsistency</c>). /// </summary> private void CheckHolesNotNested(IPolygon p, GeometryGraph graph) { var nestedTester = new IndexedNestedRingTester(graph); foreach (ILinearRing innerHole in p.Holes) { nestedTester.Add(innerHole); } bool isNonNested = nestedTester.IsNonNested(); if (!isNonNested) { _validErr = new TopologyValidationError(TopologyValidationErrors.NestedHoles, nestedTester.NestedPoint); } }
/// <summary> /// /// </summary> /// <param name="graph"></param> private void CheckConsistentArea(GeometryGraph graph) { ConsistentAreaTester cat = new ConsistentAreaTester(graph); bool isValidArea = cat.IsNodeConsistentArea; if (!isValidArea) { _validErr = new TopologyValidationError(TopologyValidationErrors.SelfIntersection, cat.InvalidPoint); return; } if (cat.HasDuplicateRings) { _validErr = new TopologyValidationError(TopologyValidationErrors.DuplicateRings, cat.InvalidPoint); return; } }
/// <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(ILinearRing shell, IPolygon p, GeometryGraph graph) { Coordinate[] shellPts = shell.Coordinates; // test if shell is inside polygon shell ILinearRing polyShell = p.Shell; 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 = PointLocation.IsInRing(shellPt, polyPts); if (!insidePolyShell) { return; } // if no holes, this is an error! if (p.NumInteriorRings <= 0) { _validErr = new TopologyValidationError(TopologyValidationErrors.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.NumInteriorRings; i++) { ILinearRing hole = p.Holes[i]; badNestedPt = CheckShellInsideHole(shell, hole, graph); if (badNestedPt == null) { return; } } _validErr = new TopologyValidationError(TopologyValidationErrors.NestedShells, badNestedPt); }
/// <summary> /// /// </summary> /// <param name="g"></param> private void CheckValid(IGeometry g) { _validErr = null; if (g.IsEmpty) { return; } if (g is IPoint) { CheckValid((IPoint)g); } else if (g is IMultiPoint) { CheckValid((IMultiPoint)g); } else if (g is ILinearRing) // LineString also handles LinearRings { CheckValid((ILinearRing)g); } else if (g is ILineString) { CheckValid((ILineString)g); } else if (g is IPolygon) { CheckValid((IPolygon)g); } else if (g is IMultiPolygon) { CheckValid((IMultiPolygon)g); } else if (g is IGeometryCollection) { CheckValid((IGeometryCollection)g); } else { throw new NotSupportedException(g.GetType().FullName); } }
/// <summary> /// Check that a ring does not self-intersect, except at its endpoints. /// Algorithm is to count the number of times each node along edge occurs. /// If any occur more than once, that must be a self-intersection. /// </summary> private void CheckNoSelfIntersectingRing(EdgeIntersectionList eiList) { HashSet <Coordinate> nodeSet = new HashSet <Coordinate>(); bool isFirst = true; foreach (EdgeIntersection ei in eiList) { if (isFirst) { isFirst = false; continue; } if (nodeSet.Contains(ei.Coordinate)) { _validErr = new TopologyValidationError(TopologyValidationErrors.RingSelfIntersection, ei.Coordinate); return; } else { nodeSet.Add(ei.Coordinate); } } }