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)); }