| | 1 | | using System; |
| | 2 | | using Itinero.Network.Attributes; |
| | 3 | |
|
| | 4 | | namespace Itinero.Instructions.Types.Generators; |
| | 5 | |
|
| | 6 | | internal class FollowAlongGenerator : IInstructionGenerator |
| | 7 | | { |
| 8 | 8 | | public string Name { get; } = "followalong"; |
| | 9 | |
|
| | 10 | | public BaseInstruction? Generate(IndexedRoute route, int offset) |
| 4 | 11 | | { |
| 4 | 12 | | if (offset == 0 || offset == route.Last) |
| 0 | 13 | | { |
| | 14 | | // We can have never a follow along as first or as last locations... |
| 0 | 15 | | return null; |
| | 16 | | } |
| | 17 | |
|
| 4 | 18 | | var usedShapes = 1; |
| 4 | 19 | | var totalDistance = route.DistanceToNextPoint(offset); |
| 4 | 20 | | route.Meta[offset].Attributes.TryGetValue("name", out var name); |
| 11 | 21 | | while (offset + usedShapes < route.Last) |
| 9 | 22 | | { |
| 9 | 23 | | var dAngle = route.DirectionChangeAt(offset + usedShapes); |
| 9 | 24 | | if (Math.Abs(dAngle) > 35) |
| 2 | 25 | | { |
| | 26 | | // To much turn for a follow along... |
| 2 | 27 | | break; |
| | 28 | | } |
| | 29 | |
|
| 7 | 30 | | route.Meta[offset + usedShapes].Attributes.TryGetValue("name", out var newName); |
| 7 | 31 | | if (name != newName) |
| 0 | 32 | | { |
| | 33 | | // Different street! |
| 0 | 34 | | break; |
| | 35 | | } |
| 7 | 36 | | route.Meta[offset + usedShapes].Attributes.TryGetValue("junction", out var junctionType); |
| 7 | 37 | | if (junctionType == "roundabout") |
| 0 | 38 | | { |
| | 39 | | // We cancel on roundabouts, in order to generate a roundabout-instruction for them |
| 0 | 40 | | break; |
| | 41 | | } |
| | 42 | |
|
| | 43 | |
|
| 7 | 44 | | var distance = route.DistanceToNextPoint(offset + usedShapes); |
| 7 | 45 | | totalDistance += distance; |
| | 46 | |
|
| 7 | 47 | | usedShapes++; |
| 7 | 48 | | } |
| | 49 | | // In degrees. Difference in bearing between start- and end |
| 4 | 50 | | var totalChange = |
| 4 | 51 | | (route.ArrivingDirectionAt(offset + usedShapes) - route.ArrivingDirectionAt(offset)).NormalizeDegrees(); |
| | 52 | |
|
| | 53 | | // A follow along is not allowed to turn more then 45 degrees in total; otherwise this is a 'followBend' |
| 4 | 54 | | if (Math.Abs(totalChange) >= 45) |
| 2 | 55 | | { |
| 2 | 56 | | return null; |
| | 57 | | } |
| | 58 | |
|
| | 59 | | // THere is little directional change - does it turn at most a little bit? |
| 2 | 60 | | if (Math.Abs(totalChange) / totalDistance >= 2.5) |
| 0 | 61 | | { |
| | 62 | | // Nope, we turn more then 2.5°/m, this is 'followBend'-material |
| 0 | 63 | | return null; |
| | 64 | | } |
| | 65 | |
|
| | 66 | |
|
| 2 | 67 | | return new FollowAlongInstruction( |
| 2 | 68 | | route, |
| 2 | 69 | | offset, |
| 2 | 70 | | offset + usedShapes, |
| 2 | 71 | | totalChange |
| 2 | 72 | | ); |
| 4 | 73 | | } |
| | 74 | | } |