コード例 #1
0
        private List <GraphNode> GetRoute(Point from, Point to)
        {
            lock (_syncObject)
            {
                var   x = (int)Math.Floor((double)from.X / _searchWayAreaSize);
                var   y = (int)Math.Floor((double)from.Y / _searchWayAreaSize);
                Point startAreaIndex = new Point(x, y);

                var startNode = new GraphNode(startAreaIndex, startAreaIndex)
                {
                    SourceWP = new WayPoint(from.X, from.Y),
                    TargetWP = new WayPoint(from.X, from.Y)
                };

                x = (int)Math.Floor((double)to.X / _searchWayAreaSize);
                y = (int)Math.Floor((double)to.Y / _searchWayAreaSize);
                Point endAreaIndex = new Point(x, y);

                var endNode = new GraphNode(endAreaIndex, endAreaIndex)
                {
                    SourceWP = new WayPoint(to.X, to.Y),
                    TargetWP = new WayPoint(to.X, to.Y)
                };

                try
                {
                    _patensyGraph.AddVertex(startNode);

                    IEnumerable <GraphNode> nodesAroundStartNode =
                        _patensyGraph.Vertices.Where(n => n.SourceArea == startAreaIndex || n.TargetArea == startAreaIndex);

                    bool hasRouteFromStart = false;
                    foreach (var node in nodesAroundStartNode)
                    {
                        int routeLenght;
                        if (HasRoute(startNode, node, out routeLenght))
                        {
                            var edgeFromStart = new QuickGraph.Edge <GraphNode>(startNode, node);
                            _patensyGraph.AddEdge(edgeFromStart);
                            _weightsDictionary.Add(edgeFromStart, routeLenght);
                            hasRouteFromStart = true;
                        }
                    }

                    if (!hasRouteFromStart)
                    {
                        return(null);
                    }

                    _patensyGraph.AddVertex(endNode);

                    IEnumerable <GraphNode> nodesAroundEndNode =
                        _patensyGraph.Vertices.Where(n => n.SourceArea == endAreaIndex || n.TargetArea == endAreaIndex);

                    bool hasRouteToEnd = false;
                    foreach (var node in nodesAroundEndNode)
                    {
                        int routeLenght;
                        if (HasRoute(node, endNode, out routeLenght))
                        {
                            var edgeToEnd = new QuickGraph.Edge <GraphNode>(node, endNode);
                            _patensyGraph.AddEdge(edgeToEnd);
                            _weightsDictionary.Add(edgeToEnd, routeLenght);
                            hasRouteToEnd = true;
                        }
                    }

                    if (!hasRouteToEnd)
                    {
                        return(null);
                    }

                    if (_weightsDictionary.Count < _patensyGraph.EdgeCount)
                    {
                        throw new InvalidOperationException(string.Format("Не определен вес {0} ребер", _patensyGraph.EdgeCount - _weightsDictionary.Count));
                    }

                    Func <QuickGraph.Edge <GraphNode>, double> func =
                        AlgorithmExtensions.GetIndexer <QuickGraph.Edge <GraphNode>, double>(_weightsDictionary);

                    IEnumerable <QuickGraph.Edge <GraphNode> > path = null;
                    var  tryFunc = _patensyGraph.ShortestPathsDijkstra(func, startNode);
                    bool result  = tryFunc(endNode, out path);

                    if (result)
                    {
                        List <GraphNode> route = new List <GraphNode>();
                        foreach (var edge in path)
                        {
                            if (route.Count == 0)
                            {
                                route.Add(edge.Target);
                            }
                            else
                            {
                                if (route.Last().Equals(edge.Target))
                                {
                                    route.Add(edge.Source);
                                }
                                else
                                {
                                    route.Add(edge.Target);
                                }
                            }
                        }
                        return(route);
                    }
                    else
                    {
                        return(null);
                    }
                }
                finally
                {
                    foreach (var edge in _patensyGraph.Edges.Where(e => e.Source.Equals(startNode)))
                    {
                        _weightsDictionary.Remove(edge);
                    }
                    foreach (var edge in _patensyGraph.Edges.Where(e => e.Target.Equals(endNode)))
                    {
                        _weightsDictionary.Remove(edge);
                    }

                    _patensyGraph.RemoveVertex(startNode);
                    _patensyGraph.RemoveVertex(endNode);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Finds all routes containing the text "(auto)" and tries to auto-route them by using all non-auto routes
        /// </summary>
        /// <param name="updateNavObjXmlFileName"></param>
        public void MakeRoutes(string updateNavObjXmlFileName)
        {
            XDocument docNavObj = XDocument.Load(updateNavObjXmlFileName);

            var autoRoutes = new List <AutoRouteEntry>();

            var idToVertexMap   = new Dictionary <string, RouteVertex>();
            var nameToVertexMap = new Dictionary <string, RouteVertex>();
            var edgeWeightMap   = new Dictionary <QuickGraph.Edge <RouteVertex>, double>();
            var nonUniqueNames  = new List <string>();

            // Process each (non-auto) route into a "all routes" graph,
            // and add auto-routes to a separate list for later processing
            var graph = new QuickGraph.UndirectedGraph <RouteVertex, QuickGraph.Edge <RouteVertex> >();

            foreach (var elemRoute in docNavObj.Element(nsGpx + "gpx").Elements(nsGpx + "rte"))
            {
                RouteVertex previousVertex = null;

                // Is this an auto-route?
                AutoRouteEntry autoRouteEntry = GetAutoRouteEntry(elemRoute);
                if (autoRouteEntry != null)
                {
                    autoRoutes.Add(autoRouteEntry);
                    continue;
                }

                // Process each route point in route, adding vertices and edges as we follow the route
                foreach (var elemRoutePoint in elemRoute.Elements(nsGpx + "rtept"))
                {
                    string routePointId = RouteVertex.GetElementId(elemRoutePoint);

                    // Get this route point's vertex (existing, or create new and add to graph)
                    RouteVertex elementVertex;

                    if (!idToVertexMap.TryGetValue(routePointId, out elementVertex))
                    {
                        elementVertex = new RouteVertex {
                            RoutePointElement = elemRoutePoint
                        };
                        graph.AddVertex(elementVertex);

                        // Add new vertex to dictionaries
                        idToVertexMap.Add(routePointId, elementVertex);
                        string elementVertexName = elementVertex.Name;
                        if (nameToVertexMap.ContainsKey(elementVertexName))
                        {
                            nonUniqueNames.Add(elementVertexName);
                        }
                        else
                        {
                            nameToVertexMap.Add(elementVertexName, elementVertex);
                        }
                    }

                    // Did we get to this vertex from another vertex? If so, add the edge and calculate its weight
                    if (previousVertex != null)
                    {
                        var edge = new QuickGraph.Edge <RouteVertex>(previousVertex, elementVertex);
                        graph.AddEdge(edge);

                        // Pre-calculate edge weight = distance in meters
                        Coordinate coordOrigin      = previousVertex.Coordinate;
                        Coordinate coordDestination = elementVertex.Coordinate;
                        double     weight           = GeoCalculator.GetDistance(coordOrigin, coordDestination, 1, DistanceUnit.Meters);
                        edgeWeightMap[edge] = weight;
                    }

                    // Save current vertex as previous for next vertex
                    previousVertex = elementVertex;
                }
            }

            // Find best routes for each AutoRouteEntry
            foreach (AutoRouteEntry arEntry in autoRoutes)
            {
                // Check that auto-route uses unique names
                var nonUniqueUsed = arEntry.WaypointNames.Where(x => nonUniqueNames.Contains(x)).ToList();
                if (nonUniqueUsed.Count > 0)
                {
                    SetRouteError(arEntry.RouteElement, "Non-unique waypoint name(s): " + string.Join(", ", nonUniqueUsed));
                    continue;
                }
                // Check for unknown names
                var unknownWaypoints = arEntry.WaypointNames.Where(x => !nameToVertexMap.ContainsKey(x)).ToList();
                if (unknownWaypoints.Count > 0)
                {
                    SetRouteError(arEntry.RouteElement, "Unknown waypoint name(s): " + string.Join(", ", unknownWaypoints));
                    continue;
                }

                var  routeElement  = arEntry.RouteElement;
                bool firstPart     = true;
                bool firstWaypoint = true;

                // Process the auto route a 'pair of waypoints' at a time
                for (int i = 0; i < arEntry.WaypointNames.Count - 1; i++)
                {
                    RouteVertex start = nameToVertexMap[arEntry.WaypointNames[i]];
                    RouteVertex stop  = nameToVertexMap[arEntry.WaypointNames[i + 1]];

                    var shortestPaths = graph.ShortestPathsDijkstra((x) => edgeWeightMap[x], start);
                    if (shortestPaths(stop, out var result))
                    {
                        // If first part of auto route, clear the existing route data
                        if (firstPart)
                        {
                            foreach (var deleteMe in routeElement.Elements(nsGpx + "rtept").ToList())
                            {
                                deleteMe.Remove();
                            }
                            firstPart = false;
                        }

                        RouteVertex currentPos = start;
                        foreach (var edge in result)
                        {
                            // Graph is not directional, so edges can be in 'reverse' direction
                            // We should not use current position vertex as next vertex
                            RouteVertex nextVertex = edge.Source != currentPos ? edge.Source : edge.Target;

                            // If this is the very first waypoint of the complete auto route - add it to output (if not first edge, the waypoint has already been put into the route)
                            if (firstWaypoint)
                            {
                                var pointElement = new XElement(currentPos.RoutePointElement);
                                routeElement.Add(pointElement);
                                firstWaypoint = false;
                            }

                            routeElement.Add(new XElement(nextVertex.RoutePointElement));
                            currentPos = nextVertex;
                        }
                    }
                    else
                    {
                        SetRouteError(arEntry.RouteElement, "No route found from: \"" + start.Name + "\" to \"" + stop.Name + "\"");
                        break;
                    }
                }
            }

            // Overwrite original navobj file
            docNavObj.Save(updateNavObjXmlFileName);
        }