UNPKG

@ngageoint/geopackage

Version:
365 lines 17.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TileBoundingBoxUtils = void 0; var projectionConstants_1 = require("../projection/projectionConstants"); var tileGrid_1 = require("./tileGrid"); var boundingBox_1 = require("../boundingBox"); /** * This module exports utility functions for [slippy map (XYZ)](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) * tile calculations. * * @module tiles/tileBoundingBoxUtils */ var TileBoundingBoxUtils = /** @class */ (function () { function TileBoundingBoxUtils() { } /** * Calculate the bounds in tile coordinates that covers the given bounding box * at the given zoom level. The result object contains the keys `minX`, `maxX`, * `minY`, and `maxY`, which are tile column and row values in the XYZ tile * scheme. * * @param {BoundingBox} webMercatorBoundingBox bounds in EPSG:3857 coordinates (meters) * @param {number} zoom the integral zoom level * @returns {{minX: number, maxX: number, minY: number, maxY: number}} bounds in tile column and row coordinates */ TileBoundingBoxUtils.webMercatorTileBox = function (webMercatorBoundingBox, zoom) { var tilesPerSide = TileBoundingBoxUtils.tilesPerSideWithZoom(zoom); var tileSize = TileBoundingBoxUtils.tileSizeWithTilesPerSide(tilesPerSide); var minLonClip = Math.max(-projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, webMercatorBoundingBox.minLongitude); var maxLonClip = Math.min(projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, webMercatorBoundingBox.maxLongitude); var minLatClip = Math.max(-projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, webMercatorBoundingBox.minLatitude); var maxLatClip = Math.min(projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, webMercatorBoundingBox.maxLatitude); var minX = Math.floor((minLonClip + projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH) / tileSize); var maxX = Math.max(0, Math.ceil((maxLonClip + projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH) / tileSize) - 1); var minY = Math.floor((projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH - maxLatClip) / tileSize); var maxY = Math.max(0, Math.ceil((projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH - minLatClip) / tileSize) - 1); return new boundingBox_1.BoundingBox(minX, maxX, minY, maxY); }; TileBoundingBoxUtils.determinePositionAndScale = function (geoPackageTileBoundingBox, tileHeight, tileWidth, totalBoundingBox, totalHeight, totalWidth) { var p = {}; var finalTileWidth = totalBoundingBox.maxLongitude - totalBoundingBox.minLongitude; var xoffsetMin = geoPackageTileBoundingBox.minLongitude - totalBoundingBox.minLongitude; var xpercentageMin = xoffsetMin / finalTileWidth; var finalTileHeight = totalBoundingBox.maxLatitude - totalBoundingBox.minLatitude; var yoffsetMax = totalBoundingBox.maxLatitude - geoPackageTileBoundingBox.maxLatitude; var ypercentageMax = yoffsetMax / finalTileHeight; var finalTilePixelsPerUnitWidth = totalWidth / finalTileWidth; var widthInFinalTileUnits = (geoPackageTileBoundingBox.maxLongitude - geoPackageTileBoundingBox.minLongitude) * finalTilePixelsPerUnitWidth; var finalTilePixelsPerUnitHeight = totalHeight / finalTileHeight; var heightInFinalTileUnits = (geoPackageTileBoundingBox.maxLatitude - geoPackageTileBoundingBox.minLatitude) * finalTilePixelsPerUnitHeight; p.yPositionInFinalTileStart = ypercentageMax * totalHeight; p.xPositionInFinalTileStart = xpercentageMin * totalWidth; p.dx = p.xPositionInFinalTileStart; p.dy = p.yPositionInFinalTileStart; p.sx = 0; p.sy = 0; p.dWidth = widthInFinalTileUnits; p.dHeight = heightInFinalTileUnits; p.sWidth = tileWidth; p.sHeight = tileHeight; return p; }; /** * Calculate the bounds in EPSG:3857 coordinates of the tile at the given XYZ * coordinates coordinates and zoom level. * * @param {number} x tile column * @param {number} y tile row * @param {number} zoom zoom level * @param {*} [options] options object * @return {BoundingBox} a bounding box in EPSG:3857 meters */ TileBoundingBoxUtils.getWebMercatorBoundingBoxFromXYZ = function (x, y, zoom, options) { var tilesPerSide = TileBoundingBoxUtils.tilesPerSideWithZoom(zoom); var tileSize = TileBoundingBoxUtils.tileSizeWithTilesPerSide(tilesPerSide); // correct the x number to be between 0 and tilesPerSide while (x < 0) { x = x + tilesPerSide; } while (x >= tilesPerSide) { x = x - tilesPerSide; } var meterBuffer = 0; if (options && options.buffer && options.tileSize) { var pixelBuffer = options.buffer; var metersPerPixel = tileSize / options.tileSize; meterBuffer = metersPerPixel * pixelBuffer; } var minLon = -1 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH + x * tileSize - meterBuffer; var maxLon = -1 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH + (x + 1) * tileSize + meterBuffer; var minLat = projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH - (y + 1) * tileSize - meterBuffer; var maxLat = projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH - y * tileSize + meterBuffer; minLon = Math.max(-1 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, minLon); maxLon = Math.min(projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, maxLon); minLat = Math.max(-1 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, minLat); maxLat = Math.min(projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH, maxLat); return new boundingBox_1.BoundingBox(minLon, maxLon, minLat, maxLat); }; /** * Get the tile size in meters * * @param tilesPerSide tiles per side * * @return meters */ TileBoundingBoxUtils.tileSizeWithTilesPerSide = function (tilesPerSide) { return (2 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH) / tilesPerSide; }; TileBoundingBoxUtils.intersects = function (boundingBoxA, boundingBoxB) { return TileBoundingBoxUtils.intersection(boundingBoxA, boundingBoxB) != null; }; TileBoundingBoxUtils.intersection = function (boundingBoxA, boundingBoxB) { var x1 = Math.max(boundingBoxA.minLongitude, boundingBoxB.minLongitude); var y1 = Math.max(boundingBoxA.minLatitude, boundingBoxB.minLatitude); var x2 = Math.min(boundingBoxA.maxLongitude, boundingBoxB.maxLongitude); var y2 = Math.min(boundingBoxA.maxLatitude, boundingBoxB.maxLatitude); if (x1 > x2 || y1 > y2) { return null; } return new boundingBox_1.BoundingBox(x1, x2, y1, y2); }; /** * Get the tiles per side, width and height, at the zoom level * * @param zoom zoom level * * @return tiles per side */ TileBoundingBoxUtils.tilesPerSideWithZoom = function (zoom) { return 1 << zoom; }; /** * Get the tile grid * @param {BoundingBox} totalBoundingBox web mercator total bounding box * @param {Number} matrixWidth matrix width * @param {Number} matrixHeight matrix height * @param {BoundingBox} boundingBox bounding box * * @return tile grid */ TileBoundingBoxUtils.getTileGridWithTotalBoundingBox = function (totalBoundingBox, matrixWidth, matrixHeight, boundingBox) { var minColumn = TileBoundingBoxUtils.getTileColumnWithTotalBoundingBox(totalBoundingBox, matrixWidth, boundingBox.minLongitude); var maxColumn = TileBoundingBoxUtils.getTileColumnWithTotalBoundingBox(totalBoundingBox, matrixWidth, boundingBox.maxLongitude); if (minColumn < matrixWidth && maxColumn >= 0) { if (minColumn < 0) { minColumn = 0; } if (maxColumn >= matrixWidth) { maxColumn = matrixWidth - 1; } } var maxRow = TileBoundingBoxUtils.getRowWithTotalBoundingBox(totalBoundingBox, matrixHeight, boundingBox.minLatitude); var minRow = TileBoundingBoxUtils.getRowWithTotalBoundingBox(totalBoundingBox, matrixHeight, boundingBox.maxLatitude); if (minRow < matrixHeight && maxRow >= 0) { if (minRow < 0) { minRow = 0; } if (maxRow >= matrixHeight) { maxRow = matrixHeight - 1; } } return new tileGrid_1.TileGrid(minColumn, maxColumn, minRow, maxRow); }; /** * Get the tile column of the longitude in degrees * * @param {BoundingBox} webMercatorTotalBox web mercator total bounding box * @param {Number} matrixWidth matrix width * @param {Number} longitude longitude * @param {Boolean} [max] * * @return tile column */ TileBoundingBoxUtils.getTileColumnWithTotalBoundingBox = function (webMercatorTotalBox, matrixWidth, longitude) { var minX = webMercatorTotalBox.minLongitude; var maxX = webMercatorTotalBox.maxLongitude; var tileId; if (longitude < minX) { tileId = -1; } else if (longitude >= maxX) { tileId = matrixWidth; } else { var matrixWidthMeters = maxX - minX; var tileWidth = matrixWidthMeters / matrixWidth; var tileIdDouble = (longitude - minX) / tileWidth; tileId = ~~tileIdDouble; } return tileId; }; /** * Get the tile row of the latitude in degrees * * @param {BoundingBox} webMercatorTotalBox web mercator total bounding box * @param {Number} matrixHeight matrix height * @param {Number} latitude latitude * @param {Boolean} [max] * @return tile row */ TileBoundingBoxUtils.getRowWithTotalBoundingBox = function (webMercatorTotalBox, matrixHeight, latitude) { var minY = webMercatorTotalBox.minLatitude; var maxY = webMercatorTotalBox.maxLatitude; var tileId; if (latitude < minY) { tileId = matrixHeight; } else if (latitude >= maxY) { tileId = -1; } else { var matrixHeightMeters = maxY - minY; var tileHeight = matrixHeightMeters / matrixHeight; var tileIdDouble = (maxY - latitude) / tileHeight; tileId = ~~tileIdDouble; } return tileId; }; /** * Get the web mercator bounding box of the tile column and row in the tile * matrix using the total bounding box * * @param {BoundingBox} box web mercator total bounding box * @param {TileMatrix} tileMatrix tile matrix * @param {Number} tileColumn tile column * @param {Number} tileRow tile row * * @return web mercator bounding box */ TileBoundingBoxUtils.getTileBoundingBox = function (box, tileMatrix, tileColumn, tileRow) { var tileMatrixWidth = tileMatrix.matrix_width; var tileMatrixHeight = tileMatrix.matrix_height; var tileGrid = new tileGrid_1.TileGrid(tileColumn, tileColumn, tileRow, tileRow); var matrixMinX = box.minLongitude; var matrixMaxX = box.maxLongitude; var matrixWidth = matrixMaxX - matrixMinX; var tileWidth = matrixWidth / tileMatrixWidth; // Find the longitude range var minLon = matrixMinX + tileWidth * tileGrid.min_x; var maxLon = minLon + tileWidth * (tileGrid.max_x + 1 - tileGrid.min_x); // Get the tile height var matrixMinY = box.minLatitude; var matrixMaxY = box.maxLatitude; var matrixHeight = matrixMaxY - matrixMinY; var tileHeight = matrixHeight / tileMatrixHeight; // Find the latitude range var maxLat = matrixMaxY - tileHeight * tileGrid.min_y; var minLat = maxLat - tileHeight * (tileGrid.max_y + 1 - tileGrid.min_y); return new boundingBox_1.BoundingBox(minLon, maxLon, minLat, maxLat); }; TileBoundingBoxUtils.getTileGridBoundingBox = function (matrixSetBoundingBox, tileMatrixWidth, tileMatrixHeight, tileGrid) { // Get the tile width var matrixMinX = matrixSetBoundingBox.minLongitude; var matrixWidth = matrixSetBoundingBox.width; var tileWidth = matrixWidth / tileMatrixWidth; // Find the longitude range var minLon = matrixMinX + tileWidth * tileGrid.min_x; var maxLon = minLon + tileWidth * (tileGrid.max_x + 1 - tileGrid.min_x); // Get the tile height var matrixMaxY = matrixSetBoundingBox.maxLatitude; var matrixHeight = matrixSetBoundingBox.height; var tileHeight = matrixHeight / tileMatrixHeight; // Find the latitude range var maxLat = matrixMaxY - tileHeight * tileGrid.min_y; var minLat = maxLat - tileHeight * (tileGrid.max_y + 1 - tileGrid.min_y); return new boundingBox_1.BoundingBox(minLon, maxLon, minLat, maxLat); }; TileBoundingBoxUtils.getXPixel = function (width, boundingBox, longitude) { return (longitude - boundingBox.minLongitude) / boundingBox.width * width; }; TileBoundingBoxUtils.getLongitudeFromPixel = function (width, boundingBox, tileBoundingBox, pixel) { return (pixel / width) * tileBoundingBox.width + boundingBox.minLongitude; }; TileBoundingBoxUtils.getYPixel = function (height, boundingBox, latitude) { return ((boundingBox.maxLatitude - latitude) / boundingBox.height) * height; }; TileBoundingBoxUtils.getLatitudeFromPixel = function (height, boundingBox, tileBoundingBox, pixel) { return boundingBox.maxLatitude - ((pixel / height) * tileBoundingBox.height); }; /** * Get the tile size in meters * @param tilesPerSide tiles per side * @return {Number} tile size */ TileBoundingBoxUtils.tileSize = function (tilesPerSide) { return (2 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH) / tilesPerSide; }; /** * Get the zoom level from the tile size in meters * @param tileSize tile size in meters * @return {Number} zoom level * @since 1.2.0 */ TileBoundingBoxUtils.zoomLevelOfTileSize = function (tileSize) { var tilesPerSide = (2 * projectionConstants_1.ProjectionConstants.WEB_MERCATOR_HALF_WORLD_WIDTH) / tileSize; return Math.log(tilesPerSide) / Math.log(2); }; /** * Get the tile width in degrees * @param tilesPerSide tiles per side * @return {Number} tile width degrees */ TileBoundingBoxUtils.tileWidthDegrees = function (tilesPerSide) { return 360.0 / tilesPerSide; }; /** * Get the tile height in degrees * @param tilesPerSide tiles per side * @return {Number} tile height degrees */ TileBoundingBoxUtils.prototype.statictileHeightDegrees = function (tilesPerSide) { return 180.0 / tilesPerSide; }; /** * Get the tiles per side, width and height, at the zoom level * @param zoom zoom level * @return {Number} tiles per side */ TileBoundingBoxUtils.tilesPerSide = function (zoom) { return Math.pow(2, zoom); }; /** * Get the tile size in meters at the zoom level * @param zoom zoom level * @return {Number} tile size in meters * @since 2.0.0 */ TileBoundingBoxUtils.tileSizeWithZoom = function (zoom) { var tilesPerSide = this.tilesPerSide(zoom); return this.tileSize(tilesPerSide); }; /** * Get the tolerance distance in meters for the zoom level and pixels length * @param zoom zoom level * @param pixels pixel length * @return {Number} tolerance distance in meters * @since 2.0.0 */ TileBoundingBoxUtils.toleranceDistance = function (zoom, pixels) { var tileSize = this.tileSizeWithZoom(zoom); return tileSize / pixels; }; /** * Get the tolerance distance in meters for the zoom level and pixels length * @param zoom zoom level * @param pixelWidth pixel width * @param pixelHeight pixel height * @return {Number} tolerance distance in meters * @since 2.0.0 */ TileBoundingBoxUtils.toleranceDistanceWidthAndHeight = function (zoom, pixelWidth, pixelHeight) { return this.toleranceDistance(zoom, Math.max(pixelWidth, pixelHeight)); }; TileBoundingBoxUtils.getFloatRoundedRectangle = function (width, height, boundingBox, boundingBoxSection) { var left = Math.round(TileBoundingBoxUtils.getXPixel(width, boundingBox, boundingBoxSection.minLongitude)); var right = Math.round(TileBoundingBoxUtils.getXPixel(width, boundingBox, boundingBoxSection.maxLongitude)); var top = Math.round(TileBoundingBoxUtils.getYPixel(height, boundingBox, boundingBoxSection.maxLatitude)); var bottom = Math.round(TileBoundingBoxUtils.getYPixel(height, boundingBox, boundingBoxSection.minLatitude)); var isValid = left < right && top < bottom; return { left: left, right: right, bottom: bottom, top: top, isValid: isValid }; }; return TileBoundingBoxUtils; }()); exports.TileBoundingBoxUtils = TileBoundingBoxUtils; //# sourceMappingURL=tileBoundingBoxUtils.js.map