Skip to content

Commit

Permalink
Merge df67b65 into ff55172
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Jan 18, 2020
2 parents ff55172 + df67b65 commit 0a7cd9a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 41 deletions.
73 changes: 36 additions & 37 deletions modules/geo-layers/src/tile-layer/utils/viewport-util.js
Expand Up @@ -2,6 +2,9 @@ import {lngLatToWorld} from '@math.gl/web-mercator';

const TILE_SIZE = 512;

/**
* gets the bounding box of a viewport
*/
function getBoundingBox(viewport) {
const corners = [
viewport.unproject([0, 0]),
Expand All @@ -10,13 +13,17 @@ function getBoundingBox(viewport) {
viewport.unproject([viewport.width, viewport.height])
];
return [
corners.reduce((minLng, p) => (minLng < p[0] ? minLng : p[0]), 180),
corners.reduce((minLat, p) => (minLat < p[1] ? minLat : p[1]), 90),
corners.reduce((maxLng, p) => (maxLng > p[0] ? maxLng : p[0]), -180),
corners.reduce((maxLat, p) => (maxLat > p[1] ? maxLat : p[1]), -90)
Math.min(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
Math.min(corners[0][1], corners[1][1], corners[2][1], corners[3][1]),
Math.max(corners[0][0], corners[1][0], corners[2][0], corners[3][0]),
Math.max(corners[0][1], corners[1][1], corners[2][1], corners[3][1])
];
}

/*
* get the OSM tile index at the given location
* https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
*/
function getTileIndex(lngLat, scale) {
let [x, y] = lngLatToWorld(lngLat);
x *= scale / TILE_SIZE;
Expand All @@ -30,48 +37,40 @@ function getTileIndex(lngLat, scale) {
* return tiles that are on maxZoom.
*/
export function getTileIndices(viewport, maxZoom, minZoom) {
const z = Math.ceil(viewport.zoom);
if (minZoom && z < minZoom) {
let z = Math.ceil(viewport.zoom);
if (Number.isFinite(minZoom) && z < minZoom) {
return [];
}
if (Number.isFinite(maxZoom) && z > maxZoom) {
z = maxZoom;
}

const bbox = getBoundingBox(viewport);
const scale = 2 ** z;
let [minX, minY] = getTileIndex([bbox[0], bbox[3]], scale);
let [maxX, maxY] = getTileIndex([bbox[2], bbox[1]], scale);
/*
| TILE | TILE | TILE |
|(minPixel) |(maxPixel)
|(minIndex) |(maxIndex)
minX, maxX could be out of bounds if longitude is near the 180 meridian or multiple worlds
are shown:
| |
actual -2 -1 0 1 2 3
expected 2 3 0 1 2 3
*/
minX = Math.max(0, Math.floor(minX));
maxX = Math.min(scale, Math.ceil(maxX));
minY = Math.max(0, Math.floor(minY));
maxY = Math.min(scale, Math.ceil(maxY));

const indices = [];
const [minX, minY] = getTileIndex([bbox[0], bbox[3]], scale);
const [maxX, maxY] = getTileIndex([bbox[2], bbox[1]], scale);
const indices = {};

for (let x = minX; x < maxX; x++) {
for (let y = minY; y < maxY; y++) {
if (maxZoom && z > maxZoom) {
indices.push(getAdjustedTileIndex({x, y, z}, maxZoom));
} else {
indices.push({x, y, z});
}
/*
| TILE | TILE | TILE |
|(minX) |(maxX)
*/
for (let x = Math.floor(minX); x < maxX; x++) {
for (let y = Math.floor(minY); y < maxY; y++) {
// Cast to valid x between [0, scale]
const normalizedX = x - Math.floor(x / scale) * scale;
// dedupe
const key = `${z}-${normalizedX}-${y}`;
indices[key] = indices[key] || {x: normalizedX, y, z};
}
}

return indices;
}

/**
* Calculates and returns a new tile index {x, y, z}, with z being the given adjustedZ.
*/
function getAdjustedTileIndex({x, y, z}, adjustedZ) {
const m = Math.pow(2, z - adjustedZ);
return {
x: Math.floor(x / m),
y: Math.floor(y / m),
z: adjustedZ
};
return Object.values(indices);
}
20 changes: 16 additions & 4 deletions test/modules/geo-layers/tile-layer/viewport-util.spec.js
Expand Up @@ -82,23 +82,35 @@ const TEST_CASES = [
title: 'z0 repeat',
viewport: new WebMercatorViewport({
width: 800,
height: 400,
height: 200,
longitude: -90,
latitude: 0,
zoom: 0
}),
minZoom: undefined,
maxZoom: undefined,
output: ['0,0,0']
},
{
title: 'near 180 meridian',
viewport: new WebMercatorViewport({
width: 800,
height: 200,
longitude: -152,
latitude: 0,
zoom: 3
}),
maxZoom: 2,
output: ['0,1,2', '0,2,2', '3,1,2', '3,2,2']
}
];

function getTileIds(tiles) {
const set = new Set();
const ids = [];
for (const tile of tiles) {
set.add(`${tile.x},${tile.y},${tile.z}`);
ids.push(`${tile.x},${tile.y},${tile.z}`);
}
return Array.from(set).sort();
return Array.from(ids).sort();
}

test('getTileIndices', t => {
Expand Down

0 comments on commit 0a7cd9a

Please sign in to comment.