s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
93 lines (92 loc) • 4.12 kB
JavaScript
import { project } from '../mat4.js';
import { bboxST, getNeighborsIJ, idFromFace, idFromIJ, pointFromLonLat, pointFromSTGL, pointMulScalar, pointNormalize, pointToIJ, } from 'gis-tools/index.js';
import { boxIntersects, pointBoundaries } from './index.js';
const ZERO_TILES = [0, 1, 2, 3, 4, 5];
/**
* Given a camera position, get the tiles in current view
* @param zoom - the zoom level
* @param lon - the longitude
* @param lat - the latitude
* @param matrix - the projection matrix
* @param radius - the radius of the sphere
* @returns list of Tile IDs
*/
export function getTilesInViewS2(zoom, lon, lat, matrix, radius = 1) {
if (zoom < 1)
return ZERO_TILES.map((face) => ({ id: idFromFace(face), face, zoom: 0, x: 0, y: 0 }));
const tiles = [];
const checkList = [];
const checkedTiles = new Set();
zoom = zoom << 0; // move to whole number
let stBbox, tLProj, tRProj, bLProj, bRProj;
// grab the first tile and prep neighbors for checks
const [face, i, j] = pointToIJ(pointFromLonLat({ x: lon, y: lat }), zoom);
tiles.push({ id: idFromIJ(face, i, j, zoom), face, zoom, x: i, y: j });
checkedTiles.add(`${String(face)}-${String(i)}-${String(j)}`);
addNeighbors(face, zoom, i, j, checkedTiles, checkList);
const zero = project(matrix, { x: 0, y: 0, z: 0 }).z;
while (checkList.length > 0) {
// grab a tile to check and get its face and bounds
const check = checkList.pop();
if (check === undefined)
break;
const [face, i, j] = check;
stBbox = bboxST(i, j, zoom);
// grab the four points from the bbox and project them
tLProj = project(matrix, pointMulScalar(pointNormalize(pointFromSTGL(face, stBbox[0], stBbox[3])), radius));
tRProj = project(matrix, pointMulScalar(pointNormalize(pointFromSTGL(face, stBbox[2], stBbox[3])), radius));
bLProj = project(matrix, pointMulScalar(pointNormalize(pointFromSTGL(face, stBbox[0], stBbox[1])), radius));
bRProj = project(matrix, pointMulScalar(pointNormalize(pointFromSTGL(face, stBbox[2], stBbox[1])), radius));
// check if any of the 4 edge points or lines interact with a -1 to 1 x and y projection plane
// if tile is part of the view, we add to tiles and tileSet and add all surounding tiles
if (lessThanZero(zero, bLProj.z, bRProj.z, tLProj.z, tRProj.z) &&
(pointBoundaries(bLProj, bRProj, tLProj, tRProj) ||
boxIntersects(bLProj, bRProj, tLProj, tRProj))) {
const id = idFromIJ(face, i, j, zoom);
tiles.push({ id, face, zoom, x: i, y: j });
addNeighbors(face, zoom, i, j, checkedTiles, checkList);
}
}
// we sort by id to avoid text filtering to awkwardly swap back and forth
return tiles.sort((a, b) => {
if (a.id > b.id)
return 1;
else if (a.id < b.id)
return -1;
else
return 0;
});
}
/**
* Add neighbors to the checkList
* @param face - the face of the S2 sphere
* @param zoom - the zoom level
* @param i - the i tile-coordinate
* @param j - the j tile-coordinate
* @param checkedTiles - the set of tiles we have already checked
* @param checkList - the list of tiles to check
*/
function addNeighbors(face, zoom, i, j, checkedTiles, checkList) {
// add the surounding tiles we have not checked
for (const [nFace, nI, nJ] of getNeighborsIJ(face, i, j, zoom)) {
const fij = `${String(nFace)}-${String(nI)}-${String(nJ)}`;
if (!checkedTiles.has(fij)) {
checkedTiles.add(fij);
checkList.push([nFace, nI, nJ]);
}
}
}
/**
* check if any 4 points in a rectangle is less than zero
* @param zero - the zero reference point to compare against
* @param bl - bottom left point
* @param br - bottom right point
* @param tl - top left point
* @param tr - top right point
* @returns true if any point is less than zero
*/
export function lessThanZero(zero, bl, br, tl, tr) {
if (bl < zero || br < zero || tl < zero || tr < zero)
return true;
return false;
}