/// <summary> /// Calculates routes for edges in a graph, so that they avoid nodes. /// </summary> public Dictionary <TEdge, RoutedEdge> RouteEdges <TEdge>(IEnumerable <IRect> nodes, IEnumerable <TEdge> edges) where TEdge : class, IEdge { var routeGraph = RouteGraph.InitializeVertices(nodes, edges, 0, 0); var routedEdges = new Dictionary <TEdge, RoutedEdge>(); var occludedEdges = new List <TEdge>(); foreach (var edge in edges) { var straightEdge = routeGraph.TryRouteEdgeStraight(edge); if (straightEdge != null) { routedEdges[edge] = straightEdge; } else { occludedEdges.Add(edge); } } if (occludedEdges.Count > 0) { // there are some edges that couldn't be routed as straight lines routeGraph.ComputeVisibilityGraph(); foreach (var edge in occludedEdges) { RoutedEdge routedEdge = routeGraph.RouteEdge(edge); routedEdges[edge] = routedEdge; } } return(routedEdges); }
public List <RoutedEdge> RouteEdges(IEnumerable <IRect> nodes, IEnumerable <IEdge> edges) { var routeGraph = RouteGraph.InitializeVertices(nodes, edges); List <RoutedEdge> routedEdges = new List <RoutedEdge>(); var occludedEdges = new List <IEdge>(); foreach (IEdge edge in edges) { var straightEdge = routeGraph.TryRouteEdgeStraight(edge); if (straightEdge != null) { routedEdges.Add(straightEdge); } else { occludedEdges.Add(edge); } } if (occludedEdges.Count > 0) { // there are some edges that couldn't be routed as straight lines routeGraph.ComputeVisibilityGraph(); foreach (IEdge edge in occludedEdges) { RoutedEdge routedEdge = routeGraph.RouteEdge(edge); routedEdges.Add(routedEdge); } } return(routedEdges); }
public AStarShortestPathFinder(RouteGraph routeGraph) { this.graph = routeGraph; }
/// <summary> /// Initializes the RouteGraph by vertices close to corners of all nodes. /// </summary> /// <param name="boundX">X coordinates of vertices cannot be lower than this value (so that edges stay in boundaries).</param> /// <param name="boundY">Y coordinates of vertices cannot be lower than this value (so that edges stay in boundaries).</param> public static RouteGraph InitializeVertices(IEnumerable <IRect> nodes, IEnumerable <IEdge> edges, int boundX, int boundY) { var graph = new RouteGraph(); // add vertices for node corners foreach (var node in nodes) { graph.Boxes.Add(node); foreach (var vertex in GetRectCorners(node, boxPadding)) { if (vertex.X >= boundX && vertex.Y >= boundY) { graph.Vertices.Add(vertex); } } } // add vertices for egde endpoints foreach (var multiEdgeGroup in edges.GroupBy(edge => GetStartEnd(edge))) { int multiEdgeCount = multiEdgeGroup.Count(); IRect fromRect = multiEdgeGroup.First().From; IRect toRect = multiEdgeGroup.First().To; var sourceCenter = GeomUtils.RectCenter(fromRect); var targetCenter = GeomUtils.RectCenter(toRect); if (Math.Abs(sourceCenter.X - targetCenter.X) > Math.Abs(sourceCenter.Y - targetCenter.Y) || (fromRect == toRect)) { // the line is horizontal double multiEdgeSpanSource = GetMultiEdgeSpan(fromRect.Height, multiEdgeCount, multiEdgeGap); double multiEdgeSpanTarget = GetMultiEdgeSpan(toRect.Height, multiEdgeCount, multiEdgeGap); double originSourceCurrentY = sourceCenter.Y - multiEdgeSpanSource / 2; double originTargetCurrentY = targetCenter.Y - multiEdgeSpanTarget / 2; foreach (var edge in multiEdgeGroup) { Point2D sourceOrigin = new Point2D(sourceCenter.X, originSourceCurrentY); Point2D targetOrigin = new Point2D(targetCenter.X, originTargetCurrentY); // Here user could provide custom edgeStart and edgeEnd // inflate boxes a little so that edgeStart and edgeEnd are a little outside of the box (to prevent floating point errors) if (edge.From == edge.To) { // special case - self edge var edgeStart = new Point2D(fromRect.Left + fromRect.Width + 0.01, originSourceCurrentY); var edgeEnd = new Point2D(fromRect.Left + fromRect.Width / 2, fromRect.Top); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); } else { var edgeStart = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.From.Inflated(1e-3)); var edgeEnd = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.To.Inflated(1e-3)); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); } originSourceCurrentY += multiEdgeSpanSource / (multiEdgeCount - 1); originTargetCurrentY += multiEdgeSpanTarget / (multiEdgeCount - 1); } } else { // the line is vertical double multiEdgeSpanSource = GetMultiEdgeSpan(fromRect.Width, multiEdgeCount, multiEdgeGap); double multiEdgeSpanTarget = GetMultiEdgeSpan(toRect.Width, multiEdgeCount, multiEdgeGap); double originSourceCurrentX = sourceCenter.X - multiEdgeSpanSource / 2; double originTargetCurrentX = targetCenter.X - multiEdgeSpanTarget / 2; foreach (var edge in multiEdgeGroup) { Point2D sourceOrigin = new Point2D(originSourceCurrentX, sourceCenter.Y); Point2D targetOrigin = new Point2D(originTargetCurrentX, targetCenter.Y); // Here user could provide custom edgeStart and edgeEnd // inflate boxes a little so that edgeStart and edgeEnd are a little outside of the box (to prevent floating point errors) var edgeStart = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.From.Inflated(1e-3)); var edgeEnd = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.To.Inflated(1e-3)); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); originSourceCurrentX += multiEdgeSpanSource / (multiEdgeCount - 1); originTargetCurrentX += multiEdgeSpanTarget / (multiEdgeCount - 1); } } } return(graph); }
public DijkstraShortestPathFinder(RouteGraph routeGraph) { this.graph = routeGraph; }
public static RouteGraph InitializeVertices(IEnumerable<IRect> nodes, IEnumerable<IEdge> edges) { var graph = new RouteGraph(); // add vertices for node corners foreach (var node in nodes) { graph.Boxes.Add(node); foreach (var vertex in GetRectCorners(node, boxPadding)) { graph.Vertices.Add(vertex); } } // add vertices for egde endpoints foreach (var multiEdgeGroup in edges.GroupBy(edge => GetStartEnd(edge))) { int multiEdgeCount = multiEdgeGroup.Count(); IRect fromRect = multiEdgeGroup.First().From; IRect toRect = multiEdgeGroup.First().To; var sourceCenter = GeomUtils.RectCenter(fromRect); var targetCenter = GeomUtils.RectCenter(toRect); if (Math.Abs(sourceCenter.X - targetCenter.X) > Math.Abs(sourceCenter.Y - targetCenter.Y) || (fromRect == toRect)) { // the line is horizontal double multiEdgeSpanSource = GetMultiEdgeSpan(fromRect.Height, multiEdgeCount, multiEdgeGap); double multiEdgeSpanTarget = GetMultiEdgeSpan(toRect.Height, multiEdgeCount, multiEdgeGap); double originSourceCurrentY = sourceCenter.Y - multiEdgeSpanSource / 2; double originTargetCurrentY = targetCenter.Y - multiEdgeSpanTarget / 2; foreach (var edge in multiEdgeGroup) { Point2D sourceOrigin = new Point2D(sourceCenter.X, originSourceCurrentY); Point2D targetOrigin = new Point2D(targetCenter.X, originTargetCurrentY); // Here user could provide custom edgeStart and edgeEnd // inflate boxes a little so that edgeStart and edgeEnd are a little outside of the box (to prevent floating point errors) if (edge.From == edge.To) { var edgeStart = new Point2D(fromRect.Left + fromRect.Width + 0.01, originSourceCurrentY); var edgeEnd = new Point2D(fromRect.Left + fromRect.Width / 2, fromRect.Top); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); } else { var edgeStart = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.From.Inflated(1e-3)); var edgeEnd = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.To.Inflated(1e-3)); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); } originSourceCurrentY += multiEdgeSpanSource / (multiEdgeCount - 1); originTargetCurrentY += multiEdgeSpanTarget / (multiEdgeCount - 1); } } else { // the line is vertical double multiEdgeSpanSource = GetMultiEdgeSpan(fromRect.Width, multiEdgeCount, multiEdgeGap); double multiEdgeSpanTarget = GetMultiEdgeSpan(toRect.Width, multiEdgeCount, multiEdgeGap); double originSourceCurrentX = sourceCenter.X - multiEdgeSpanSource / 2; double originTargetCurrentX = targetCenter.X - multiEdgeSpanTarget / 2; foreach (var edge in multiEdgeGroup) { Point2D sourceOrigin = new Point2D(originSourceCurrentX, sourceCenter.Y); Point2D targetOrigin = new Point2D(originTargetCurrentX, targetCenter.Y); // Here user could provide custom edgeStart and edgeEnd // inflate boxes a little so that edgeStart and edgeEnd are a little outside of the box (to prevent floating point errors) var edgeStart = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.From.Inflated(1e-3)); var edgeEnd = GeomUtils.LineRectIntersection(sourceOrigin, targetOrigin, edge.To.Inflated(1e-3)); graph.AddEdgeEndpointVertices(edge, edgeStart, edgeEnd); originSourceCurrentX += multiEdgeSpanSource / (multiEdgeCount - 1); originTargetCurrentX += multiEdgeSpanTarget / (multiEdgeCount - 1); } } } return graph; }