/// <summary> /// /// </summary> /// <param name="de"></param> /// <returns></returns> public override DirectedEdge GetNext(DirectedEdge de) { return de.Next; }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="er"></param> public override void SetEdgeRing(DirectedEdge de, EdgeRing er) { de.EdgeRing = er; }
/// <summary> /// Collect edges from Area inputs which should be in the result but /// which have not been included in a result area. /// This happens ONLY: /// during an intersection when the boundaries of two /// areas touch in a line segment /// OR as a result of a dimensional collapse. /// </summary> /// <param name="de"></param> /// <param name="opCode"></param> /// <param name="edges"></param> public virtual void CollectBoundaryTouchEdge(DirectedEdge de, SpatialFunctions opCode, IList edges) { Label label = de.Label; if (de.IsLineEdge) return; // only interested in area edges if (de.IsVisited) return; // already processed if (de.IsInteriorAreaEdge) return; // added to handle dimensional collapses if (de.Edge.IsInResult) return; // if the edge linework is already included, don't include it again // sanity check for labelling of result edgerings Assert.IsTrue(!(de.IsInResult || de.Sym.IsInResult) || !de.Edge.IsInResult); // include the linework if it's in the result of the operation if (OverlayOp.IsResultOfOp(label, opCode) && opCode == SpatialFunctions.Intersection) { edges.Add(de.Edge); de.VisitedEdge = true; } }
/// <summary> /// /// </summary> /// <param name="start"></param> /// <param name="geometryFactory"></param> public MaximalEdgeRing(DirectedEdge start, IGeometryFactory geometryFactory) : base(start, geometryFactory) { }
/// <summary> /// /// </summary> /// <param name="de"></param> private void CheckForRightmostCoordinate(DirectedEdge de) { IList<Coordinate> coord = de.Edge.Coordinates; for (int i = 0; i < coord.Count - 1; i++) { // only check vertices which are the start or end point of a non-horizontal segment // <FIX> MD 19 Sep 03 - NO! we can test all vertices, since the rightmost must have a non-horiz segment adjacent to it if (_minCoord == null || coord[i].X > _minCoord.X) { _minDe = de; _minIndex = i; _minCoord = coord[i]; } } }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="opCode"></param> /// <param name="edges"></param> public void CollectLineEdge(DirectedEdge de, SpatialFunctions opCode, IList edges) { Label label = de.Label; Edge e = de.Edge; // include Curve edges which are in the result if (de.IsLineEdge) { if (!de.IsVisited && OverlayOp.IsResultOfOp(label, opCode) && !e.IsCovered) { edges.Add(e); de.VisitedEdge = true; } } }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="er"></param> abstract public void SetEdgeRing(DirectedEdge de, EdgeRing er);
/// <summary> /// Compute depths for all dirEdges via breadth-first traversal of nodes in graph. /// </summary> /// <param name="startEdge">Edge to start processing with.</param> // <FIX> MD - use iteration & queue rather than recursion, for speed and robustness private void ComputeDepths(DirectedEdge startEdge) { ISet nodesVisited = new HashedSet(); Queue nodeQueue = new Queue(); Node startNode = startEdge.Node; nodeQueue.Enqueue(startNode); nodesVisited.Add(startNode); startEdge.IsVisited = true; while (nodeQueue.Count != 0) { Node n = (Node)nodeQueue.Dequeue(); nodesVisited.Add(n); // compute depths around node, starting at this edge since it has depths assigned ComputeNodeDepth(n); // add all adjacent nodes to process queue, unless the node has been visited already IEnumerator i = ((DirectedEdgeStar)n.Edges).GetEnumerator(); while (i.MoveNext()) { DirectedEdge de = (DirectedEdge)i.Current; DirectedEdge sym = de.Sym; if (sym.IsVisited) continue; Node adjNode = sym.Node; if (!(nodesVisited.Contains(adjNode))) { nodeQueue.Enqueue(adjNode); nodesVisited.Add(adjNode); } } } }
/// <summary> /// Finds all non-horizontal segments intersecting the stabbing line /// in the input dirEdge. /// The stabbing line is the ray to the right of stabbingRayLeftPt. /// </summary> /// <param name="stabbingRayLeftPt">The left-hand origin of the stabbing line.</param> /// <param name="dirEdge"></param> /// <param name="stabbedSegments">The current list of DepthSegments intersecting the stabbing line.</param> private void FindStabbedSegments(Coordinate stabbingRayLeftPt, DirectedEdge dirEdge, IList stabbedSegments) { IList<Coordinate> pts = dirEdge.Edge.Coordinates; for (int i = 0; i < pts.Count - 1; i++) { _seg.P0 = pts[i]; _seg.P1 = pts[i + 1]; // ensure segment always points upwards if (_seg.P0.Y > _seg.P1.Y) _seg.Reverse(); // skip segment if it is left of the stabbing line double maxx = Math.Max(_seg.P0.X, _seg.P1.X); if (maxx < stabbingRayLeftPt.X) continue; // skip horizontal segments (there will be a non-horizontal one carrying the same depth info if (_seg.IsHorizontal) continue; // skip if segment is above or below stabbing line if (stabbingRayLeftPt.Y < _seg.P0.Y || stabbingRayLeftPt.Y > _seg.P1.Y) continue; // skip if stabbing ray is right of the segment if (CGAlgorithms.ComputeOrientation(_seg.CP0, _seg.cP1, stabbingRayLeftPt) == CGAlgorithms.Right) continue; // stabbing line cuts this segment, so record it int depth = dirEdge.GetDepth(Positions.Left); // if segment direction was flipped, use RHS depth instead if (! _seg.P0.Equals(pts[i])) depth = dirEdge.GetDepth(Positions.Right); DepthSegment ds = new DepthSegment(_seg, depth); stabbedSegments.Add(ds); } }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <returns></returns> abstract public DirectedEdge GetNext(DirectedEdge de);
/// <summary> /// Add a set of edges to the graph. For each edge two DirectedEdges /// will be created. DirectedEdges are NOT linked by this method. /// </summary> /// <param name="edgesToAdd"></param> public virtual void AddEdges(IList edgesToAdd) { // create all the nodes for the edges for (IEnumerator it = edgesToAdd.GetEnumerator(); it.MoveNext(); ) { Edge e = (Edge)it.Current; _edges.Add(e); DirectedEdge de1 = new DirectedEdge(e, true); DirectedEdge de2 = new DirectedEdge(e, false); de1.Sym = de2; de2.Sym = de1; Add(de1); Add(de2); } }
/// <summary> /// /// </summary> /// <param name="dirEdgeList"></param> public void FindEdge(IList dirEdgeList) { /* * Check all forward DirectedEdges only. This is still general, * because each edge has a forward DirectedEdge. */ for (IEnumerator i = dirEdgeList.GetEnumerator(); i.MoveNext(); ) { DirectedEdge de = (DirectedEdge)i.Current; if (!de.IsForward) continue; CheckForRightmostCoordinate(de); } /* * If the rightmost point is a node, we need to identify which of * the incident edges is rightmost. */ Assert.IsTrue(_minIndex != 0 || _minCoord.Equals(_minDe.Coordinate), "inconsistency in rightmost processing"); if (_minIndex == 0) FindRightmostEdgeAtNode(); else FindRightmostEdgeAtVertex(); /* * now check that the extreme side is the R side. * If not, use the sym instead. */ _orientedDe = _minDe; Positions rightmostSide = GetRightmostSide(_minDe, _minIndex); if (rightmostSide == Positions.Left) _orientedDe = _minDe.Sym; }
/// <summary> /// /// </summary> /// <param name="de"></param> /// <param name="index"></param> /// <returns></returns> private Positions GetRightmostSide(DirectedEdge de, int index) { Positions side = GetRightmostSideOfSegment(de, index); if (side < 0) side = GetRightmostSideOfSegment(de, index - 1); if (side < 0) { // reaching here can indicate that segment is horizontal _minCoord = null; CheckForRightmostCoordinate(de); } return side; }
/// <summary> /// /// </summary> /// <param name="start"></param> private static void VisitLinkedDirectedEdges(DirectedEdge start) { DirectedEdge startDe = start; DirectedEdge de = start; do { Assert.IsTrue(de != null, "found null Directed Edge"); de.IsVisited = true; de = de.Next; } while (de != startDe); }
/// <summary> /// Collect all the points from the DirectedEdges of this ring into a contiguous list. /// </summary> /// <param name="start"></param> protected virtual void ComputePoints(DirectedEdge start) { StartDe = start; DirectedEdge de = start; bool isFirstEdge = true; do { Assert.IsTrue(de != null, "found null Directed Edge"); if (de == null) continue; if (de.EdgeRing == this) throw new TopologyException("Directed Edge visited twice during ring-building at " + de.Coordinate); _edges.Add(de); Label label = de.Label; Assert.IsTrue(label.IsArea()); MergeLabel(label); AddPoints(de.Edge, de.IsForward, isFirstEdge); isFirstEdge = false; SetEdgeRing(de, this); de = GetNext(de); } while (de != StartDe); }
/// <summary> /// /// </summary> /// <param name="de"></param> public virtual void ComputeDepths(DirectedEdge de) { int edgeIndex = FindIndex(de); int startDepth = de.GetDepth(Positions.Left); int targetLastDepth = de.GetDepth(Positions.Right); // compute the depths from this edge up to the end of the edge array int nextDepth = ComputeDepths(edgeIndex + 1, EdgeList.Count, startDepth); // compute the depths for the initial part of the array int lastDepth = ComputeDepths(0, edgeIndex, nextDepth); if (lastDepth != targetLastDepth) throw new TopologyException("depth mismatch at " + de.Coordinate); }
/// <summary> /// /// </summary> /// <param name="start"></param> /// <param name="geometryFactory"></param> protected EdgeRing(DirectedEdge start, IGeometryFactory geometryFactory) { _innerGeometryFactory = geometryFactory; ComputePoints(start); ComputeRing(); }
/// <summary> /// /// </summary> /// <param name="de"></param> private void CopySymDepths(DirectedEdge de) { DirectedEdge sym = de.Sym; sym.SetDepth(Positions.Left, de.GetDepth(Positions.Right)); sym.SetDepth(Positions.Right, de.GetDepth(Positions.Left)); }
/// <summary> /// /// </summary> private void FindRightmostEdgeAtNode() { Node node = _minDe.Node; DirectedEdgeStar star = (DirectedEdgeStar)node.Edges; _minDe = star.GetRightmostEdge(); // the DirectedEdge returned by the previous call is not // necessarily in the forward direction. Use the sym edge if it isn't. if (!_minDe.IsForward) { _minDe = _minDe.Sym; _minIndex = _minDe.Edge.Coordinates.Count - 1; } }