forked from qedus/osmpbf
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathosm_types.go
310 lines (255 loc) · 6.24 KB
/
osm_types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package gosmonaut
import (
"bytes"
"encoding/json"
"fmt"
"math"
)
// OSMType represents the type of an OSM entity.
type OSMType uint8
// OSM Types: node, way, relation.
const (
NodeType OSMType = 1 << iota
WayType
RelationType
)
// OSMEntity is the common interface of all OSM entities.
type OSMEntity interface {
GetID() int64
GetType() OSMType
GetTags() OSMTags
fmt.Stringer
}
/* Node */
// Node represents an OSM node element. Lat and Lon have a precision of up to 7
// decimals (OSM default).
type Node struct {
ID int64
Lat, Lon float64
Tags OSMTags
}
type rawNode struct {
id int64
lat, lon coordinate
}
// GetID returns the ID.
func (n Node) GetID() int64 {
return n.ID
}
// GetType always returns NodeType.
func (n Node) GetType() OSMType {
return NodeType
}
// GetTags returns the tags.
func (n Node) GetTags() OSMTags {
return n.Tags
}
func (n Node) String() string {
return prettyPrintEntity(n)
}
// MarshalJSON prints the JSON representation of the node.
func (n Node) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string `json:"type"`
ID int64 `json:"id"`
Lat coordinate `json:"lat"`
Lon coordinate `json:"lon"`
Tags OSMTags `json:"tags,omitempty"`
}{"node", n.ID, newCoordinate(n.Lat), newCoordinate(n.Lon), n.Tags})
}
/* Way */
// Way represents an OSM way element.
type Way struct {
ID int64
Tags OSMTags
Nodes []Node
}
type rawWay struct {
id int64
refs []int64
}
// GetID returns the ID.
func (w Way) GetID() int64 {
return w.ID
}
// GetType always returns WayType.
func (w Way) GetType() OSMType {
return WayType
}
// GetTags returns the tags.
func (w Way) GetTags() OSMTags {
return w.Tags
}
func (w Way) String() string {
return prettyPrintEntity(w)
}
// MarshalJSON prints the JSON representation of the way.
func (w Way) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string `json:"type"`
ID int64 `json:"id"`
Tags OSMTags `json:"tags"`
Nodes []Node `json:"nodes"`
}{"way", w.ID, w.Tags, w.Nodes})
}
/* Relation */
// Relation represents an OSM relation element.
type Relation struct {
ID int64
Tags OSMTags
Members []Member
}
// GetID returns the ID.
func (r Relation) GetID() int64 {
return r.ID
}
// GetType always returns RelationType.
func (r Relation) GetType() OSMType {
return RelationType
}
// GetTags returns the tags.
func (r Relation) GetTags() OSMTags {
return r.Tags
}
func (r Relation) String() string {
return prettyPrintEntity(r)
}
// MarshalJSON prints the JSON representation of the relation.
func (r Relation) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string `json:"type"`
ID int64 `json:"id"`
Tags OSMTags `json:"tags"`
Members []Member `json:"members"`
}{"relation", r.ID, r.Tags, r.Members})
}
// Member represents a member of a relation.
type Member struct {
Role string `json:"role"`
Entity OSMEntity `json:"entity"`
}
/* OSMTypeSet */
// OSMTypeSet is used to enable/disable OSM types.
type OSMTypeSet uint8
// NewOSMTypeSet returns a new OSMTypeSet with the given types enabled/disabled.
func NewOSMTypeSet(nodes, ways, relations bool) OSMTypeSet {
var s OSMTypeSet
s.Set(NodeType, nodes)
s.Set(WayType, ways)
s.Set(RelationType, relations)
return s
}
// Set enables/disables the given type.
func (s *OSMTypeSet) Set(t OSMType, enabled bool) {
if enabled {
*s = OSMTypeSet(uint8(*s) | uint8(t))
} else {
*s = OSMTypeSet(uint8(*s) & (^uint8(t)))
}
}
// Get returns true if the given type is enabled.
func (s *OSMTypeSet) Get(t OSMType) bool {
return uint8(*s)&uint8(t) != 0
}
/* OSM Tags */
// OSMTags represents a key-value mapping for OSM tags.
type OSMTags []string // Alternating array of keys/values
// NewOSMTags creates new OSMTags and can be used if the number of tags is
// known.
func NewOSMTags(n int) OSMTags {
if n < 0 {
n = 0
}
return make([]string, 0, n*2)
}
// NewOSMTagsFromMap creates new OSMTags that contains the tags from the given
// map.
func NewOSMTagsFromMap(m map[string]string) OSMTags {
t := NewOSMTags(len(m))
for k, v := range m {
t = append(t, k, v)
}
return t
}
// Set adds or updates the value for the given key.
func (t *OSMTags) Set(key, val string) {
if i, ok := t.index(key); ok {
t.set(i+1, val)
} else {
*t = append(*t, key, val)
}
}
// Get returns the value for the given key or false if the key does not exist.
func (t *OSMTags) Get(key string) (string, bool) {
if i, ok := t.index(key); ok {
return t.get(i + 1), true
}
return "", false
}
// Has returns true if the given key exists.
func (t *OSMTags) Has(key string) bool {
_, ok := t.index(key)
return ok
}
// HasValue return true if the given key exists and its value is val.
func (t *OSMTags) HasValue(key, val string) bool {
if i, ok := t.index(key); ok {
return t.get(i+1) == val
}
return false
}
// Map returns the map representation of the tags.
func (t *OSMTags) Map() map[string]string {
m := make(map[string]string, t.Len())
for i := 0; i < len(*t); i += 2 {
m[t.get(i)] = t.get(i + 1)
}
return m
}
func (t OSMTags) String() string {
return prettyPrintEntity(t)
}
// MarshalJSON prints the JSON representation of the tags.
func (t OSMTags) MarshalJSON() ([]byte, error) {
return json.Marshal(t.Map())
}
// Len returns the number of tags.
func (t *OSMTags) Len() int {
return len(*t) / 2
}
func (t *OSMTags) get(i int) string {
return []string(*t)[i]
}
func (t *OSMTags) set(i int, s string) {
[]string(*t)[i] = s
}
func (t *OSMTags) index(key string) (int, bool) {
for i := 0; i < len(*t); i += 2 {
if t.get(i) == key {
return i, true
}
}
return -1, false
}
/* Helpers */
// Print an OSM entity as JSON with indention
func prettyPrintEntity(m json.Marshaler) string {
b := new(bytes.Buffer)
enc := json.NewEncoder(b)
enc.SetIndent("", " ")
enc.Encode(m)
return b.String()
}
/* Coordinate */
const coordPrecision = 10000000 // 7 decimals (OSM default)
// We use an int32 for coordinates to safe memory
type coordinate int32
func newCoordinate(c float64) coordinate {
return coordinate(math.Round(c * coordPrecision))
}
func (c coordinate) float() float64 {
return float64(c) / coordPrecision
}
func (c coordinate) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%.7f", c.float())), nil
}