@deck.gl/geo-layers
Version:
deck.gl layers supporting geospatial use cases and GIS formats
183 lines (153 loc) • 5.32 kB
JavaScript
import { getOSMTileIndices } from './tile-2d-traversal';
const TILE_SIZE = 512;
const DEFAULT_EXTENT = [-Infinity, -Infinity, Infinity, Infinity];
export const urlType = {
type: 'url',
value: null,
validate: (value, propType) => propType.optional && value === null || typeof value === 'string' || Array.isArray(value) && value.every(url => typeof url === 'string'),
equals: (value1, value2) => {
if (value1 === value2) {
return true;
}
if (!Array.isArray(value1) || !Array.isArray(value2)) {
return false;
}
const len = value1.length;
if (len !== value2.length) {
return false;
}
for (let i = 0; i < len; i++) {
if (value1[i] !== value2[i]) {
return false;
}
}
return true;
}
};
function transformBox(bbox, modelMatrix) {
const transformedCoords = [modelMatrix.transformAsPoint([bbox[0], bbox[1]]), modelMatrix.transformAsPoint([bbox[2], bbox[1]]), modelMatrix.transformAsPoint([bbox[0], bbox[3]]), modelMatrix.transformAsPoint([bbox[2], bbox[3]])];
const transformedBox = [Math.min(...transformedCoords.map(i => i[0])), Math.min(...transformedCoords.map(i => i[1])), Math.max(...transformedCoords.map(i => i[0])), Math.max(...transformedCoords.map(i => i[1]))];
return transformedBox;
}
export function getURLFromTemplate(template, properties) {
if (!template || !template.length) {
return null;
}
if (Array.isArray(template)) {
const index = Math.abs(properties.x + properties.y) % template.length;
template = template[index];
}
const {
x,
y,
z
} = properties;
return template.replace(/\{x\}/g, x).replace(/\{y\}/g, y).replace(/\{z\}/g, z).replace(/\{-y\}/g, Math.pow(2, z) - y - 1);
}
function getBoundingBox(viewport, zRange, extent) {
let bounds;
if (zRange && zRange.length === 2) {
const [minZ, maxZ] = zRange;
const bounds0 = viewport.getBounds({
z: minZ
});
const bounds1 = viewport.getBounds({
z: maxZ
});
bounds = [Math.min(bounds0[0], bounds1[0]), Math.min(bounds0[1], bounds1[1]), Math.max(bounds0[2], bounds1[2]), Math.max(bounds0[3], bounds1[3])];
} else {
bounds = viewport.getBounds();
}
if (!viewport.isGeospatial) {
return [Math.max(Math.min(bounds[0], extent[2]), extent[0]), Math.max(Math.min(bounds[1], extent[3]), extent[1]), Math.min(Math.max(bounds[2], extent[0]), extent[2]), Math.min(Math.max(bounds[3], extent[1]), extent[3])];
}
return [Math.max(bounds[0], extent[0]), Math.max(bounds[1], extent[1]), Math.min(bounds[2], extent[2]), Math.min(bounds[3], extent[3])];
}
function getIndexingCoords(bbox, scale, modelMatrixInverse) {
if (modelMatrixInverse) {
const transformedTileIndex = transformBox(bbox, modelMatrixInverse).map(i => i * scale / TILE_SIZE);
return transformedTileIndex;
}
return bbox.map(i => i * scale / TILE_SIZE);
}
function getScale(z, tileSize) {
return Math.pow(2, z) * TILE_SIZE / tileSize;
}
export function osmTile2lngLat(x, y, z) {
const scale = getScale(z, TILE_SIZE);
const lng = x / scale * 360 - 180;
const n = Math.PI - 2 * Math.PI * y / scale;
const lat = 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
return [lng, lat];
}
function tile2XY(x, y, z, tileSize) {
const scale = getScale(z, tileSize);
return [x / scale * TILE_SIZE, y / scale * TILE_SIZE];
}
export function tileToBoundingBox(viewport, x, y, z, tileSize = TILE_SIZE) {
if (viewport.isGeospatial) {
const [west, north] = osmTile2lngLat(x, y, z);
const [east, south] = osmTile2lngLat(x + 1, y + 1, z);
return {
west,
north,
east,
south
};
}
const [left, top] = tile2XY(x, y, z, tileSize);
const [right, bottom] = tile2XY(x + 1, y + 1, z, tileSize);
return {
left,
top,
right,
bottom
};
}
function getIdentityTileIndices(viewport, z, tileSize, extent, modelMatrixInverse) {
const bbox = getBoundingBox(viewport, null, extent);
const scale = getScale(z, tileSize);
const [minX, minY, maxX, maxY] = getIndexingCoords(bbox, scale, modelMatrixInverse);
const indices = [];
for (let x = Math.floor(minX); x < maxX; x++) {
for (let y = Math.floor(minY); y < maxY; y++) {
indices.push({
x,
y,
z
});
}
}
return indices;
}
export function getTileIndices({
viewport,
maxZoom,
minZoom,
zRange,
extent,
tileSize = TILE_SIZE,
modelMatrix,
modelMatrixInverse,
zoomOffset = 0
}) {
let z = viewport.isGeospatial ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset : Math.ceil(viewport.zoom) + zoomOffset;
if (Number.isFinite(minZoom) && z < minZoom) {
if (!extent) {
return [];
}
z = minZoom;
}
if (Number.isFinite(maxZoom) && z > maxZoom) {
z = maxZoom;
}
let transformedExtent = extent;
if (modelMatrix && modelMatrixInverse && extent && !viewport.isGeospatial) {
transformedExtent = transformBox(extent, modelMatrix);
}
return viewport.isGeospatial ? getOSMTileIndices(viewport, z, zRange, extent) : getIdentityTileIndices(viewport, z, tileSize, transformedExtent || DEFAULT_EXTENT, modelMatrixInverse);
}
export function isURLTemplate(s) {
return /(?=.*{z})(?=.*{x})(?=.*({y}|{-y}))/.test(s);
}
//# sourceMappingURL=utils.js.map