private static Route.Meta[] ReadShapeMeta(dynamic token) { var dArray = token.First; var shapeMetas = new Route.Meta[dArray.Count]; for (var i = 0; i < dArray.Count; i++) { var dItem = dArray[i]; shapeMetas[i] = new Route.Meta(); foreach (var token1 in dItem) { switch (token1.Name) { case "Shape": shapeMetas[i].Shape = token1.Value; break; case "Attributes": shapeMetas[i].Attributes = ReadAttributes(token1); break; } } } return(shapeMetas); }
/// <summary> /// Adds instructions as attributes to route. /// </summary> public static void AddInstructions(this Route route, IEnumerable <Instruction> instructions) { var metas = new Dictionary <int, Route.Meta>(); foreach (var meta in route.ShapeMeta) { metas.Add(meta.Shape, meta); } foreach (var instruction in instructions) { var shapeIndex = instruction.Shape; Route.Meta shapeMeta; if (!metas.TryGetValue(shapeIndex, out shapeMeta)) { shapeMeta = new Route.Meta() { Attributes = new AttributeCollection(), Shape = shapeIndex }; float distance, time; route.DistanceAndTimeAt(shapeIndex, out distance, out time); shapeMeta.Distance = distance; shapeMeta.Time = time; metas.Add(shapeIndex, shapeMeta); } shapeMeta.Attributes.AddOrReplace("instruction", instruction.Text); shapeMeta.Attributes.AddOrReplace("instruction_type", instruction.Type); } }
/// <summary> /// Constructor of the InstructionProperties. /// </summary> /// <param name="Instruction">The instruction to convert to a GeoJsonFeature.</param> /// <param name="Next">The next instruction.</param> /// <param name="route">The Route object.</param> public InstructionProperties(Instruction Instruction, Instruction Next, Route route) { this.type = "Feature"; this.properties = new Dictionary <string, string> (); this.geometry = new GeoJsonPoint(route.Shape[Instruction.Shape]); this.Instruction = Instruction; properties.Add("instruction", Instruction.Text); Route.Meta meta = route.ShapeMetaFor(Instruction.Shape); properties.Add("colour", Instruction.GetAttribute("cyclecolour", route)); properties.Add("ref", Instruction.GetAttribute("cycleref", route)); float time; float dist; route.DistanceAndTimeAt(Instruction.Shape, out dist, out time); properties.Add("distance", dist.ToString(new CultureInfo("en-US"))); properties.Add("type", Instruction.Type); if (Next != null) { Route.Meta nextMeta = route.ShapeMetaFor(Next.Shape); properties.Add("nextColour", Next.GetAttribute("cyclecolour", route)); properties.Add("nextRef", Next.GetAttribute("cycleref", route)); if (Instruction.Type != "start" && Instruction.Type != "stop") { this.Angle = route.RelativeDirectionAt(Instruction.Shape); properties.Add("angle", Angle.Direction.ToString()); } } }
public void TestProjectOne() { var route = new Route() { Shape = new Coordinate[] { new Coordinate() { Latitude = 51.268977112538806f, Longitude = 4.800424575805664f }, new Coordinate() { Latitude = 51.26830584177533f, Longitude = 4.8006391525268555f }, new Coordinate() { Latitude = 51.267768818104585f, Longitude = 4.801325798034667f }, new Coordinate() { Latitude = 51.26674845584085f, Longitude = 4.801068305969238f }, new Coordinate() { Latitude = 51.26551325015766f, Longitude = 4.801154136657715f } }, ShapeMeta = new Route.Meta[] { new Route.Meta() { Shape = 0 }, new Route.Meta() { Shape = 2, Distance = 100, Time = 60 }, new Route.Meta() { Shape = 4, Distance = 200, Time = 120 } }, Attributes = new AttributeCollection(), TotalDistance = 200, TotalTime = 120 }; // calculate actual distance/times. Route.Meta previousMeta = null; foreach (var meta in route.ShapeMeta) { meta.Distance = 0; meta.Time = 0; if (previousMeta != null) { for (var s = previousMeta.Shape; s < meta.Shape; s++) { meta.Distance = meta.Distance + Coordinate.DistanceEstimateInMeter( route.Shape[s], route.Shape[s + 1]); } meta.Time = meta.Distance / 16.6667f; // 60km/h } previousMeta = meta; } route.TotalDistance = route.ShapeMeta[route.ShapeMeta.Length - 1].Distance; route.TotalTime = route.ShapeMeta[route.ShapeMeta.Length - 1].Time; float time, distance; int shape; Coordinate projected; Assert.IsTrue(route.ProjectOn(new Coordinate(51.26856092582056f, 4.800623059272766f), out projected, out shape, out distance, out time)); Assert.AreEqual(0, shape); Assert.IsTrue(time > route.ShapeMeta[0].Time); Assert.IsTrue(time < route.ShapeMeta[1].Time); Assert.IsTrue(route.ProjectOn(new Coordinate(51.26795342069926f, 4.801229238510132f), out projected, out shape, out distance, out time)); Assert.AreEqual(1, shape); Assert.IsTrue(time > route.ShapeMeta[0].Time); Assert.IsTrue(time < route.ShapeMeta[1].Time); Assert.IsTrue(route.ProjectOn(new Coordinate(51.26712438141587f, 4.801207780838013f), out projected, out shape, out distance, out time)); Assert.AreEqual(2, shape); Assert.IsTrue(time > route.ShapeMeta[1].Time); Assert.IsTrue(time < route.ShapeMeta[2].Time); Assert.IsTrue(route.ProjectOn(new Coordinate(51.26610064830449f, 4.801395535469055f), out projected, out shape, out distance, out time)); Assert.AreEqual(3, shape); Assert.IsTrue(time > route.ShapeMeta[1].Time); Assert.IsTrue(time < route.ShapeMeta[2].Time); }
/// <summary> /// Adds the shape point between from and to and the target location itself. /// </summary> private void Add(uint from, uint to, uint next) { if (from == Constants.NO_VERTEX && _source.IsVertex()) { // replace from with the vertex. from = _source.VertexId(_routerDb); if (from == to) { // nothing to be done. return; } } if (next == Constants.NO_VERTEX && _target.IsVertex()) { // replace next with the vertex. next = _target.VertexId(_routerDb); //if (to == next) //{ // nothing to be done. // return; //} } // get shapepoints and edge. var shape = new List <Coordinate>(0); RoutingEdge edge = null; Coordinate? targetLocation = null; var distance = 0f; var direction = true; if (from == Constants.NO_VERTEX && to == Constants.NO_VERTEX) { // from is the source and to is the target. if (_source.EdgeId != _target.EdgeId) { // a route inside one edge but source and target do not match. this.ErrorMessage = "Target and source have to be on the same vertex with a route with only virtual vertices."; return; } shape = _source.ShapePointsTo(_routerDb, _target); distance = _source.DistanceTo(_routerDb, _target); edge = _routerDb.Network.GetEdge(_source.EdgeId); targetLocation = _target.Location(); shape.Add(targetLocation.Value); } else if (from == Constants.NO_VERTEX) { // from is the source and to is a regular vertex. edge = _routerDb.Network.GetEdge(_source.EdgeId); var toOnEdge = _routerDb.Network.CreateRouterPointForVertex(to, edge.GetOther(to)); shape = _source.ShapePointsTo(_routerDb, toOnEdge); distance = _source.DistanceTo(_routerDb, toOnEdge); targetLocation = _routerDb.Network.GetVertex(to); shape.Add(targetLocation.Value); } else if (to == Constants.NO_VERTEX) { // from is a regular vertex and to is the target. edge = _routerDb.Network.GetEdge(_target.EdgeId); var fromOnEdge = _routerDb.Network.CreateRouterPointForVertex(from, edge.GetOther(from)); shape = fromOnEdge.ShapePointsTo(_routerDb, _target); distance = fromOnEdge.DistanceTo(_routerDb, _target); targetLocation = _target.Location(); shape.Add(targetLocation.Value); } else { // both are just regular vertices. edge = _routerDb.Network.GetEdgeEnumerator(from).First(x => x.To == to); direction = !edge.DataInverted; if (this.AddShorcut(edge)) { return; } distance = edge.Data.Distance; var shapeEnumerable = edge.Shape; if (shapeEnumerable != null) { if (edge.DataInverted) { shapeEnumerable = shapeEnumerable.Reverse(); } shape.AddRange(shapeEnumerable); } targetLocation = _routerDb.Network.GetVertex(to); shape.Add(targetLocation.Value); } // get edge details. var profile = _routerDb.EdgeProfiles.Get(edge.Data.Profile); var speed = this._profile.Speed(profile); var time = 0f; if (speed.Value != 0) { time = distance / speed.Value; } var meta = _routerDb.EdgeMeta.Get(edge.Data.MetaId); var attributes = new AttributeCollection(meta); attributes.AddOrReplace(profile); attributes.AddOrReplace("profile", _profile.FullName); // add shape and meta. _shape.AddRange(shape); var previousMeta = _shapeMeta[_shapeMeta.Count - 1]; var shapeMeta = new Route.Meta() { Shape = _shape.Count - 1, Attributes = attributes, AttributesDirection = direction }; shapeMeta.Distance = distance + previousMeta.Distance; shapeMeta.Time = time + previousMeta.Time; _shapeMeta.Add(shapeMeta); // add sidestreets. if (to != Constants.NO_VERTEX) { _branches.AddBranches(_routerDb, _shape.Count - 1, to, edge.Id, next); } }
/// <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; }
/// <summary> /// Exectes the actual run of the algorithm. /// </summary> protected override void DoRun() { if (_route.Shape == null || _route.Shape.Length == 0 || _route.ShapeMeta == null || _route.ShapeMeta.Length == 0) { return; } _aggregatedRoute = new Route(); if (_route.Attributes != null) { _aggregatedRoute.Attributes = new AttributeCollection(_route.Attributes); } _aggregatedRoute.Shape = _route.Shape.Clone() as Coordinate[]; if (_route.Stops != null) { _aggregatedRoute.Stops = new Route.Stop[_route.Stops.Length]; for (var s = 0; s < _route.Stops.Length; s++) { _aggregatedRoute.Stops[s] = _route.Stops[s].Clone(); } } if (_route.Branches != null) { _aggregatedRoute.Branches = new Route.Branch[_route.Branches.Length]; for (var s = 0; s < _route.Branches.Length; s++) { _aggregatedRoute.Branches[s] = _route.Branches[s].Clone(); } } Route.Meta current = null; var metas = new List <Route.Meta>(); if (_route.ShapeMeta[0].Shape == 0) { metas.Add(_route.ShapeMeta[0].Clone()); } for (int i = 1; i < _route.ShapeMeta.Length; i++) { // try to aggregate. if (current == null) { // there is no current yet, set it. current = _route.ShapeMeta[i].Clone(); } else { // try to merge the current segment with the next one. var aggregated = _aggregate(current, _route.ShapeMeta[i]); // expecting an already new object. if (aggregated == null) { // the current segment could not be merged with the next, add it to the final route. metas.Add(current); current = _route.ShapeMeta[i].Clone(); } else { // keep the aggregated as current. aggregated.Shape = _route.ShapeMeta[i].Shape; // make sure to set the shape-index correctly. current = aggregated; } } } if (current != null) { // add the final segment. metas.Add(current); } _aggregatedRoute.ShapeMeta = metas.ToArray(); this.HasSucceeded = true; }