UNPKG

open-vector-tile

Version:

This library reads/writes Open Vector Tiles

164 lines 6.05 kB
import { readFeature, writeOVFeature } from './vectorFeature.js'; import { decodeShape, encodeShape } from './shape.js'; /** * The Open Vector Layer class represents a layer in an Open Vector Tile. * Contains an extent, name, version, and features. * The features will utilize the layer extent to decode geometry. */ export class OVectorLayer { version = 1; name = ''; extent = 4_096; #shapeIndex = -1; #mShapeIndex = -1; #features = new Map(); #pbf; #cache; #featuresPos = []; /** * @param pbf - the pbf protocol we are reading from * @param end - the position to stop at * @param cache - the cache where all data is stored in a column format */ constructor(pbf, end, cache) { this.#pbf = pbf; this.#cache = cache; pbf.readFields(this.#readLayer, this, end); } /** * @param tag - the tag to know what kind of data to read * @param layer - the layer to mutate * @param pbf - the pbf to read from */ #readLayer(tag, layer, pbf) { // lets convert from switch to if statements if (tag === 1) layer.version = pbf.readVarint(); else if (tag === 2) layer.name = layer.#cache.getColumn(1 /* OColumnName.string */, pbf.readVarint()); else if (tag === 3) layer.extent = decodeExtent(pbf.readVarint()); else if (tag === 4) layer.#featuresPos.push(pbf.pos); else if (tag === 5) layer.#shapeIndex = pbf.readVarint(); else if (tag === 6) layer.#mShapeIndex = pbf.readVarint(); } /** @returns - The number of features in the layer */ get length() { return this.#featuresPos.length; } /** @returns - The shape of the features properties */ get shape() { return decodeShape(this.#shapeIndex, this.#cache); } /** @returns - The shape of the M-Values */ get mShape() { if (this.#mShapeIndex === -1) return undefined; return decodeShape(this.#mShapeIndex, this.#cache); } /** * should return OVectorFeature which is a type combining all 6 feature types * @param i - The index of the feature * @returns - A feature at the given index */ feature(i) { if (i < 0 || i >= this.#featuresPos.length) throw new Error('feature index out of bounds'); let feature = this.#features.get(i); if (feature !== undefined) return feature; this.#pbf.pos = this.#featuresPos[i]; feature = readFeature(this.#pbf.readBytes(), this.extent, this.#cache, this.shape, this.mShape); this.#features.set(i, feature); return feature; } } /** * @param extent - number are in 512, 1024, 2048, 4096, 8192 * @returns - remap to smaller values: 0 -> 512, 1 -> 1024, 2 -> 2048, 3 -> 4096, 4 -> 8192 */ export function encodeExtent(extent) { if (extent === 16_384) return 5; else if (extent === 8_192) return 4; else if (extent === 4_096) return 3; else if (extent === 2_048) return 2; else if (extent === 1_024) return 1; else if (extent === 512) return 0; else throw new Error('invalid extent, must be 512, 1_024, 2_048, 4_096, 8_192, or 16_384'); } /** * @param encExtent - number are in 0, 1, 2, 3, 4 * @returns - remap to smaller values: 0 -> 512, 1 -> 1024, 2 -> 2048, 3 -> 4096, 4 -> 8192 */ export function decodeExtent(encExtent) { if (encExtent === 5) return 16_384; else if (encExtent === 4) return 8_192; else if (encExtent === 3) return 4_096; else if (encExtent === 2) return 2_048; else if (encExtent === 1) return 1_024; else if (encExtent === 0) return 512; else throw new Error('invalid encoded extent, must be 0, 1, 2, 3, 4, or 5'); } /** * Because of the Column Cache, a layer will contain: * - version 1 byte * - extent (1 byte) - 1 -> 1024, 2 -> 2048, 3 -> 4096, 4 -> 8192 * - name (varint) - index into the string columns table * - features (writeMessage) - for each feature * @param layerCache - object containing the layer and the cache * @param layerCache.layer - the layer to encode into the Protobuffer * @param layerCache.cache - the cache where all column level data is stored * @param layerCache.verbose - set to true to print out write information * @param pbf - the pbf protocol we are writing to */ export function writeOVLayer(layerCache, pbf) { const { layer, cache, verbose } = layerCache; pbf.writeVarintField(1, layer.version); pbf.writeVarintField(2, cache.addColumnData(1 /* OColumnName.string */, layer.name)); pbf.writeVarintField(3, encodeExtent(layer.extent)); pbf.writeVarintField(5, encodeShape(cache, layer.shape)); if (layer.mShape !== undefined) pbf.writeVarintField(6, encodeShape(cache, layer.mShape)); // sort by feature type layer.features = layer.features.sort((a, b) => a.type - b.type); for (const feature of layer.features) pbf.writeBytesField(4, writeOVFeature(feature, layer.shape, layer.mShape, cache)); if (verbose) { const totals = { points: 0, lines: 0, polys: 0, points3D: 0, lines3D: 0, polys3D: 0, all: 0 }; for (const feature of layer.features) { if (feature.type === 1) totals.points += 1; else if (feature.type === 2) totals.lines += 1; else if (feature.type === 3) totals.polys += 1; else if (feature.type === 4) totals.points3D += 1; else if (feature.type === 5) totals.lines3D += 1; else if (feature.type === 6) totals.polys3D += 1; totals.all += 1; } console.info(totals); console.info(`wrote "${layer.name}" with extent "${layer.extent}" and version "${layer.version}"\n`); } } //# sourceMappingURL=vectorLayer.js.map