private void CheckIntersection(StatusItem left, StatusItem right, IBST <SweepEvent> events) { Vector2?intersect = left.LineObject.Intersect(right.LineObject); if (intersect != null) { Vector2?otherIntersect = right.LineObject.Intersect(left.LineObject); if (intersect != null) { float y = ((Vector2)intersect).y; if (y < Line.Point1.y) { if (y > left.LineObject.YInterval.Min && y < left.LineObject.YInterval.Max && y > right.LineObject.YInterval.Min && y < right.LineObject.YInterval.Max) { SweepEvent ev = new SweepEvent(EventType.INTERSECT); ev.StatusItem = left; ev.IntersectingStatusItem = right; if (!events.Contains(ev)) { events.Insert(ev); } } } } } }
private void DivideSegment(SweepEvent ev, Vector2D pos, IBST <SweepEvent> events) { // "Right event" of the "left line segment" resulting from dividing ev.Segment var r = new SweepEvent(pos, false, ev, ev.PolygonType); // "Left event" of the "right line segment" resulting from dividing ev.Segment var l = new SweepEvent(pos, true, ev.OtherEvent, ev.PolygonType); if (SweepEvent.CompareTo(l, ev.OtherEvent) > 0 ) // Avoid a rounding error. The left event would be processed after the right event { ev.OtherEvent.IsStart = true; l.IsStart = false; } ev.OtherEvent.OtherEvent = l; ev.OtherEvent = r; events.Insert(l); events.Insert(r); }
private int PossibleIntersection(SweepEvent ev1, SweepEvent ev2, IBST <SweepEvent> events) { Vector2D intersectionPoint; var nIntersections = FindIntersections(ev1.Point, ev1.OtherEvent.Point, ev2.Point, ev2.OtherEvent.Point, out intersectionPoint); if (nIntersections == 0) { return(0); // no intersection } // If the intersection is between two endpoints if (nIntersections == 1 && (ev1.Point.Equals(ev2.Point) || ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point))) { return(0); // the line segments intersect at an endpoint of both line segments } if (nIntersections == 2 && ev1.PolygonType == ev2.PolygonType) { // The line segments overlap, but they belong to the same polygon throw new ArgumentException(string.Format("Sorry, edges of the same polygon overlap ({0} and {1})", ev1, ev2)); } // The line segments associated to ev1 and ev2 intersect if (nIntersections == 1) { if (!ev1.Point.Equals(intersectionPoint) && !ev1.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev1.Segment { DivideSegment(ev1, intersectionPoint, events); } if (!ev2.Point.Equals(intersectionPoint) && !ev2.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev2.Segment { DivideSegment(ev2, intersectionPoint, events); } return(1); } // The line segments associated to ev1 and ev2 overlap var sortedEvents = new List <SweepEvent>(); var leftEqual = false; var rightEqual = false; if (ev1.Point.Equals(ev2.Point)) { leftEqual = true; } else if (SweepEvent.CompareTo(ev1, ev2) == 1) { sortedEvents.Add(ev2); sortedEvents.Add(ev1); } else { sortedEvents.Add(ev1); sortedEvents.Add(ev2); } if (ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point)) { rightEqual = true; } else if (SweepEvent.CompareTo(ev1.OtherEvent, ev2.OtherEvent) == 1) { sortedEvents.Add(ev2.OtherEvent); sortedEvents.Add(ev1.OtherEvent); } else { sortedEvents.Add(ev1.OtherEvent); sortedEvents.Add(ev2.OtherEvent); } if (leftEqual) { // Both line segments are equal or share the left endpoint ev2.EdgeType = EdgeType.NonContributing; ev1.EdgeType = (ev2.InOut == ev1.InOut) ? EdgeType.SameTransition : EdgeType.DifferentTransition; if (!rightEqual) { DivideSegment(sortedEvents[1].OtherEvent, sortedEvents[0].Point, events); } return(2); } if (rightEqual) { // The line segments share the right endpoint DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); return(3); } if (sortedEvents[0] != sortedEvents[3].OtherEvent) { // No line segment includes totally the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[1], sortedEvents[2].Point, events); return(3); } // One line segment includes the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[3].OtherEvent, sortedEvents[2].Point, events); return(3); }
private void HandleEvent(IBST <SweepEvent> events, IBST <StatusItem> status, SweepEvent ev) { ResultEvents.Add(ev); // Optimization 2 if ((Operation == OperationType.Intersection && ev.Point.x > RightBound) || (Operation == OperationType.Difference && ev.Point.x > SubjectBoundingBox.xMax)) { // We need to connect edges now, so just clear all events. This will result in us immediately // going to ConnectEdges() since there are no more events to handle. InitializeEvents(new List <SweepEvent>()); return; } if (ev.IsStart) // The line segment must be inserted into status { ev.StatusItem = new StatusItem(ev); if (!status.Insert(ev.StatusItem)) { throw new ArgumentException("Failed to insert into state"); } StatusItem prev; var prevFound = status.FindNextSmallest(ev.StatusItem, out prev); ComputeFields(ev, prev, prevFound); StatusItem next; if (status.FindNextBiggest(ev.StatusItem, out next)) { // Process a possible intersection between "ev" and its next neighbor in status if (PossibleIntersection(ev, next.SweepEvent, events) == 2) { ComputeFields(ev, prev, prevFound); ComputeFields(next.SweepEvent, ev.StatusItem, true); } } // Process a possible intersection between "ev" and its previous neighbor in status if (prevFound) { if (PossibleIntersection(prev.SweepEvent, ev, events) == 2) { StatusItem prevprev; var prevprevFound = status.FindNextSmallest(prev, out prevprev); ComputeFields(prev.SweepEvent, prevprev, prevprevFound); ComputeFields(ev, prev, prevFound); } } } else { // The line segment must be removed from status ev = ev.OtherEvent; // We work with the left event StatusItem prev, next; var prevFound = status.FindNextSmallest(ev.StatusItem, out prev); var nextFound = status.FindNextBiggest(ev.StatusItem, out next); // Delete line segment associated to "ev" from status and check for intersection between the neighbors of "ev" in status status.Delete(ev.StatusItem); if (nextFound && prevFound) { PossibleIntersection(prev.SweepEvent, next.SweepEvent, events); } } }
public void HandleEvent(IBST <IntersectionSweepEvent> events, IBST <IntersectionStatusItem> status, IntersectionSweepEvent ev) { if (ev.IsStart) { ev.StatusItem = new IntersectionStatusItem(ev); status.Insert(ev.StatusItem); IntersectionStatusItem prev, next; bool prevFound = status.FindNextSmallest(ev.StatusItem, out prev); bool nextFound = status.FindNextBiggest(ev.StatusItem, out next); if (prevFound) { LineSegment otherSegment = prev.SweepEvent.Segment; Vector2? intersection = ev.Segment.IntersectProper(otherSegment); if (intersection != null) { events.Insert(new IntersectionSweepEvent(intersection.Value, false, false, ev.Segment, otherSegment)); } } if (nextFound) { LineSegment otherSegment = next.SweepEvent.Segment; Vector2? intersection = ev.Segment.IntersectProper(otherSegment); if (intersection != null) { events.Insert(new IntersectionSweepEvent(intersection.Value, false, false, ev.Segment, otherSegment)); } } } else if (ev.IsEnd) { ev = ev.OtherEvent; if (ev.StatusItem == null) { return; } IntersectionStatusItem prev, next; bool prevFound = status.FindNextSmallest(ev.StatusItem, out prev); bool nextFound = status.FindNextBiggest(ev.StatusItem, out next); status.Delete(ev.StatusItem); if (nextFound && prevFound) { LineSegment segment = prev.SweepEvent.Segment; LineSegment otherSegment = next.SweepEvent.Segment; Vector2? intersection = segment.IntersectProper(otherSegment); if (intersection != null) { events.Insert(new IntersectionSweepEvent(intersection.Value, false, false, segment, otherSegment)); } } } else if (ev.IsIntersection) { // stop on first intersection intersected = new List <Edge> { new Edge(new Vertex(ev.Segment.Point1), new Vertex(ev.Segment.Point2)), new Edge(new Vertex(ev.OtherSegment.Point1), new Vertex(ev.OtherSegment.Point2)) }; events.Clear(); status.Clear(); } else { throw new Exception("Invalid event type"); } }
public BSTInOrderIterator(IBST <T> bst) { root = bst; Reset(); }
public new void HandleEvent(IBST <SweepEvent> events, IBST <StatusItem> status, SweepEvent ev) { // keep track of added events for visualization producedEvents.Add(ev); if (ev.IsStart) { ComparePreEvent = true; if (!status.Insert(ev.StatusItem)) { throw new ArgumentException("Failed to insert into state"); } StatusItem prev; if (status.FindNextSmallest(ev.StatusItem, out prev)) { CheckIntersection(prev, ev.StatusItem, events); } StatusItem next; if (status.FindNextBiggest(ev.StatusItem, out next)) { CheckIntersection(ev.StatusItem, next, events); } } else if (ev.IsEnd) { ComparePreEvent = false; StatusItem prev; bool hasPrev = status.FindNextSmallest(ev.StatusItem, out prev); StatusItem next; bool hasNext = status.FindNextBiggest(ev.StatusItem, out next); if (!status.Delete(ev.StatusItem)) { throw new InvalidInitialGeneralPosition("Could not delete from status : ("); } if (hasPrev && hasNext) { CheckIntersection(prev, next, events); } } else if (ev.IsIntersection) { StatusItem left = ev.StatusItem; StatusItem right = ev.IntersectingStatusItem; this.intersections.Add(new Intersection(left.LineObject, right.LineObject)); // Remove ComparePreEvent = true; if (!status.Delete(left)) { throw new InvalidInitialGeneralPosition(left + " not deleted."); } if (!status.Delete(right)) { throw new InvalidInitialGeneralPosition(right + " not deleted."); } // Swap ComparePreEvent = false; // Add status.Insert(left); status.Insert(right); // NOTE: At this point, ComparePreEvent = false implies that right PRECEDES left now StatusItem prev; if (status.FindNextSmallest(right, out prev)) { CheckIntersection(prev, right, events); } StatusItem next; if (status.FindNextBiggest(left, out next)) { CheckIntersection(left, next, events); } } }