private void AddGroupIntersectionsToRestrictedRay(Obstacle obstacle, IList <IntersectionInfo> intersections)
        {
            // We'll let the lines punch through any intersections with groups, but track the location so we can enable/disable crossing.
            foreach (var intersectionInfo in intersections)
            {
                var intersect = SpliceUtility.RawIntersection(intersectionInfo, currentRestrictedRay.Start);

                // Skip intersections that are past the end of the restricted segment (though there may still be some
                // there if we shorten it later, but we'll skip them later).
                var distSquared = (intersect - currentRestrictedRay.Start).LengthSquared;
                if (distSquared > restrictedRayLengthSquared)
                {
                    continue;
                }

                var dirTowardIntersect = PointComparer.GetPureDirection(currentRestrictedRay.Start, currentRestrictedRay.End);
                var polyline           = (Polyline)intersectionInfo.Segment1; // this is the second arg to GetAllIntersections
                var dirsOfSide         = CompassVector.VectorDirection(polyline.Derivative(intersectionInfo.Par1));

                // The derivative is always clockwise, so if the side contains the rightward rotation of the
                // direction from the ray origin, then we're hitting it from the inside; otherwise from the outside.
                var dirToInsideOfGroup = dirTowardIntersect;
                if (0 != (dirsOfSide & CompassVector.RotateRight(dirTowardIntersect)))
                {
                    dirToInsideOfGroup = CompassVector.OppositeDir(dirToInsideOfGroup);
                }
                CurrentGroupBoundaryCrossingMap.AddIntersection(intersect, obstacle, dirToInsideOfGroup);
            }
        }
Beispiel #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);
            }
        }
        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);
        }
Beispiel #4
0
        private void LookForCloserNonGroupIntersectionToRestrictRay(IList <IntersectionInfo> intersections)
        {
            int numberOfGoodIntersections            = 0;
            IntersectionInfo closestIntersectionInfo = null;
            var localLeastDistSquared = this.restrictedRayLengthSquared;
            var testDirection         = PointComparer.GetDirections(restrictedIntersectionTestSegment.Start, restrictedIntersectionTestSegment.End);

            foreach (var intersectionInfo in intersections)
            {
                var intersect      = SpliceUtility.RawIntersection(intersectionInfo, currentRestrictedRay.Start);
                var dirToIntersect = PointComparer.GetDirections(currentRestrictedRay.Start, intersect);

                if (dirToIntersect == CompassVector.OppositeDir(testDirection))
                {
                    continue;
                }

                ++numberOfGoodIntersections;

                if (Directions.None == dirToIntersect)
                {
                    localLeastDistSquared   = 0.0;
                    closestIntersectionInfo = intersectionInfo;
                    continue;
                }

                var distSquared = (intersect - currentRestrictedRay.Start).LengthSquared;
                if (distSquared < localLeastDistSquared)
                {
                    // Rounding may falsely report two intersections as different when they are actually "Close",
                    // e.g. a horizontal vs. vertical intersection on a slanted edge.
                    var rawDistSquared = (intersectionInfo.IntersectionPoint - currentRestrictedRay.Start).LengthSquared;
                    if (rawDistSquared < ApproximateComparer.SquareOfDistanceEpsilon)
                    {
                        continue;
                    }

                    localLeastDistSquared   = distSquared;
                    closestIntersectionInfo = intersectionInfo;
                }
            }

            if (null != closestIntersectionInfo)
            {
                // If there was only one intersection and it is quite close to an end, ignore it.
                // If there is more than one intersection, we have crossed the obstacle so we want it.
                if (numberOfGoodIntersections == 1)
                {
                    var intersect = SpliceUtility.RawIntersection(closestIntersectionInfo, currentRestrictedRay.Start);
                    if (ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.Start) ||
                        ApproximateComparer.CloseIntersections(intersect, this.currentRestrictedRay.End))
                    {
                        return;
                    }
                }
                this.restrictedRayLengthSquared = localLeastDistSquared;
                currentRestrictedRay.End        = SpliceUtility.MungeClosestIntersectionInfo(currentRestrictedRay.Start, closestIntersectionInfo
                                                                                             , !StaticGraphUtility.IsVertical(currentRestrictedRay.Start, currentRestrictedRay.End));
            }
        }