forked from paulmach/osm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node.go
163 lines (131 loc) · 4.2 KB
/
node.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
package osm
import (
"sort"
"time"
"github.com/gogo/protobuf/proto"
"github.com/paulmach/orb"
"github.com/paulmach/osm/internal/osmpb"
)
// NodeID corresponds the primary key of a node.
// The node id + version uniquely identify a node.
type NodeID int64
// ObjectID is a helper returning the object id for this node id.
func (id NodeID) ObjectID(v int) ObjectID {
return ObjectID(id.ElementID(v))
}
// FeatureID is a helper returning the feature id for this node id.
func (id NodeID) FeatureID() FeatureID {
return FeatureID(nodeMask | (id << versionBits))
}
// ElementID is a helper to convert the id to an element id.
func (id NodeID) ElementID(v int) ElementID {
return id.FeatureID().ElementID(v)
}
// Node is an osm point and allows for marshalling to/from osm xml.
type Node struct {
XMLName xmlNameJSONTypeNode `xml:"node" json:"type"`
ID NodeID `xml:"id,attr" json:"id"`
Lat float64 `xml:"lat,attr" json:"lat"`
Lon float64 `xml:"lon,attr" json:"lon"`
User string `xml:"user,attr" json:"user,omitempty"`
UserID UserID `xml:"uid,attr" json:"uid,omitempty"`
Visible bool `xml:"visible,attr" json:"visible"`
Version int `xml:"version,attr" json:"version,omitempty"`
ChangesetID ChangesetID `xml:"changeset,attr" json:"changeset,omitempty"`
Timestamp time.Time `xml:"timestamp,attr" json:"timestamp"`
Tags Tags `xml:"tag" json:"tags,omitempty"`
// Committed, is the estimated time this object was committed
// and made visible in the central OSM database.
Committed *time.Time `xml:"committed,attr,omitempty" json:"committed,omitempty"`
}
// ObjectID returns the object id of the node.
func (n *Node) ObjectID() ObjectID {
return n.ID.ObjectID(n.Version)
}
// FeatureID returns the feature id of the node.
func (n *Node) FeatureID() FeatureID {
return n.ID.FeatureID()
}
// ElementID returns the element id of the node.
func (n *Node) ElementID() ElementID {
return n.ID.ElementID(n.Version)
}
// CommittedAt returns the best estimate on when this element
// became was written/committed into the database.
func (n *Node) CommittedAt() time.Time {
if n.Committed != nil {
return *n.Committed
}
return n.Timestamp
}
// TagMap returns the element tags as a key/value map.
func (n *Node) TagMap() map[string]string {
return n.Tags.Map()
}
// Point returns the orb.Point location for the node.
// Will be (0, 0) for "deleted" nodes.
func (n *Node) Point() orb.Point {
return orb.Point{n.Lon, n.Lat}
}
// Nodes is a list of nodes with helper functions on top.
type Nodes []*Node
// IDs returns the ids for all the ways.
func (ns Nodes) IDs() []NodeID {
result := make([]NodeID, len(ns))
for i, n := range ns {
result[i] = n.ID
}
return result
}
// FeatureIDs returns the feature ids for all the nodes.
func (ns Nodes) FeatureIDs() FeatureIDs {
r := make(FeatureIDs, len(ns))
for i, n := range ns {
r[i] = n.FeatureID()
}
return r
}
// ElementIDs returns the element ids for all the nodes.
func (ns Nodes) ElementIDs() ElementIDs {
r := make(ElementIDs, len(ns))
for i, n := range ns {
r[i] = n.ElementID()
}
return r
}
// Marshal encodes the nodes using protocol buffers.
func (ns Nodes) Marshal() ([]byte, error) {
if len(ns) == 0 {
return nil, nil
}
ss := &stringSet{}
encoded := marshalNodes(ns, ss, true)
encoded.Strings = ss.Strings()
return proto.Marshal(encoded)
}
// UnmarshalNodes will unmarshal the data into a list of nodes.
func UnmarshalNodes(data []byte) (Nodes, error) {
if len(data) == 0 {
return nil, nil
}
pbf := &osmpb.DenseNodes{}
err := proto.Unmarshal(data, pbf)
if err != nil {
return nil, err
}
return unmarshalNodes(pbf, pbf.GetStrings(), nil)
}
type nodesSort Nodes
// SortByIDVersion will sort the set of nodes first by id and then version
// in ascending order.
func (ns Nodes) SortByIDVersion() {
sort.Sort(nodesSort(ns))
}
func (ns nodesSort) Len() int { return len(ns) }
func (ns nodesSort) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
func (ns nodesSort) Less(i, j int) bool {
if ns[i].ID == ns[j].ID {
return ns[i].Version < ns[j].Version
}
return ns[i].ID < ns[j].ID
}