diff --git a/js/src/decoder/MltDecoder.ts b/js/src/decoder/MltDecoder.ts index 13ec8f7a..1e62df1f 100644 --- a/js/src/decoder/MltDecoder.ts +++ b/js/src/decoder/MltDecoder.ts @@ -3,7 +3,6 @@ import { Layer } from '../data/Layer'; import { MapLibreTile } from '../data/MapLibreTile'; import { PhysicalLevelTechnique } from '../metadata/stream/PhysicalLevelTechnique'; import { StreamMetadataDecoder } from '../metadata/stream/StreamMetadataDecoder'; -import { FeatureTableSchema, TileSetMetadata } from "../metadata/mlt_tileset_metadata_pb"; import { IntWrapper } from './IntWrapper'; import { DecodingUtils } from './DecodingUtils'; import { IntegerDecoder } from './IntegerDecoder'; @@ -14,7 +13,32 @@ class MltDecoder { private static ID_COLUMN_NAME = "id"; private static GEOMETRY_COLUMN_NAME = "geometry"; - public static decodeMlTile(tile: Uint8Array, tileMetadata: TileSetMetadata): MapLibreTile { + public static generateFeatureTables(tilesetMetadata: any): any { + const featureTables = []; + for (let i=0; i { + // https://github.com/bufbuild/protobuf-es/blob/main/docs/runtime_api.md#accessing-oneof-groups + if (column.name === "geometry" || column.name === "id") { + columns.push({ + "name": column.name + }); + } else { + columns.push({ + "name": column.name, + "type": column.type.value.type.value + }); + } + table['columns'] = columns; + featureTables[i] = table; + }); + } + return featureTables; + } + + public static decodeMlTile(tile: Uint8Array, featureTables: any): MapLibreTile { const offset = new IntWrapper(0); const mltLayers: Layer[] = []; while (offset.get() < tile.length) { @@ -31,12 +55,13 @@ class MltDecoder { const maxTileExtent = infos[2]; const featureTableId = infos[0]; const numFeatures = infos[3]; - const metadata = tileMetadata.featureTables[featureTableId]; - if (!metadata) { + // Optimize metadata usage + const featureTableMeta = featureTables[featureTableId]; + if (!featureTableMeta) { console.log(`could not find metadata for feature table id: ${featureTableId}`); return; } - for (const columnMetadata of metadata.columns) { + for (const columnMetadata of featureTableMeta.columns) { const columnName = columnMetadata.name; const numStreams = DecodingUtils.decodeVarint(tile, offset, 1)[0]; if (columnName === "id") { @@ -45,7 +70,7 @@ class MltDecoder { const presentStream = DecodingUtils.decodeBooleanRle(tile, presentStreamMetadata.numValues(), presentStreamMetadata.byteLength(), offset); } // TODO: handle switching on physicalType - // const physicalType = columnMetadata.type.value.type.value; + // const physicalType = columnMetadata.type; const idDataStreamMetadata = StreamMetadataDecoder.decode(tile, offset); ids = idDataStreamMetadata.physicalLevelTechnique() === PhysicalLevelTechnique.FAST_PFOR @@ -56,7 +81,7 @@ class MltDecoder { const geometryColumn = GeometryDecoder.decodeGeometryColumn(tile, numStreams, offset); geometries = GeometryDecoder.decodeGeometry(geometryColumn); } else { - const propertyColumn = PropertyDecoder.decodePropertyColumn(tile, offset, columnMetadata, numStreams); + const propertyColumn = PropertyDecoder.decodePropertyColumn(tile, offset, columnMetadata.type, numStreams); if (propertyColumn instanceof Map) { for (const [key, value] of propertyColumn.entries()) { properties[key] = value; @@ -67,14 +92,14 @@ class MltDecoder { } } - const layer = MltDecoder.convertToLayer(ids, geometries, properties, metadata, numFeatures); + const layer = MltDecoder.convertToLayer(ids, geometries, properties, featureTableMeta.name, numFeatures); mltLayers.push(layer); } return new MapLibreTile(mltLayers); } - private static convertToLayer(ids: number[], geometries, properties, metadata: FeatureTableSchema, numFeatures: number): Layer { + private static convertToLayer(ids: number[], geometries, properties, name: string, numFeatures: number): Layer { // if (numFeatures != geometries.length || numFeatures != ids.length) { // console.log( // "Warning, in convertToLayer the size of ids(" @@ -84,7 +109,7 @@ class MltDecoder { // + "), and features(" // + numFeatures // + ") are not equal for layer: " - // + metadata.name); + // + name); // } const features: Feature[] = new Array(numFeatures); const vals = Object.entries(properties); @@ -98,7 +123,7 @@ class MltDecoder { features[j] = feature; } - return new Layer(metadata.name, features); + return new Layer(name, features); } } diff --git a/js/src/decoder/PropertyDecoder.ts b/js/src/decoder/PropertyDecoder.ts index d167a42d..c1160c2d 100644 --- a/js/src/decoder/PropertyDecoder.ts +++ b/js/src/decoder/PropertyDecoder.ts @@ -1,6 +1,5 @@ import { StreamMetadata } from '../metadata/stream/StreamMetadata'; import { StreamMetadataDecoder } from '../metadata/stream/StreamMetadataDecoder'; -import { Column, ScalarType } from "../metadata/mlt_tileset_metadata_pb"; import { IntWrapper } from './IntWrapper'; import { DecodingUtils } from './DecodingUtils'; import { IntegerDecoder } from './IntegerDecoder'; @@ -8,14 +7,25 @@ import { FloatDecoder } from './FloatDecoder'; import { DoubleDecoder } from './DoubleDecoder'; import { StringDecoder } from './StringDecoder'; +enum ScalarType { + BOOLEAN = 0, + INT_8 = 1, + UINT_8 = 2, + INT_32 = 3, + UINT_32 = 4, + INT_64 = 5, + UINT_64 = 6, + FLOAT = 7, + DOUBLE = 8, + STRING = 9 +} + class PropertyDecoder { - public static decodePropertyColumn(data: Uint8Array, offset: IntWrapper, column: Column, numStreams: number) { + public static decodePropertyColumn(data: Uint8Array, offset: IntWrapper, physicalType: number, numStreams: number) { let presentStreamMetadata: StreamMetadata | null = null; - // https://github.com/bufbuild/protobuf-es/blob/main/docs/runtime_api.md#accessing-oneof-groups - const scalarColumn = column.type.case; - if (scalarColumn !== undefined) { + if (physicalType !== undefined) { let presentStream = null; let numValues = 0; if (numStreams > 1) { @@ -23,7 +33,6 @@ class PropertyDecoder { numValues = presentStreamMetadata.numValues(); presentStream = DecodingUtils.decodeBooleanRle(data, presentStreamMetadata.numValues(), presentStreamMetadata.byteLength(), offset); } - const physicalType = column.type.value.type.value; switch (physicalType) { case ScalarType.BOOLEAN: { const dataStreamMetadata = StreamMetadataDecoder.decode(data, offset); diff --git a/js/src/decoder/StringDecoder.ts b/js/src/decoder/StringDecoder.ts index f54f041d..408a8bb7 100644 --- a/js/src/decoder/StringDecoder.ts +++ b/js/src/decoder/StringDecoder.ts @@ -2,6 +2,8 @@ import { IntWrapper } from './IntWrapper'; import { StreamMetadataDecoder } from '../metadata/stream/StreamMetadataDecoder'; import { IntegerDecoder } from './IntegerDecoder'; +const textDecoder = new TextDecoder("utf-8"); + export class StringDecoder { /* @@ -67,19 +69,17 @@ export class StringDecoder { const decodedValues: string[] = []; let lengthOffset = 0; let strOffset = 0; - const decoder = new TextDecoder("utf-8"); for (let i = 0; i < numValues; i++) { const present = presentStream[i]; if (present) { const length = lengthStream[lengthOffset++]; - const value = decoder.decode(utf8Values.slice(strOffset, strOffset + length)); + const value = textDecoder.decode(utf8Values.slice(strOffset, strOffset + length)); decodedValues.push(value); strOffset += length; } else { decodedValues.push(null); } } - return decodedValues; } @@ -89,9 +89,8 @@ export class StringDecoder { ): string[] { const dictionary: string[] = []; let dictionaryOffset = 0; - const decoder = new TextDecoder("utf-8"); for (const length of lengthStream) { - const value = decoder.decode(utf8Values.slice(dictionaryOffset, dictionaryOffset + length)); + const value = textDecoder.decode(utf8Values.slice(dictionaryOffset, dictionaryOffset + length)); dictionary.push(value); dictionaryOffset += length; } diff --git a/js/src/index.ts b/js/src/index.ts index a748eca9..31299398 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -1,2 +1 @@ export { MltDecoder } from './decoder/MltDecoder'; -export { TileSetMetadata } from './metadata/mlt_tileset_metadata_pb';