From 108982a72961a5466235670fcdb0fa730fcf2664 Mon Sep 17 00:00:00 2001 From: Oliver Tonnhofer Date: Sat, 19 Jan 2013 13:50:44 +0100 Subject: [PATCH] parse dense nodes; add node/way/relation models --- model/model.pb.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++ model/model.proto | 31 ++++++++++ model/nodes.go | 40 +++++++++++++ parser.go | 55 ++++++++++++++++- 4 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 model/model.pb.go create mode 100644 model/model.proto create mode 100644 model/nodes.go diff --git a/model/model.pb.go b/model/model.pb.go new file mode 100644 index 0000000..f8433c6 --- /dev/null +++ b/model/model.pb.go @@ -0,0 +1,149 @@ +// Code generated by protoc-gen-go. +// source: model.proto +// DO NOT EDIT! + +package model + +import proto "code.google.com/p/goprotobuf/proto" +import json "encoding/json" +import math "math" + +// Reference proto, json, and math imports to suppress error if they are not otherwise used. +var _ = proto.Marshal +var _ = &json.SyntaxError{} +var _ = math.Inf + +type RelationMember_MemberType int32 + +const ( + RelationMember_NODE RelationMember_MemberType = 0 + RelationMember_WAY RelationMember_MemberType = 1 + RelationMember_RELATION RelationMember_MemberType = 2 +) + +var RelationMember_MemberType_name = map[int32]string{ + 0: "NODE", + 1: "WAY", + 2: "RELATION", +} +var RelationMember_MemberType_value = map[string]int32{ + "NODE": 0, + "WAY": 1, + "RELATION": 2, +} + +func (x RelationMember_MemberType) Enum() *RelationMember_MemberType { + p := new(RelationMember_MemberType) + *p = x + return p +} +func (x RelationMember_MemberType) String() string { + return proto.EnumName(RelationMember_MemberType_name, int32(x)) +} +func (x RelationMember_MemberType) MarshalJSON() ([]byte, error) { + return json.Marshal(x.String()) +} +func (x *RelationMember_MemberType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(RelationMember_MemberType_value, data, "RelationMember_MemberType") + if err != nil { + return err + } + *x = RelationMember_MemberType(value) + return nil +} + +type Tag struct { + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (this *Tag) Reset() { *this = Tag{} } +func (this *Tag) String() string { return proto.CompactTextString(this) } +func (*Tag) ProtoMessage() {} + +func (this *Tag) GetKey() string { + if this != nil && this.Key != nil { + return *this.Key + } + return "" +} + +func (this *Tag) GetVal() string { + if this != nil && this.Val != nil { + return *this.Val + } + return "" +} + +type Way struct { + Id *int64 `protobuf:"varint,1,req,name=id" json:"id,omitempty"` + Tags []*Tag `protobuf:"bytes,2,rep,name=tags" json:"tags,omitempty"` + Nodes []int64 `protobuf:"varint,3,rep,packed,name=nodes" json:"nodes,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (this *Way) Reset() { *this = Way{} } +func (this *Way) String() string { return proto.CompactTextString(this) } +func (*Way) ProtoMessage() {} + +func (this *Way) GetId() int64 { + if this != nil && this.Id != nil { + return *this.Id + } + return 0 +} + +type Relation struct { + Id *int64 `protobuf:"varint,1,req,name=id" json:"id,omitempty"` + Tags []*Tag `protobuf:"bytes,2,rep,name=tags" json:"tags,omitempty"` + Members []*RelationMember `protobuf:"bytes,3,rep,name=members" json:"members,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (this *Relation) Reset() { *this = Relation{} } +func (this *Relation) String() string { return proto.CompactTextString(this) } +func (*Relation) ProtoMessage() {} + +func (this *Relation) GetId() int64 { + if this != nil && this.Id != nil { + return *this.Id + } + return 0 +} + +type RelationMember struct { + MemberIds *int64 `protobuf:"varint,1,req,name=member_ids" json:"member_ids,omitempty"` + MemberTypes *RelationMember_MemberType `protobuf:"varint,2,req,name=member_types,enum=model.RelationMember_MemberType" json:"member_types,omitempty"` + MemberRoles *string `protobuf:"bytes,3,req,name=member_roles" json:"member_roles,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (this *RelationMember) Reset() { *this = RelationMember{} } +func (this *RelationMember) String() string { return proto.CompactTextString(this) } +func (*RelationMember) ProtoMessage() {} + +func (this *RelationMember) GetMemberIds() int64 { + if this != nil && this.MemberIds != nil { + return *this.MemberIds + } + return 0 +} + +func (this *RelationMember) GetMemberTypes() RelationMember_MemberType { + if this != nil && this.MemberTypes != nil { + return *this.MemberTypes + } + return 0 +} + +func (this *RelationMember) GetMemberRoles() string { + if this != nil && this.MemberRoles != nil { + return *this.MemberRoles + } + return "" +} + +func init() { + proto.RegisterEnum("model.RelationMember_MemberType", RelationMember_MemberType_name, RelationMember_MemberType_value) +} diff --git a/model/model.proto b/model/model.proto new file mode 100644 index 0000000..4c5ffa4 --- /dev/null +++ b/model/model.proto @@ -0,0 +1,31 @@ +package model; + +message Tag { + required string key = 1; + required string val = 2; +} + +message Way { + required int64 id = 1; + + repeated Tag tags = 2; + repeated int64 nodes = 3 [packed = true]; +} + +message Relation { + required int64 id = 1; + + repeated Tag tags = 2; + repeated RelationMember members = 3; +} + +message RelationMember { + required int64 member_ids = 1; + enum MemberType { + NODE = 0; + WAY = 1; + RELATION = 2; + } + required MemberType member_types = 2; + required string member_roles = 3; +} \ No newline at end of file diff --git a/model/nodes.go b/model/nodes.go new file mode 100644 index 0000000..0700ebd --- /dev/null +++ b/model/nodes.go @@ -0,0 +1,40 @@ +package model + +import "code.google.com/p/goprotobuf/proto" +import "log" + +type Node struct { + Id int64 + Tags map[string]string + Lon uint32 + Lat uint32 +} + +const COORD_FACTOR float64 = 11930464.7083 // ((2<<31)-1)/360.0 + +func coordToInt(coord float64) uint32 { + return uint32((coord + 180.0) * COORD_FACTOR) +} + +func intToCoord(coord uint32) float64 { + return float64((float64(coord) / COORD_FACTOR) - 180.0) +} + +func (this *Node) WgsCoord() (lon float64, lat float64) { + lon = intToCoord(this.Lon) + lat = intToCoord(this.Lat) + return +} + +func (this *Node) FromWgsCoord(lon float64, lat float64) { + this.Lon = coordToInt(lon) + this.Lat = coordToInt(lat) +} + +func (this *Way) Marshal() []byte { + data, err := proto.Marshal(this) + if err != nil { + log.Fatal("marshaling error: ", err) + } + return data +} diff --git a/parser.go b/parser.go index 3ee57bf..3db53bb 100644 --- a/parser.go +++ b/parser.go @@ -7,6 +7,7 @@ import ( // "goposm/osmpbf/fileformat" "bytes" "compress/zlib" + "goposm/model" "io" "log" "os" @@ -20,13 +21,11 @@ type PBF struct { } func Open(filename string) (f *PBF, err error) { - f = new(PBF) - f.filename = filename file, err := os.Open(filename) - f.file = file if err != nil { return nil, err } + f = &PBF{filename: filename, file: file} return f, nil } @@ -101,6 +100,53 @@ func ReadPrimitiveBlock(file *os.File, offset int64, size int32) *osmpbf.Primiti return block } +// type Node struct { +// Id int64 +// Tags map[string]string +// Lon uint32 +// Lat uint32 +// } + +func DenseNodeTags(stringtable []string, keyvals []int32) (tags map[string]string, nextPos int) { + tags = make(map[string]string) + nextPos = 0 + for { + keyId := keyvals[nextPos] + nextPos += 1 + if keyId == 0 { + return + } + key := stringtable[keyId] + valId := keyvals[nextPos] + nextPos += 1 + val := stringtable[valId] + + tags[key] = val + } + return +} + +func ReadDenseNodes(dense *osmpbf.DenseNodes, block *osmpbf.PrimitiveBlock) (nodes []model.Node) { + var lastId int64 + var lastLon, lastLat int64 + nodes = make([]model.Node, len(dense.Id)) + granularity := int64(block.GetGranularity()) + latOffset := block.GetLatOffset() + lonOffset := block.GetLonOffset() + coordScale := 0.000000001 + + for i := range nodes { + lastId += dense.Id[i] + lastLon += dense.Lon[i] + lastLat += dense.Lat[i] + nodes[i].Id = lastId + nodes[i].FromWgsCoord( + (coordScale * float64(lonOffset+(granularity*lastLon))), + (coordScale * float64(latOffset+(granularity*lastLat)))) + } + return nodes +} + func blockPositions(filename string) { pbf, err := Open(filename) @@ -121,6 +167,9 @@ func blockPositions(filename string) { for _, group := range block.Primitivegroup { dense := group.GetDense() if dense != nil { + nodes := ReadDenseNodes(dense, block) + lon, lat := nodes[1].WgsCoord() + fmt.Printf("%12d %10.8f %10.8f\n", nodes[0].Id, lon, lat) nodesCounter += len(dense.Id) } nodesCounter += len(group.Nodes)