/// <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) { ILinearRing shell = p.Shell; IPointInRing pir = new McPointInRing(shell); for (int i = 0; i < p.NumHoles; i++) { LinearRing hole = (LinearRing)p.GetInteriorRingN(i); Coordinate 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; } bool outside = !pir.IsInside(holePt); if (outside) { _validErr = new TopologyValidationError(TopologyValidationErrorType.HoleOutsideShell, holePt); return; } } }
/// <summary> /// /// </summary> /// <param name="ring"></param> private void CheckClosedRing(ILinearRing ring) { if (!ring.IsClosed) { _validErr = new TopologyValidationError(TopologyValidationErrorType.RingNotClosed, ring.Coordinates[0]); } }
/// <summary> /// /// </summary> /// <param name="graph"></param> private void CheckTooFewPoints(GeometryGraph graph) { if (graph.HasTooFewPoints) { _validErr = new TopologyValidationError(TopologyValidationErrorType.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(TopologyValidationErrorType.DisconnectedInteriors, cit.Coordinate); } }
/// <summary> /// /// </summary> /// <param name="coords"></param> private void CheckInvalidCoordinates(IEnumerable <Coordinate> coords) { foreach (Coordinate c in coords) { if (!IsValidCoordinate(c)) { _validErr = new TopologyValidationError(TopologyValidationErrorType.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) { QuadtreeNestedRingTester nestedTester = new QuadtreeNestedRingTester(graph); foreach (LinearRing innerHole in p.Holes) { nestedTester.Add(innerHole); } bool isNonNested = nestedTester.IsNonNested(); if (!isNonNested) { _validErr = new TopologyValidationError(TopologyValidationErrorType.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(TopologyValidationErrorType.SelfIntersection, cat.InvalidPoint); return; } if (cat.HasDuplicateRings) { _validErr = new TopologyValidationError(TopologyValidationErrorType.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(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> /// 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) { var 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(TopologyValidationErrorType.RingSelfIntersection, ei.Coordinate); return; } nodeSet.Add(ei.Coordinate); } }
/// <summary> /// /// </summary> /// <param name="g"></param> private void CheckValid(IGeometry g) { _validErr = null; if (g.IsEmpty) { return; } CheckValidCoordinates(g); if (g is ILineString) { CheckValidLineString(g); } ILinearRing r = g as ILinearRing; if (r != null) { CheckValidRing(r); } IPolygon p = g as IPolygon; if (p != null) { CheckValidPolygon(p); } IMultiPolygon mp = g as IMultiPolygon; if (mp != null) { CheckValidMultipolygon(mp); } else { IGeometryCollection gc = g as IGeometryCollection; if (gc != null) { CheckValidCollection(gc); } } }
/// <summary> /// /// </summary> /// <param name="g"></param> private void CheckValid(IGeometry g) { _validErr = null; if (g.IsEmpty) return; CheckValidCoordinates(g); if (g is ILineString) CheckValidLineString(g); ILinearRing r = g as ILinearRing; if (r != null) CheckValidRing(r); IPolygon p = g as IPolygon; if (p != null) CheckValidPolygon(p); IMultiPolygon mp = g as IMultiPolygon; if (mp != null) CheckValidMultipolygon(mp); else { IGeometryCollection gc = g as IGeometryCollection; if (gc != null) CheckValidCollection(gc); } }
/// <summary> /// /// </summary> /// <param name="ring"></param> private void CheckClosedRing(ILinearRing ring) { if (!ring.IsClosed) _validErr = new TopologyValidationError(TopologyValidationErrorType.RingNotClosed, ring.Coordinates[0]); }
/// <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) { ISet nodeSet = new ListSet(); bool isFirst = true; foreach (EdgeIntersection ei in eiList) { if (isFirst) { isFirst = false; continue; } if (nodeSet.Contains(ei.Coordinate)) { _validErr = new TopologyValidationError(TopologyValidationErrorType.RingSelfIntersection, ei.Coordinate); return; } nodeSet.Add(ei.Coordinate); } }
/// <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) { ILinearRing shell = p.Shell; IPointInRing pir = new McPointInRing(shell); for (int i = 0; i < p.NumHoles; i++) { LinearRing hole = (LinearRing)p.GetInteriorRingN(i); Coordinate 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; bool outside = !pir.IsInside(holePt); if (outside) { _validErr = new TopologyValidationError(TopologyValidationErrorType.HoleOutsideShell, holePt); 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) { QuadtreeNestedRingTester nestedTester = new QuadtreeNestedRingTester(graph); foreach (LinearRing innerHole in p.Holes) nestedTester.Add(innerHole); bool isNonNested = nestedTester.IsNonNested(); if (!isNonNested) _validErr = new TopologyValidationError(TopologyValidationErrorType.NestedHoles, nestedTester.NestedPoint); }
/// <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="graph"></param> private void CheckConnectedInteriors(GeometryGraph graph) { ConnectedInteriorTester cit = new ConnectedInteriorTester(graph); if (!cit.IsInteriorsConnected()) _validErr = new TopologyValidationError(TopologyValidationErrorType.DisconnectedInteriors, cit.Coordinate); }
/// <summary> /// /// </summary> /// <param name="coords"></param> private void CheckInvalidCoordinates(IEnumerable<Coordinate> coords) { foreach (Coordinate c in coords) { if (!IsValidCoordinate(c)) { _validErr = new TopologyValidationError(TopologyValidationErrorType.InvalidCoordinate, c); return; } } }