コード例 #1
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="g0"></param>
        public GeometryGraphOperation(IGeometry g0)
        {
            ComputationPrecision = g0.PrecisionModel;

            arg = new GeometryGraph[1];
            arg[0] = new GeometryGraph(0, g0);;
        }
コード例 #2
0
        public GeometryGraphOperation(IGeometry g0, IGeometry g1, IBoundaryNodeRule boundaryNodeRule)
        {
            // use the most precise model for the result
            if (g0.PrecisionModel.CompareTo(g1.PrecisionModel) >= 0)
                 ComputationPrecision = g0.PrecisionModel;
            else ComputationPrecision = g1.PrecisionModel;

            arg = new GeometryGraph[2];
            arg[0] = new GeometryGraph(0, g0, boundaryNodeRule);
            arg[1] = new GeometryGraph(1, g1, boundaryNodeRule);
        }
コード例 #3
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(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;
 }
コード例 #4
0
 /// <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 void ComputeIntersectionNodes(GeometryGraph geomGraph, int argIndex)
 {
     foreach (Edge e in geomGraph.Edges)
     {
         Location eLoc = e.Label.GetLocation(argIndex);
         foreach (EdgeIntersection ei in e.EdgeIntersectionList)
         {
             RelateNode n = (RelateNode) _nodes.AddNode(ei.Coordinate);
             if (eLoc == Location.Boundary)
                 n.SetLabelBoundary(argIndex);
             else if (n.Label.IsNull(argIndex))
                 n.SetLabel(argIndex, Location.Interior);
         }
     }
 }
コード例 #5
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="geomGraph"></param>
        public 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<EdgeEnd> eeList = eeBuilder.ComputeEdgeEnds(geomGraph.Edges);
            InsertEdgeEnds(eeList);
        }
コード例 #6
0
        /// <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(Location.Null);
            IEnumerator<EdgeEnd> it = GetEnumerator();
            while(it.MoveNext())
            {
                EdgeEnd ee = it.Current;
                Edge e = ee.Edge;
                Label eLabel = e.Label;
                for (int i = 0; i < 2; i++)
                {
                    Location eLoc = eLabel.GetLocation(i);
                    if (eLoc == Location.Interior || eLoc == Location.Boundary)
                        _label.SetLocation(i, Location.Interior);
                }
            }
        }
コード例 #7
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="arg"></param>
 public RelateComputer(GeometryGraph[] arg)
 {
     _arg = arg;
 }
コード例 #8
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 bool HasNonEndpointIntersection(GeometryGraph graph)
 {
     foreach (Edge e in graph.Edges)
     {
         int maxSegmentIndex = e.MaximumSegmentIndex;
         foreach (EdgeIntersection ei in e.EdgeIntersectionList)
         {
             if (!ei.IsEndPoint(maxSegmentIndex))
             {
                 _nonSimpleLocation = ei.Coordinate;
                 return true;
             }
         }
     }
     return false;
 }
コード例 #9
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="graph"></param>
 public SweeplineNestedRingTester(GeometryGraph graph)
 {
     this.graph = graph;
 }
コード例 #10
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="geomIndex"></param>
 /// <param name="p"></param>
 /// <param name="geom"></param>
 /// <returns></returns>
 private Location GetLocation(int geomIndex, Coordinate p, GeometryGraph[] geom)
 {
     // compute location only on demand
     if (_ptInAreaLocation[geomIndex] == Location.Null) 
         _ptInAreaLocation[geomIndex] = SimplePointInAreaLocator.Locate(p, geom[geomIndex].Geometry);            
     return _ptInAreaLocation[geomIndex];
 }
コード例 #11
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="geomGraph"></param>
 public ConsistentAreaTester(GeometryGraph geomGraph)
 {
     this.geomGraph = geomGraph;
 }
コード例 #12
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="graph"></param>
 public QuadtreeNestedRingTester(GeometryGraph graph)
 {
     _graph = graph;
 }
コード例 #13
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 Coordinate CheckShellInsideHole(ILinearRing shell, ILinearRing hole, GeometryGraph graph)
 {
     Coordinate[] shellPts = shell.Coordinates;
     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);
         if (insideShell) 
             return holePt;
         return null;
     }
     Assert.ShouldNeverReachHere("points in shell and hole appear to be equal");
     return null;
 }
コード例 #14
0
        /// <summary>
        /// Checks validity of a LinearRing.
        /// </summary>
        /// <param name="g"></param>
        private void CheckValid(ILinearRing g)
        {
            CheckInvalidCoordinates(g.Coordinates);
            if (validErr != null) return;
            CheckClosedRing(g);
            if (validErr != null) return;

            GeometryGraph graph = new GeometryGraph(0, g);
            CheckTooFewPoints(graph);
            if (validErr != null) return;
            LineIntersector li = new RobustLineIntersector();
            graph.ComputeSelfNodes(li, true);
            CheckNoSelfIntersectingRings(graph);
        }
コード例 #15
0
 /// <summary>
 /// Checks validity of a LineString.  
 /// Almost anything goes for lineStrings!
 /// </summary>
 /// <param name="g"></param>
 private void CheckValid(ILineString g)
 {
     CheckInvalidCoordinates(g.Coordinates);
     if (validErr != null) return;
     GeometryGraph graph = new GeometryGraph(0, g);
     CheckTooFewPoints(graph);
 }
コード例 #16
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(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 = CGAlgorithms.IsPointInRing(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);
        }
コード例 #17
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="g"></param>
        private void CheckValid(IMultiPolygon g)
        {
            foreach(IPolygon 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(IPolygon p in g.Geometries)
            {                
                CheckHolesInShell(p, graph);
                if (validErr != null) return;
            }
            foreach (IPolygon p in g.Geometries)
            {                                
                CheckHolesNotNested(p, graph);
                if (validErr != null) return;
            }
            CheckShellsNotNested(g, graph);
            if (validErr != null) return;
            CheckConnectedInteriors(graph);
        }
コード例 #18
0
 /// <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);
 }
コード例 #19
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="graph"></param>
 private void CheckTooFewPoints(GeometryGraph graph)
 {
     if (graph.HasTooFewPoints)
     {
         validErr = new TopologyValidationError(TopologyValidationErrors.TooFewPoints,
             graph.InvalidPoint);
         return;
     }
 }
コード例 #20
0
 public IndexedNestedRingTester(GeometryGraph graph)
 {
     _graph = graph;
 }
コード例 #21
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(TopologyValidationErrors.SelfIntersection, cat.InvalidPoint);
         return;
     }
     if (cat.HasDuplicateRings)
     {
         validErr = new TopologyValidationError(TopologyValidationErrors.DuplicateRings, cat.InvalidPoint);
         return;
     }
 }
コード例 #22
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="geomGraph"></param>
        public virtual void ComputeLabelling(GeometryGraph[] geomGraph)
        {
            ComputeEdgeEndLabels(geomGraph[0].BoundaryNodeRule);
            // 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.
            * 
            * Note 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 };
            foreach (var e in Edges)
            {
                Label label = e.Label;
                for (int geomi = 0; geomi < 2; geomi++) 
                    if (label.IsLine(geomi) && label.GetLocation(geomi) == Location.Boundary)
                        hasDimensionalCollapseEdge[geomi] = true;                
            }
            foreach (var e in Edges)
            {
                Label label = e.Label;        
                for (int geomi = 0; geomi < 2; geomi++) 
                {
                    if (label.IsAnyNull(geomi)) 
                    {
                        Location loc;
                        if (hasDimensionalCollapseEdge[geomi])
                            loc = Location.Exterior;                
                        else 
                        {
                            Coordinate p = e.Coordinate;
                            loc = GetLocation(geomi, p, geomGraph);
                        }
                        label.SetAllLocationsIfNull(geomi, loc);
                    }
                }        
            }        
        }
コード例 #23
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;
     }
 }
コード例 #24
0
 /// <summary>
 /// 
 /// </summary>
 public bool IsAreaLabelsConsistent(GeometryGraph geometryGraph)
 {
     ComputeEdgeEndLabels(geometryGraph.BoundaryNodeRule);
     return CheckAreaLabelsConsistent(0);
 }
コード例 #25
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.NumInteriorRings; i++)
            {
                ILinearRing hole = p.Holes[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(TopologyValidationErrors.HoleOutsideShell, holePt);
                    return;
                }
            }            
        }
コード例 #26
0
        private 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)
            {
                _nonSimpleLocation = si.ProperIntersectionPoint;
                return false;
            }
            if (HasNonEndpointIntersection(graph)) return false;
            if (_isClosedEndpointsInInterior)
            {
                if (HasClosedEndpointIntersection(graph)) return false;
            }
            return true;
        }
コード例 #27
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)
 {
     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);        
 }
コード例 #28
0
        /// <summary> 
       /// Tests that no edge intersection is the endpoint of a closed line.
       /// This ensures that closed lines are not touched at their endpoint,
       /// which is an interior point according to the Mod-2 rule
       /// To check this we compute the degree of each endpoint.
       /// The degree of endpoints of closed lines
       /// must be exactly 2.
        /// </summary>
        private bool HasClosedEndpointIntersection(GeometryGraph graph)
        {
            IDictionary<Coordinate, EndpointInfo> endPoints = new SortedDictionary<Coordinate, EndpointInfo>();
            foreach (Edge e in graph.Edges)
            {
                //int maxSegmentIndex = e.MaximumSegmentIndex;
                bool isClosed = e.IsClosed;
                Coordinate p0 = e.GetCoordinate(0);
                AddEndpoint(endPoints, p0, isClosed);
                Coordinate p1 = e.GetCoordinate(e.NumPoints - 1);
                AddEndpoint(endPoints, p1, isClosed);
            }

            foreach (EndpointInfo eiInfo in endPoints.Values)
            {
                if (eiInfo.IsClosed && eiInfo.Degree != 2)
                {
                    _nonSimpleLocation = eiInfo.Point;
                    return true;
                }
            }
            return false;
        }
コード例 #29
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(IMultiPolygon mp, GeometryGraph graph)
 {            
     for (int i = 0; i < mp.NumGeometries; i++)
     {                
         IPolygon p = (IPolygon) mp.GetGeometryN(i);
         ILinearRing shell = p.Shell;
         for (int j = 0; j < mp.NumGeometries; j++)
         {                    
             if (i == j)
                 continue;
             IPolygon p2 = (IPolygon) mp.GetGeometryN(j);                    
             CheckShellNotNested(shell, p2, graph);
             if (validErr != null) return;
         }                
     }         
 }
コード例 #30
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="geomGraph"></param>
 public ConnectedInteriorTester(GeometryGraph geomGraph)
 {
     _geomGraph = geomGraph;
 }
コード例 #31
0
 /// <summary>
 ///
 /// </summary>
 public bool IsAreaLabelsConsistent(GeometryGraph geometryGraph)
 {
     ComputeEdgeEndLabels(geometryGraph.BoundaryNodeRule);
     return(CheckAreaLabelsConsistent(0));
 }