/// <summary>
        ///
        /// </summary>
        /// <param name="g0"></param>
        public GeometryGraphOperation(IGeometry g0)
        {
            ComputationPrecision = new PrecisionModel(g0.PrecisionModel);

            Arg = new GeometryGraph[1];
            Arg[0] = new GeometryGraph(0, g0);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="g0"></param>
        /// <param name="g1"></param>
        public GeometryGraphOperation(IGeometry g0, IGeometry g1)
        {
            // use the most precise model for the result
            ComputationPrecision = g0.PrecisionModel.CompareTo(g1.PrecisionModel) >= 0 ? new PrecisionModel(g0.PrecisionModel) : new PrecisionModel(g1.PrecisionModel);

            Arg = new GeometryGraph[2];
            Arg[0] = new GeometryGraph(0, g0);
            Arg[1] = new GeometryGraph(1, g1);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="geomGraph"></param>
        public virtual void Build(GeometryGraph geomGraph)
        {
            // compute nodes for intersections between previously noded edges
            ComputeIntersectionNodes(geomGraph, 0);
            /*
            * Copy the labelling for the nodes in the parent Geometry.  These override
            * any labels determined by intersections.
            */
            CopyNodesAndLabels(geomGraph, 0);

            /*
            * Build EdgeEnds for all intersections.
            */
            EdgeEndBuilder eeBuilder = new EdgeEndBuilder();
            IList eeList = eeBuilder.ComputeEdgeEnds(geomGraph.GetEdgeEnumerator());
            InsertEdgeEnds(eeList);
        }
Example #4
0
 /// <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();
 }
Example #5
0
 /// <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);
 }
Example #6
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="geom"></param>
 /// <returns></returns>
 private static bool IsSimpleLinearGeometry(IGeometry geom)
 {
     if (geom.IsEmpty)
         return true;
     GeometryGraph graph = new GeometryGraph(0, geom);
     LineIntersector li = new RobustLineIntersector();
     SegmentIntersector si = graph.ComputeSelfNodes(li, true);
     // if no self-intersection, must be simple
     if (!si.HasIntersection) return true;
     if (si.HasProperIntersection) return false;
     if (HasNonEndpointIntersection(graph)) return false;
     if (HasClosedEndpointIntersection(graph)) return false;
     return true;
 }
 /// <summary>
 /// Insert nodes for all intersections on the edges of a Geometry.
 /// Label the created nodes the same as the edge label if they do not already have a label.
 /// This allows nodes created by either self-intersections or
 /// mutual intersections to be labelled.
 /// Endpoint nodes will already be labelled from when they were inserted.
 /// Precondition: edge intersections have been computed.
 /// </summary>
 /// <param name="geomGraph"></param>
 /// <param name="argIndex"></param>
 public virtual void ComputeIntersectionNodes(GeometryGraph geomGraph, int argIndex)
 {
     for (IEnumerator edgeIt = geomGraph.GetEdgeEnumerator(); edgeIt.MoveNext(); )
     {
         Edge e = (Edge)edgeIt.Current;
         LocationType eLoc = e.Label.GetLocation(argIndex);
         for (IEnumerator eiIt = e.EdgeIntersectionList.GetEnumerator(); eiIt.MoveNext(); )
         {
             EdgeIntersection ei = (EdgeIntersection)eiIt.Current;
             RelateNode n = (RelateNode)_nodes.AddNode(ei.Coordinate);
             if (eLoc == LocationType.Boundary)
                 n.SetLabelBoundary(argIndex);
             else if (n.Label.IsNull(argIndex))
                 n.SetLabel(argIndex, LocationType.Interior);
         }
     }
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="geomGraph"></param>
 public ConsistentAreaTester(GeometryGraph geomGraph)
 {
     _geomGraph = geomGraph;
 }
Example #9
0
 /// <summary>
 /// Find a point from the list of testCoords
 /// that is NOT a node in the edge for the list of searchCoords.
 /// </summary>
 /// <param name="testCoords"></param>
 /// <param name="searchRing"></param>
 /// <param name="graph"></param>
 /// <returns>The point found, or <c>null</c> if none found.</returns>
 public static Coordinate FindPointNotNode(IList<Coordinate> testCoords, ILinearRing searchRing, GeometryGraph graph)
 {
     // find edge corresponding to searchRing.
     Edge searchEdge = graph.FindEdge(searchRing);
     // find a point in the testCoords which is not a node of the searchRing
     EdgeIntersectionList eiList = searchEdge.EdgeIntersectionList;
     // somewhat inefficient - is there a better way? (Use a node map, for instance?)
     foreach (Coordinate pt in testCoords)
         if (!eiList.IsIntersection(pt))
             return pt;
     return null;
 }
Example #10
0
 /// <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;
     }
 }
Example #11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="geom"></param>
        public virtual void ComputeLabelling(GeometryGraph[] geom)
        {
            ComputeEdgeEndLabels();
            // Propagate side labels  around the edges in the star
            // for each parent Geometry
            PropagateSideLabels(0);
            PropagateSideLabels(1);

            /*
            * If there are edges that still have null labels for a point
            * this must be because there are no area edges for that point incident on this node.
            * In this case, to label the edge for that point we must test whether the
            * edge is in the interior of the point.
            * To do this it suffices to determine whether the node for the edge is in the interior of an area.
            * If so, the edge has location Interior for the point.
            * In all other cases (e.g. the node is on a line, on a point, or not on the point at all) the edge
            * has the location Exterior for the point.
            *
            * Notice that the edge cannot be on the Boundary of the point, since then
            * there would have been a parallel edge from the Geometry at this node also labelled Boundary
            * and this edge would have been labelled in the previous step.
            *
            * This code causes a problem when dimensional collapses are present, since it may try and
            * determine the location of a node where a dimensional collapse has occurred.
            * The point should be considered to be on the Exterior
            * of the polygon, but locate() will return Interior, since it is passed
            * the original Geometry, not the collapsed version.
            *
            * If there are incident edges which are Line edges labelled Boundary,
            * then they must be edges resulting from dimensional collapses.
            * In this case the other edges can be labelled Exterior for this Geometry.
            *
            * MD 8/11/01 - NOT True!  The collapsed edges may in fact be in the interior of the Geometry,
            * which means the other edges should be labelled Interior for this Geometry.
            * Not sure how solve this...  Possibly labelling needs to be split into several phases:
            * area label propagation, symLabel merging, then finally null label resolution.
            */
            bool[] hasDimensionalCollapseEdge = { false, false };
            for (IEnumerator it = GetEnumerator(); it.MoveNext(); )
            {
                EdgeEnd e = (EdgeEnd)it.Current;
                Label label = e.Label;
                for (int geomi = 0; geomi < 2; geomi++)
                    if (label.IsLine(geomi) && label.GetLocation(geomi) == LocationType.Boundary)
                        hasDimensionalCollapseEdge[geomi] = true;
            }
            for (IEnumerator it = GetEnumerator(); it.MoveNext(); )
            {
                EdgeEnd e = (EdgeEnd)it.Current;
                Label label = e.Label;
                for (int geomi = 0; geomi < 2; geomi++)
                {
                    if (label.IsAnyNull(geomi))
                    {
                        LocationType loc;
                        if (hasDimensionalCollapseEdge[geomi])
                            loc = LocationType.Exterior;
                        else
                        {
                            Coordinate p = e.Coordinate;
                            loc = GetLocation(geomi, p, geom);
                        }
                        label.SetAllLocationsIfNull(geomi, loc);
                    }
                }
            }
        }
Example #12
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="g"></param>
        private void CheckValidMultipolygon(IMultiPolygon g)
        {
            foreach (Polygon p in g.Geometries)
            {
                CheckInvalidCoordinates(p);
                if (_validErr != null) return;
                CheckClosedRings(p);
                if (_validErr != null) return;
            }

            GeometryGraph graph = new GeometryGraph(0, g);
            CheckTooFewPoints(graph);
            if (_validErr != null) return;
            CheckConsistentArea(graph);
            if (_validErr != null) return;
            if (!IsSelfTouchingRingFormingHoleValid)
            {
                CheckNoSelfIntersectingRings(graph);
                if (_validErr != null) return;
            }
            foreach (Polygon p in g.Geometries)
            {
                CheckHolesInShell(p, graph);
                if (_validErr != null) return;
            }
            foreach (Polygon p in g.Geometries)
            {
                CheckHolesNotNested(p, graph);
                if (_validErr != null) return;
            }
            CheckShellsNotNested(g, graph);
            if (_validErr != null) return;
            CheckConnectedInteriors(graph);
        }
Example #13
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="graph"></param>
 private void CheckTooFewPoints(GeometryGraph graph)
 {
     if (graph.HasTooFewPoints)
     {
         _validErr = new TopologyValidationError(TopologyValidationErrorType.TooFewPoints, graph.InvalidPoint);
         return;
     }
 }
Example #14
0
        /// <summary>
        /// Checks the validity of a polygon and sets the validErr flag.
        /// </summary>
        /// <param name="g"></param>
        private void CheckValidPolygon(IPolygon g)
        {
            CheckClosedRings(g);
            if (_validErr != null) return;

            GeometryGraph graph = new GeometryGraph(0, g);
            CheckConsistentArea(graph);
            if (_validErr != null) return;
            if (!IsSelfTouchingRingFormingHoleValid)
            {
                CheckNoSelfIntersectingRings(graph);
                if (_validErr != null) return;
            }
            CheckHolesInShell(g, graph);
            if (_validErr != null) return;
            CheckHolesNotNested(g, graph);
            if (_validErr != null) return;
            CheckConnectedInteriors(graph);
        }
Example #15
0
 /// <summary>
 /// Checks validity of a LinearRing.
 /// </summary>
 /// <param name="g"></param>
 private void CheckValidRing(ILinearRing g)
 {
     CheckClosedRing(g);
     if (_validErr != null) return;
     GeometryGraph graph = new GeometryGraph(0, g);
     LineIntersector li = new RobustLineIntersector();
     graph.ComputeSelfNodes(li, true);
     CheckNoSelfIntersectingRings(graph);
 }
Example #16
0
 /// <summary>
 /// Checks validity of a LineString.
 /// Almost anything goes for lineStrings!
 /// </summary>
 /// <param name="g"></param>
 private void CheckValidLineString(IGeometry g)
 {
     GeometryGraph graph = new GeometryGraph(0, g);
     CheckTooFewPoints(graph);
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="graph"></param>
 public QuadtreeNestedRingTester(GeometryGraph graph)
 {
     _graph = graph;
 }
Example #18
0
 /// <summary>
 /// Check that there is no ring which self-intersects (except of course at its endpoints).
 /// This is required by OGC topology rules (but not by other models
 /// such as ESRI SDE, which allow inverted shells and exverted holes).
 /// </summary>
 /// <param name="graph"></param>
 private void CheckNoSelfIntersectingRings(GeometryGraph graph)
 {
     for (IEnumerator i = graph.GetEdgeEnumerator(); i.MoveNext(); )
     {
         Edge e = (Edge)i.Current;
         CheckNoSelfIntersectingRing(e.EdgeIntersectionList);
         if (_validErr != null) return;
     }
 }
Example #19
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="arg"></param>
 public RelateComputer(GeometryGraph[] arg)
 {
     _arg = arg;
 }
Example #20
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="g"></param>
 /// <param name="li"></param>
 /// <param name="includeProper"></param>
 /// <returns></returns>
 public virtual SegmentIntersector ComputeEdgeIntersections(GeometryGraph g, LineIntersector li, bool includeProper)
 {
     SegmentIntersector si = new SegmentIntersector(li, includeProper, true);
     si.SetBoundaryNodes(BoundaryNodes, g.BoundaryNodes);
     EdgeSetIntersector esi = CreateEdgeSetIntersector();
     esi.ComputeIntersections(Edges, g.Edges, si);
     return si;
 }
Example #21
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="geomIndex"></param>
 /// <param name="p"></param>
 /// <param name="geom"></param>
 /// <returns></returns>
 public virtual LocationType GetLocation(int geomIndex, Coordinate p, GeometryGraph[] geom)
 {
     // compute location only on demand
     if (_ptInAreaLocation[geomIndex] == LocationType.Null)
         _ptInAreaLocation[geomIndex] = SimplePointInAreaLocator.Locate(p, geom[geomIndex].Geometry);
     return _ptInAreaLocation[geomIndex];
 }
Example #22
0
 /// <summary>
 /// For all edges, check if there are any intersections which are NOT at an endpoint.
 /// The Geometry is not simple if there are intersections not at endpoints.
 /// </summary>
 /// <param name="graph"></param>
 private static bool HasNonEndpointIntersection(GeometryGraph graph)
 {
     for (IEnumerator i = graph.GetEdgeEnumerator(); i.MoveNext(); )
     {
         Edge e = (Edge)i.Current;
         int maxSegmentIndex = e.MaximumSegmentIndex;
         for (IEnumerator eiIt = e.EdgeIntersectionList.GetEnumerator(); eiIt.MoveNext(); )
         {
             EdgeIntersection ei = (EdgeIntersection)eiIt.Current;
             if (!ei.IsEndPoint(maxSegmentIndex))
                 return true;
         }
     }
     return false;
 }
Example #23
0
        /// <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="graph"></param>
 public SweeplineNestedRingTester(GeometryGraph graph)
 {
     _graph = graph;
 }
        /// <summary>
        /// Compute the labelling for all dirEdges in this star, as well
        /// as the overall labelling.
        /// </summary>
        /// <param name="geom"></param>
        public override void ComputeLabelling(GeometryGraph[] geom)
        {
            base.ComputeLabelling(geom);

            // determine the overall labelling for this DirectedEdgeStar
            // (i.e. for the node it is based at)
            _label = new Label(LocationType.Null);
            IEnumerator it = GetEnumerator();
            while (it.MoveNext())
            {
                EdgeEnd ee = (EdgeEnd)it.Current;
                Edge e = ee.Edge;
                Label eLabel = e.Label;
                for (int i = 0; i < 2; i++)
                {
                    LocationType eLoc = eLabel.GetLocation(i);
                    if (eLoc == LocationType.Interior || eLoc == LocationType.Boundary)
                        _label.SetLocation(i, LocationType.Interior);
                }
            }
        }
Example #26
0
 /// <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);
 }
Example #27
0
 /// <summary>
 /// Test that no edge intersection is the
 /// endpoint of a closed line.  To check this we compute the
 /// degree of each endpoint. The degree of endpoints of closed lines
 /// must be exactly 2.
 /// </summary>
 /// <param name="graph"></param>
 private static bool HasClosedEndpointIntersection(GeometryGraph graph)
 {
     IDictionary endPoints = new SortedList();
     for (IEnumerator i = graph.GetEdgeEnumerator(); i.MoveNext(); )
     {
         Edge e = (Edge)i.Current;
         bool isClosed = e.IsClosed;
         Coordinate p0 = e.GetCoordinate(0);
         AddEndpoint(endPoints, p0, isClosed);
         Coordinate p1 = e.GetCoordinate(e.NumPoints - 1);
         AddEndpoint(endPoints, p1, isClosed);
     }
     for (IEnumerator i = endPoints.Values.GetEnumerator(); i.MoveNext(); )
     {
         EndpointInfo eiInfo = (EndpointInfo)i.Current;
         if (eiInfo.IsClosed && eiInfo.Degree != 2)
             return true;
     }
     return false;
 }
Example #28
0
 /// <summary>
 /// Tests that no element polygon is wholly in the interior of another element polygon.
 /// Preconditions:
 /// Shells do not partially overlap.
 /// Shells do not touch along an edge.
 /// No duplicate rings exists.
 /// This routine relies on the fact that while polygon shells may touch at one or
 /// more vertices, they cannot touch at ALL vertices.
 /// </summary>
 private void CheckShellsNotNested(IGeometry mp, GeometryGraph graph)
 {
     for (int i = 0; i < mp.NumGeometries; i++)
     {
         Polygon p = (Polygon)mp.GetGeometryN(i);
         LinearRing shell = (LinearRing)p.ExteriorRing;
         for (int j = 0; j < mp.NumGeometries; j++)
         {
             if (i == j)
                 continue;
             Polygon p2 = (Polygon)mp.GetGeometryN(j);
             CheckShellNotNested(shell, p2, graph);
             if (_validErr != null) return;
         }
     }
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="geomGraph"></param>
 public ConnectedInteriorTester(GeometryGraph geomGraph)
 {
     _geomGraph = geomGraph;
 }
Example #30
0
        /// <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);
        }