fix decoding encoreding
This commit is contained in:
parent
1442647132
commit
30339c9bdd
|
@ -0,0 +1,95 @@
|
|||
package polylines
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type chunks []int32
|
||||
|
||||
// Parse splices an integer into chunks
|
||||
func (c *chunks) Parse(element int32) {
|
||||
|
||||
c.slice(element, 5)
|
||||
|
||||
}
|
||||
|
||||
// ParseLine converts and splices string into integer chunks
|
||||
func (c *chunks) ParseLine(line string) {
|
||||
|
||||
chunkSlice := []int32{}
|
||||
|
||||
for index, letter := range line {
|
||||
elementInt := int32(letter) - 63
|
||||
if index != len(line)-1 {
|
||||
elementInt = elementInt & 31
|
||||
}
|
||||
|
||||
chunkSlice = append(chunkSlice, elementInt)
|
||||
}
|
||||
|
||||
*c = chunkSlice
|
||||
|
||||
}
|
||||
|
||||
// String returns the chunks as polyline in base64
|
||||
func (c *chunks) String() string {
|
||||
|
||||
c.or()
|
||||
s := ""
|
||||
for i := range *c {
|
||||
s += string((*c)[i])
|
||||
}
|
||||
return s
|
||||
|
||||
}
|
||||
|
||||
// Coordinate converts integer chunks into a single coordinate
|
||||
func (c *chunks) Coordinate(precision uint32) float64 {
|
||||
resultInt := int32(0)
|
||||
|
||||
for i, element := range *c {
|
||||
resultInt += element << uint32(i*5)
|
||||
}
|
||||
|
||||
if resultInt&1 == 1 {
|
||||
resultInt = ^resultInt
|
||||
}
|
||||
resultInt = resultInt >> 1
|
||||
|
||||
return float64(resultInt) / math.Pow10(int(precision))
|
||||
}
|
||||
|
||||
// slice splits elements into group of "length" bits
|
||||
func (c *chunks) slice(element int32, length int) {
|
||||
|
||||
if element == 0 {
|
||||
*c = []int32{0}
|
||||
return
|
||||
}
|
||||
chunkSlice := []int32{}
|
||||
|
||||
bitMask := int32(31)
|
||||
|
||||
for i := 0; int32(math.Pow(2, float64(i))) <= element; i += 5 {
|
||||
group := (element >> uint(i)) & bitMask
|
||||
chunkSlice = append(chunkSlice, group)
|
||||
}
|
||||
|
||||
*c = chunkSlice
|
||||
|
||||
}
|
||||
|
||||
// or sets the 6th bit to 1 for every chunk except the last one
|
||||
// as indicator bit for coordinate boundaries.
|
||||
// It also adds 63 (decimal) to every group to ensure it is in
|
||||
// ASCII range
|
||||
func (c *chunks) or() {
|
||||
|
||||
for i := range *c {
|
||||
if i < len(*c)-1 {
|
||||
(*c)[i] = (*c)[i] | 0x20
|
||||
}
|
||||
(*c)[i] += 63
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,62 @@ import (
|
|||
"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
|
||||
|
|
|
@ -5,12 +5,79 @@ import (
|
|||
"github.com/twpayne/go-polyline"
|
||||
)
|
||||
|
||||
func Encode(line orb.LineString) string {
|
||||
// // Encode encodes coordinates to the "Encoded Polyline Algorithm Format"
|
||||
// // More info: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
||||
// // points: points of the polyline
|
||||
// // 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 Encode(linestring orb.LineString, precision uint32) string {
|
||||
|
||||
// encoded := ""
|
||||
|
||||
// latitude := 0.0
|
||||
// longitude := 0.0
|
||||
|
||||
// for _, point := range linestring {
|
||||
// polyLatitude := encodeElement(point.Lat()-latitude, precision)
|
||||
// encoded += polyLatitude
|
||||
|
||||
// polyLongitude := encodeElement(point.Lon()-longitude, precision)
|
||||
// encoded += polyLongitude
|
||||
|
||||
// // to conserve space, points only include the offset from the previous point
|
||||
// latitude = point.Lat()
|
||||
// longitude = point.Lon()
|
||||
|
||||
// }
|
||||
|
||||
// return encoded
|
||||
|
||||
// }
|
||||
|
||||
// // Encode5 is a short call for Encode with precision set to 5
|
||||
// // Accuracy is about one meter
|
||||
// func Encode5(linestring orb.LineString) string {
|
||||
// return Encode(linestring, 5)
|
||||
// }
|
||||
|
||||
// // Encode6 is a short call for Encode with precision set to 6
|
||||
// // Accuracy is about ten centimeters
|
||||
// func Encode6(linestring orb.LineString) string {
|
||||
// return Encode(linestring, 6)
|
||||
// }
|
||||
|
||||
// // encodeElement encodes an coordinate element (i.e. latitude or longitude)
|
||||
// // to the "Encoded Polyline Algorithm Format"
|
||||
// func encodeElement(element float64, precision uint32) string {
|
||||
|
||||
// elementInt := int32(math.Round(element * math.Pow10(int(precision))))
|
||||
// elementInt = elementInt << 1
|
||||
// if element < 0 {
|
||||
// elementInt = ^elementInt
|
||||
// }
|
||||
|
||||
// var c chunks
|
||||
// c.Parse(elementInt)
|
||||
|
||||
// return c.String()
|
||||
|
||||
// }
|
||||
|
||||
// // round n to precision digits
|
||||
// func round(n float64, precision uint32) float64 {
|
||||
|
||||
// factor := math.Pow10(int(precision))
|
||||
// return math.Round(n*factor) / factor
|
||||
|
||||
// }
|
||||
|
||||
func Encode(line orb.LineString, precision uint32) string {
|
||||
|
||||
preparedLine := [][]float64{}
|
||||
|
||||
for _, point := range line {
|
||||
preparedLine = append(preparedLine, []float64{point.Lon(), point.Lat()})
|
||||
preparedLine = append(preparedLine, []float64{point.Lat(), point.Lon()})
|
||||
}
|
||||
|
||||
return string(polyline.EncodeCoords(preparedLine))
|
||||
|
|
10
valhalla.go
10
valhalla.go
|
@ -10,6 +10,7 @@ import (
|
|||
"git.coopgo.io/coopgo-platform/routing-service/encoding/polylines"
|
||||
"git.coopgo.io/coopgo-platform/routing-service/proto/valhalla"
|
||||
"github.com/paulmach/orb"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
|
@ -47,11 +48,14 @@ func (v *ValhallaRouting) Route(locations []orb.Point) (route *Route, err error)
|
|||
|
||||
resp, err := v.protocolBufferRequest(request, "route")
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("pb request to valhalla error")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Any("resp", resp).Msg("valhalla response")
|
||||
|
||||
if resp.Directions == nil || resp.Directions.Routes == nil || len(resp.Directions.Routes) < 1 {
|
||||
return nil, errors.New("no routes returnes by valhalla")
|
||||
return nil, errors.New("no routes returned by valhalla")
|
||||
}
|
||||
|
||||
decodedLinestring := orb.LineString{}
|
||||
|
@ -66,7 +70,7 @@ func (v *ValhallaRouting) Route(locations []orb.Point) (route *Route, err error)
|
|||
routeLeg := RouteLeg{
|
||||
Distance: float64(leg.Summary.Length),
|
||||
Duration: time.Duration(leg.Summary.Time) * time.Second,
|
||||
Polyline: polylines.Encode(decodedShape),
|
||||
Polyline: polylines.Encode(decodedShape, 5),
|
||||
}
|
||||
|
||||
legs = append(legs, routeLeg)
|
||||
|
@ -74,7 +78,7 @@ func (v *ValhallaRouting) Route(locations []orb.Point) (route *Route, err error)
|
|||
|
||||
return &Route{
|
||||
Summary: RouteSummary{
|
||||
Polyline: polylines.Encode(decodedLinestring),
|
||||
Polyline: polylines.Encode(decodedLinestring, 5),
|
||||
},
|
||||
Legs: legs,
|
||||
}, nil
|
||||
|
|
Loading…
Reference in New Issue