| | 1 | | using System; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using Itinero.Instructions.Types; |
| | 4 | | using Itinero.Routes; |
| | 5 | |
|
| | 6 | | namespace Itinero.Instructions.Generators; |
| | 7 | |
|
| | 8 | | /// <summary> |
| | 9 | | /// Constructs instructions using the instruction constructors and adds an end-instruction. |
| | 10 | | /// </summary> |
| | 11 | | /// <remarks> |
| | 12 | | /// Given a list of instruction constructors, this will construct a route in the following way: |
| | 13 | | /// - Try to generate a base instruction with the first instruction in the list. If this fails, try the next one |
| | 14 | | /// - Check the shape-index of the generated instruction and move the index of the route forward |
| | 15 | | /// - Try to generate a new instruction as described above |
| | 16 | | /// |
| | 17 | | /// This means that the list of 'baseInstructionConstructors' should go from "very specialized" to "very generic", e.g. |
| | 18 | | /// the roundabout-instruction-constructor should be at the first position as that instruction will only trigger in spe |
| | 19 | | /// whereas the 'follow the road/go left/go right' instruction will always trigger but is not very informative. |
| | 20 | | /// |
| | 21 | | /// An 'end'-instruction will always an automatically be appended. Adding the 'endInstructionGenerator' via the construc |
| | 22 | | /// _two_ end instructions |
| | 23 | | /// </remarks> |
| | 24 | | public class LinearInstructionListGenerator : IInstructionListGenerator |
| | 25 | | { |
| | 26 | | private readonly IReadOnlyList<Types.Generators.IInstructionGenerator> _constructors; |
| | 27 | |
|
| 8 | 28 | | internal LinearInstructionListGenerator(IReadOnlyList<Types.Generators.IInstructionGenerator> constructors) |
| 8 | 29 | | { |
| 8 | 30 | | _constructors = constructors; |
| 8 | 31 | | } |
| | 32 | |
|
| | 33 | | /// <inhertdoc/> |
| | 34 | | public IReadOnlyList<BaseInstruction> GenerateInstructions(Route route) |
| 8 | 35 | | { |
| 8 | 36 | | var indexedRoute = new IndexedRoute(route); |
| 8 | 37 | | var instructions = new List<BaseInstruction>(); |
| | 38 | |
|
| 8 | 39 | | var currentIndex = 0; |
| 35 | 40 | | while (currentIndex < indexedRoute.Last) |
| 27 | 41 | | { |
| 27 | 42 | | var instruction = this.ConstructNext(indexedRoute, currentIndex); |
| 27 | 43 | | instructions.Add(instruction); |
| 27 | 44 | | if (instruction.ShapeIndexEnd == currentIndex) |
| 7 | 45 | | { |
| 7 | 46 | | currentIndex++; |
| 7 | 47 | | } |
| | 48 | | else |
| 20 | 49 | | { |
| 20 | 50 | | currentIndex = instruction.ShapeIndexEnd; |
| 20 | 51 | | } |
| 27 | 52 | | } |
| | 53 | |
|
| 8 | 54 | | instructions.Add(new EndInstruction(indexedRoute)); |
| | 55 | |
|
| 8 | 56 | | return instructions; |
| 8 | 57 | | } |
| | 58 | |
|
| | 59 | | private BaseInstruction ConstructNext(IndexedRoute r, int currentOffset) |
| 27 | 60 | | { |
| 162 | 61 | | foreach (var constructor in _constructors) |
| 54 | 62 | | { |
| 54 | 63 | | var instruction = constructor.Generate(r, currentOffset); |
| 54 | 64 | | if (instruction != null) |
| 27 | 65 | | { |
| 27 | 66 | | return instruction; |
| | 67 | | } |
| 27 | 68 | | } |
| | 69 | |
|
| 0 | 70 | | throw new Exception("Could not generate instruction for offset " + currentOffset); |
| 27 | 71 | | } |
| | 72 | | } |