Skip to content

Commit

Permalink
Merge pull request #13 from ryankurte/fix/geometry-types
Browse files Browse the repository at this point in the history
Approach to solve issue #12 using interface{} and casts
  • Loading branch information
ryankurte authored May 16, 2017
2 parents 63111ae + a65d946 commit eaf7747
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 22 deletions.
55 changes: 40 additions & 15 deletions lib/map_matching/map_matching_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ package mapmatching
import (
"os"
"testing"
)

import (
"github.com/stretchr/testify/assert"

"github.com/ryankurte/go-mapbox/lib/base"
)

Expand All @@ -30,9 +30,16 @@ func TestMapMatching(t *testing.T) {

MapMatching := NewMapMaptching(b)

t.Run("Can Lookup Map Matching", func(t *testing.T) {
timeStamps := []int64{1492878132, 1492878142, 1492878152, 1492878172, 1492878182, 1492878192, 1492878202, 1492878302}
radiusList := []int{9, 6, 8, 11, 8, 4, 8, 8}
timeStamps := []int64{1492878132, 1492878142, 1492878152, 1492878172, 1492878182, 1492878192, 1492878202, 1492878302}
radiusList := []int{9, 6, 8, 11, 8, 4, 8, 8}

locs := []base.Location{{37.75319556403746, -122.44254112243651}, {37.75373846204306, -122.44238018989562},
{37.754111702111146, -122.44199395179749}, {37.75473941979767, -122.44177401065825},
{37.755570713402115, -122.4412429332733}, {37.756401997666046, -122.44113564491273},
{37.75677098309616, -122.44228899478911}, {37.756949113334784, -122.4424821138382}}

t.Run("Map matching supports Polyline", func(t *testing.T) {

var opts RequestOpts
opts.SetGeometries(GeometryPolyline)
opts.SetOverview(OverviewFull)
Expand All @@ -41,19 +48,37 @@ func TestMapMatching(t *testing.T) {
opts.SetAnnotations([]AnnotationType{AnnotationDistance, AnnotationSpeed})
opts.SetRadiuses(radiusList)

locs := []base.Location{{37.75319556403746, -122.44254112243651}, {37.75373846204306, -122.44238018989562},
{37.754111702111146, -122.44199395179749}, {37.75473941979767, -122.44177401065825},
{37.755570713402115, -122.4412429332733}, {37.756401997666046, -122.44113564491273},
{37.75677098309616, -122.44228899478911}, {37.756949113334784, -122.4424821138382}}
res, err := MapMatching.GetMatching(locs, RoutingCycling, &opts)
assert.Nil(t, err)

assert.EqualValues(t, Codes(res.Code), CodeOK)

_, err = res.Matchings[0].GetGeometryPolyline()
assert.Nil(t, err)

_, err = res.Matchings[0].GetGeometryGeojson()
assert.NotNil(t, err)
})

t.Run("Map matching supports GeometryGeojson", func(t *testing.T) {

var opts RequestOpts
opts.SetGeometries(GeometryGeojson)
opts.SetOverview(OverviewFull)
opts.SetTimestamps(timeStamps)
opts.SetSteps(false)
opts.SetAnnotations([]AnnotationType{AnnotationDistance, AnnotationSpeed})
opts.SetRadiuses(radiusList)

res, err := MapMatching.GetMatching(locs, RoutingCycling, &opts)
if err != nil {
t.Error(err)
}
assert.Nil(t, err)

assert.EqualValues(t, Codes(res.Code), CodeOK)

if Codes(res.Code) != CodeOK {
t.Errorf("Invalid response code: %s", res.Code)
}
_, err = res.Matchings[0].GetGeometryGeojson()
assert.Nil(t, err)

_, err = res.Matchings[0].GetGeometryPolyline()
assert.NotNil(t, err)
})
}
79 changes: 72 additions & 7 deletions lib/map_matching/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

package mapmatching

import (
"fmt"
)

// MatchingResponse is the response from GetMatching
// https://www.mapbox.com/api-documentation/#match-response-object
type MatchingResponse struct {
Expand All @@ -17,28 +21,89 @@ type MatchingResponse struct {
Tracepoint []TracePoint
}

type Coordinate []float64

type GeojsonGeometry struct {
Coordinates []Coordinate
}

type PolylineGeometry string

// Matchings it a route object with additional confidence field
// https://www.mapbox.com/api-documentation/#match-object
type Matchings struct {
Confidence float64
Distance float32
Duration float32
Geometry string
Distance float64
Duration float64
Geometry interface{} // Issue: must support polyline (string) or geojson (object)
Legs []MatchingLeg
}

func (m *Matchings) GetGeometryGeojson() (*GeojsonGeometry, error) {
geojson, ok := m.Geometry.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("Malformed geojson geometry (expected map[string]interface, received %t)", m.Geometry)
}

t, ok := geojson["type"]
if !ok {
return nil, fmt.Errorf("Malformed geojson geometry (no type defined)")
}
if t != "LineString" {
return nil, fmt.Errorf("Malformed geojson geometry (incorrect type name: %s)", t)
}

v, ok := geojson["coordinates"]
if !ok {
return nil, fmt.Errorf("Malformed geojson geometry (no coordinates defined)")
}
values, ok := v.([]interface{})
//values, ok := v.([][]float64)
if !ok {
return nil, fmt.Errorf("Malformed geojson geometry (coordinates are not an array of float pairs)")
}

geometry := GeojsonGeometry{}
for _, v := range values {
value, ok := v.([]interface{})
if !ok {
return nil, fmt.Errorf("Could not cast value to coordinate slice (type: %t)", v)
}
lat, ok := value[0].(float64)
if !ok {
return nil, fmt.Errorf("Error casting lat (type: %t)", value[0])
}
lng, ok := value[1].(float64)
if !ok {
return nil, fmt.Errorf("Error casting lng (type: %t)", value[1])
}

geometry.Coordinates = append(geometry.Coordinates, []float64{lat, lng})
}

return &geometry, nil
}

func (m *Matchings) GetGeometryPolyline() (string, error) {
g, ok := m.Geometry.(string)
if !ok {
return "", fmt.Errorf("Non polyline geometry (type: %t)", m.Geometry)
}
return g, nil
}

//MatchingLeg legs inside the matching object
type MatchingLeg struct {
Step []float32
Step []float64
Summary string
Duration float32
Distance float32
Duration float64
Distance float64
}

// TracePoint represents the location an input point was matched with
type TracePoint struct {
WaypointIndex int16
Location []float32
Location []float64
Name string
MatchingsIndex int16
}
Expand Down

0 comments on commit eaf7747

Please sign in to comment.