Example #1
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);
            }
        }
        internal ObstaclePortEntrance(ObstaclePort oport, Point unpaddedBorderIntersect, Directions 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);
            }
        }
        private ObstaclePort CreateObstaclePort(Obstacle obstacle, Port port) {
            // This will replace any previous specification for the port (last one wins).
            Debug.Assert(!obstaclePortMap.ContainsKey(port), "Port is used by more than one obstacle");

            if (null == port.Curve) {
                return null;
            }

            var roundedLocation = ApproximateComparer.Round(port.Location);
            if (PointLocation.Outside == Curve.PointRelativeToCurveLocation(roundedLocation, obstacle.InputShape.BoundaryCurve)) {
                // Obstacle.Port is outside Obstacle.Shape; handle it as a FreePoint.
                return null;
            }

            if ((obstacle.InputShape.BoundaryCurve != port.Curve) 
                && (PointLocation.Outside == Curve.PointRelativeToCurveLocation(roundedLocation, port.Curve))) {
                // Obstacle.Port is outside port.Curve; handle it as a FreePoint.
                return null;
            }

            var oport = new ObstaclePort(port, obstacle);
            obstaclePortMap[port] = oport;
            return oport;
        }
 private void CreateEntrancesForCornerPort(Rectangle curveBox, ObstaclePort oport, Point location) {
     // This must be a corner or it would have been within one of the bounds and handled elsewhere.
     // Therefore create an entrance in both directions, with the first direction selected so that
     // the second can be obtained via RotateRight.
     Directions outDir = Directions.North;
     if (PointComparer.Equal(location, curveBox.LeftBottom)) {
         outDir = Directions.South;
     }
     else if (PointComparer.Equal(location, curveBox.LeftTop)) {
         outDir = Directions.West;
     }
     else if (PointComparer.Equal(location, curveBox.RightTop)) {
         outDir = Directions.North;
     }
     else if (PointComparer.Equal(location, curveBox.RightBottom)) {
         outDir = Directions.East;
     }
     else {
         Debug.Assert(false, "Expected Port to be on corner of curveBox");
     }
     oport.CreatePortEntrance(location, outDir, this.ObstacleTree);
     oport.CreatePortEntrance(location, CompassVector.RotateRight(outDir), this.ObstacleTree);
 }
 private void CreatePortEntrance(Rectangle curveBox, ObstaclePort oport, Point unpaddedBorderIntersect, Directions outDir) {
     oport.CreatePortEntrance(unpaddedBorderIntersect, outDir, this.ObstacleTree);
     ScanDirection scanDir = ScanDirection.GetInstance(outDir);
     double axisDistanceBetweenIntersections = StaticGraphUtility.GetRectangleBound(curveBox, outDir) - scanDir.Coord(unpaddedBorderIntersect);
     if (axisDistanceBetweenIntersections < 0.0) {
         axisDistanceBetweenIntersections = -axisDistanceBetweenIntersections;
     }
     if (axisDistanceBetweenIntersections > ApproximateComparer.IntersectionEpsilon) {
         // This is not on an extreme boundary of the unpadded curve (it's on a sloping (nonrectangular) boundary),
         // so we need to generate another entrance in one of the perpendicular directions (depending on which
         // way the side slopes).  Derivative is always clockwise.
         Directions perpDirs = CompassVector.VectorDirection(GetDerivative(oport, unpaddedBorderIntersect));
         Directions perpDir = perpDirs & ~(outDir | CompassVector.OppositeDir(outDir));
         if (Directions. None != (outDir & perpDirs)) {
             // If the derivative is in the same direction as outDir then perpDir is toward the obstacle
             // interior and must be reversed.
             perpDir = CompassVector.OppositeDir(perpDir);
         }
         oport.CreatePortEntrance(unpaddedBorderIntersect, perpDir, this.ObstacleTree);
     }
 }
 private static Point GetDerivative(ObstaclePort oport, Point borderPoint) {
     // This is only used for ObstaclePorts, which have ensured Port.Curve is not null.
     double param = oport.PortCurve.ClosestParameter(borderPoint);
     var deriv = oport.PortCurve.Derivative(param);
     var parMid = (oport.PortCurve.ParStart + oport.PortCurve.ParEnd) / 2;
     if (!InteractiveObstacleCalculator.CurveIsClockwise(oport.PortCurve, oport.PortCurve[parMid])) {
         deriv = -deriv;
     }
     return deriv;
 }
 private void CreatePortEntrancesAtBorderIntersections(Rectangle curveBox, ObstaclePort oport, Point location
                             , Point unpaddedBorderIntersect0, Point unpaddedBorderIntersect1) {
     // Allow entry from both sides, except from the opposite side of a point on the border.
     Directions dir = PointComparer.GetPureDirection(unpaddedBorderIntersect0, unpaddedBorderIntersect1);
     if (!PointComparer.Equal(unpaddedBorderIntersect0, location)) {
         CreatePortEntrance(curveBox, oport, unpaddedBorderIntersect1, dir);
     }
     if (!PointComparer.Equal(unpaddedBorderIntersect1, location)) {
         CreatePortEntrance(curveBox, oport, unpaddedBorderIntersect0, CompassVector.OppositeDir(dir));
     }
 }
        private void CreateObstaclePortEntrancesFromPortEntry(ObstaclePort oport) {
            // Create a PortEntrance for each of one or more midpoints of each of the spans of the PortEntry. 
            foreach (var midPoint in oport.Port.PortEntry.GetEntryPoints()) {
                var borderPoint = ApproximateComparer.Round(midPoint);
                Directions derivDirs = CompassVector.VectorDirection(GetDerivative(oport, borderPoint));

                // The deriv is clockwise so if it moves East then it is on top and Port visibility extends to
                // the North; otherwise it extends to the South. Similarly, if the deriv moves South then visibility
                // must extend to the East, else West.  If it is flat or perpendicular then visibility extends in
                // only one direction.  Due to clockwiseness, we can just RotateLeft to get to the desired extension.
                Directions dir = derivDirs & (Directions.North | Directions.South);
                if (Directions. None != dir) {
                    oport.CreatePortEntrance(borderPoint, CompassVector.RotateLeft(dir), this.ObstacleTree);
                }
                dir = derivDirs & (Directions.East | Directions.West);
                if (Directions. None != dir) {
                    oport.CreatePortEntrance(borderPoint, CompassVector.RotateLeft(dir), this.ObstacleTree);
                }
            }
        }
        private void CreateObstaclePortEntrancesFromPoints(ObstaclePort oport) {
            var graphBox = graphGenerator.ObstacleTree.GraphBox;
            var curveBox = new Rectangle(ApproximateComparer.Round(oport.PortCurve.BoundingBox.LeftBottom)
                                             , ApproximateComparer.Round(oport.PortCurve.BoundingBox.RightTop));

            // This Port does not have a PortEntry, so we'll have visibility edges to its location
            // in the Horizontal and Vertical directions (possibly all 4 directions, if not on boundary).
            //
            // First calculate the intersection with the obstacle in all directions.  Do nothing in the
            // horizontal direction for port locations that are on the unpadded vertical extremes, because
            // this will have a path that moves alongside a rectilinear obstacle side in less than the
            // padding radius and will thus create the PaddedBorderIntersection on the side rather than top
            // (and vice-versa for the vertical direction).  We'll have an edge in the vertical direction
            // to the padded extreme boundary ScanSegment, and the Nudger will modify paths as appropriate
            // to remove unnecessary bends.
            
            // Use the unrounded port location to intersect with its curve.
            Point location = ApproximateComparer.Round(oport.PortLocation);
            Point xx0, xx1;
            bool found = false;
            if (!PointComparer.Equal(location.Y, curveBox.Top)
                    && !PointComparer.Equal(location.Y, curveBox.Bottom)) {
                found = true;
                var hSeg = new LineSegment(graphBox.Left, location.Y, graphBox.Right, location.Y);
                GetBorderIntersections(location, hSeg, oport.PortCurve, out xx0, out xx1);
                var wBorderIntersect = new Point(Math.Min(xx0.X, xx1.X), location.Y);
                if (wBorderIntersect.X < curveBox.Left) {        // Handle rounding error
                    wBorderIntersect.X = curveBox.Left;
                }
                var eBorderIntersect = new Point(Math.Max(xx0.X, xx1.X), location.Y);
                if (eBorderIntersect.X > curveBox.Right) {
                    eBorderIntersect.X = curveBox.Right;
                }
                CreatePortEntrancesAtBorderIntersections(curveBox, oport, location, wBorderIntersect, eBorderIntersect);
            } // endif horizontal pass is not at vertical extreme

            if (!PointComparer.Equal(location.X, curveBox.Left)
                    && !PointComparer.Equal(location.X, curveBox.Right)) {
                found = true;
                var vSeg = new LineSegment(location.X, graphBox.Bottom, location.X, graphBox.Top);
                GetBorderIntersections(location, vSeg, oport.PortCurve, out xx0, out xx1);
                var sBorderIntersect = new Point(location.X, Math.Min(xx0.Y, xx1.Y));
                if (sBorderIntersect.Y < graphBox.Bottom) {      // Handle rounding error
                    sBorderIntersect.Y = graphBox.Bottom;
                }
                var nBorderIntersect = new Point(location.X, Math.Max(xx0.Y, xx1.Y));
                if (nBorderIntersect.Y > graphBox.Top) {
                    nBorderIntersect.Y = graphBox.Top;
                }
                CreatePortEntrancesAtBorderIntersections(curveBox, oport, location, sBorderIntersect, nBorderIntersect);
            } // endif vertical pass is not at horizontal extreme

            if (!found) {
                // This must be on a corner, else one of the above would have matched.
                this.CreateEntrancesForCornerPort(curveBox, oport, location);
            }
        }
 private void CreateObstaclePortEntrancesIfNeeded(ObstaclePort oport) {
     if (0 != oport.PortEntrances.Count) {
         return;
     }
     
     // Create the PortEntrances with initial information:  border intersect and outer edge direction.
     if (null == oport.Port.PortEntry) {
         this.CreateObstaclePortEntrancesFromPoints(oport);
     } else {
         this.CreateObstaclePortEntrancesFromPortEntry(oport);
     }
 }
        private void AddObstaclePortToGraph(ObstaclePort oport) {
            // If the port's position has changed without UpdateObstacles() being called, recreate it.
            if (oport.LocationHasChanged) {
                RemoveObstaclePort(oport.Port);
                oport = CreateObstaclePort(oport.Obstacle, oport.Port);
                if (null == oport)
                {
                    // Port has been moved outside obstacle; return and let caller add it as a FreePoint.
                    return;
                }
            }
            oport.AddToGraph(TransUtil, RouteToCenterOfObstacles);
            obstaclePortsInGraph.Add(oport);

            this.CreateObstaclePortEntrancesIfNeeded(oport);

            // We've determined the entrypoints on the obstacle boundary for each PortEntry,
            // so now add them to the VisGraph.
            foreach (var entrance in oport.PortEntrances) {
                AddObstaclePortEntranceToGraph(entrance);
            }
            return;
        }
        private void AddPortToGraph(Port port, ObstaclePort oport) {
            if (null != oport) {
                AddObstaclePortToGraph(oport);
                return;
            }

            // This is a FreePoint, either a Waypoint or a Port not in an Obstacle.Ports list.
            AddFreePointToGraph(port.Location);
        }
        internal Set<Shape> FindAncestorsAndObstaclePort(Port port, out ObstaclePort oport) {
            oport = FindObstaclePort(port);
            if (0 == AncestorSets.Count) {
                return null;
            }
            if (null != oport) {
                return AncestorSets[oport.Obstacle.InputShape];
            }

            // This is a free Port (not associated with an obstacle) or a Waypoint; return all spatial parents.
            return new Set<Shape>(ObstacleTree.Root.AllHitItems(new Rectangle(port.Location, port.Location), shape => shape.IsGroup)
                                        .Select(obs => obs.InputShape));
        }