/// <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>
 public 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>
        /// 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 void CollectBoundaryTouchEdge(DirectedEdge de, SpatialFunction opCode, IList<Edge> 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 == SpatialFunction.Intersection)
            {
                edges.Add(de.Edge);
                de.VisitedEdge = true;
            }
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 /// <param name="er"></param>
 public override void SetEdgeRing(DirectedEdge de, EdgeRing er)
 {
     de.MinEdgeRing = er;
 }
 /// <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.Length - 1;
     }
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="start"></param>
 /// <param name="geometryFactory"></param>
 public MinimalEdgeRing(DirectedEdge start, IGeometryFactory geometryFactory) 
     : base(start, geometryFactory) { }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 /// <returns></returns>
 public override DirectedEdge GetNext(DirectedEdge de)
 {
     return de.NextMin;
 }
Beispiel #8
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="start"></param>
 /// <param name="geometryFactory"></param>
 protected EdgeRing(DirectedEdge start, GeometryFactory geometryFactory)
 {
     _geometryFactory = geometryFactory;
     ComputePoints(start);
     ComputeRing();
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 private void CheckForRightmostCoordinate(DirectedEdge de)
 {
     Coordinate[] coord = de.Edge.Coordinates;
     for (int i = 0; i < coord.Length - 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];
         }
     }
 }
Beispiel #10
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 /// <param name="er"></param>
 public abstract void SetEdgeRing(DirectedEdge de, EdgeRing er);
Beispiel #11
0
        private EdgeRing _shell; // if non-null, the ring is a hole and this EdgeRing is its containing shell

        #endregion Fields

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="start"></param>
        /// <param name="geometryFactory"></param>
        protected EdgeRing(DirectedEdge start, IGeometryFactory geometryFactory)
        {
            _geometryFactory = geometryFactory;
            ComputePoints(start);
            ComputeRing();
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 private static 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>
 /// <param name="de"></param>
 /// <param name="opCode"></param>
 /// <param name="edges"></param>
 public void CollectLineEdge(DirectedEdge de, SpatialFunction opCode, IList<Edge> 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>
 /// 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 static void ComputeDepths(DirectedEdge startEdge)
 {
     Set<Node> nodesVisited = new Set<Node>();
     Queue<Node> nodeQueue = new Queue<Node>();
     Node startNode = startEdge.Node;
     nodeQueue.Enqueue(startNode);
     nodesVisited.Add(startNode);
     startEdge.Visited = true;
     while (nodeQueue.Count != 0)
     {
         Node n = 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
         foreach (DirectedEdge de in (DirectedEdgeStar)n.Edges)
         {
             DirectedEdge sym = de.Sym;
             if (sym.IsVisited) continue;
             Node adjNode = sym.Node;
             if (!(nodesVisited.Contains(adjNode)))
             {
                 nodeQueue.Enqueue(adjNode);
                 nodesVisited.Add(adjNode);
             }
         }
     }
 }
        /// <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 void AddEdges(IList<Edge> edgesToAdd)
        {
            // create all the nodes for the edges
            foreach (Edge e in edgesToAdd)
            {
                _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);
            }
        }
Beispiel #16
0
        /// <summary>
        /// Traverse the star of DirectedEdges, linking the included edges together.
        /// To link two dirEdges, the next pointer for an incoming dirEdge
        /// is set to the next outgoing edge.
        /// DirEdges are only linked if:
        /// they belong to an area (i.e. they have sides)
        /// they are marked as being in the result
        /// Edges are linked in CCW order (the order they are stored).
        /// This means that rings have their face on the Right
        /// (in other words, the topological location of the face is given by the RHS label of the DirectedEdge).
        /// PRECONDITION: No pair of dirEdges are both marked as being in the result.
        /// </summary>
        public void LinkResultDirectedEdges()
        {
            // make sure edges are copied to resultAreaEdges list
            GetResultAreaEdges();
            // find first area edge (if any) to start linking at
            DirectedEdge firstOut = null;
            DirectedEdge incoming = null;
            int          state    = ScanningForIncoming;

            // link edges in CCW order
            for (int i = 0; i < _resultAreaEdgeList.Count; i++)
            {
                var nextOut = _resultAreaEdgeList[i];
                var nextIn  = nextOut.Sym;

                // skip de's that we're not interested in
                if (!nextOut.Label.IsArea())
                {
                    continue;
                }

                // record first outgoing edge, in order to link the last incoming edge
                if (firstOut == null && nextOut.IsInResult)
                {
                    firstOut = nextOut;
                }

                switch (state)
                {
                case ScanningForIncoming:
                    if (!nextIn.IsInResult)
                    {
                        continue;
                    }
                    incoming = nextIn;
                    state    = LinkingToOutgoing;
                    break;

                case LinkingToOutgoing:
                    if (!nextOut.IsInResult)
                    {
                        continue;
                    }
                    incoming.Next = nextOut;
                    state         = ScanningForIncoming;
                    break;

                default:
                    break;
                }
            }
            if (state == LinkingToOutgoing)
            {
                if (firstOut == null)
                {
                    throw new TopologyException("no outgoing dirEdge found", Coordinate);
                }
                Assert.IsTrue(firstOut.IsInResult, "unable to link last incoming dirEdge");
                incoming.Next = firstOut;
            }
        }
        /*
         * /// <summary>
         * ///
         * /// </summary>
         * public DirectedEdgeStar() { }
         */

        /// <summary>
        /// Insert a directed edge in the list.
        /// </summary>
        /// <param name="ee"></param>
        public override void Insert(EdgeEnd ee)
        {
            DirectedEdge de = (DirectedEdge)ee;

            InsertEdgeEnd(de, de);
        }
        /// <summary>
        /// Traverse the star of edges, maintaing the current location in the result
        /// area at this node (if any).
        /// If any L edges are found in the interior of the result, mark them as covered.
        /// </summary>
        public void FindCoveredLineEdges()
        {
            // Since edges are stored in CCW order around the node,
            // as we move around the ring we move from the right to the left side of the edge

            /*
             * Find first DirectedEdge of result area (if any).
             * The interior of the result is on the RHS of the edge,
             * so the start location will be:
             * - Interior if the edge is outgoing
             * - Exterior if the edge is incoming
             */
            Location startLoc = Location.Null;

            foreach (DirectedEdge nextOut in Edges)
            {
                DirectedEdge nextIn = nextOut.Sym;
                if (!nextOut.IsLineEdge)
                {
                    if (nextOut.IsInResult)
                    {
                        startLoc = Location.Interior;
                        break;
                    }
                    if (nextIn.IsInResult)
                    {
                        startLoc = Location.Exterior;
                        break;
                    }
                }
            }
            // no A edges found, so can't determine if Curve edges are covered or not
            if (startLoc == Location.Null)
            {
                return;
            }

            /*
             * move around ring, keeping track of the current location
             * (Interior or Exterior) for the result area.
             * If Curve edges are found, mark them as covered if they are in the interior
             */
            Location currLoc = startLoc;

            foreach (DirectedEdge nextOut in Edges)
            {
                DirectedEdge nextIn = nextOut.Sym;
                if (nextOut.IsLineEdge)
                {
                    nextOut.Edge.Covered = (currLoc == Location.Interior);
                }
                else
                {
                    // edge is an Area edge
                    if (nextOut.IsInResult)
                    {
                        currLoc = Location.Exterior;
                    }
                    if (nextIn.IsInResult)
                    {
                        currLoc = Location.Interior;
                    }
                }
            }
        }
Beispiel #19
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="de"></param>
 /// <returns></returns>
 public abstract DirectedEdge GetNext(DirectedEdge de);
 /// <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;
 }
Beispiel #21
0
        /// <summary> 
        /// Collect all the points from the DirectedEdges of this ring into a contiguous list.
        /// </summary>
        /// <param name="start"></param>
        protected void ComputePoints(DirectedEdge start)
        {
            startDe = start;
            DirectedEdge de = start;
            bool isFirstEdge = true;
            do
            {
                if (de == null)
                    throw new TopologyException("found null Directed Edge");
                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>
        /// <param name="i"></param>
        /// <returns></returns>
        private Positions GetRightmostSideOfSegment(DirectedEdge de, int i)
        {
            Edge e = de.Edge;
            Coordinate[] coord = e.Coordinates;

            if (i < 0 || i + 1 >= coord.Length)
                return Positions.Parallel;
            if (coord[i].Y == coord[i + 1].Y)
                return Positions.Parallel;

            Positions pos = Positions.Left;
            if (coord[i].Y < coord[i + 1].Y)
                pos = Positions.Right;

            return pos;
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="start"></param>
 protected void VisitLinkedDirectedEdges(DirectedEdge start)
 {
     DirectedEdge startDe = start;
     DirectedEdge de = start;
     do
     {
         Assert.IsTrue(de != null, "found null Directed Edge");
         de.Visited = true;
         de = de.Next;
     }
     while (de != startDe);
 }
        /// <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<DepthSegment> stabbedSegments)
        {
            Coordinate[] pts = dirEdge.Edge.Coordinates;
            for (int i = 0; i < pts.Length - 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
                var 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.P0, _seg.P1, 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);
                var ds = new DepthSegment(_seg, depth);
                stabbedSegments.Add(ds);
            }
        }