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; }
/// <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)); }