-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode.go
More file actions
86 lines (76 loc) · 2.4 KB
/
Copy pathnode.go
File metadata and controls
86 lines (76 loc) · 2.4 KB
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
package osmbr
import "fmt"
// NodeBuf is caller-managed memory for decoding individual Node entities.
// Non-dense nodes are rare in practice; most OSM data uses DenseNodes.
// Reuse across calls to avoid per-node allocations.
type NodeBuf struct {
Keys []uint32 // string table indices for tag keys
Vals []uint32 // string table indices for tag values
}
// NodeScanner iterates over individual Node messages in a PrimitiveGroup.
// Obtain one via GroupScanner.NodeScanner. NodeScanner is a value type.
// Note: in practice, OSM planet files and extracts use DenseNodes exclusively.
type NodeScanner struct {
m msg
err error
}
// Next decodes the next Node into buf and returns its ID, lat, and lon.
// Resets buf slices to [:0] then appends (capacity preserved).
// Returns (0, 0, 0, false) when no more nodes remain.
// lat and lon are raw sint64 values. Convert to nanodegrees:
//
// lat_nanodeg = lat * int64(pb.Granularity) + pb.LatOffset
//
// Pass a non-nil info to also decode the Node's Info; nil skips it.
func (ns *NodeScanner) Next(buf *NodeBuf, info *InfoBuf) (id, lat, lon int64, ok bool) {
for ns.m.next() {
if ns.m.field != 1 { // repeated Node
ns.m.skip()
continue
}
nodeData := ns.m.bytes()
if ns.m.err != nil {
ns.err = fmt.Errorf("osmbr: Node message: %w", ns.m.err)
return 0, 0, 0, false
}
buf.Keys = buf.Keys[:0]
buf.Vals = buf.Vals[:0]
id, lat, lon = 0, 0, 0
// See WayScanner.Next: info is optional per entity and must not carry
// over from the previous Node.
if info != nil {
*info = InfoBuf{}
}
var nodeMsg msg
nodeMsg.reset(nodeData)
for nodeMsg.next() {
switch nodeMsg.field {
case 1: // id (sint64)
id = nodeMsg.sint64()
case 2: // keys (packed uint32)
buf.Keys = nodeMsg.repeatedUint32(buf.Keys)
case 3: // vals (packed uint32)
buf.Vals = nodeMsg.repeatedUint32(buf.Vals)
case 4: // info
decodeOptionalInfo(&nodeMsg, info)
case 8: // lat (sint64)
lat = nodeMsg.sint64()
case 9: // lon (sint64)
lon = nodeMsg.sint64()
default:
nodeMsg.skip()
}
}
if nodeMsg.err != nil {
ns.err = fmt.Errorf("osmbr: Node: %w", nodeMsg.err)
return 0, 0, 0, false
}
return id, lat, lon, true
}
if ns.m.err != nil {
ns.err = fmt.Errorf("osmbr: PrimitiveGroup: %w", ns.m.err)
}
return 0, 0, 0, false
}
// Err returns the first error encountered during iteration.
func (ns *NodeScanner) Err() error { return ns.err }