-
Notifications
You must be signed in to change notification settings - Fork 319
/
Copy pathAlternativeRoute.swift
145 lines (125 loc) · 5.93 KB
/
AlternativeRoute.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import Foundation
import MapboxDirections
import MapboxNavigationNative
import Turf
/**
Representation of an alternative route with relation to the original.
This struct contains main and alternative routes which are sharing same origin and destination points, but differ at some point.
*/
public struct AlternativeRoute: Identifiable {
/// Alternative route identifier type
public typealias ID = UInt32
/// Brief statistics of a route for traveling
public struct RouteInfo {
/// Expected travel distance
public let distance: LocationDistance
/// Expected travel duration
public let duration: TimeInterval
public init(distance: LocationDistance, duration: TimeInterval) {
self.distance = distance
self.duration = duration
}
}
/// Alternative route identificator.
///
/// It is unique withing the same navigation session.
public let id: ID
/// Original (main) route data
public let indexedRouteResponse: IndexedRouteResponse
/// Intersection on the main route, where alternative route branches.
public let mainRouteIntersection: Intersection
/// Intersection on the alternative route, where it splits from the main route.
public let alternativeRouteIntersection: Intersection
/// Alternative route statistics, counting from the split point.
public let infoFromDeviationPoint: RouteInfo
/// Alternative route statistics, counting from it's origin.
public let infoFromOrigin: RouteInfo
/// The difference of distances between alternative and the main routes
public let distanceDelta: LocationDistance
/// The difference of expected travel time between alternative and the main routes
public let expectedTravelTimeDelta: TimeInterval
init?(alternativeRoute nativeRouteAlternative: RouteAlternative) {
guard let indexedRouteResponse = nativeRouteAlternative.indexedRouteResponse() else {
return nil
}
self.init(indexedRouteResponse: indexedRouteResponse, alternativeRoute: nativeRouteAlternative)
}
init?(indexedRouteResponse: IndexedRouteResponse, alternativeRoute nativeRouteAlternative: RouteAlternative) {
var indexedRouteResponse = indexedRouteResponse
indexedRouteResponse.routeIndex = Int(nativeRouteAlternative.route.getRouteIndex())
guard let mainRoute = indexedRouteResponse.currentRoute else {
return nil
}
self.id = nativeRouteAlternative.id
self.indexedRouteResponse = indexedRouteResponse
var legIndex = Int(nativeRouteAlternative.mainRouteFork.legIndex)
var segmentIndex = Int(nativeRouteAlternative.mainRouteFork.segmentIndex)
guard let mainIntersection = mainRoute.findIntersection(on: legIndex, by: segmentIndex) else {
return nil
}
self.mainRouteIntersection = mainIntersection
legIndex = Int(nativeRouteAlternative.alternativeRouteFork.legIndex)
segmentIndex = Int(nativeRouteAlternative.alternativeRouteFork.segmentIndex)
guard let alternativeIntersection = indexedRouteResponse.currentRoute?.findIntersection(on: legIndex, by: segmentIndex) else {
return nil
}
self.alternativeRouteIntersection = alternativeIntersection
self.infoFromDeviationPoint = .init(distance: nativeRouteAlternative.infoFromFork.distance,
duration: nativeRouteAlternative.infoFromFork.duration)
self.infoFromOrigin = .init(distance: nativeRouteAlternative.infoFromStart.distance,
duration: nativeRouteAlternative.infoFromStart.duration)
self.distanceDelta = infoFromOrigin.distance - mainRoute.distance
self.expectedTravelTimeDelta = infoFromOrigin.duration - mainRoute.expectedTravelTime
}
/**
:nodoc:
Creates new `AlternativeRoute` instance.
For test purposes only. SDK does not support custom `AlternativeRoute`s.
*/
public init(id: ID,
indexedRouteResponse: IndexedRouteResponse,
mainRouteIntersection: Intersection,
alternativeRouteIntersection: Intersection,
infoFromDeviationPoint: RouteInfo,
infoFromOrigin: RouteInfo,
distanceDelta: LocationDistance,
expectedTravelTimeDelta: TimeInterval) {
self.id = id
self.indexedRouteResponse = indexedRouteResponse
self.mainRouteIntersection = mainRouteIntersection
self.alternativeRouteIntersection = alternativeRouteIntersection
self.infoFromDeviationPoint = infoFromDeviationPoint
self.infoFromOrigin = infoFromOrigin
self.distanceDelta = distanceDelta
self.expectedTravelTimeDelta = expectedTravelTimeDelta
}
}
extension Route {
fileprivate func findIntersection(on legIndex: Int, by segmentIndex: Int) -> Intersection? {
guard legs.count > legIndex else {
return nil
}
let leg = legs[legIndex]
guard let stepindex = leg.segmentRangesByStep.firstIndex(where: { $0.contains(segmentIndex) }) else {
return nil
}
guard let intersectionIndex = leg.steps[stepindex].segmentIndicesByIntersection?.firstIndex(where: { $0 == segmentIndex }) else {
return nil
}
return leg.steps[stepindex].intersections?[intersectionIndex]
}
}
extension RouteAlternative {
func indexedRouteResponse() -> IndexedRouteResponse? {
guard let decoded =
RerouteController.decode(routeRequest: route.getRequestUri(),
routeResponse: route.getResponseJsonRef()) else {
return nil
}
return IndexedRouteResponse(
routeResponse: decoded.routeResponse,
routeIndex: Int(route.getRouteIndex()),
responseOrigin: route.getRouterOrigin()
)
}
}