forked from holizz/go-tile-server
/
pbf.go
133 lines (114 loc) · 2.2 KB
/
pbf.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
package tiles
import (
"fmt"
"io"
"os"
"github.com/qedus/osmpbf"
)
type ItemType int
const (
ItemTypeNode = iota
ItemTypeWay
ItemTypeRelation
)
type OsmData struct {
Nodes map[int64]Node
Ways map[int64]Way
Features map[string][]FeatureRef
}
type FeatureRef struct {
Id int64
Type ItemType
}
type Node struct {
Lon_, Lat_ float64
Id int64
}
func (p Node) Lon() float64 { return p.Lon_ }
func (p Node) Lat() float64 { return p.Lat_ }
func NodeFromPbf(n *osmpbf.Node) Node {
return Node{
Lon_: n.Lon,
Lat_: n.Lat,
Id: n.ID,
}
}
type Way struct {
NodeIDs []int64
Id int64
Tags map[string]string
}
func WayFromPbf(w *osmpbf.Way) Way {
return Way{
NodeIDs: w.NodeIDs,
Id: w.ID,
Tags: w.Tags,
}
}
func (w Way) Match(feature Feature) bool {
for key, val := range w.Tags {
for _, tag := range feature.Tags {
if key == tag.Key && (val == tag.Val || tag.Val == "*") {
return true
}
}
}
return false
}
func (w Way) MatchAny(features map[string]Feature) (string, bool) {
for name, feature := range features {
if w.Match(feature) {
return name, true
}
}
return "", false
}
func (w Way) GetNodes(nodes map[int64]Node) []Node {
newNodes := []Node{}
for _, id := range w.NodeIDs {
newNodes = append(newNodes, nodes[id])
}
return newNodes
}
func ParsePbf(path string) (*OsmData, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
d := osmpbf.NewDecoder(f)
err = d.Start(10)
if err != nil {
return nil, err
}
data := &OsmData{
Nodes: map[int64]Node{},
Ways: map[int64]Way{},
Features: map[string][]FeatureRef{},
}
for {
if v, err := d.Decode(); err == io.EOF {
break
} else if err != nil {
return nil, err
} else {
switch v := v.(type) {
case *osmpbf.Node:
node := NodeFromPbf(v)
data.Nodes[node.Id] = node
case *osmpbf.Way:
way := WayFromPbf(v)
fName, ok := way.MatchAny(mapFeatures)
if ok {
data.Ways[way.Id] = way
data.Features[fName] = append(data.Features[fName], FeatureRef{way.Id, ItemTypeWay})
}
case *osmpbf.Relation:
// Ignore
default:
return nil, fmt.Errorf("unknown type %T", v)
}
}
}
return data, nil
}