- this works just fine when the encodedPolyline provides [lat, lon]
- but when the parameters of a GET are setup to provide [lat, lon, elevation] (please see decodePolylineWithElevation); it breaks due to index out of range elsewhere (connected to this)
- connected issue is: I try to split up the coordinates based on xyz for a specific format compatibility
if let first = step.coordinatesStartIndex, let last = step.coordinatesEndIndex {
// last is 62 whilst coordinates' count at this juncture is 56 ISSUE is here
// why would this happen only when I also request elevation to be included in the encodedPolyline? Am I not decoding it properly? :/
let myCoordinates = Array(coordinates[first...last])
stepGeometry.append(myCoordinates)
}
References for decoding: graphhopper/WebHelper.java at d70b63660ac5200b03c38ba3406b8f93976628a6 · graphhopper/graphhopper · GitHub
public func decodePolyline(_ encodedPolyline: String, precision: Double = 1e5) -> [LocationCoordinate2D]? {
let data = encodedPolyline.data(using: .utf8)!
return data.withUnsafeBytes { byteArray -> [LocationCoordinate2D]? in
let length = data.count
var position = 0
var decodedCoordinates = [LocationCoordinate2D]()
var lat = 0.0
var lon = 0.0
while position < length {
do {
let resultingLat = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lat += resultingLat
let resultingLon = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lon += resultingLon
} catch {
return nil
}
decodedCoordinates.append(LocationCoordinate2D(latitude: lat, longitude: lon))
}
return decodedCoordinates
}
}
public struct CustomPoint {
var coordinate: LocationCoordinate2D
var elevation: Double
}
public func decodePolylineWithElevation(_ encodedPolyline: String, precision: Double = 1e5) -> [CustomPoint]? {
let data = encodedPolyline.data(using: .utf8)!
return data.withUnsafeBytes { byteArray -> [BMPoint]? in
let length = data.count
var position = 0
var decodedPoints = [BMPoint]()
var lat = 0.0
var lon = 0.0
var elevation = 0.0
while position < length {
do {
let resultingLat = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lat += resultingLat
let resultingLon = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
lon += resultingLon
let resultingElevation = try decodeSingleCoordinate(byteArray: byteArray, length: length, position: &position, precision: precision)
elevation += resultingElevation
} catch {
return nil
}
decodedPoints.append(CustomPoint(coordinate: LocationCoordinate2D(latitude: lat, longitude: lon), elevation: elevation))
}
return decodedPoints
}
}
private func decodeSingleCoordinate(byteArray: UnsafeRawBufferPointer, length: Int, position: inout Int, precision: Double = 1e5) throws -> Double {
guard position < length else { throw PolylineError.singleCoordinateDecodingError }
let bitMask = Int8(0x1F)
var coordinate: Int32 = 0
var currentChar: Int8
var componentCounter: Int32 = 0
var component: Int32 = 0
repeat {
currentChar = Int8(byteArray[position]) - 63
component = Int32(currentChar & bitMask)
coordinate |= (component << (5*componentCounter))
position += 1
componentCounter += 1
} while ((currentChar & 0x20) == 0x20) && (position < length) && (componentCounter < 6)
if (componentCounter == 6) && ((currentChar & 0x20) == 0x20) {
throw PolylineError.singleCoordinateDecodingError
}
if (coordinate & 0x01) == 0x01 {
coordinate = ~(coordinate >> 1)
} else {
coordinate = coordinate >> 1
}
return Double(coordinate) / precision
}