From 239487e9f076c57235988fd8895e1424710d3358 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 8 Jul 2022 17:56:44 +0200 Subject: [PATCH] Only create and load tiles within the viewport --- src/ol/extent.js | 50 ++++++++++++++++++++--------- src/ol/renderer/canvas/TileLayer.js | 30 +++++++++++++++++ src/ol/tilegrid/TileGrid.js | 17 ++++++++++ 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/ol/extent.js b/src/ol/extent.js index 67d11ad039..e9ac7aa32b 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -531,6 +531,29 @@ export function getForViewAndSize( size, opt_extent ) { + const [x0, y0, x1, y1, x2, y2, x3, y3] = getRotatedViewport( + center, + resolution, + rotation, + size + ); + return createOrUpdate( + Math.min(x0, x1, x2, x3), + Math.min(y0, y1, y2, y3), + Math.max(x0, x1, x2, x3), + Math.max(y0, y1, y2, y3), + opt_extent + ); +} + +/** + * @param {import("./coordinate.js").Coordinate} center Center. + * @param {number} resolution Resolution. + * @param {number} rotation Rotation. + * @param {import("./size.js").Size} size Size. + * @return {Array} Linear ring representing the viewport. + */ +export function getRotatedViewport(center, resolution, rotation, size) { const dx = (resolution * size[0]) / 2; const dy = (resolution * size[1]) / 2; const cosRotation = Math.cos(rotation); @@ -541,21 +564,18 @@ export function getForViewAndSize( const ySin = dy * sinRotation; const x = center[0]; const y = center[1]; - const x0 = x - xCos + ySin; - const x1 = x - xCos - ySin; - const x2 = x + xCos - ySin; - const x3 = x + xCos + ySin; - const y0 = y - xSin - yCos; - const y1 = y - xSin + yCos; - const y2 = y + xSin + yCos; - const y3 = y + xSin - yCos; - return createOrUpdate( - Math.min(x0, x1, x2, x3), - Math.min(y0, y1, y2, y3), - Math.max(x0, x1, x2, x3), - Math.max(y0, y1, y2, y3), - opt_extent - ); + return [ + x - xCos + ySin, + y - xSin - yCos, + x - xCos - ySin, + y - xSin + yCos, + x + xCos - ySin, + y + xSin + yCos, + x + xCos + ySin, + y + xSin - yCos, + x - xCos + ySin, + y - xSin - yCos, + ]; } /** diff --git a/src/ol/renderer/canvas/TileLayer.js b/src/ol/renderer/canvas/TileLayer.js index 409d8b71b4..c08bd5274a 100644 --- a/src/ol/renderer/canvas/TileLayer.js +++ b/src/ol/renderer/canvas/TileLayer.js @@ -20,6 +20,7 @@ import { equals, getHeight, getIntersection, + getRotatedViewport, getTopLeft, getWidth, intersects, @@ -308,8 +309,22 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { const tmpExtent = this.tmpExtent; const tmpTileRange = this.tmpTileRange_; this.newTiles_ = false; + const viewport = rotation + ? getRotatedViewport( + viewState.center, + resolution, + rotation, + frameState.size + ) + : undefined; for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { + if ( + rotation && + !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport) + ) { + continue; + } const tile = this.getTile(z, x, y, frameState); if (this.isDrawableTile(tile)) { const uid = getUid(this); @@ -709,6 +724,15 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { const wantedTiles = frameState.wantedTiles[tileSourceKey]; const tileQueue = frameState.tileQueue; const minZoom = tileGrid.getMinZoom(); + const rotation = frameState.viewState.rotation; + const viewport = rotation + ? getRotatedViewport( + frameState.viewState.center, + frameState.viewState.resolution, + rotation, + frameState.size + ) + : undefined; let tileCount = 0; let tile, tileRange, tileResolution, x, y, z; for (z = minZoom; z <= currentZ; ++z) { @@ -716,6 +740,12 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { tileResolution = tileGrid.getResolution(z); for (x = tileRange.minX; x <= tileRange.maxX; ++x) { for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + if ( + rotation && + !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport) + ) { + continue; + } if (currentZ - z <= preload) { ++tileCount; tile = tileSource.getTile(z, x, y, pixelRatio, projection); diff --git a/src/ol/tilegrid/TileGrid.js b/src/ol/tilegrid/TileGrid.js index fb5be9a3b5..a4f6f6dde8 100644 --- a/src/ol/tilegrid/TileGrid.js +++ b/src/ol/tilegrid/TileGrid.js @@ -9,6 +9,7 @@ import {assert} from '../asserts.js'; import {ceil, clamp, floor} from '../math.js'; import {createOrUpdate, getTopLeft} from '../extent.js'; import {createOrUpdate as createOrUpdateTileCoord} from '../tilecoord.js'; +import {intersectsLinearRing} from '../geom/flat/intersectsextent.js'; import {isSorted, linearFindNearest} from '../array.js'; import {toSize} from '../size.js'; @@ -656,6 +657,22 @@ class TileGrid { return clamp(z, this.minZoom, this.maxZoom); } + /** + * The tile with the provided tile coordinate intersects the given viewport. + * @param {import('../tilecoord.js').TileCoord} tileCoord Tile coordinate. + * @param {Array} viewport Viewport as returned from {@link module:ol/extent.getRotatedViewport}. + * @return {boolean} The tile with the provided tile coordinate intersects the given viewport. + */ + tileCoordIntersectsViewport(tileCoord, viewport) { + return intersectsLinearRing( + viewport, + 0, + viewport.length, + 2, + this.getTileCoordExtent(tileCoord) + ); + } + /** * @param {!import("../extent.js").Extent} extent Extent for this tile grid. * @private