Skip to content

Commit

Permalink
Split up encoding/decoding into packages
Browse files Browse the repository at this point in the history
  • Loading branch information
JackWink committed May 14, 2018
1 parent fd760f0 commit ad72c31
Show file tree
Hide file tree
Showing 12 changed files with 605 additions and 437 deletions.
143 changes: 6 additions & 137 deletions decode.go
Original file line number Diff line number Diff line change
@@ -1,156 +1,25 @@
package geobuf

import (
"github.com/cairnapp/go-geobuf/pkg/math"
"github.com/cairnapp/go-geobuf/proto"
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"

"github.com/cairnapp/go-geobuf/pkg/decode"
"github.com/cairnapp/go-geobuf/proto"
)

func Decode(msg proto.Data) interface{} {
switch v := msg.DataType.(type) {
case *proto.Data_Geometry_:
geo := v.Geometry
return decodeGeometry(geo, msg.Precision, msg.Dimensions)
return decode.DecodeGeometry(geo, msg.Precision, msg.Dimensions)
case *proto.Data_Feature_:
return decodeFeature(msg, v.Feature, msg.Precision, msg.Dimensions)
return decode.DecodeFeature(msg, v.Feature, msg.Precision, msg.Dimensions)
case *proto.Data_FeatureCollection_:
collection := geojson.NewFeatureCollection()
for _, feature := range v.FeatureCollection.Features {
collection.Append(decodeFeature(msg, feature, msg.Precision, msg.Dimensions))
collection.Append(decode.DecodeFeature(msg, feature, msg.Precision, msg.Dimensions))
}
return collection
}
return struct{}{}
}

func decodeFeature(msg proto.Data, feature *proto.Data_Feature, precision, dimension uint32) *geojson.Feature {
geo := feature.Geometry
decodedGeo := decodeGeometry(geo, msg.Precision, msg.Dimensions)
geoFeature := geojson.NewFeature(decodedGeo.Geometry())
for i := 0; i < len(feature.Properties); i = i + 2 {
keyIdx := feature.Properties[i]
valIdx := feature.Properties[i+1]
val := feature.Values[valIdx]
switch actualVal := val.ValueType.(type) {
case *proto.Data_Value_BoolValue:
geoFeature.Properties[msg.Keys[keyIdx]] = actualVal.BoolValue
case *proto.Data_Value_DoubleValue:
geoFeature.Properties[msg.Keys[keyIdx]] = actualVal.DoubleValue
case *proto.Data_Value_StringValue:
geoFeature.Properties[msg.Keys[keyIdx]] = actualVal.StringValue
case *proto.Data_Value_PosIntValue:
geoFeature.Properties[msg.Keys[keyIdx]] = uint(actualVal.PosIntValue)
case *proto.Data_Value_NegIntValue:
geoFeature.Properties[msg.Keys[keyIdx]] = int(actualVal.NegIntValue) * -1
case *proto.Data_Value_JsonValue:
geoFeature.Properties[msg.Keys[keyIdx]] = actualVal.JsonValue
}
}
switch id := feature.IdType.(type) {
case *proto.Data_Feature_Id:
geoFeature.ID = id.Id
case *proto.Data_Feature_IntId:
geoFeature.ID = id.IntId
}
return geoFeature
}

func decodeGeometry(geo *proto.Data_Geometry, precision, dimensions uint32) *geojson.Geometry {
switch geo.Type {
case proto.Data_Geometry_POINT:
return geojson.NewGeometry(makePoint(geo.Coords, precision))
case proto.Data_Geometry_MULTIPOINT:
return geojson.NewGeometry(makeMultiPoint(geo.Coords, precision, dimensions))
case proto.Data_Geometry_LINESTRING:
return geojson.NewGeometry(makeLineString(geo.Coords, precision, dimensions))
case proto.Data_Geometry_MULTILINESTRING:
return geojson.NewGeometry(makeMultiLineString(geo.Lengths, geo.Coords, precision, dimensions))
case proto.Data_Geometry_POLYGON:
return geojson.NewGeometry(makePolygon(geo.Lengths, geo.Coords, precision, dimensions))
case proto.Data_Geometry_MULTIPOLYGON:
return geojson.NewGeometry(makeMultiPolygon(geo.Lengths, geo.Coords, precision, dimensions))
}
return &geojson.Geometry{}
}

func makePoint(inCords []int64, precision uint32) orb.Point {
point := [2]float64{}
converted := makeCoords(inCords, precision)
copy(point[:], converted[:])
return orb.Point(point)
}

func makeMultiPoint(inCords []int64, precision uint32, dimension uint32) orb.MultiPoint {
return orb.MultiPoint(makeLine(inCords, precision, dimension, false))
}

func makeMultiPolygon(lengths []uint32, inCords []int64, precision uint32, dimension uint32) orb.MultiPolygon {
polyCount := int(lengths[0])
polygons := make([]orb.Polygon, polyCount)
lengths = lengths[1:]
for i := 0; i < polyCount; i += 1 {
ringCount := lengths[0]
polygons[i] = makePolygon(lengths[1:ringCount+1], inCords, precision, dimension)
skip := 0
for i := 0; i < int(ringCount); i += 1 {
skip += int(lengths[i]) * int(dimension)
}

lengths = lengths[ringCount:]
inCords = inCords[skip:]
}
return orb.MultiPolygon(polygons)
}

func makePolygon(lengths []uint32, inCords []int64, precision uint32, dimension uint32) orb.Polygon {
lines := make([]orb.Ring, len(lengths))
for i, length := range lengths {
l := int(length * dimension)
lines[i] = makeRing(inCords[:l], precision, dimension)
inCords = inCords[l:]
}
poly := orb.Polygon(lines)
return poly
}

func makeMultiLineString(lengths []uint32, inCords []int64, precision uint32, dimension uint32) orb.MultiLineString {
lines := make([]orb.LineString, len(lengths))
for i, length := range lengths {
l := int(length * dimension)
lines[i] = makeLineString(inCords[:l], precision, dimension)
inCords = inCords[l:]
}
return orb.MultiLineString(lines)
}

func makeRing(inCords []int64, precision uint32, dimension uint32) orb.Ring {
points := makeLine(inCords, precision, dimension, true)
points = append(points, points[0])
return orb.Ring(points)
}

func makeLineString(inCords []int64, precision uint32, dimension uint32) orb.LineString {
return orb.LineString(makeLine(inCords, precision, dimension, false))
}

func makeLine(inCords []int64, precision uint32, dimension uint32, isClosed bool) []orb.Point {
points := make([]orb.Point, len(inCords)/int(dimension))
prevCords := [2]int64{}
for i, j := 0, 1; j < len(inCords); i, j = i+2, j+2 {
prevCords[0] += inCords[i]
prevCords[1] += inCords[j]
points[i/2] = makePoint(prevCords[:], precision)
}
return points
}

func makeCoords(inCords []int64, precision uint32) []float64 {
ret := make([]float64, len(inCords))
e := math.DecodePrecision(precision)

for i, val := range inCords {
ret[i] = math.FloatWithPrecision(val, uint32(e))
}
return ret
}
4 changes: 2 additions & 2 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func TestDecodeFeatureIntId(t *testing.T) {
p.Properties["string"] = "string"
p.Properties["bool"] = true
encoded := Encode(p)

spew.Dump(encoded)
decoded := Decode(*encoded)

if !reflect.DeepEqual(p, decoded) {
Expand Down Expand Up @@ -195,6 +195,7 @@ func TestDecodeFeatureStringId(t *testing.T) {
p.Properties["string"] = "string"
p.Properties["bool"] = true
encoded := Encode(p)
spew.Dump(encoded)

decoded := Decode(*encoded)

Expand Down Expand Up @@ -248,7 +249,6 @@ func TestDecodeFeatureCollection(t *testing.T) {
encoded := Encode(collection)

decoded := Decode(*encoded)
spew.Dump(decoded)

if !reflect.DeepEqual(collection, decoded) {
t.Errorf("Expected %+v, got %+v", p, decoded)
Expand Down
Loading

0 comments on commit ad72c31

Please sign in to comment.