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  }