APP在保存轨迹时,如果只有较少的数据时,还能应对,如果面对上百到上千的轨迹点时,数据量还是相当大,我们不仅要考虑简单的存储方式,也要考虑存储时的磁盘空间占用情况。
此项问题,在Google地图开发中开到了他们常用的轨迹压缩算法 Polyline encoding algorith[1],将大量的点位坐标转换为字符串实现压缩,比如:
ml{yDk|dzRrg@pGn\\lEdU_NzXbAtNhCrU?tT?fTuCvM`@pPQbPr@hO{AfNtAjLuA|K?bIgBjM|DbEm@lEuAxGcA?G?G?gE?}|@
这个是已将25条经纬度进行压缩后的字符串,无论是传输到服务器还是本地存储,都有极大便利,在使用时,将坐标转换回来方可使用。
代码
已经在Playground
中执行通过
struct Polyline {
private static func encodeCoordinate(_ coordinate: Double) -> String {
var coord = Int(round(coordinate * 1e5))
coord <<= 1
if coord < 0 {
coord = ~coord
}
var encodedString = ""
while coord >= 0x20 {
let value = (0x20 | (coord & 0x1f)) + 63
encodedString.append(Character(UnicodeScalar(value)!))
coord >>= 5
}
coord += 63
encodedString.append(Character(UnicodeScalar(coord)!))
return encodedString
}
//编码
public static func encodePolyline(_ coordinates:[(latitude: Double, longitude: Double)])->String{
var encodedPolyline = ""
var previousLatitude = 0.0
var previousLongitude = 0.0
for coordinate in coordinates {
let latitudeChange = coordinate.latitude - previousLatitude
let longitudeChange = coordinate.longitude - previousLongitude
encodedPolyline += Polyline.encodeCoordinate(latitudeChange)
encodedPolyline += Polyline.encodeCoordinate(longitudeChange)
previousLatitude = coordinate.latitude
previousLongitude = coordinate.longitude
}
return encodedPolyline
}
private static func decodeCoordinate(from encodedString: inout String) -> Double {
var coordinate = 0
var shift = 0
var result = 0
var continueDecoding = true
while continueDecoding && !encodedString.isEmpty {
let character = encodedString.removeFirst().unicodeScalars.first!.value - 63
result = Int(character) & 0x1F
coordinate |= (result << shift)
shift += 5
continueDecoding = (character >= 0x20)
}
if (coordinate & 1) != 0 {
coordinate = ~(coordinate >> 1)
} else {
coordinate >>= 1
}
return Double(coordinate) * 1e-5
}
// 解码一条多段线
public static func decodePolyline(_ encodedString: String) -> [(latitude: Double, longitude: Double)] {
var encodedString = encodedString
var coordinates: [(latitude: Double, longitude: Double)] = []
var latitude = 0.0
var longitude = 0.0
while !encodedString.isEmpty {
let latitudeChange = decodeCoordinate(from: &encodedString)
let longitudeChange = decodeCoordinate(from: &encodedString)
latitude += latitudeChange
longitude += longitudeChange
coordinates.append((latitude: latitude, longitude: longitude))
}
return coordinates
}
}
使用
// 测试数据
let coordinates = [
(latitude: 30.61975,longitude:104.06870),
(latitude: 30.61325,longitude:104.06733),
(latitude: 30.60853,longitude:104.06630),
(latitude: 30.60498,longitude:104.06870),
(latitude: 30.60084,longitude:104.06836),
(latitude: 30.59833,longitude:104.06767),
(latitude: 30.59471,longitude:104.06767),
(latitude: 30.59124,longitude:104.06767),
(latitude: 30.58784,longitude:104.06842),
(latitude: 30.58548,longitude:104.06825),
(latitude: 30.58267,longitude:104.06834),
(latitude: 30.57993,longitude:104.06808),
(latitude: 30.57732,longitude:104.06854),
(latitude: 30.57488,longitude:104.06811),
(latitude: 30.57274,longitude:104.06854),
(latitude: 30.57067,longitude:104.06854),
(latitude: 30.56905,longitude:104.06906),
(latitude: 30.56675,longitude:104.06811),
(latitude: 30.56577,longitude:104.06834),
(latitude: 30.56474,longitude:104.06877),
(latitude: 30.56333,longitude:104.06911),
(latitude: 30.56333,longitude:104.06915),
(latitude: 30.56333,longitude:104.06919),
(latitude: 30.56333,longitude:104.07019),
(latitude: 30.56333,longitude:104.08010),
]
let str = Polyline.encodePolyline(coordinates)
let v = Polyline.decodePolyline(str)
检查
利用Google的实用工具[2],对以上生成的数据进行检查