github.com/omniscale/go-osm@v0.3.1/parser/pbf/pbf.go (about) 1 package pbf 2 3 import ( 4 "time" 5 6 "github.com/omniscale/go-osm" 7 "github.com/omniscale/go-osm/parser/pbf/internal/osmpbf" 8 ) 9 10 func readDenseNodes( 11 dense *osmpbf.DenseNodes, 12 block *osmpbf.PrimitiveBlock, 13 stringtable stringTable, 14 allNodes bool, 15 includeMD bool) (coords []osm.Node, nodes []osm.Node) { 16 17 var lastID int64 18 var lastLon, lastLat int64 19 20 var lastTimestamp int64 21 var lastChangeset int64 22 var lastUID int32 23 var lastUserSID int32 24 25 coords = make([]osm.Node, len(dense.Id)) 26 if allNodes { 27 nodes = make([]osm.Node, 0, len(dense.Id)) 28 } else { 29 // most nodes have no tags 30 nodes = make([]osm.Node, 0, len(dense.Id)/8) 31 } 32 granularity := int64(block.GetGranularity()) 33 latOffset := block.GetLatOffset() 34 lonOffset := block.GetLonOffset() 35 coordScale := 0.000000001 36 lastKeyValPos := 0 37 38 var metadata *osm.Metadata 39 40 for i := range coords { 41 lastID += dense.Id[i] 42 lastLon += dense.Lon[i] 43 lastLat += dense.Lat[i] 44 coords[i].ID = lastID 45 coords[i].Long = (coordScale * float64(lonOffset+(granularity*lastLon))) 46 coords[i].Lat = (coordScale * float64(latOffset+(granularity*lastLat))) 47 48 if includeMD { 49 lastTimestamp += dense.Denseinfo.Timestamp[i] 50 lastChangeset += dense.Denseinfo.Changeset[i] 51 lastUID += dense.Denseinfo.Uid[i] 52 lastUserSID += dense.Denseinfo.UserSid[i] 53 54 metadata = &osm.Metadata{ 55 Version: dense.Denseinfo.Version[i], 56 Timestamp: time.Unix(lastTimestamp, 0), 57 Changeset: lastChangeset, 58 UserID: lastUID, 59 UserName: stringtable[lastUserSID], 60 } 61 } 62 var tags map[string]string 63 addToNodes := allNodes 64 if stringtable != nil && len(dense.KeysVals) > 0 { 65 if dense.KeysVals[lastKeyValPos] != 0 { 66 tags = parseDenseNodeTags(stringtable, &dense.KeysVals, &lastKeyValPos) 67 if tags != nil { 68 if _, ok := tags["created_by"]; len(tags) > 1 || !ok { 69 // don't add nodes with only created_by tag to nodes 70 addToNodes = true 71 } 72 } 73 } else { 74 lastKeyValPos += 1 75 } 76 } 77 if addToNodes { 78 nd := coords[i] 79 nd.Tags = tags 80 nd.Metadata = metadata 81 nodes = append(nodes, nd) 82 } 83 } 84 85 return coords, nodes 86 } 87 88 func parseDenseNodeTags(stringtable stringTable, keysVals *[]int32, pos *int) map[string]string { 89 // make map later if needed 90 var result map[string]string 91 for { 92 if *pos >= len(*keysVals) { 93 return result 94 } 95 key := (*keysVals)[*pos] 96 *pos += 1 97 if key == 0 { 98 return result 99 } 100 val := (*keysVals)[*pos] 101 *pos += 1 102 if result == nil { 103 result = make(map[string]string) 104 } 105 result[stringtable[key]] = stringtable[val] 106 } 107 } 108 109 func parseTags(stringtable stringTable, keys []uint32, vals []uint32) map[string]string { 110 if len(keys) == 0 { 111 return nil 112 } 113 tags := make(map[string]string, len(keys)) 114 for i := 0; i < len(keys); i++ { 115 key := stringtable[keys[i]] 116 val := stringtable[vals[i]] 117 tags[key] = val 118 } 119 return tags 120 } 121 122 func readNodes( 123 nodes []osmpbf.Node, 124 block *osmpbf.PrimitiveBlock, 125 stringtable stringTable, 126 allNodes bool, 127 includeMD bool, 128 ) ([]osm.Node, []osm.Node) { 129 130 coords := make([]osm.Node, len(nodes)) 131 nds := make([]osm.Node, 0, len(nodes)/8) 132 granularity := int64(block.GetGranularity()) 133 latOffset := block.GetLatOffset() 134 lonOffset := block.GetLonOffset() 135 coordScale := 0.000000001 136 137 var metadata *osm.Metadata 138 139 for i := range nodes { 140 id := nodes[i].Id 141 lon := nodes[i].Lon 142 lat := nodes[i].Lat 143 coords[i].ID = id 144 coords[i].Long = (coordScale * float64(lonOffset+(granularity*lon))) 145 coords[i].Lat = (coordScale * float64(latOffset+(granularity*lat))) 146 var tags map[string]string 147 addToNodes := allNodes 148 if includeMD { 149 version := int32(0) 150 if nodes[i].Info.Version != nil { 151 version = *nodes[i].Info.Version 152 } 153 metadata = &osm.Metadata{ 154 Version: version, 155 Timestamp: time.Unix(nodes[i].Info.Timestamp, 0), 156 Changeset: nodes[i].Info.Changeset, 157 UserID: nodes[i].Info.Uid, 158 UserName: stringtable[nodes[i].Info.UserSid], 159 } 160 } 161 if stringtable != nil { 162 tags = parseTags(stringtable, nodes[i].Keys, nodes[i].Vals) 163 if tags != nil { 164 if _, ok := tags["created_by"]; len(tags) > 1 || !ok { 165 // don't add nodes with only created_by tag to nodes 166 addToNodes = true 167 } 168 } 169 } 170 if addToNodes { 171 nd := coords[i] 172 nd.Tags = tags 173 nd.Metadata = metadata 174 nds = append(nds, nd) 175 } 176 } 177 return coords, nds 178 } 179 180 func parseDeltaRefs(refs []int64) []int64 { 181 result := make([]int64, len(refs)) 182 var lastRef int64 183 184 for i, refDelta := range refs { 185 lastRef += refDelta 186 result[i] = lastRef 187 } 188 return result 189 } 190 191 func readWays( 192 ways []osmpbf.Way, 193 block *osmpbf.PrimitiveBlock, 194 stringtable stringTable, 195 includeMD bool, 196 ) []osm.Way { 197 198 result := make([]osm.Way, len(ways)) 199 200 for i := range ways { 201 id := ways[i].Id 202 result[i].ID = id 203 result[i].Tags = parseTags(stringtable, ways[i].Keys, ways[i].Vals) 204 result[i].Refs = parseDeltaRefs(ways[i].Refs) 205 if includeMD { 206 version := int32(0) 207 if ways[i].Info.Version != nil { 208 version = *ways[i].Info.Version 209 } 210 metadata := &osm.Metadata{ 211 Version: version, 212 Timestamp: time.Unix(ways[i].Info.Timestamp, 0), 213 Changeset: ways[i].Info.Changeset, 214 UserID: ways[i].Info.Uid, 215 UserName: stringtable[ways[i].Info.UserSid], 216 } 217 result[i].Metadata = metadata 218 } 219 } 220 return result 221 } 222 223 func parseRelationMembers(rel osmpbf.Relation, stringtable stringTable) []osm.Member { 224 result := make([]osm.Member, len(rel.Memids)) 225 226 var lastID int64 227 for i := range rel.Memids { 228 lastID += rel.Memids[i] 229 result[i].ID = lastID 230 result[i].Role = stringtable[rel.RolesSid[i]] 231 result[i].Type = osm.MemberType(rel.Types[i]) 232 } 233 return result 234 } 235 236 func readRelations( 237 relations []osmpbf.Relation, 238 block *osmpbf.PrimitiveBlock, 239 stringtable stringTable, 240 includeMD bool, 241 ) []osm.Relation { 242 243 result := make([]osm.Relation, len(relations)) 244 245 for i := range relations { 246 id := relations[i].Id 247 result[i].ID = id 248 result[i].Tags = parseTags(stringtable, relations[i].Keys, relations[i].Vals) 249 result[i].Members = parseRelationMembers(relations[i], stringtable) 250 if includeMD { 251 version := int32(0) 252 if relations[i].Info.Version != nil { 253 version = *relations[i].Info.Version 254 } 255 metadata := &osm.Metadata{ 256 Version: version, 257 Timestamp: time.Unix(relations[i].Info.Timestamp, 0), 258 Changeset: relations[i].Info.Changeset, 259 UserID: relations[i].Info.Uid, 260 UserName: stringtable[relations[i].Info.UserSid], 261 } 262 result[i].Metadata = metadata 263 } 264 } 265 return result 266 } 267 268 type stringTable []string 269 270 func newStringTable(source *osmpbf.StringTable) stringTable { 271 result := make(stringTable, len(source.S)) 272 for i, bytes := range source.S { 273 result[i] = string(bytes) 274 } 275 return result 276 }