Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# 5.1.0

- [encode] minor: preserve `alt_name:{lang}` as different from `name:{lang}`
- [decode] minor: export baseFields, enabling consumers to understand what is part of the base of georender and what is a tag beyond that.


# 5.0.0

- [fork] scoped from [[email protected]](https://www.npmjs.com/package/georender-pack)
- [encode] major: changes the encoding and decoding schema to include additional values based on tags. if no additional tags are included, then only an additional 0 is written to the end of the buffer
- [schema] minor: adds the georender schema here, local to the repo to track changes.
60 changes: 58 additions & 2 deletions decode.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
var getNormals = require('polyline-normals')
var varint = require('varint')
var getLoops = require('./lib/get-loops.js')
var tagValueTypes = require('./lib/tag-value-types.js')

module.exports = function (buffers) {
var baseFields = {
point: ['types', 'ids', 'positions', 'labels'],
line: ['types', 'ids', 'positions', 'normals', 'labels'],
area: ['types', 'ids', 'positions', 'cells', 'labels'],
areaBorder: ['types', 'ids', 'positions', 'normals'],
}

module.exports = decode
module.exports.baseFields = baseFields

function decode (buffers) {
var sizes = {
point: { types: 0, ids: 0, positions: 0 },
line: { types: 0, ids: 0, positions: 0, normals: 0 },
Expand Down Expand Up @@ -149,6 +160,7 @@ module.exports = function (buffers) {
data.point.positions[offsets.point.positions++] = buf.readFloatLE(offset)
offset+=4
offset = decodeLabels(buf, offset, data.point, id)
offset = decodeTags(buf, offset, data.point, id)
}
else if (featureType === 2) {
var type = varint.decode(buf, offset)
Expand Down Expand Up @@ -200,6 +212,7 @@ module.exports = function (buffers) {
data.line.normals[offsets.line.normals++] = data.line.normals[normOffset-2]
data.line.normals[offsets.line.normals++] = data.line.normals[normOffset-1]
offset = decodeLabels(buf, offset, data.line, id)
offset = decodeTags(buf, offset, data.line, id)
}
else if (featureType === 3) {
var type = varint.decode(buf, offset)
Expand Down Expand Up @@ -244,6 +257,7 @@ module.exports = function (buffers) {
}
pindex+=plen
offset = decodeLabels(buf, offset, data.area, id)
offset = decodeTags(buf, offset, data.area, id)
}
else if (featureType === 4) {
var type = varint.decode(buf, offset)
Expand Down Expand Up @@ -302,21 +316,27 @@ module.exports = function (buffers) {
addAreaBorderPositions(data, offsets, positions, id, type, false)
pindex+=plen
offset = decodeLabels(buf, offset, data.area, id)
offset = decodeTags(buf, offset, data.area, id)
}
}
if (offsets.areaBorder.types !== data.areaBorder.types.length) {
data.areaBorder.types = data.areaBorder.types.subarray(0, offsets.areaBorder.types)
data.areaBorder.positions = data.areaBorder.positions.subarray(0, offsets.areaBorder.positions)
data.areaBorder.normals = data.areaBorder.normals.subarray(0, offsets.areaBorder.normals)
}
// spread tags from data.area to data.areaBorders
for (const field in data.areaBorder) {
if (baseFields.areaBorder.includes(field)) continue
data.areaBorder[field] = data.area[field].subarray(0, data.area[field].length)
}
return data
}

function decodeLabels (buf, offset, data, id) {
do {
var labelLength = varint.decode(buf, offset)
if (labelLength === 0) continue
offset+=varint.decode.bytes
if (labelLength === 0) { continue }
var labelData = buf.slice(offset, offset+labelLength)
offset+=labelLength
if (!data.labels[id]) data.labels[id] = []
Expand All @@ -325,6 +345,42 @@ function decodeLabels (buf, offset, data, id) {
return offset
}

function decodeTags (buf, offset, data, id) {
do {
try {
var tagKeyLength = varint.decode(buf, offset)
}
catch (error) {
return offset
}

offset+=varint.decode.bytes
if (tagKeyLength === 0) { continue }
var tagKey = buf.slice(offset, offset + tagKeyLength).toString()
offset += tagKeyLength
var tagValueType = buf.readUInt8(offset)
offset += 1

var tagValue
if (tagValueType === tagValueTypes.INT) {
tagValue = parseInt(varint.decode(buf, offset).toString())
offset += varint.decode.bytes
}
else if (tagValueType === tagValueTypes.FLOAT) {
tagValue = buf.readFloatLE(offset)
offset += 4
}
else if (tagValueType === tagValueTypes.STRING) {
var tagValueLength = varint.decode(buf, offset)
offset += varint.decode.bytes
tagValue = buf.slice(offset, offset + tagValueLength).toString()
offset += tagValueLength
}
if (!Array.isArray(data[tagKey])) data[tagKey] = new Array(data.types.length).fill(tagValue)
} while (tagKeyLength > 0)
return offset
}

function addAreaBorderPositions(data, offsets, positions, id, type, closed) {
if (positions.length < 2) return
var positionsCount = 2+6+(4*positions.length)
Expand Down
144 changes: 131 additions & 13 deletions encode.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,30 @@ var osmIsArea = require('osm-is-area')
var varint = require('varint')
var sortMembers = require('./lib/sort.js')
var tagPriorities = require('./lib/tagpriorities.json')
var tagValueTypes = require('./lib/tag-value-types.js')

var features = {}
for (var i=0; i<featuresJSON.length; i++) {
features[featuresJSON[i]] = i
}

module.exports = function (item, deps) {
module.exports = function (item, deps, opts) {
var type = features['place.other']
var tags = Object.entries(item.tags)
// TODO this does not quite work yet, lets figure it out before considering it
// var featureTypes = opts && opts.featureTypes
var includeTags = opts && (opts.includeAllTags === true || opts.includeTags === '*')
? '*'
: opts && opts.includeTags && Array.isArray(opts.includeTags)
? opts.includeTags
: []

// if (Array.isArray(featureTypes)) {
// features = {}
// for (var i=0; i<featureTypes.length; i++) {
// features[featureTypes[i]] = i
// }
// }
if(tags.length !== 0){
var arr = []
var priorities = []
Expand All @@ -39,11 +54,20 @@ module.exports = function (item, deps) {
}
var id = item.id

var includedTags = includeTags === '*'
? item.tags
: tags.filter(t => includeTags.includes(t[0]))
.reduce((acc, curr) => {
acc[curr[0]] = curr[1]
return acc
}, {})

if (item.type === 'node') {
var typeLen = varint.encodingLength(type)
var idLen = varint.encodingLength(id)
var labelLen = getLabelLen(item.tags)
var buf = Buffer.alloc(9 + typeLen + idLen + labelLen)
var tagLen = getTagLen(includedTags)
var buf = Buffer.alloc(9 + typeLen + idLen + labelLen + tagLen)
var offset = 0
buf.writeUInt8(0x01, offset)
offset+=1
Expand All @@ -55,7 +79,8 @@ module.exports = function (item, deps) {
offset+=4
buf.writeFloatLE(item.lat, offset)
offset+=4
writeLabelData(item.tags, buf, offset)
offset = writeLabelData(item.tags, buf, offset)
offset = writeTagData(includedTags, buf, offset)
}
if (item.type === 'way') {
for (var i=0; i<item.refs.length; i++) {
Expand All @@ -82,7 +107,8 @@ module.exports = function (item, deps) {
cSize+=varint.encodingLength(cells[i])
}
var labelLen = getLabelLen(item.tags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCountLen + pCount*4*2 + cLen + cSize + labelLen)
var tagLen = getTagLen(includedTags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCountLen + pCount*4*2 + cLen + cSize + labelLen + tagLen)
var offset = 0
buf.writeUInt8(0x03, 0)
offset+=1
Expand All @@ -102,7 +128,8 @@ module.exports = function (item, deps) {
varint.encode(cells[i], buf, offset)
offset+=varint.encode.bytes
}
writeLabelData(item.tags, buf, offset)
offset = writeLabelData(item.tags, buf, offset)
offset = writeTagData(includedTags, buf, offset)
}
else if (item.refs.length > 1) {
var typeLen = varint.encodingLength(type)
Expand All @@ -116,7 +143,8 @@ module.exports = function (item, deps) {
var pCount = coords.length/2
var pCountLen = varint.encodingLength(pCount)
var labelLen = getLabelLen(item.tags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCount*4*2 + pCountLen + labelLen)
var tagLen = getTagLen(includedTags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCount*4*2 + pCountLen + labelLen + tagLen)
var offset = 0
buf.writeUInt8(0x02, 0)
offset+=1
Expand All @@ -130,7 +158,8 @@ module.exports = function (item, deps) {
buf.writeFloatLE(coords[i], offset)
offset+=4
}
writeLabelData(item.tags, buf, offset)
offset = writeLabelData(item.tags, buf, offset)
offset = writeTagData(includedTags, buf, offset)
}
else {
var buf = Buffer.alloc(0)
Expand Down Expand Up @@ -189,6 +218,7 @@ module.exports = function (item, deps) {
ppositions = []
holes = []
ref0 = -1
closed = false
}
if (!deps[smembers[i].id]) continue
var member = deps[smembers[i].id]
Expand Down Expand Up @@ -244,7 +274,8 @@ module.exports = function (item, deps) {
cSize+=varint.encodingLength(cells[i])
}
var labelLen = getLabelLen(item.tags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCountLen + pCount*4*2 + cLen + cSize + labelLen)
var tagLen = getTagLen(includedTags)
var buf = Buffer.alloc(1 + typeLen + idLen + pCountLen + pCount*4*2 + cLen + cSize + labelLen + tagLen)
var offset = 0
buf.writeUInt8(0x03, 0)
offset+=1
Expand All @@ -264,7 +295,8 @@ module.exports = function (item, deps) {
varint.encode(item, buf, offset)
offset+=varint.encode.bytes
})
writeLabelData(item.tags, buf, offset)
offset = writeLabelData(item.tags, buf, offset)
offset = writeTagData(includedTags, buf, offset)
}
else {
var buf = Buffer.alloc(0)
Expand All @@ -273,11 +305,16 @@ module.exports = function (item, deps) {
return buf
}

var nameRegEx = /^([^:]+_|)name($|:)/
var nameReplaceRegEx = /^(|[^:]+_)name($|:)/

function getLabelLen (tags) {
var labelLen = 1
Object.keys(tags).forEach(function (key) {
if (!/^([^:]+_|)name($|:)/.test(key)) { return }
var pre = key.replace(/^(|[^:]+_)name($|:)/,'')
if (!nameRegEx.test(key)) { return }
var pre = key.startsWith('alt_name:')
? key.replace(nameReplaceRegEx,'alt:')
: key.replace(nameReplaceRegEx,'')
var dataLen = Buffer.byteLength(pre) + 1
+ Buffer.byteLength(tags[key])
labelLen += varint.encodingLength(dataLen) + dataLen
Expand All @@ -287,8 +324,10 @@ function getLabelLen (tags) {

function writeLabelData (tags, buf, offset) {
Object.keys(tags).forEach(function (key) {
if (!/^([^:]+_|)name($|:)/.test(key)) { return }
var pre = key.replace(/^(|[^:]+_)name($|:)/,'')
if (!nameRegEx.test(key)) { return }
var pre = key.startsWith('alt_name:')
? key.replace(nameReplaceRegEx,'alt:')
: key.replace(nameReplaceRegEx,'')
var dataLen = Buffer.byteLength(pre) + 1
+ Buffer.byteLength(tags[key])
varint.encode(dataLen, buf, offset)
Expand All @@ -301,3 +340,82 @@ function writeLabelData (tags, buf, offset) {
offset+=varint.encode.bytes
return offset
}

function getTagLen (tags) {
var tagLen = 0
Object.keys(tags).forEach(function (key) {
if (nameRegEx.test(key)) { return }
var tagKey = key
var tagValue = tags[key]
if (typeof tagValue === 'object' || Array.isArray(tagValue)) { return }
var tagValueType
var tagValueLen
if (Number.isInteger(tagValue)) {
tagValueType = tagValueTypes.INT
tagValueLen = varint.encodingLength(tagValue)
}
else if (isNaN(tagValue)) {
tagValueType = tagValueTypes.STRING
tagValueLen = varint.encodingLength(Buffer.byteLength(tagValue)) + Buffer.byteLength(tagValue)
}
else {
tagValueType = tagValueTypes.FLOAT
tagValueLen = 4
}
var dataLen = varint.encodingLength(Buffer.byteLength(tagKey)) + Buffer.byteLength(tagKey) +
varint.encodingLength(tagValueType) +
tagValueLen
tagLen += dataLen
})
// we end with a 0 to signal we are done reading tag data
tagLen += varint.encodingLength(0)
return tagLen
}

function writeTagData (tags, buf, offset) {
Object.keys(tags).forEach(function (key) {
if (nameRegEx.test(key)) { return }
var tagKey = key
var tagValue = tags[key]
if (typeof tagValue === 'object' || Array.isArray(tagValue)) { return }
var tagValueType
var tagValueLen
if (Number.isInteger(tagValue)) {
tagValueType = tagValueTypes.INT
tagValueLen = varint.encodingLength(tagValue)
}
else if (isNaN(tagValue)) {
tagValueType = tagValueTypes.STRING
tagValueLen = Buffer.byteLength(tagValue)
}
else {
tagValueType = tagValueTypes.FLOAT
tagValueLen = 4
}

varint.encode(Buffer.byteLength(tagKey), buf, offset)
offset += varint.encode.bytes
buf.write(tagKey, offset)
offset += Buffer.byteLength(tagKey)

buf.writeUInt8(tagValueType, offset)
offset += 1
if (tagValueType === tagValueTypes.INT) {
varint.encode(tagValue, buf, offset)
offset += varint.encode.bytes
}
else if (tagValueType === tagValueTypes.FLOAT) {
buf.writeFloatLE(tagValue, offset)
offset += 4
}
else if (tagValueType === tagValueTypes.STRING) {
varint.encode(tagValueLen, buf, offset)
offset += varint.encode.bytes
buf.write(tagValue, offset)
offset += tagValueLen
}
})
varint.encode(0, buf, offset)
offset+=varint.encode.bytes
return offset
}
5 changes: 5 additions & 0 deletions lib/tag-value-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
INT: 0x01,
FLOAT: 0x02,
STRING: 0x03,
}
Loading