public void Remove(SweepLineSegment s)
            {
                // remove the node from the balanced binary tree
                BinaryTreeNode <SweepLineSegment> nd = tree.Find(s);

                if (nd == null)
                {
                    return;                           // not there
                }
                // get the above and below segments pointing to each other
                BinaryTreeNode <SweepLineSegment> nx = nd.Next();

                if (nx != null)
                {
                    SweepLineSegment sx = nx.Value;
                    sx.Below = s.Below;
                }
                BinaryTreeNode <SweepLineSegment> np = nd.Previous();

                if (np != null)
                {
                    SweepLineSegment sp = np.Value;
                    sp.Above = s.Above;
                }
                tree.Remove(nd);                       // now  can safely remove it
            }
            public SweepLineSegment Find(Event E)
            {
                // need a segment to find it in the tree
                SweepLineSegment s = new SweepLineSegment();

                s.Edge  = E.Edge;
                s.Above = null;
                s.Below = null;

                BinaryTreeNode <SweepLineSegment> nd = tree.Find(s);

                return(nd?.Value);
            }
            public SweepLineSegment Add(Event E)
            {
                SweepLineSegment segToAdd = new SweepLineSegment {
                    Edge = E.Edge
                };

                // if it is being added, then it must be a LEFT edge event
                // but need to determine which endpoint is the left one
                Microsoft.Xna.Framework.Vector2 v1 = polygon.At(segToAdd.Edge);
                Microsoft.Xna.Framework.Vector2 v2 = polygon.At(segToAdd.Edge + 1);

                // determine which is leftmost
                if (XYOrder(v1, v2) < 0)
                {
                    segToAdd.LeftVertex  = v1;
                    segToAdd.RightVertex = v2;
                }
                else
                {
                    segToAdd.LeftVertex  = v2;
                    segToAdd.RightVertex = v1;
                }
                segToAdd.Above = null;
                segToAdd.Below = null;

                // add a node to the balanced binary tree
                BinaryTreeNode <SweepLineSegment> nd = tree.Add(segToAdd);
                BinaryTreeNode <SweepLineSegment> nx = nd.Next();
                BinaryTreeNode <SweepLineSegment> np = nd.Previous();

                if (nx != null)
                {
                    segToAdd.Above       = nx.Value;
                    segToAdd.Above.Below = segToAdd;
                }
                if (np != null)
                {
                    segToAdd.Below       = np.Value;
                    segToAdd.Below.Above = segToAdd;
                }

                return(segToAdd);
            }
            // test intersect of 2 segments and return: 0=none, 1=intersect
            public bool Intersect(SweepLineSegment s1, SweepLineSegment s2)
            {
                // no intersect if either segment doesn't exist
                if (s1 == null || s2 == null)
                {
                    return(false);
                }

                // check for consecutive edges in polygon
                int e1 = s1.Edge;
                int e2 = s2.Edge;

                if (((e1 + 1) % polygon.Count == e2) || (e1 == (e2 + 1) % polygon.Count))
                {
                    return(false);                          // no non-simple intersect since consecutive
                }
                // test for existence of an intersect point
                double lsign, rsign;

                lsign = IsLeft(s1.LeftVertex, s1.RightVertex, s2.LeftVertex);  //  s2 left point sign
                rsign = IsLeft(s1.LeftVertex, s1.RightVertex, s2.RightVertex); //  s2 right point sign

                if (lsign * rsign > 0)                                         // s2 endpoints have same sign  relative to s1
                {
                    return(false);                                             // => on same side => no intersect is possible
                }
                lsign = IsLeft(s2.LeftVertex, s2.RightVertex, s1.LeftVertex);  //  s1 left point sign
                rsign = IsLeft(s2.LeftVertex, s2.RightVertex, s1.RightVertex); //  s1 right point sign

                if (lsign * rsign > 0)                                         // s1 endpoints have same sign  relative to s2
                {
                    return(false);                                             // => on same side => no intersect is possible
                }
                // the segments s1 and s2 straddle each other
                return(true);                           // => an intersect exists
            }
        /// <summary>
        /// Computes the intersection of one or more line strings.
        /// </summary>
        public void Compute()
        {
            // source: http://geomalgorithms.com/a09-_intersect-3.html

            _intersections = new List <Coordinate>();
            _edgeIndices   = new List <Tuple <Int32, Int32> >();
            Event              currentEvent = _eventQueue.Next();
            SweepLineSegment   segment;
            IList <Coordinate> intersections;

            while (currentEvent != null)
            {
                if (currentEvent is EndPointEvent)
                {
                    EndPointEvent endPointEvent = (EndPointEvent)currentEvent;
                    switch (endPointEvent.Type)
                    {
                    // Left endpoint event: check for possible intersection with below and / or above segments.
                    case EventType.Left:
                        segment = _sweepLine.Add(endPointEvent);
                        if (segment.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Above.LeftCoordinate, segment.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment,
                                    Above  = segment.Above
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        break;

                    // Right endpoint event: check for possible intersection of the below and above segments.
                    case EventType.Right:
                        segment = _sweepLine.Search(endPointEvent);
                        if (segment != null)
                        {
                            if (segment.Above != null && segment.Below != null)
                            {
                                intersections = LineAlgorithms.Intersection(segment.Above.LeftCoordinate,
                                                                            segment.Above.RightCoordinate,
                                                                            segment.Below.LeftCoordinate,
                                                                            segment.Below.RightCoordinate,
                                                                            PrecisionModel);

                                if (intersections.Count > 0)
                                {
                                    IntersectionEvent intersectionEvent = new IntersectionEvent
                                    {
                                        Vertex = intersections[0],
                                        Below  = segment.Below,
                                        Above  = segment.Above
                                    };
                                    if (!_eventQueue.Contains(intersectionEvent))
                                    {
                                        _eventQueue.Add(intersectionEvent);
                                    }
                                }
                            }
                            _sweepLine.Remove(segment);
                        }
                        break;
                    }
                }

                // Intersection point event: switch the two concerned segments and check for possible intersection with their below and above segments.
                else if (currentEvent is IntersectionEvent)
                {
                    IntersectionEvent intersectionEvent = (IntersectionEvent)currentEvent;

                    /*
                     * Segment order before intersection: segmentBelow <-> segmentAbove <-> segment <-> segmentAboveAbove
                     * Segment order after intersection:  segmentBelow <-> segment <-> segmentAbove <-> segmentAboveAbove
                     */
                    segment = intersectionEvent.Above;
                    SweepLineSegment segmentAbove = intersectionEvent.Below;

                    // Handle closing intersection points when segments (partially) overlap each other.
                    if (intersectionEvent.IsClose)
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));
                        }
                    }

                    // It is possible that the previously detected intersection point is not a real intersection, because a new segment started between them,
                    // therefore a repeated check is necessary to carry out.
                    else if (_sweepLine.Add(intersectionEvent))
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));

                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 1 && !intersections[1].Equals(intersections[0]))
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex  = intersections[1],
                                    Below   = segment,
                                    Above   = segmentAbove,
                                    IsClose = true,
                                };
                                _eventQueue.Add(newIntersectionEvent);
                            }
                        }

                        if (segmentAbove.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        segmentAbove.Above.LeftCoordinate, segmentAbove.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segmentAbove,
                                    Above  = segmentAbove.Above
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }

                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }
                    }
                }

                currentEvent = _eventQueue.Next();
            }
            _hasResult = true;
        }
Beispiel #6
0
        /// <summary>
        /// Processes the intersection event.
        /// </summary>
        /// <param name="intersectionEvent">The intersection event.</param>
        private void ProcessIntersectionEvent(IntersectionEvent intersectionEvent)
        {
            SweepLineSegment segment;
            Intersection     intersection;

            /*
             * segment order before intersection: segmentBelow <-> segmentAbove <-> segment <-> segmentAboveAbove
             * segment order after intersection:  segmentBelow <-> segment <-> segmentAbove <-> segmentAboveAbove
             */
            segment = intersectionEvent.Above;
            SweepLineSegment segmentAbove = intersectionEvent.Below;

            // dandle closing intersection points when segments (partially) overlap each other
            if (intersectionEvent.IsClosing)
            {
                if (!this.sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                {
                    this.intersections.Add(intersectionEvent.Vertex);
                    this.edgeIndexes.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                      Math.Max(segment.Edge, segmentAbove.Edge)));
                }
            }

            // it is possible that the previously detected intersection point is not a real intersection, because a new segment started between them,
            // therefore a repeated check is necessary to carry out
            else if (this.sweepLine.Add(intersectionEvent))
            {
                if (!this.sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                {
                    this.intersections.Add(intersectionEvent.Vertex);
                    this.edgeIndexes.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                      Math.Max(segment.Edge, segmentAbove.Edge)));

                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate, this.PrecisionModel);

                    if (intersection.Type == IntersectionType.Interval)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex    = intersection.End,
                            Below     = segment,
                            Above     = segmentAbove,
                            IsClosing = true,
                        };
                        this.eventQueue.Add(newIntersectionEvent);
                    }
                }

                if (segmentAbove.Above != null)
                {
                    intersection = LineAlgorithms.Intersection(segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate, segmentAbove.Above.LeftCoordinate, segmentAbove.Above.RightCoordinate, this.PrecisionModel);

                    if (intersection != null && intersection.Coordinate.X >= intersectionEvent.Vertex.X)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segmentAbove,
                            Above  = segmentAbove.Above
                        };
                        if (!this.eventQueue.Contains(newIntersectionEvent))
                        {
                            this.eventQueue.Add(newIntersectionEvent);
                        }
                    }
                }

                if (segment.Below != null)
                {
                    intersection = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, this.PrecisionModel);

                    if (intersection != null && intersection.Coordinate.X >= intersectionEvent.Vertex.X)
                    {
                        IntersectionEvent newIntersectionEvent = new IntersectionEvent
                        {
                            Vertex = intersection.Coordinate,
                            Below  = segment.Below,
                            Above  = segment
                        };
                        if (!this.eventQueue.Contains(newIntersectionEvent))
                        {
                            this.eventQueue.Add(newIntersectionEvent);
                        }
                    }
                }
            }
        }
 static int SLsegComparison(SweepLineSegment a, SweepLineSegment b)
 {
     return(a.Edge.CompareTo(b.Edge));
 }