2023-03-27 18:57:28 +00:00
|
|
|
package polylines
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
|
|
|
|
"github.com/paulmach/orb"
|
|
|
|
)
|
|
|
|
|
2023-03-29 22:45:55 +00:00
|
|
|
// // Decode decodes coordinates to the "Encoded Polyline Algorithm Format"
|
|
|
|
// // More info: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
|
|
|
// // polyline: polyline string in "Encoded Polyline Algorithm Format"
|
|
|
|
// // precision: usually 5 or 6; Google's original algorithm uses 5 digits of decimal precision,
|
|
|
|
// // which is accurate to about a meter. A precision of 6 gives you an accuracy of about 10cm
|
|
|
|
// // more info: https://mapzen.com/blog/polyline-precision/
|
|
|
|
// func Decode(polyline string, precision uint32) orb.LineString {
|
|
|
|
|
|
|
|
// group := ""
|
|
|
|
// coordinates := []float64{}
|
|
|
|
|
|
|
|
// for _, letter := range polyline {
|
|
|
|
// group += string(letter)
|
|
|
|
|
|
|
|
// if (int32(letter)-63)&0x20 == 0 {
|
|
|
|
// coordinates = append(coordinates, decodeElement(group, precision))
|
|
|
|
// group = ""
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// points := orb.LineString{}
|
|
|
|
// for i := 1; i < len(coordinates); i += 2 {
|
|
|
|
// points = append(points, orb.Point{round(coordinates[i], precision), round(coordinates[i-1], precision)})
|
|
|
|
// }
|
|
|
|
|
|
|
|
// for i := range points {
|
|
|
|
// if i > 0 {
|
|
|
|
// points[i][1] = round(points[i-1].Lat()+points[i].Lat(), precision)
|
|
|
|
// points[i][0] = round(points[i-1].Lon()+points[i].Lon(), precision)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return points
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // Decode5 is a short call for Decode with precision set to 5
|
|
|
|
// // Accuracy is about one meter
|
|
|
|
// func Decode5(polyline string) orb.LineString {
|
|
|
|
// return Decode(polyline, 5)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // Decode6 is a short call for Decode with precision set to 6
|
|
|
|
// // Accuracy is about ten centimeters
|
|
|
|
// func Decode6(polyline string) orb.LineString {
|
|
|
|
// return Decode(polyline, 6)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// // decodeElement decodes an coordinate element (i.e. latitude or longitude)
|
|
|
|
// // from the "Encoded Polyline Algorithm Format"
|
|
|
|
// func decodeElement(group string, precision uint32) float64 {
|
|
|
|
|
|
|
|
// var c chunks
|
|
|
|
// c.ParseLine(group)
|
|
|
|
// return c.Coordinate(precision)
|
|
|
|
// }
|
|
|
|
|
2023-03-27 18:57:28 +00:00
|
|
|
func Decode(encoded *string, precisionOptional ...int) orb.LineString {
|
|
|
|
// default to 6 digits of precision
|
|
|
|
precision := 6
|
|
|
|
if len(precisionOptional) > 0 {
|
|
|
|
precision = precisionOptional[0]
|
|
|
|
}
|
|
|
|
factor := math.Pow10(precision)
|
|
|
|
|
|
|
|
// Coordinates have variable length when encoded, so just keep
|
|
|
|
// track of whether we've hit the end of the string. In each
|
|
|
|
// loop iteration, a single coordinate is decoded.
|
|
|
|
lat, lng := 0, 0
|
|
|
|
var coordinates orb.LineString
|
|
|
|
index := 0
|
|
|
|
for index < len(*encoded) {
|
|
|
|
// Consume varint bits for lat until we run out
|
|
|
|
var byte int = 0x20
|
|
|
|
shift, result := 0, 0
|
|
|
|
for byte >= 0x20 {
|
|
|
|
byte = int((*encoded)[index]) - 63
|
|
|
|
result |= (byte & 0x1f) << shift
|
|
|
|
shift += 5
|
|
|
|
index++
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if we need to go negative or not
|
|
|
|
if (result & 1) > 0 {
|
|
|
|
lat += ^(result >> 1)
|
|
|
|
} else {
|
|
|
|
lat += result >> 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume varint bits for lng until we run out
|
|
|
|
byte = 0x20
|
|
|
|
shift, result = 0, 0
|
|
|
|
for byte >= 0x20 {
|
|
|
|
byte = int((*encoded)[index]) - 63
|
|
|
|
result |= (byte & 0x1f) << shift
|
|
|
|
shift += 5
|
|
|
|
index++
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if we need to go negative or not
|
|
|
|
if (result & 1) > 0 {
|
|
|
|
lng += ^(result >> 1)
|
|
|
|
} else {
|
|
|
|
lng += result >> 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// scale the int back to floating point and storeLineString it
|
2023-03-29 16:55:21 +00:00
|
|
|
coordinates = append(coordinates, orb.Point{float64(lng) / factor, float64(lat) / factor})
|
2023-03-27 18:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return coordinates
|
|
|
|
}
|