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)); }
// Return value is whether or not we added a new segment. bool AddSegment(Point start, Point end, Obstacle eventObstacle , BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide , SweepEvent action, double weight) { DevTraceInfoVgGen(1, "Adding Segment [{0} -> {1} {2}] weight {3}", start, end, weight); DevTraceInfoVgGen(2, " side {0}", lowNborSide); DevTraceInfoVgGen(2, " -> side {0}", highNborSide); if (PointComparer.Equal(start, end)) { return(false); } // See if the new segment subsumes or can be subsumed by the last one. gbcList may be null. PointAndCrossingsList gbcList = CurrentGroupBoundaryCrossingMap.GetOrderedListBetween(start, end); bool extendStart, extendEnd; bool wasSubsumed = ScanSegment.Subsume(ref hintScanSegment, start, end, weight, gbcList, ScanDirection , ParallelScanSegments, out extendStart, out extendEnd); if (!wasSubsumed) { Debug.Assert((weight != ScanSegment.ReflectionWeight) || (ParallelScanSegments.Find(start, end) == null), "Reflection segments already in the ScanSegmentTree should should have been detected before calling AddSegment"); hintScanSegment = ParallelScanSegments.InsertUnique(new ScanSegment(start, end, weight, gbcList)).Item; } else if (weight == ScanSegment.ReflectionWeight) { // Do not continue this; it is probably a situation where a side is at a tiny angle from the axis, // resulting in an initial reflection segment that is parallel and very close to the extreme-vertex-derived // segment, so as the staircase progresses they eventually converge due to floating-point rounding. // See RectilinearFilesTest.ReflectionStaircasesConverge. return(false); } // Do reflections only if the new segment is not overlapped. if (ScanSegment.OverlappedWeight != weight) { // If these fire, it's probably an indication that isOverlapped is not correctly set // and one of the neighbors is an OverlapSide from CreateScanSegments. Debug.Assert(lowNborSide is HighObstacleSide, "lowNbor is not HighObstacleSide"); Debug.Assert(highNborSide is LowObstacleSide, "highNbor is not LowObstacleSide"); // If we are closing the obstacle then the initial Obstacles of the reflections (the ones it // will bounce between) are the opposite neighbors. Otherwise, the OpenVertexEvent obstacle // is the ReflectionEvent initial obstacle. if (action is CloseVertexEvent) { // If both neighbor sides reflect upward, they can't intersect, so we don't need // to store a lookahead site (if neither reflect upward, StoreLookaheadSite no-ops). if (!SideReflectsUpward(lowNborSide) || !SideReflectsUpward(highNborSide)) { // Try to store both; only one will "take" (for the upward-reflecting side). // The initial Obstacle is the opposite neighbor. if (extendStart) { this.StoreLookaheadSite(highNborSide.Obstacle, lowNborSide, start, wantExtreme: false); } if (extendEnd) { this.StoreLookaheadSite(lowNborSide.Obstacle, highNborSide, end, wantExtreme: false); } } } else { if (extendStart) { StoreLookaheadSite(eventObstacle, LowNeighborSides.GroupSideInterveningBeforeLowNeighbor, lowNborSide, start); } if (extendEnd) { StoreLookaheadSite(eventObstacle, HighNeighborSides.GroupSideInterveningBeforeHighNeighbor, highNborSide, end); } } } DevTraceInfoVgGen(2, "HintScanSegment {0}{1}", hintScanSegment, wasSubsumed ? " (subsumed)" : ""); DevTrace_DumpScanSegmentsDuringAdd(3); return(true); }