public Location ToLocation(LocationDatabase locDb)
        {
            Location loc;

            if (locDb.TryGet(mId, out loc))
            {
                return(loc);
            }

            loc      = new Location(mId, Name, LocationType._StartPoint, Coords, "");
            loc.Icon = mIcon;
            return(loc);
        }
Пример #2
0
        public static Route FromXml(XmlElement ele, LocationDatabase locDb)
        {
            Route r = new Route(double.Parse(ele.GetAttribute("distance")));

            foreach (XmlElement locNode in ele.GetElementsByTagName("loc"))
            {
                Location loc;
                if (!locDb.TryGet(int.Parse(locNode.GetAttribute("id")), out loc))
                {
                    loc = Location.FromXml(locNode, true);
                }

                r.Add(loc);
            }
            return(r);
        }
Пример #3
0
        /// <summary>
        /// Finds the shortest route from any number of start locations to a specific end location
        /// </summary>
        /// <param name="startPoints">The list of the alternate start points</param>
        /// <param name="startLocation">The specific start point specified by the user, or
        ///		NO_LOCATION if the algorithm should only use the locations in startPoints.</param>
        /// <param name="endLocation">The route destination</param>
        /// <param name="p">This will describe the graph generated for route finding.
        ///		Pass it as the parameter to FindRoute(RouteFinderPackage) to find the
        ///		next-longer route.</param>
        /// <returns>The shortest route from endLocation to any of the start points.</returns>
        public static Route FindRoute(LocationDatabase locDb, ICollection <RouteStart> startPoints,
                                      ICollection <PortalDevice> portalDevices, Location startLocation, Location endLocation,
                                      out RouteFinderPackage p)
        {
            // Implementation Notes:
            //   - Based on Dijkstra's Algorithm
            //   - Maintains two "Q" lists, one for portal entrances and one for portal exits.
            //   - "Running" edges exist from portal exits to portal entrances, but only if
            //	   the two points are in the same region (i.e., island).
            //   - "Portal" edges exist from portal entrances to portal exits.
            //   - Finds the route backwards, starting at the end location and working until
            //     it gets to any of the start locations
            //
            // Reference: http://en.wikipedia.org/wiki/Dijkstra's_algorithm
            // 1   function Dijkstra(G, w, s)
            // 2      for each vertex v in V[G]                       // Initializations
            // 3            d[v] := infinity
            // 4            previous[v] := undefined
            // 5      d[s] := 0
            // 6      S := empty set
            // 7      Q := set of all vertices
            // 8      while Q is not an empty set
            // 9            u := Extract_Min(Q)
            // 10           S := S union {u}
            // 11           for each edge (u,v) outgoing from u
            // 12                 if d[v] > d[u] + w(u,v)             // Relax (u,v)
            // 13                       d[v] := d[u] + w(u,v)
            // 14                       previous[v] := u

            LazyLoadRegions();
            p = new RouteFinderPackage();

            // Estimate the number of vertices..
            int numLocations = locDb.PortalLocations.Count + startPoints.Count + portalDevices.Count + 4;

            // The vertices representing portal entrances
            p.entranceVertices = new Dictionary <int, Vertex>(numLocations);
            // The vertices representing portal exits
            p.exitVertices = new Dictionary <int, Vertex>(numLocations);

            // (7) Q := set of all vertices
            // (2-4) Done in Vertex constructors
            foreach (Location portal in locDb.PortalLocations)
            {
                if (portal.UseInRouteFinding)
                {
                    Vertex entrance, exit;
                    p.entranceVertices[portal.Id] = entrance = new Vertex(portal, VertexCategory.Entrance);
                    p.exitVertices[portal.Id]     = exit = new Vertex(portal, VertexCategory.Exit);

                    double portalWeight = mPortalWeight;
                    if (portal.Type == LocationType.UndergroundPortal)
                    {
                        portalWeight *= 2;
                    }

                    Edge edge = new Edge(entrance, exit, portalWeight);

                    //entrance.OutgoingEdges.Add(edge);
                    exit.IncomingEdges.Add(edge);
                }
            }

            // Add portal devices
            foreach (PortalDevice device in portalDevices)
            {
                if (device.Detected && device.Enabled)
                {
                    foreach (Location dest in device.Destinations)
                    {
                        Vertex entrance, exit;
                        p.entranceVertices[dest.Id] = entrance = new Vertex(dest, VertexCategory.Entrance);
                        p.exitVertices[dest.Id]     = exit = new Vertex(dest, VertexCategory.Exit);

                        Edge edge = new Edge(entrance, exit, device.RunDistance);

                        //entrance.OutgoingEdges.Add(edge);
                        exit.IncomingEdges.Add(edge);
                    }
                }
            }

            // Add vertices for start and end if they aren't already in the list.
            p.startVertices = new List <Vertex>(startPoints.Count);
            Dictionary <Vertex, double> startVerticesExtraRun = new Dictionary <Vertex, double>();
            Vertex end;

            // startVerticies are like portal exits - make sure they're in the
            // exit list, and not in the entrance list
            Vertex start;

            foreach (RouteStart startPoint in startPoints)
            {
                if (startPoint.Enabled && startPoint.Coords != Coordinates.NO_COORDINATES)
                {
                    if (!p.exitVertices.TryGetValue(startPoint.Id, out start))
                    {
                        start = new Vertex(startPoint.ToLocation(locDb), VertexCategory.Exit);
                        p.exitVertices[startPoint.Id] = start;
                    }
                    p.entranceVertices.Remove(startPoint.Id);
                    start.IncomingEdges.Clear();

                    if (start.Loc.ExitCoords == Coordinates.NO_COORDINATES)
                    {
                        start.Loc.ExitCoords = start.Loc.Coords;
                    }

                    p.startVertices.Add(start);
                    if (startPoint.RunDistance > 0)
                    {
                        startVerticesExtraRun[start] = startPoint.RunDistance;
                    }
                }
            }
            if (startLocation != null && startLocation != Location.NO_LOCATION)
            {
                if (!p.exitVertices.TryGetValue(startLocation.Id, out start))
                {
                    start = new Vertex(startLocation, VertexCategory.Exit);
                    p.exitVertices[startLocation.Id] = start;
                }
                start.IncomingEdges.Clear();
                p.entranceVertices.Remove(startLocation.Id);

                if (start.Loc.ExitCoords == Coordinates.NO_COORDINATES)
                {
                    // Create a copy so as to not modify the original Location
                    start.Loc            = new Location(start.Loc.Id, start.Loc);
                    start.Loc.ExitCoords = start.Loc.Coords;
                }

                p.startVertices.Add(start);
            }

            // end is like a portal entrance - make sure it's in the
            // entrance list, and not in the exit list
            if (!p.entranceVertices.TryGetValue(endLocation.Id, out end))
            {
                end = new Vertex(endLocation, VertexCategory.Entrance);
                p.entranceVertices[endLocation.Id] = end;
            }
            p.exitVertices.Remove(endLocation.Id);
            //end.OutgoingEdges.Clear();

            // (5) d[s] := 0
            end.ShortestPathCost = 0;

            // Add edges for running from each portal exit to each portal entrance
            // ONLY add edges if the two vertices have the same region ID (i.e., are
            // on the same island).
            foreach (Vertex exit in p.exitVertices.Values)
            {
                foreach (Vertex entrance in p.entranceVertices.Values)
                {
                    if (entrance.Loc != exit.Loc && entrance.RegionId == exit.RegionId)
                    {
                        double distance = exit.Loc.ExitCoords.DistanceTo(entrance.Loc.Coords);
                        double extraRun;
                        if (startVerticesExtraRun.TryGetValue(exit, out extraRun))
                        {
                            distance += extraRun;
                        }

                        if (distance < mMaxRunDistance)
                        {
                            Edge e = new Edge(exit, entrance, distance);
                            //exit.OutgoingEdges.Add(e);
                            entrance.IncomingEdges.Add(e);
                        }
                    }
                }
            }

            return(FindRoute(p));
        }