| | 1 | | using System; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using System.Linq; |
| | 4 | | using Itinero.Routes; |
| | 5 | |
|
| | 6 | | namespace Itinero.Instructions; |
| | 7 | |
|
| | 8 | | /// <summary> |
| | 9 | | /// Contains extension methods for further operations after instruction generation. |
| | 10 | | /// </summary> |
| | 11 | | // ReSharper disable once InconsistentNaming |
| | 12 | | public static class IRouteAndInstructionsExtensions |
| | 13 | | { |
| | 14 | |
|
| | 15 | | /// <summary> |
| | 16 | | /// Adds the instructions to the route object. |
| | 17 | | /// </summary> |
| | 18 | | /// <remarks> |
| | 19 | | /// Some instructions have a length of 0 (thus: instruction.ShapeIndex == instruction.ShapeIndexEnd). |
| | 20 | | /// This will result in multiple shapeMetas pointing to the same 'shape'. Use <see cref="RemoveDuplicateShapeMet |
| | 21 | | /// to remove them. |
| | 22 | | /// </remarks> |
| | 23 | | /// <param name="routeAndInstructions">The route and the instructions.</param> |
| | 24 | | /// <param name="keyForLanguage">A callback to configure the key per language code.</param> |
| | 25 | | /// <returns>Another augmented route and the same instructions.</returns> |
| | 26 | | public static IRouteAndInstructions AugmentRoute(this IRouteAndInstructions routeAndInstructions, |
| | 27 | | Func<string, string>? keyForLanguage = null) |
| 2 | 28 | | { |
| 2 | 29 | | keyForLanguage ??= l => $"instruction:{l}"; |
| | 30 | |
|
| 2 | 31 | | var route = routeAndInstructions.Route; |
| 2 | 32 | | var instructions = routeAndInstructions.Instructions; |
| 2 | 33 | | var shapeMetas = routeAndInstructions.Route.ShapeMeta; |
| | 34 | |
|
| 2 | 35 | | var metas = new List<Route.Meta>(); |
| | 36 | | // 'instructions' and 'shapeMeta' might have different boundaries - so reusing the old shapeMeta's is not possib |
| | 37 | | // We build a new set of shapeMeta instead |
| 2 | 38 | | var instructionPointer = 0; |
| 2 | 39 | | var shapeMetaPointer = 0; |
| 2 | 40 | | var routeCount = shapeMetas.Last().Shape; |
| | 41 | |
|
| 2 | 42 | | Route.Meta? lastMeta = null; |
| 7 | 43 | | while ((lastMeta?.Shape ?? 0) < routeCount && |
| 7 | 44 | | instructionPointer < instructions.Count && |
| 7 | 45 | | shapeMetaPointer < shapeMetas.Count) |
| 5 | 46 | | { |
| 5 | 47 | | var currentMeta = shapeMetas[shapeMetaPointer]; |
| 5 | 48 | | var currentInstruction = instructions[instructionPointer]; |
| | 49 | |
|
| | 50 | |
|
| 5 | 51 | | var latestIncludedPoint = Math.Min( |
| 5 | 52 | | currentMeta.Shape, |
| 5 | 53 | | currentInstruction.BaseInstruction.ShapeIndexEnd); |
| | 54 | |
|
| 5 | 55 | | var attributes = new List<(string key, string value)>(currentMeta.Attributes); |
| 25 | 56 | | foreach (var (languageCode, text) in currentInstruction.Text) |
| 5 | 57 | | { |
| 5 | 58 | | attributes.Add((keyForLanguage(languageCode), text)); |
| 5 | 59 | | } |
| | 60 | |
|
| 5 | 61 | | var distance = route.DistanceBetween(lastMeta?.Shape ?? 0, latestIncludedPoint); |
| 5 | 62 | | var speed = currentMeta.Distance / currentMeta.Time; |
| | 63 | |
|
| 5 | 64 | | var meta = new Route.Meta |
| 5 | 65 | | { |
| 5 | 66 | | Shape = latestIncludedPoint, |
| 5 | 67 | | AttributesAreForward = currentMeta.AttributesAreForward, |
| 5 | 68 | | Attributes = attributes, |
| 5 | 69 | | Profile = currentMeta.Profile, |
| 5 | 70 | | Distance = distance, |
| 5 | 71 | | Time = speed * distance |
| 5 | 72 | | }; |
| | 73 | |
|
| 5 | 74 | | if (currentMeta.Shape == meta.Shape) |
| 3 | 75 | | { |
| 3 | 76 | | shapeMetaPointer++; |
| 3 | 77 | | } |
| | 78 | |
|
| 5 | 79 | | if (currentInstruction.BaseInstruction.ShapeIndexEnd == meta.Shape) |
| 2 | 80 | | { |
| 2 | 81 | | instructionPointer++; |
| 2 | 82 | | } |
| | 83 | |
|
| 5 | 84 | | metas.Add(meta); |
| 5 | 85 | | lastMeta = meta; |
| 5 | 86 | | } |
| | 87 | |
|
| 2 | 88 | | var augmentedRoute = new Route |
| 2 | 89 | | { |
| 2 | 90 | | Attributes = route.Attributes, |
| 2 | 91 | | Branches = route.Branches, |
| 2 | 92 | | Profile = route.Profile, |
| 2 | 93 | | Shape = route.Shape, |
| 2 | 94 | | Stops = route.Stops, |
| 2 | 95 | | TotalDistance = route.TotalDistance, |
| 2 | 96 | | TotalTime = route.TotalTime, |
| 2 | 97 | | ShapeMeta = metas |
| 2 | 98 | | }; |
| | 99 | |
|
| 2 | 100 | | return new RouteAndInstructions(augmentedRoute, instructions); |
| 2 | 101 | | } |
| | 102 | | } |