Example #1
0
        /// <summary>
        /// Executes the route build step.
        /// </summary>
        /// <returns></returns>
        protected override void DoRun(CancellationToken cancellationToken)
        {
            if (!_search.HasRun)
            {
                throw new InvalidOperationException("Cannot build a route before the search was executed.");
            }
            if (!_search.HasSucceeded)
            {
                throw new InvalidOperationException("Cannot build a route when the search did not succeed.");
            }

            var stops = new List <Tuple <uint, StopProfile> >();
            var trips = new List <uint?>();

            var connectionEnumerator = _search.Db.GetConnectionsEnumerator(Data.DefaultSorting.DepartureTime);
            var stopEnumerator       = _search.Db.GetStopsEnumerator();
            var tripEnumerator       = _search.Db.GetTripsEnumerator();

            // get best target stop.
            var targetProfiles   = _search.ArrivalProfiles;
            var targetProfileIdx = _search.GetBest(targetProfiles, 10 * 60);
            var targetStop       = _search.ArrivalStops[targetProfileIdx];

            // build route along that target.
            var profiles   = _search.GetStopProfiles(targetStop);
            var profileIdx = profiles.GetLeastTransfers();

            stops.Add(new Tuple <uint, StopProfile>(targetStop, profiles[profileIdx]));
            while (!profiles[profileIdx].IsFirst)
            {
                var previousStopId = uint.MaxValue;
                if (profiles[profileIdx].IsConnection)
                { // this profile represent an arrival via a connection, add the trip and move down to where
                    // the trip was boarded.
                    connectionEnumerator.MoveTo(profiles[profileIdx].PreviousConnectionId);
                    trips.Add(connectionEnumerator.TripId);

                    // get trip status.
                    var tripStatus = _search.GetTripStatus(connectionEnumerator.TripId);
                    previousStopId = tripStatus.StopId;

                    // get next profiles.
                    profiles   = _search.GetStopProfiles(previousStopId);
                    profileIdx = profiles.GetLeastTransfers();

                    // when the next also has a connection this is a transfer.
                    if (profiles[profileIdx].IsConnection)
                    { // move to connection and check it out.
                        stops.Add(new Tuple <uint, StopProfile>(previousStopId, new StopProfile()
                        {
                            PreviousStopId = previousStopId,
                            Seconds        = tripStatus.DepartureTime
                        }));
                        trips.Add(null);
                    }

                    // check for a difference in departure time and arrival time of the profile.
                    // if there is a difference insert a waiting period.
                    if (!profiles[profileIdx].IsConnection &&
                        profiles[profileIdx].Seconds != connectionEnumerator.DepartureTime)
                    { // this is a waiting period.
                        stops.Add(new Tuple <uint, StopProfile>(previousStopId, new StopProfile()
                        {
                            PreviousStopId = previousStopId,
                            Seconds        = tripStatus.DepartureTime
                        }));
                        trips.Add(null);
                    }

                    // add stop.
                    stops.Add(new Tuple <uint, StopProfile>(previousStopId, profiles[profileIdx]));
                }
                else if (profiles[profileIdx].IsTransfer)
                { // this profile respresent an arrival via a transfers from a given stop.
                    trips.Add(null);
                    previousStopId = profiles[profileIdx].PreviousStopId;

                    // get next profiles.
                    profiles   = _search.GetStopProfiles(previousStopId);
                    profileIdx = profiles.GetLeastTransfers();

                    // add stop.
                    stops.Add(new Tuple <uint, StopProfile>(previousStopId, profiles[profileIdx]));
                }
                else
                { // no previous connection or stop or first, what is this?
                    throw new Exception("A profile was found as part of the path that is not a transfer, connection or first.");
                }
            }

            // reverse stops/connections.
            stops.Reverse();
            trips.Reverse();

            if (_intermediateStops)
            { // expand trips.
                for (var i = 0; i < trips.Count; i++)
                {
                    if (trips[i].HasValue)
                    { // there is a trip, expand it.
                        var lastStop  = stops[i + 1].Item1;
                        var firstStop = stops[i].Item1;
                        if (!stops[i + 1].Item2.IsConnection)
                        {
                            throw new Exception("Last stop of a trip is not a connection, it should be.");
                        }
                        var connection = stops[i + 1].Item2.PreviousConnectionId;
                        connectionEnumerator.MoveTo(connection);
                        var firstI = i;
                        while (true)
                        { // add departure stop of connection if it doesn't equal the first stop.
                            if (firstStop == connectionEnumerator.DepartureStop)
                            {
                                break;
                            }
                            if (!connectionEnumerator.MoveToPreviousConnection())
                            {
                                throw new Exception("There has to be a previous stop, have not reached the first stop for this trip yet.");
                            }
                            stops.Insert(firstI + 1, new Tuple <uint, StopProfile>(connectionEnumerator.ArrivalStop, new StopProfile()
                            {
                                PreviousConnectionId = connectionEnumerator.Id,
                                Seconds = connectionEnumerator.ArrivalTime
                            }));
                            trips.Insert(i, trips[i].Value);
                            i++;
                        }
                    }
                }
            }

            // set the duration.
            _duration = stops[stops.Count - 1].Item2.Seconds -
                        stops[0].Item2.Seconds;

            // keep stops.
            _stops = new List <uint>();
            for (var i = 0; i < stops.Count; i++)
            {
                _stops.Add(stops[i].Item1);
            }

            // convert the stop and connection sequences into an actual route.
            // _route = new Route();
            var routeShape      = new List <Coordinate>();
            var routeShapeMetas = new List <Route.Meta>();
            var routeStops      = new List <Route.Stop>();

            // get the first stop.
            if (!stopEnumerator.MoveTo(stops[0].Item1))
            {
                throw new Exception(string.Format("Stop {0} not found.", stops[0].Item1));
            }
            routeShape.Add(new Coordinate(stopEnumerator.Latitude, stopEnumerator.Longitude));
            var attributes = new AttributeCollection();

            attributes.AddOrReplace(Constants.TimeOfDayKey, stops[0].Item2.Seconds.ToInvariantString());
            routeShapeMetas.Add(new Route.Meta()
            {
                Attributes = attributes,
                Shape      = 0
            });
            var stopAttributes = _search.Db.StopAttributes.Get(stopEnumerator.MetaId);

            routeStops.Add(new Route.Stop()
            {
                Shape      = 0,
                Attributes = stopAttributes,
                Coordinate = new Coordinate(stopEnumerator.Latitude, stopEnumerator.Longitude)
            });

            var departureTime = stops[0].Item2.Seconds;

            for (int idx = 1; idx < stops.Count; idx++)
            {
                // get the next ...->trip->stop->... pair.
                var trip = trips[idx - 1];
                if (!stopEnumerator.MoveTo(stops[idx].Item1))
                {
                    throw new Exception(string.Format("Stop {0} not found.", stops[0].Item1));
                }

                // add shapepoints between stops if present.
                var shapePoints = _search.Db.ShapesDb.Get(stops[idx - 1].Item1, stops[idx].Item1);
                if (shapePoints != null)
                {
                    foreach (var shapePoint in shapePoints)
                    {
                        routeShape.Add(new Coordinate(shapePoint.Latitude, shapePoint.Longitude));
                    }
                }

                // add stop shapepoint.
                routeShape.Add(new Coordinate(stopEnumerator.Latitude, stopEnumerator.Longitude));

                // add stop.
                stopAttributes = _search.Db.StopAttributes.Get(stopEnumerator.MetaId);
                routeStops.Add(new Route.Stop()
                {
                    Shape      = routeShape.Count - 1,
                    Attributes = stopAttributes,
                    Coordinate = new Coordinate(stopEnumerator.Latitude, stopEnumerator.Longitude)
                });

                // add timing info.
                attributes = new AttributeCollection();
                attributes.AddOrReplace(Constants.TimeOfDayKey, stops[idx].Item2.Seconds.ToInvariantString());

                // get route information.
                if (trip == null)
                {
                    if (idx == 1)
                    { // first trip null is waiting period.
                        var meta = new Route.Meta()
                        {
                            Shape      = routeShape.Count - 1,
                            Attributes = attributes
                        };
                        meta.Time    = stops[idx].Item2.Seconds - departureTime;
                        meta.Profile = Constants.WaitProfile;
                        routeShapeMetas.Add(meta);
                    }
                    else if (routeShapeMetas[routeShapeMetas.Count - 1].Profile == Constants.TransferProfile)
                    { // a waiting period.
                        var meta = new Route.Meta()
                        {
                            Shape      = routeShape.Count - 1,
                            Attributes = attributes
                        };
                        meta.Time    = stops[idx].Item2.Seconds - departureTime;
                        meta.Profile = Constants.WaitProfile;
                        routeShapeMetas.Add(meta);
                    }
                    else
                    { // a regular transfer.
                        var meta = new Route.Meta()
                        {
                            Shape      = routeShape.Count - 1,
                            Attributes = attributes
                        };
                        meta.Time    = stops[idx].Item2.Seconds - departureTime;
                        meta.Profile = Constants.TransferProfile;
                        routeShapeMetas.Add(meta);
                    }
                }
                else
                {
                    if (!tripEnumerator.MoveTo(trip.Value))
                    {
                        throw new Exception(string.Format("Trip {0} not found.", connectionEnumerator.TripId));
                    }

                    attributes.AddOrReplaceWithPrefix("trip_", _search.Db.TripAttributes.Get(tripEnumerator.MetaId));
                    attributes.AddOrReplaceWithPrefix("agency_", _search.Db.AgencyAttributes.Get(tripEnumerator.AgencyId));

                    var meta = new Route.Meta()
                    {
                        Shape      = routeShape.Count - 1,
                        Attributes = attributes
                    };
                    meta.Time    = stops[idx].Item2.Seconds - departureTime;
                    meta.Profile = Constants.VehicleProfile;
                    routeShapeMetas.Add(meta);
                }
            }

            // build actual route.
            _route           = new Route();
            _route.Shape     = routeShape.ToArray();
            _route.ShapeMeta = routeShapeMetas.ToArray();
            _route.Stops     = routeStops.ToArray();
            if (_route.ShapeMeta.Length > 0)
            {
                _route.TotalDistance = _route.ShapeMeta[_route.ShapeMeta.Length - 1].Distance;
                _route.TotalTime     = _route.ShapeMeta[_route.ShapeMeta.Length - 1].Time;
            }

            this.HasSucceeded = true;
        }