Esempio n. 1
0
 // Set the initial ActiveLowSide and ActiveHighSide of the obstacle starting at this point.
 internal void CreateInitialSides(PolylinePoint startPoint, ScanDirection scanDir)
 {
     Debug.Assert((null == ActiveLowSide) && (null == ActiveHighSide)
                  , "Cannot call SetInitialSides when sides are already set");
     ActiveLowSide  = new LowObstacleSide(this, startPoint, scanDir);
     ActiveHighSide = new HighObstacleSide(this, startPoint, scanDir);
     if (scanDir.IsFlat(ActiveHighSide))
     {
         // No flat sides in the scanline; we'll do lookahead processing in the scanline to handle overlaps
         // with existing segments, and normal neighbor handling will take care of collinear OpenVertexEvents.
         ActiveHighSide = new HighObstacleSide(this, ActiveHighSide.EndVertex, scanDir);
     }
 }
        } // end ProcessEvent(OpenVertexEvent)

        void ProcessEvent(LowBendVertexEvent lowVertEvent) {
            // Note:  we only draw lines only from "interesting" vertices, which would be those
            // that open or close an obstacle, as well as staircase Reflections (see doc). This means
            // Low/HighVertexEvents routines will just track the change in ActiveLowSide/ActiveHighSide.

            // This is a vertex on the low side of the obstacle.  Update the ActiveLowSide in the obstacle
            // and scanline (this also checks for Reflection events).
            var obstacle = lowVertEvent.Obstacle;
            var lowSide = new LowObstacleSide(obstacle, lowVertEvent.Vertex, ScanDirection);

            // If the new lowSide is flat we don't remove it due to potential overlaps; that lets any collinear 
            // OpenVertexEvents know they are overlapped (touching == overlap).  When we get to CloseVertexEvent,
            // keeping the current ActiveLowSide in the scanline tells us how when the interior sides stop
            // so we know when we've found a neighbor.  Similarly, if we're turning down toward the
            // scanline, we let CloseVertexEvent remove the side (in case there are coincident vertices).
            // That leaves the case of still ascending, where we replace the side in the scanline.
            if (ScanDirection.ComparePerpCoord(lowSide.End, lowSide.Start) > 0) {
                this.RemoveSideFromScanLine(this.scanLine.Find(obstacle.ActiveLowSide), lowVertEvent.Site);
                AddSideToScanLine(lowSide, lowVertEvent.Site);
                obstacle.ActiveLowSide = lowSide;
                EnqueueLowBendVertexEvent(lowSide);
            }
        } // end ProcessEvent(LowBendVertexEvent)
Esempio n. 3
0
 internal LowReflectionEvent(BasicReflectionEvent previousSite, LowObstacleSide 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;
 }
        // As described in the document, we currently don't create ScanSegments where a flat top/bottom boundary may have
        // intervals that are embedded within overlapped segments:
        //      obstacle1 |  |obstacle2  | obstacle3 |          | obstacle4 | obstacle2|  |
        //                |  +-----------|===========|??????????|===========|----------+  | obstacle5
        //   ...__________|              |___________|          |___________|             |__________...
        // Here, there will be no ScanSegment created at ??? along the border of obstacle2 between obstacle3
        // and obstacle4.  This is not a concern because that segment is useless anyway; a path from outside
        // obstacle2 will not be able to see it unless there is another obstacle in that gap, and then that
        // obstacle's side-derived ScanSegments will create non-overlapped edges; and there are already edges
        // from the upper/lower extreme vertices of obstacle 3 and obstacle4 to ensure a connected graph.
        // If there is a routing from an obstacle outside obstacle2 to one embedded within obstacle2, the
        // port visibility will create the necessary edges.
        //
        // We don't try to determine nesting depth and create different VisibilityEdge weights to prevent spurious
        // nested-obstacle crossings; we just care about overlapped vs. not-overlapped.
        // If this changes, we would have to: Find the overlap depth at the lowNborSide intersection,
        // then increment/decrement according to side type as we move from low to high, then create a different
        // ScanSegment at each obstacle-side crossing, making ScanSegment.IsOverlapped a depth instead of bool.
        // Then pass that depth through to VisibilityEdge as an increased weight.  (This would also automatically
        // handle the foregoing situation of non-overlapped intervals in the middle of a flat top/bottom border,
        // not that it would really gain anything).
        void CreateScanSegments(Obstacle obstacle, HighObstacleSide lowNborSide, BasicObstacleSide lowOverlapSide, 
                                BasicObstacleSide highOverlapSide, LowObstacleSide highNborSide, BasicVertexEvent vertexEvent) {
            // If we have either of the high/low OverlapSides, we'll need to see if they're inside
            // another obstacle.  If not, they end the overlap.
            if ((null == highOverlapSide) || IntersectionAtSideIsInsideAnotherObstacle(highOverlapSide, vertexEvent)) {
                highOverlapSide = highNborSide;
            }
            if ((null == lowOverlapSide) || IntersectionAtSideIsInsideAnotherObstacle(lowOverlapSide, vertexEvent)) {
                lowOverlapSide = lowNborSide;
            }

            // There may be up to 3 segments; for a simple diagram, |# means low-side border of
            // obstacle '#' and #| means high-side, with 'v' meaning our event vertex.  Here are
            // the two cases where we create a single non-overlapped ScanSegment (from the Low
            // side in the diagram, but the same logic works for the High side).
            //  - non-overlapped:   1|  v  |2
            //                 ...---+     +---...
            //  - non-overlapped to an "inner" highNbor on a flat border:   1|  vLow  |2   vHigh
            //                                                          ...---+  +-----+=========...
            // This may be the low side of a flat bottom or top border, so lowNbor or highNbor 
            // may be in the middle of the border.
            Point lowNborIntersect = ScanLineIntersectSide(vertexEvent.Site, lowNborSide);
            Point highNborIntersect = ScanLineIntersectSide(vertexEvent.Site, highNborSide);
            bool lowNborEndpointIsOverlapped = IntersectionAtSideIsInsideAnotherObstacle(lowNborSide,
                        vertexEvent.Obstacle /*obstacleToIgnore*/, lowNborIntersect);

            if (!lowNborEndpointIsOverlapped && (lowNborSide == lowOverlapSide)) {
                // Nothing is overlapped so create one segment.
                AddSegment(lowNborIntersect, highNborIntersect, obstacle, lowNborSide, highNborSide, vertexEvent,
                        ScanSegment.NormalWeight);
                return;
            }

            // Here are the different interval combinations for overlapped cases.
            //  - non-overlapped, overlapped:  1|  |2  v  |3
            //                            ...---+  +------+===...
            //  - non-overlapped, overlapped, non-overlapped:  1|  |2  v  2|  |3
            //                                                ==+  +-------+  +--...
            //  - overlapped:   |1  2|  v  |3  ...1|
            //            ...---+====+-----+===...-+
            //  - overlapped, non-overlapped:  |1  2|  v  1|  |3
            //                           ...---+====+------+  +---...
            // We will not start overlapped and then go to non-overlapped and back to overlapped,
            // because we would have found the overlap-ending/beginning sides as nearer neighbors.

            // Get the other intersections we'll want.
            Point highOverlapIntersect = (highOverlapSide == highNborSide) ? highNborIntersect
                                            : ScanLineIntersectSide(vertexEvent.Site, highOverlapSide);
            Point lowOverlapIntersect = (lowOverlapSide == lowNborSide) ? lowNborIntersect
                                            : ScanLineIntersectSide(vertexEvent.Site, lowOverlapSide);

            // Create the segments.
            if (!lowNborEndpointIsOverlapped) {
                // First interval is non-overlapped; there is a second overlapped interval, and may be a 
                // third non-overlapping interval if another obstacle surrounded this vertex.
                AddSegment(lowNborIntersect, lowOverlapIntersect, obstacle, lowNborSide, lowOverlapSide, vertexEvent,
                        ScanSegment.NormalWeight);
                AddSegment(lowOverlapIntersect, highOverlapIntersect, obstacle, lowOverlapSide, highOverlapSide, vertexEvent,
                        ScanSegment.OverlappedWeight);
                if (highOverlapSide != highNborSide) {
                    AddSegment(highOverlapIntersect, highNborIntersect, obstacle, highOverlapSide, highNborSide, vertexEvent,
                        ScanSegment.NormalWeight);
                }
            }
            else {
                // Starts off overlapped so ignore lowOverlapSide.
                AddSegment(lowNborIntersect, highOverlapIntersect, obstacle, lowNborSide, highOverlapSide, vertexEvent, 
                        ScanSegment.OverlappedWeight);
                if (highOverlapSide != highNborSide) {
                    AddSegment(highOverlapIntersect, highNborIntersect, obstacle, highOverlapSide, highNborSide, vertexEvent,
                        ScanSegment.NormalWeight);
                }
            }
        }
Esempio n. 6
0
        // As described in the document, we currently don't create ScanSegments where a flat top/bottom boundary may have
        // intervals that are embedded within overlapped segments:
        //      obstacle1 |  |obstacle2  | obstacle3 |          | obstacle4 | obstacle2|  |
        //                |  +-----------|===========|??????????|===========|----------+  | obstacle5
        //   ...__________|              |___________|          |___________|             |__________...
        // Here, there will be no ScanSegment created at ??? along the border of obstacle2 between obstacle3
        // and obstacle4.  This is not a concern because that segment is useless anyway; a path from outside
        // obstacle2 will not be able to see it unless there is another obstacle in that gap, and then that
        // obstacle's side-derived ScanSegments will create non-overlapped edges; and there are already edges
        // from the upper/lower extreme vertices of obstacle 3 and obstacle4 to ensure a connected graph.
        // If there is a routing from an obstacle outside obstacle2 to one embedded within obstacle2, the
        // port visibility will create the necessary edges.
        //
        // We don't try to determine nesting depth and create different VisibilityEdge weights to prevent spurious
        // nested-obstacle crossings; we just care about overlapped vs. not-overlapped.
        // If this changes, we would have to: Find the overlap depth at the lowNborSide intersection,
        // then increment/decrement according to side type as we move from low to high, then create a different
        // ScanSegment at each obstacle-side crossing, making ScanSegment.IsOverlapped a depth instead of bool.
        // Then pass that depth through to VisibilityEdge as an increased weight.  (This would also automatically
        // handle the foregoing situation of non-overlapped intervals in the middle of a flat top/bottom border,
        // not that it would really gain anything).
        void CreateScanSegments(Obstacle obstacle, HighObstacleSide lowNborSide, BasicObstacleSide lowOverlapSide,
                                BasicObstacleSide highOverlapSide, LowObstacleSide highNborSide, BasicVertexEvent vertexEvent)
        {
            // If we have either of the high/low OverlapSides, we'll need to see if they're inside
            // another obstacle.  If not, they end the overlap.
            if ((null == highOverlapSide) || IntersectionAtSideIsInsideAnotherObstacle(highOverlapSide, vertexEvent))
            {
                highOverlapSide = highNborSide;
            }

            if ((null == lowOverlapSide) || IntersectionAtSideIsInsideAnotherObstacle(lowOverlapSide, vertexEvent))
            {
                lowOverlapSide = lowNborSide;
            }

            // There may be up to 3 segments; for a simple diagram, |# means low-side border of
            // obstacle '#' and #| means high-side, with 'v' meaning our event vertex.  Here are
            // the two cases where we create a single non-overlapped ScanSegment (from the Low
            // side in the diagram, but the same logic works for the High side).
            //  - non-overlapped:   1|  v  |2
            //                 ...---+     +---...
            //  - non-overlapped to an "inner" highNbor on a flat border:   1|  vLow  |2   vHigh
            //                                                          ...---+  +-----+=========...
            // This may be the low side of a flat bottom or top border, so lowNbor or highNbor
            // may be in the middle of the border.
            Point lowNborIntersect            = ScanLineIntersectSide(vertexEvent.Site, lowNborSide);
            Point highNborIntersect           = ScanLineIntersectSide(vertexEvent.Site, highNborSide);
            bool  lowNborEndpointIsOverlapped = IntersectionAtSideIsInsideAnotherObstacle(lowNborSide,
                                                                                          vertexEvent.Obstacle /*obstacleToIgnore*/, lowNborIntersect);

            if (!lowNborEndpointIsOverlapped && (lowNborSide == lowOverlapSide))
            {
                // Nothing is overlapped so create one segment.
                AddSegment(lowNborIntersect, highNborIntersect, obstacle, lowNborSide, highNborSide, vertexEvent,
                           ScanSegment.NormalWeight);
                return;
            }

            // Here are the different interval combinations for overlapped cases.
            //  - non-overlapped, overlapped:  1|  |2  v  |3
            //                            ...---+  +------+===...
            //  - non-overlapped, overlapped, non-overlapped:  1|  |2  v  2|  |3
            //                                                ==+  +-------+  +--...
            //  - overlapped:   |1  2|  v  |3  ...1|
            //            ...---+====+-----+===...-+
            //  - overlapped, non-overlapped:  |1  2|  v  1|  |3
            //                           ...---+====+------+  +---...
            // We will not start overlapped and then go to non-overlapped and back to overlapped,
            // because we would have found the overlap-ending/beginning sides as nearer neighbors.

            // Get the other intersections we'll want.
            Point highOverlapIntersect = (highOverlapSide == highNborSide) ? highNborIntersect
                                            : ScanLineIntersectSide(vertexEvent.Site, highOverlapSide);
            Point lowOverlapIntersect = (lowOverlapSide == lowNborSide) ? lowNborIntersect
                                            : ScanLineIntersectSide(vertexEvent.Site, lowOverlapSide);

            // Create the segments.
            if (!lowNborEndpointIsOverlapped)
            {
                // First interval is non-overlapped; there is a second overlapped interval, and may be a
                // third non-overlapping interval if another obstacle surrounded this vertex.
                AddSegment(lowNborIntersect, lowOverlapIntersect, obstacle, lowNborSide, lowOverlapSide, vertexEvent,
                           ScanSegment.NormalWeight);
                AddSegment(lowOverlapIntersect, highOverlapIntersect, obstacle, lowOverlapSide, highOverlapSide, vertexEvent,
                           ScanSegment.OverlappedWeight);
                if (highOverlapSide != highNborSide)
                {
                    AddSegment(highOverlapIntersect, highNborIntersect, obstacle, highOverlapSide, highNborSide, vertexEvent,
                               ScanSegment.NormalWeight);
                }
            }
            else
            {
                // Starts off overlapped so ignore lowOverlapSide.
                AddSegment(lowNborIntersect, highOverlapIntersect, obstacle, lowNborSide, highOverlapSide, vertexEvent,
                           ScanSegment.OverlappedWeight);
                if (highOverlapSide != highNborSide)
                {
                    AddSegment(highOverlapIntersect, highNborIntersect, obstacle, highOverlapSide, highNborSide, vertexEvent,
                               ScanSegment.NormalWeight);
                }
            }
        }
 // Set the initial ActiveLowSide and ActiveHighSide of the obstacle starting at this point.
 internal void CreateInitialSides(PolylinePoint startPoint, ScanDirection scanDir) {
     Debug.Assert((null == ActiveLowSide) && (null == ActiveHighSide)
                  , "Cannot call SetInitialSides when sides are already set");
     ActiveLowSide = new LowObstacleSide(this, startPoint, scanDir);
     ActiveHighSide = new HighObstacleSide(this, startPoint, scanDir);
     if (scanDir.IsFlat(ActiveHighSide)) {
         // No flat sides in the scanline; we'll do lookahead processing in the scanline to handle overlaps
         // with existing segments, and normal neighbor handling will take care of collinear OpenVertexEvents.
         ActiveHighSide = new HighObstacleSide(this, ActiveHighSide.EndVertex, scanDir);
     }
 }