// Called by LowReflectionEvent or HighReflectionEvent ctors, which are called out of // AddReflectionEvent, which in turn is called by LoadLookaheadIntersections. // In this case we know the eventObstacle and initialObstacle are the same obstacle (the // one that the reflected ray bounced off of, to generate the Left/HighReflectionEvent). internal BasicReflectionEvent(BasicReflectionEvent previousSite, Obstacle reflectingObstacle, Point site) { this.InitialObstacle = previousSite.ReflectingObstacle; this.ReflectingObstacle = reflectingObstacle; this.site = site; this.PreviousSite = previousSite; }
protected override bool InsertParallelReflectionSegment(Point start, Point end, Obstacle eventObstacle, BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide, BasicReflectionEvent action) { // See notes in InsertPerpendicularReflectionSegment for comments about an existing segment. // Here, we call AddSegment which adds the segment and continues the reflection staircase. if (null != ParallelScanSegments.Find(start, end)) { return false; } return AddSegment(start, end, eventObstacle, lowNborSide, highNborSide, action, ScanSegment.ReflectionWeight); }
void AddReflectionEvent(BasicReflectionEvent previousSite, BasicObstacleSide side, Point site) { Debug.Assert(null != scanLine.Find(side), "AddReflectionEvent could not find 'side' in the scanline"); // Add an event that will be drained when a side spanning the scanline-parallel is loaded // as the sweep moves "up". var lowSide = side as LowObstacleSide; if (lowSide != null) { eventQueue.Enqueue(new LowReflectionEvent(previousSite, lowSide, site)); } else { eventQueue.Enqueue(new HighReflectionEvent(previousSite, (HighObstacleSide)side, site)); } }
protected abstract bool InsertParallelReflectionSegment(Point start, Point end, Obstacle eventObstacle, BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide, BasicReflectionEvent action);
private bool AddParallelReflectionSegment(Obstacle eventObstacle, BasicObstacleSide lowNborSide , BasicObstacleSide highNborSide, BasicReflectionEvent action) { // If this is reflecting to a low neighbor, then that intersect is 'start' in the low-to-high // sequence, and the event site is the end; otherwise we start at the event site and end at // the high neighbor. Point intersect = ScanLineIntersectSide(action.Site, lowNborSide ?? highNborSide); Point start = (null != lowNborSide) ? intersect : action.Site; Point end = (null != lowNborSide) ? action.Site : intersect; // Now get the opposite neighbors so AddSegment can continue the reflection chain. if (null == lowNborSide) { lowNborSide = scanLine.NextLow(highNborSide).Item; } else { highNborSide = scanLine.NextHigh(lowNborSide).Item; } return InsertParallelReflectionSegment(start, end, eventObstacle, lowNborSide, highNborSide, action); }
// Determine whether the event is valid and do some common processing. bool AddPerpendicularReflectionSegment(BasicReflectionEvent currentEvent, BasicObstacleSide eventSide, BasicObstacleSide nborSide) { // If eventSide is null it means we had the wrong side type as a scanline neighbor. // If another obstacle opened up, then that obstacle (or another intervening one) should have // drained this reflection event. Debug.Assert(null != eventSide, "eventSide should not be null"); // Between the time currentEvent was queued and the time we're now processing it, another // obstacle may have opened between the previousSite and the eventSite, in which case it // removed currentEvent from the queue already. So currentEvent may be stale. The new // obstacle may have stored *another* lookahead site with the same scanline-parallel // coordinate (but higher up perpendicularly). So remove the exact site of currentEvent; // otherwise the currentEvent could be a stale event with the lower scanline-parallel // coordinate, and would remove the site from the lookahead list before the "live" event // looks for it. See RectilinearTests.ReflectionsRemoveInterceptedSite. if (lookaheadScan.RemoveExact(currentEvent.PreviousSite)) { Debug.Assert(currentEvent.InitialObstacle == currentEvent.PreviousSite.ReflectingObstacle , "Inconsistency: currentEvent.InitialObstacle != currentEvent.PreviousSite.ReflectingObstacle"); // ReSharper disable HeuristicUnreachableCode // ReSharper disable ConditionIsAlwaysTrueOrFalse if (null == eventSide) { // We've removed the event so there's nothing else to do. return false; } // ReSharper restore ConditionIsAlwaysTrueOrFalse // ReSharper restore HeuristicUnreachableCode // If the two sides intersect ahead of the scanline, we don't want the reflection. // If the reflecting side is flat, no reflection is done - that's handled by OpenVertexEvent. Debug.Assert(!IsFlat(eventSide), "Flat sides should not be encountered in reflections"); if (currentEvent.PreviousSite.IsStaircaseStep(currentEvent.ReflectingObstacle)) { // We need to draw the perpendicular lines here because we may be on the second // sweep so there won't be a subsequent sweep to draw them. And if we're on the // second sweep, we may have already loaded this segment as part of a continuation // of an overlapped segment. Either way, we only want this if we are not on an extreme // edge of the target obstacle (reflectingObstacle for the perpendicular segment, // nborSide.Obstacle for the parallel segment). Extreme vertices will generate segments. // See TestRectilinear.Reflection_Staircase_Stops_At_BoundingBox_Side*. if (!StaticGraphUtility.PointIsInRectangleInterior(currentEvent.Site, currentEvent.ReflectingObstacle.VisibilityBoundingBox)) { return false; } DevTraceInfoVgGen(1, "Perpendicular Reflection - Adding Segment [{0} -> {1}]", currentEvent.PreviousSite.Site, currentEvent.Site); DevTraceInfoVgGen(2, " -> side {0}", eventSide); // same indent as AddSegment; eventSide is highNbor if (!InsertPerpendicularReflectionSegment(currentEvent.PreviousSite.Site, currentEvent.Site)) { return false; } // If the neighbor continues the staircase and the parallel segment would hit a non-extreme point // on the neighbor, return true and the Low/HighReflectionEvent handler will add the parallel segment. if ((null != nborSide) && currentEvent.IsStaircaseStep(nborSide.Obstacle)) { return this.ScanLineCrossesObstacle(currentEvent.Site, nborSide.Obstacle); } DevTraceInfoVgGen(1, "Reflection Lookahead site {0} is not an outgoing staircase step; discontinuing", currentEvent.PreviousSite); } else { DevTraceInfoVgGen(1, "Reflection Lookahead site {0} is not an incoming staircase step; discontinuing", currentEvent.PreviousSite); } } else { DevTraceInfoVgGen(1, "Reflection Lookahead site {0} is no longer in the lookahead table; skipping", currentEvent.PreviousSite); } return false; }
internal HighReflectionEvent(BasicReflectionEvent previousSite, HighObstacleSide targetSide, Point site) : base (previousSite, targetSide.Obstacle, site) { this.Side = targetSide; }
internal LowReflectionEvent(BasicReflectionEvent previousSite, LowObstacleSide targetSide, Point site) : base(previousSite, targetSide.Obstacle, site) { this.Side = targetSide; }
protected override bool InsertParallelReflectionSegment(Point start, Point end, Obstacle eventObstacle, BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide, BasicReflectionEvent action) { Debug.Assert(false, "base.wantReflections is false in Sparse mode so this should never be called"); // ReSharper disable HeuristicUnreachableCode return(false); // ReSharper restore HeuristicUnreachableCode }
protected override bool InsertParallelReflectionSegment(Point start, Point end, Obstacle eventObstacle, BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide, BasicReflectionEvent action) { // See notes in InsertPerpendicularReflectionSegment for comments about an existing segment. // Here, we call AddSegment which adds the segment and continues the reflection staircase. if (null != ParallelScanSegments.Find(start, end)) { return(false); } return(AddSegment(start, end, eventObstacle, lowNborSide, highNborSide, action, ScanSegment.ReflectionWeight)); }
// Called by LowReflectionEvent or HighReflectionEvent ctors, which are called out of // AddReflectionEvent, which in turn is called by LoadLookaheadIntersections. // In this case we know the eventObstacle and initialObstacle are the same obstacle (the // one that the reflected ray bounced off of, to generate the Left/HighReflectionEvent). internal BasicReflectionEvent(BasicReflectionEvent previousSite, Obstacle reflectingObstacle, Point site) { this.InitialObstacle = previousSite.ReflectingObstacle; this.ReflectingObstacle = reflectingObstacle; this.site = site; this.PreviousSite = previousSite; }