/// <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> /// Computes whether one or more line strings specified by coordinates intersects with each other. /// </summary> public void Compute() { // source: http://geomalgorithms.com/a09-_intersect-3.html EndPointEvent e = _eventQueue.Next(); SweepLineSegment segment; while (e != null) { switch (e.Type) { case EventType.Left: segment = _sweepLine.Add(e); if (segment.Above != null && _sweepLine.IsAdjacent(segment.Edge, segment.Above.Edge) && segment.LeftCoordinate == segment.Above.LeftCoordinate) { _sweepLine.Intersect(segment, segment.Above); } else if (segment.Below != null && _sweepLine.IsAdjacent(segment.Edge, segment.Below.Edge) && segment.LeftCoordinate == segment.Below.LeftCoordinate) { _sweepLine.Intersect(segment, segment.Below); } if (segment.Above != null && !_sweepLine.IsAdjacent(segment.Edge, segment.Above.Edge) && LineAlgorithms.Intersects(segment.LeftCoordinate, segment.RightCoordinate, segment.Above.LeftCoordinate, segment.Above.RightCoordinate, PrecisionModel)) { _hasResult = true; _result = true; return; } if (segment.Below != null && !_sweepLine.IsAdjacent(segment.Edge, segment.Below.Edge) && LineAlgorithms.Intersects(segment.LeftCoordinate, segment.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, PrecisionModel)) { _hasResult = true; _result = true; return; } break; case EventType.Right: segment = _sweepLine.Search(e); if (segment != null) { if (segment.Above != null && segment.Below != null && !_sweepLine.IsAdjacent(segment.Below.Edge, segment.Above.Edge) && LineAlgorithms.Intersects(segment.Above.LeftCoordinate, segment.Above.RightCoordinate, segment.Below.LeftCoordinate, segment.Below.RightCoordinate, PrecisionModel)) { _hasResult = true; _result = true; return; } _sweepLine.Remove(segment); } break; } e = _eventQueue.Next(); } _hasResult = true; _result = false; }