package polylines import ( "math" "github.com/paulmach/orb" ) // // 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) // } 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 coordinates = append(coordinates, orb.Point{float64(lng) / factor, float64(lat) / factor}) } return coordinates }