forked from visgl/deck.gl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CARTO: binary data for spatial index layers (visgl#7160)
- Loading branch information
1 parent
87ddf6c
commit d6b101c
Showing
12 changed files
with
406 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
modules/carto/src/layers/schema/carto-spatial-tile-loader.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import Protobuf from 'pbf'; | ||
import {LoaderOptions, LoaderWithParser} from '@loaders.gl/loader-utils'; | ||
|
||
import {KeyValueProperties} from './carto-tile'; | ||
import {binaryToSpatialjson, Properties, SpatialJson} from './spatialjson-utils'; | ||
import {Tile, TileReader} from './carto-spatial-tile'; | ||
|
||
const CartoSpatialTileLoader: LoaderWithParser = { | ||
name: 'CARTO Spatial Tile', | ||
version: '1', | ||
id: 'cartoSpatialTile', | ||
module: 'carto', | ||
extensions: ['pbf'], | ||
mimeTypes: [ | ||
'application/vnd.carto-spatial-tile', | ||
'application/x-protobuf' // Back-compatibility | ||
], | ||
category: 'geometry', | ||
worker: false, | ||
parse: async (arrayBuffer, options) => parseCartoSpatialTile(arrayBuffer, options), | ||
parseSync: parseCartoSpatialTile, | ||
options: {} | ||
}; | ||
|
||
function parsePbf(buffer: ArrayBuffer): Tile { | ||
const pbf = new Protobuf(buffer); | ||
const tile = TileReader.read(pbf); | ||
return tile; | ||
} | ||
|
||
function unpackProperties(properties: KeyValueProperties[]): Properties[] { | ||
if (!properties || !properties.length) { | ||
return []; | ||
} | ||
return properties.map(item => { | ||
const currentRecord: Properties = {}; | ||
item.data.forEach(({key, value}) => { | ||
currentRecord[key] = value; | ||
}); | ||
return currentRecord; | ||
}); | ||
} | ||
|
||
function parseCartoSpatialTile( | ||
arrayBuffer: ArrayBuffer, | ||
options?: LoaderOptions | ||
): SpatialJson | null { | ||
if (!arrayBuffer) return null; | ||
const tile = parsePbf(arrayBuffer); | ||
|
||
const {cells} = tile; | ||
const data = { | ||
cells: {...cells, properties: unpackProperties(cells.properties)} | ||
}; | ||
|
||
return binaryToSpatialjson(data); | ||
} | ||
|
||
export default CartoSpatialTileLoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import {Indices, IndexScheme} from './spatialjson-utils'; | ||
import { | ||
KeyValueProperties, | ||
NumericProp, | ||
NumericPropKeyValueReader, | ||
PropertiesReader | ||
} from './carto-tile'; | ||
|
||
// Indices ===================================== | ||
|
||
export class IndicesReader { | ||
static read(pbf, end?: number): Indices { | ||
const {value} = pbf.readFields(IndicesReader._readField, {value: []}, end); | ||
return {value: new BigUint64Array(value)}; | ||
} | ||
static _readField(this: void, tag: number, obj, pbf) { | ||
if (tag === 1) readPackedFixed64(pbf, obj.value); | ||
} | ||
} | ||
|
||
// Cells ========================================= | ||
|
||
interface Cells { | ||
indices: Indices; | ||
properties: KeyValueProperties[]; | ||
numericProps: Record<string, NumericProp>; | ||
} | ||
|
||
class CellsReader { | ||
static read(pbf, end?: number): Cells { | ||
return pbf.readFields( | ||
CellsReader._readField, | ||
{indices: null, properties: [], numericProps: {}}, | ||
end | ||
); | ||
} | ||
static _readField(this: void, tag: number, obj: Cells, pbf) { | ||
if (tag === 1) obj.indices = IndicesReader.read(pbf, pbf.readVarint() + pbf.pos); | ||
else if (tag === 2) obj.properties.push(PropertiesReader.read(pbf, pbf.readVarint() + pbf.pos)); | ||
else if (tag === 3) { | ||
const entry = NumericPropKeyValueReader.read(pbf, pbf.readVarint() + pbf.pos); | ||
obj.numericProps[entry.key] = entry.value; | ||
} | ||
} | ||
} | ||
|
||
// Tile ======================================== | ||
|
||
// TODO this type is very similar to SpatialBinary, should align | ||
export interface Tile { | ||
scheme: IndexScheme; | ||
cells: Cells; | ||
} | ||
|
||
export class TileReader { | ||
static read(pbf, end?: number): Tile { | ||
return pbf.readFields(TileReader._readField, {scheme: 0, cells: null}, end); | ||
} | ||
static _readField(this: void, tag: number, obj: Tile, pbf) { | ||
if (tag === 1) obj.scheme = pbf.readVarint(); | ||
else if (tag === 2) obj.cells = CellsReader.read(pbf, pbf.readVarint() + pbf.pos); | ||
} | ||
} | ||
|
||
// pbf doesn't support BigInt natively, implement support for packed fixed64 type | ||
const SHIFT_LEFT_32 = BigInt((1 << 16) * (1 << 16)); | ||
|
||
function readPackedEnd(pbf) { | ||
return pbf.type === 2 ? pbf.readVarint() + pbf.pos : pbf.pos + 1; | ||
} | ||
function readFixed64(pbf) { | ||
const a = BigInt(pbf.readFixed32()); | ||
const b = BigInt(pbf.readFixed32()); | ||
return a + b * SHIFT_LEFT_32; | ||
} | ||
|
||
function readPackedFixed64(pbf, arr) { | ||
if (pbf.type !== 2) return arr.push(readFixed64(pbf)); | ||
const end = readPackedEnd(pbf); | ||
arr = arr || []; | ||
while (pbf.pos < end) arr.push(readFixed64(pbf)); | ||
return arr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import {bigIntToIndex} from '../quadbin-utils'; | ||
|
||
export type IndexScheme = 'h3' | 'quadbin'; | ||
type TypedArray = Float32Array | Float64Array; | ||
|
||
export type Indices = {value: BigUint64Array}; | ||
export type NumericProps = Record<string, {value: number[] | TypedArray}>; | ||
export type Properties = Record<string, string | number | boolean | null>; | ||
export type Cells = { | ||
indices: Indices; | ||
numericProps: NumericProps; | ||
properties: Properties[]; | ||
}; | ||
export type SpatialBinary = {scheme?: IndexScheme; cells: Cells}; | ||
export type SpatialJson = { | ||
id: string; | ||
properties: Properties; | ||
}[]; | ||
|
||
export function binaryToSpatialjson(binary: SpatialBinary): SpatialJson { | ||
const {cells} = binary; | ||
const count = cells.indices.value.length; | ||
const spatial: any[] = []; | ||
for (let i = 0; i < count; i++) { | ||
const id = bigIntToIndex(cells.indices.value[i]); | ||
|
||
const properties = {...cells.properties[i]}; | ||
for (const key of Object.keys(cells.numericProps)) { | ||
properties[key] = cells.numericProps[key].value[i]; | ||
} | ||
spatial.push({id, properties}); | ||
} | ||
|
||
return spatial; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.