コード例 #1
0
        HitTestBehavior InsideObstacleHitTest(Point location, Obstacle obstacle)
        {
            if ((obstacle == insideHitTestIgnoreObstacle1) || (obstacle == insideHitTestIgnoreObstacle2))
            {
                // It's one of the two obstacles we already know about.
                return(HitTestBehavior.Continue);
            }

            if (obstacle.IsGroup)
            {
                // Groups are handled differently from overlaps; we create ScanSegments (overlapped
                // if within a non-group obstacle, else non-overlapped), and turn on/off access across
                // the Group boundary vertices.
                return(HitTestBehavior.Continue);
            }

            if (!StaticGraphUtility.PointIsInRectangleInterior(location, obstacle.VisibilityBoundingBox))
            {
                // The point is on the obstacle boundary, not inside it.
                return(HitTestBehavior.Continue);
            }

            // Note: There are rounding issues using Curve.PointRelativeToCurveLocation at angled
            // obstacle boundaries, hence this function.
            Point high = StaticGraphUtility.RectangleBorderIntersect(obstacle.VisibilityBoundingBox, location
                                                                     , insideHitTestScanDirection.Direction)
                         + insideHitTestScanDirection.DirectionAsPoint;
            Point low = StaticGraphUtility.RectangleBorderIntersect(obstacle.VisibilityBoundingBox, location
                                                                    , insideHitTestScanDirection.OppositeDirection)
                        - insideHitTestScanDirection.DirectionAsPoint;
            var testSeg = new LineSegment(low, high);
            IList <IntersectionInfo> xxs = Curve.GetAllIntersections(testSeg, obstacle.VisibilityPolyline, true /*liftIntersections*/);

            // If this is an extreme point it can have one intersection, in which case we're either on the border
            // or outside; if it's a collinear flat boundary, there can be 3 intersections to this point which again
            // means we're on the border (and 3 shouldn't happen anymore with the curve intersection fixes and
            // PointIsInsideRectangle check above).  So the interesting case is that we have 2 intersections.
            if (2 == xxs.Count)
            {
                Point firstInt  = SpliceUtility.RawIntersection(xxs[0], location);
                Point secondInt = SpliceUtility.RawIntersection(xxs[1], location);

                // If we're on either intersection, we're on the border rather than inside.
                if (!PointComparer.Equal(location, firstInt) && !PointComparer.Equal(location, secondInt) &&
                    (location.CompareTo(firstInt) != location.CompareTo(secondInt)))
                {
                    // We're inside.  However, this may be an almost-flat side, in which case rounding
                    // could have reported the intersection with the start or end of the same side and
                    // a point somewhere on the interior of that side.  Therefore if both intersections
                    // are on the same side (integral portion of the parameter), we consider location
                    // to be on the border.  testSeg is always xxs[*].Segment0.
                    Debug.Assert(testSeg == xxs[0].Segment0, "incorrect parameter ordering to GetAllIntersections");
                    if (!ApproximateComparer.Close(Math.Floor(xxs[0].Par1), Math.Floor(xxs[1].Par1)))
                    {
                        return(HitTestBehavior.Stop);
                    }
                }
            }
            return(HitTestBehavior.Continue);
        }
コード例 #2
0
        internal ObstaclePortEntrance(ObstaclePort oport, Point unpaddedBorderIntersect, Direction outDir, ObstacleTree obstacleTree)
        {
            ObstaclePort            = oport;
            UnpaddedBorderIntersect = unpaddedBorderIntersect;
            OutwardDirection        = outDir;

            // Get the padded intersection.
            var lineSeg = new LineSegment(UnpaddedBorderIntersect, StaticGraphUtility.RectangleBorderIntersect(
                                              oport.Obstacle.VisibilityBoundingBox, UnpaddedBorderIntersect, outDir));
            IList <IntersectionInfo> xxs = Curve.GetAllIntersections(lineSeg, oport.Obstacle.VisibilityPolyline, true /*liftIntersections*/);

            Debug.Assert(1 == xxs.Count, "Expected one intersection");
            this.VisibilityBorderIntersect = ApproximateComparer.Round(SpliceUtility.RawIntersection(xxs[0], UnpaddedBorderIntersect));

            this.MaxVisibilitySegment = obstacleTree.CreateMaxVisibilitySegment(this.VisibilityBorderIntersect,
                                                                                this.OutwardDirection, out this.pointAndCrossingsList);

            // Groups are never in a clump (overlapped) but they may still have their port entrance overlapped.
            if (this.Obstacle.IsOverlapped || (this.Obstacle.IsGroup && !this.Obstacle.IsInConvexHull))
            {
                this.IsOverlapped = obstacleTree.IntersectionIsInsideAnotherObstacle(/*sideObstacle:*/ null, this.Obstacle
                                                                                     , this.VisibilityBorderIntersect, ScanDirection.GetInstance(OutwardDirection));
                if (!this.Obstacle.IsGroup || this.IsOverlapped || this.InteriorEdgeCrossesObstacle(obstacleTree))
                {
                    unpaddedToPaddedBorderWeight = ScanSegment.OverlappedWeight;
                }
            }
            if (this.Obstacle.IsInConvexHull && (unpaddedToPaddedBorderWeight == ScanSegment.NormalWeight))
            {
                SetUnpaddedToPaddedBorderWeightFromHullSiblingOverlaps(obstacleTree);
            }
        }
コード例 #3
0
        protected override void ProcessVertexEvent(RBNode <BasicObstacleSide> lowSideNode,
                                                   RBNode <BasicObstacleSide> highSideNode, BasicVertexEvent vertexEvent)
        {
            var vertexPoints = (base.ScanDirection.IsHorizontal) ? this.horizontalVertexPoints : this.verticalVertexPoints;

            vertexPoints.Insert(vertexEvent.Site);

            // For easier reading...
            var lowNborSide  = LowNeighborSides.LowNeighbor.Item;
            var highNborSide = HighNeighborSides.HighNeighbor.Item;
            var highDir      = base.ScanDirection.Direction;
            var lowDir       = base.ScanDirection.OppositeDirection;

            // Generate the neighbor side intersections, regardless of overlaps; these are the type-2 Steiner points.
            var lowSteiner  = ScanLineIntersectSide(vertexEvent.Site, lowNborSide);
            var highSteiner = ScanLineIntersectSide(vertexEvent.Site, highNborSide);

            // Add the intersections at the neighbor bounding boxes if the intersection is not at a sentinel.
            // Go in the opposite direction from the neighbor intersection to find the border between the Steiner
            // point and vertexEvent.Site (unless vertexEvent.Site is inside the bounding box).
            if (ObstacleTree.GraphBox.Contains(lowSteiner))
            {
                var bboxIntersectBeforeLowSteiner = StaticGraphUtility.RectangleBorderIntersect(lowNborSide.Obstacle.VisibilityBoundingBox, lowSteiner, highDir);
                if (PointComparer.IsPureLower(bboxIntersectBeforeLowSteiner, vertexEvent.Site))
                {
                    this.boundingBoxSteinerPoints.Insert(bboxIntersectBeforeLowSteiner);
                }
            }
            if (ObstacleTree.GraphBox.Contains(highSteiner))
            {
                var bboxIntersectBeforeHighSteiner = StaticGraphUtility.RectangleBorderIntersect(highNborSide.Obstacle.VisibilityBoundingBox, highSteiner, lowDir);
                if (PointComparer.IsPureLower(vertexEvent.Site, bboxIntersectBeforeHighSteiner))
                {
                    this.boundingBoxSteinerPoints.Insert(bboxIntersectBeforeHighSteiner);
                }
            }

            // Add the corners of the bounding box of the vertex obstacle, if they are visible to the event site.
            // This ensures that we "go around" the obstacle, as with the non-orthogonal edges in the paper.
            Point lowCorner, highCorner;

            GetBoundingCorners(lowSideNode.Item.Obstacle.VisibilityBoundingBox, vertexEvent is OpenVertexEvent, this.ScanDirection.IsHorizontal,
                               out lowCorner, out highCorner);
            if (PointComparer.IsPureLower(lowSteiner, lowCorner) || lowNborSide.Obstacle.IsInSameClump(vertexEvent.Obstacle))
            {
                vertexPoints.Insert(lowCorner);
            }

            if (PointComparer.IsPureLower(highCorner, highSteiner) || highNborSide.Obstacle.IsInSameClump(vertexEvent.Obstacle))
            {
                vertexPoints.Insert(highCorner);
            }
        }
コード例 #4
0
        /// <summary>
        /// Create a LineSegment that contains the max visibility from startPoint in the desired direction.
        /// </summary>
        internal LineSegment CreateMaxVisibilitySegment(Point startPoint, Directions dir, out PointAndCrossingsList pacList)
        {
            var graphBoxBorderIntersect = StaticGraphUtility.RectangleBorderIntersect(this.GraphBox, startPoint, dir);

            if (PointComparer.GetDirections(startPoint, graphBoxBorderIntersect) == Directions.None)
            {
                pacList = null;
                return(new LineSegment(startPoint, startPoint));
            }
            var segment = this.RestrictSegmentWithObstacles(startPoint, graphBoxBorderIntersect);

            // Store this off before other operations which overwrite it.
            pacList = this.CurrentGroupBoundaryCrossingMap.GetOrderedListBetween(segment.Start, segment.End);
            return(segment);
        }
コード例 #5
0
        internal List <DebugCurve> Test_GetScanLineDebugCurves()
        {
// ReSharper restore InconsistentNaming
            var debugCurves = new List <DebugCurve>();

            // Alternate the colors between green and blue, so that any inconsistency will stand out.
            // Use red to highlight that.
            string[]          colors   = { "green", "blue" };
            int               index    = 0;
            var               bbox     = new Rectangle();
            BasicObstacleSide prevSide = null;

            foreach (var currentSide in SideTree)
            {
                string color = colors[index];
                index ^= 1;
                if (null == prevSide)
                {
                    // Create this the first time through; adding to an empty rectangle leaves 0,0.
                    bbox = new Rectangle(currentSide.Start, currentSide.End);
                }
                else
                {
                    if (-1 != Compare(prevSide, currentSide))
                    {
                        // Note: we toggled the index, so the red replaces the colour whose turn it is now
                        // and will leave the red line bracketed by two sides of the same colour.
                        color = "red";
                    }
                    bbox.Add(currentSide.Start);
                    bbox.Add(currentSide.End);
                }
                debugCurves.Add(new DebugCurve(0.1, color, new LineSegment(currentSide.Start, currentSide.End)));
                prevSide = currentSide;
            }

            // Add the sweep line.
            Point start = StaticGraphUtility.RectangleBorderIntersect(bbox, this.linePositionAtLastInsertOrRemove, scanDirection.OppositeDirection);
            Point end   = StaticGraphUtility.RectangleBorderIntersect(bbox, this.linePositionAtLastInsertOrRemove, scanDirection.Direction);

            debugCurves.Add(new DebugCurve(0.025, "black", new LineSegment(start, end)));
            return(debugCurves);
        }