s2-tools
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
146 lines • 6.54 kB
JavaScript
import { MetadataBuilder } from 's2-tilejson';
import VectorTileWorker from './worker/tileWorker';
/**
* Build vector tiles give a guide on what sources to parse data from and how to store it
* @param buildGuide - the user defined guide on building the vector tiles
*/
export async function toVectorTiles(buildGuide) {
const { tileWriter, scheme } = buildGuide;
const vectorWorker = new VectorTileWorker();
// STEP 1: Convert all features to tile slices of said features.
await toVectorTilesSliceFeatures(buildGuide, vectorWorker);
// STEP 2: Ensure all data is prepped/sorted for reading/building tiles
await vectorWorker.sort();
// STEP 3: collect all existing multimap feature stores and build tiles
for await (const { face, zoom, x, y, data } of vectorWorker.buildTiles()) {
if (scheme === 'fzxy')
await tileWriter.writeTileS2(face, zoom, x, y, data);
else
await tileWriter.writeTileWM(zoom, x, y, data);
}
// STEP 4: build metadata based on the guide
const metaBuilder = new MetadataBuilder();
updateBuilder(metaBuilder, buildGuide);
const metadata = metaBuilder.commit();
// STEP 5: Commit the metadata
await tileWriter.commit(metadata);
}
/**
* STEP 1: Convert all features to tile slices of said features.
* @param buildGuide - the user defined guide on building the vector tiles
* @param vectorWorker - the vector tile worker to use
*/
async function toVectorTilesSliceFeatures(buildGuide, vectorWorker) {
const { vectorSources, rasterSources, layerGuides, scheme, encoding } = buildGuide;
const featuresIterator = getFeature(vectorSources, rasterSources);
// Prepare workers with init messages
const stringifiedLayerGuides = prepareLayerGuides(layerGuides);
const initMessage = {
type: 'init',
id: 0,
scheme,
encoding,
layerGuides: stringifiedLayerGuides,
};
vectorWorker.handleMessage(initMessage);
for await (const nextFeature of featuresIterator) {
const { sourceName, feature } = nextFeature;
const featureMessage = { type: 'feature', sourceName, feature };
vectorWorker.handleMessage(featureMessage);
}
}
/**
* Prepare the layer guides for workers to be stringified
* @param layerGuides - the user defined guide on building the vector tiles
* @returns the stringified layer guides
*/
function prepareLayerGuides(layerGuides) {
return layerGuides.map((layer) => {
return {
...layer,
onFeature: layer.onFeature !== undefined ? JSON.stringify(layer.onFeature) : undefined,
};
});
}
/**
* Get the features that will be stored in the tile
* @param vectorSources - the vector sources that the tile is built from and how the layers are to be stored.
* @param rasterSources - the raster sources that will be conjoined into a single rgba pixel index for tile extraction
* @yields - a features
*/
async function* getFeature(vectorSources, rasterSources) {
if (vectorSources !== undefined) {
for (const [sourceName, source] of Object.entries(vectorSources)) {
for await (const feature of source)
yield { sourceName, feature };
}
}
if (rasterSources !== undefined) {
for (const [sourceName, source] of Object.entries(rasterSources)) {
for await (const feature of source)
yield { sourceName, feature };
}
}
}
/**
* @param metaBuilder - the metadata builder to update
* @param buildGuide - the user defined guide on building the vector tiles
*/
function updateBuilder(metaBuilder, buildGuide) {
const { name, description, version, scheme, encoding, attribution, layerGuides } = buildGuide;
metaBuilder.setName(name);
metaBuilder.setExtension('pbf');
metaBuilder.setDescription(description ?? 'Built by S2-Tools');
metaBuilder.setVersion(version ?? '1.0.0');
metaBuilder.setScheme(scheme ?? 'fzxy'); // 'fzxy' | 'tfzxy' | 'xyz' | 'txyz' | 'tms'
metaBuilder.setType('vector');
metaBuilder.setEncoding(encoding ?? 'gz'); // 'gz' | 'br' | 'none'
if (attribution !== undefined) {
for (const [displayName, href] of Object.entries(attribution)) {
metaBuilder.addAttribution(displayName, href);
}
}
for (const layer of layerGuides)
metaBuilder.addLayer(layer.sourceName, layer.metadata);
}
/**
* TODO: Find all cases where prepping the data could be done wrong by the user with
* TODO: explinations of how to correct them.
* TODO: - metadata must be correct. -
* Check and display errors
* @param _layerGuides - the user defined guide on building the vector tiles
*/
function _findErrors(_layerGuides) {
// for (const layerGuide of layerGuides) {
// // const { metadata } = layerGuide;
// }
}
// TODO: tileGuide should be modifed to match metadata minzoom, maxzoom, and projection
// minzoom and maxzoom can be left alone if they already exist, but projection MUST match the
// output projection.
// TODO:
// VECTOR:
// - step 1: ship individual features to workers
// - - step 1a: splite the features into tiles, requesting all tiles from range min->max of the layer
// - - step 1b: store all those features into a multimap where the key is the tile-id and the value is the features
// - step 2: build tiles from each worker
// - - step 2a: given a tile-id, retrieve the features from the multimap
// - - step 2b: build the tile from the features, gzip, etc. then ship the buffer and metadata to main thread
// - - step 2c: store metadata into metaBuilder and the buffer into the store
// finish
//
// CLUSTER:
// - step 1: for each point, just add.
// - step 2: cluster.
// - step 3: request tiles as needed.
//
// RASTER:
// - step 1: for every pixel, store to a point index where the m-value is the rgba value
// - step 2: build tiles from the point index
// - - step 2a: start at max zoom - for each pixel in the tile search the range and find average
// of all the points in that range (remember color is logarithmic so multiply each pixel r-g-b-a by itself first)
// If too far zoomed in, find the closest pixel within a resonable radius.
// - - step 2b: after finishing max zoom, use https://github.com/rgba-image/lanczos as I move towards minzoom.
// - - sidenote: I think the easiest way to build tiles is start at 0 zoom and dive down everytime we find at least one point, then move back up
// finish
//# sourceMappingURL=index.js.map