Explicit data tile size

This commit is contained in:
Tim Schaub
2022-05-06 12:32:48 -06:00
parent b29ad01c7a
commit 38b48bd341
13 changed files with 260 additions and 59 deletions
+62 -4
View File
@@ -11,6 +11,7 @@ import {createXYZ, extentFromProjection} from '../tilegrid.js';
import {getKeyZXY} from '../tilecoord.js';
import {getUid} from '../util.js';
import {toPromise} from '../functions.js';
import {toSize} from '../size.js';
/**
* Data tile loading function. The function is called with z, x, and y tile coordinates and
@@ -26,7 +27,8 @@ import {toPromise} from '../functions.js';
* @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.
* @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided.
* @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided.
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The pixel width and height of the tiles.
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The pixel width and height of the source tiles.
* This may be different than the rendered pixel size if a `tileGrid` is provided.
* @property {number} [gutter=0] The size in pixels of the gutter around data tiles to ignore.
* This allows artifacts of rendering at tile edges to be ignored.
* Supported data should be wider and taller than the tile size by a value of `2 x gutter`.
@@ -35,7 +37,8 @@ import {toPromise} from '../functions.js';
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
* @property {boolean} [opaque=false] Whether the layer is opaque.
* @property {import("./State.js").default} [state] The source state.
* @property {number} [tilePixelRatio] Tile pixel ratio.
* @property {number} [tilePixelRatio] Deprecated. To have tiles scaled, pass a `tileSize` representing
* the source tile size and a `tileGrid` with the desired rendered tile size.
* @property {boolean} [wrapX=false] Render tiles beyond the antimeridian.
* @property {number} [transition] Transition time when fading in new tiles (in miliseconds).
* @property {number} [bandCount=4] Number of bands represented in the data.
@@ -89,6 +92,25 @@ class DataTileSource extends TileSource {
*/
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
/**
* @private
* @type {import('../size.js').Size|null}
*/
this.tileSize_ = options.tileSize ? toSize(options.tileSize) : null;
if (!this.tileSize_ && options.tilePixelRatio && tileGrid) {
const renderTileSize = toSize(tileGrid.getTileSize(0));
this.tileSize_ = [
renderTileSize[0] * options.tilePixelRatio,
renderTileSize[1] * options.tilePixelRatio,
];
}
/**
* @private
* @type {Array<import('../size.js').Size>|null}
*/
this.tileSizes_ = null;
/**
* @private
* @type {!Object<string, boolean>}
@@ -108,6 +130,34 @@ class DataTileSource extends TileSource {
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
}
/**
* Set the source tile sizes. The length of the array is expected to match the number of
* levels in the tile grid.
* @protected
* @param {Array<import('../size.js').Size>} tileSizes An array of tile sizes.
*/
setTileSizes(tileSizes) {
this.tileSizes_ = tileSizes;
}
/**
* Get the source tile size at the given zoom level. This may be different than the rendered tile
* size.
* @protected
* @param {number} z Tile zoom level.
* @return {import('../size.js').Size} The source tile size.
*/
getTileSize(z) {
if (this.tileSizes_) {
return this.tileSizes_[z];
}
if (this.tileSize_) {
return this.tileSize_;
}
const tileGrid = this.getTileGrid();
return tileGrid ? toSize(tileGrid.getTileSize(z)) : [256, 256];
}
/**
* @param {import("../proj/Projection.js").default} projection Projection.
* @return {number} Gutter.
@@ -133,6 +183,7 @@ class DataTileSource extends TileSource {
* @return {!DataTile} Tile.
*/
getTile(z, x, y, pixelRatio, projection) {
const size = this.getTileSize(z);
const tileCoordKey = getKeyZXY(z, x, y);
if (this.tileCache.containsKey(tileCoordKey)) {
return this.tileCache.get(tileCoordKey);
@@ -146,9 +197,16 @@ class DataTileSource extends TileSource {
});
}
const tile = new DataTile(
assign({tileCoord: [z, x, y], loader: loader}, this.tileOptions)
const options = assign(
{
tileCoord: [z, x, y],
loader: loader,
size: size,
},
this.tileOptions
);
const tile = new DataTile(options);
tile.key = this.getKey();
tile.addEventListener(EventType.CHANGE, this.handleTileChange_);
+47 -23
View File
@@ -13,7 +13,6 @@ import {
} from '../proj.js';
import {clamp} from '../math.js';
import {getCenter, getIntersection} from '../extent.js';
import {toSize} from '../size.js';
import {fromCode as unitsFromCode} from '../proj/Units.js';
/**
@@ -112,15 +111,17 @@ function getOrigin(image) {
* the width of the image is compared with the reference image.
* @param {GeoTIFFImage} image The image.
* @param {GeoTIFFImage} referenceImage The reference image.
* @return {number} The image resolution.
* @return {Array<number>} The map x and y units per pixel.
*/
function getResolution(image, referenceImage) {
function getResolutions(image, referenceImage) {
try {
return image.getResolution(referenceImage)[0];
return image.getResolution(referenceImage);
} catch (_) {
return (
referenceImage.fileDirectory.ImageWidth / image.fileDirectory.ImageWidth
);
return [
referenceImage.fileDirectory.ImageWidth / image.fileDirectory.ImageWidth,
referenceImage.fileDirectory.ImageHeight /
image.fileDirectory.ImageHeight,
];
}
}
@@ -449,7 +450,8 @@ class GeoTIFFSource extends DataTile {
configure_(sources) {
let extent;
let origin;
let tileSizes;
let commonRenderTileSizes;
let commonSourceTileSizes;
let resolutions;
const samplesPerPixel = new Array(sources.length);
const nodataValues = new Array(sources.length);
@@ -464,6 +466,7 @@ class GeoTIFFSource extends DataTile {
let sourceExtent;
let sourceOrigin;
const sourceTileSizes = new Array(imageCount);
const renderTileSizes = new Array(imageCount);
const sourceResolutions = new Array(imageCount);
nodataValues[sourceIndex] = new Array(imageCount);
@@ -490,8 +493,17 @@ class GeoTIFFSource extends DataTile {
sourceOrigin = getOrigin(image);
}
sourceResolutions[level] = getResolution(image, images[0]);
sourceTileSizes[level] = [image.getTileWidth(), image.getTileHeight()];
const imageResolutions = getResolutions(image, images[0]);
sourceResolutions[level] = imageResolutions[0];
const sourceTileSize = [image.getTileWidth(), image.getTileHeight()];
sourceTileSizes[level] = sourceTileSize;
const aspectRatio = imageResolutions[0] / Math.abs(imageResolutions[1]);
renderTileSizes[level] = [
sourceTileSize[0],
sourceTileSize[1] / aspectRatio,
];
}
if (!extent) {
@@ -531,11 +543,23 @@ class GeoTIFFSource extends DataTile {
);
}
if (!tileSizes) {
tileSizes = sourceTileSizes;
if (!commonRenderTileSizes) {
commonRenderTileSizes = renderTileSizes;
} else {
assertEqual(
tileSizes.slice(minZoom, tileSizes.length),
commonRenderTileSizes.slice(minZoom, commonRenderTileSizes.length),
renderTileSizes,
0,
`Tile size mismatch for source ${sourceIndex}`,
this.viewRejector
);
}
if (!commonSourceTileSizes) {
commonSourceTileSizes = sourceTileSizes;
} else {
assertEqual(
commonSourceTileSizes.slice(minZoom, commonSourceTileSizes.length),
sourceTileSizes,
0,
`Tile size mismatch for source ${sourceIndex}`,
@@ -612,10 +636,11 @@ class GeoTIFFSource extends DataTile {
minZoom: minZoom,
origin: origin,
resolutions: resolutions,
tileSizes: tileSizes,
tileSizes: commonRenderTileSizes,
});
this.tileGrid = tileGrid;
this.setTileSizes(commonSourceTileSizes);
this.setLoader(this.loadTile_.bind(this));
this.setState(State.READY);
@@ -629,8 +654,7 @@ class GeoTIFFSource extends DataTile {
}
loadTile_(z, x, y) {
const size = toSize(this.tileGrid.getTileSize(z));
const sourceTileSize = this.getTileSize(z);
const sourceCount = this.sourceImagery_.length;
const requests = new Array(sourceCount);
const addAlpha = this.addAlpha_;
@@ -642,10 +666,10 @@ class GeoTIFFSource extends DataTile {
const source = sourceInfo[sourceIndex];
const resolutionFactor = this.resolutionFactors_[sourceIndex];
const pixelBounds = [
Math.round(x * (size[0] * resolutionFactor)),
Math.round(y * (size[1] * resolutionFactor)),
Math.round((x + 1) * (size[0] * resolutionFactor)),
Math.round((y + 1) * (size[1] * resolutionFactor)),
Math.round(x * (sourceTileSize[0] * resolutionFactor)),
Math.round(y * (sourceTileSize[1] * resolutionFactor)),
Math.round((x + 1) * (sourceTileSize[0] * resolutionFactor)),
Math.round((y + 1) * (sourceTileSize[1] * resolutionFactor)),
];
const image = this.sourceImagery_[sourceIndex][z];
let samples;
@@ -671,8 +695,8 @@ class GeoTIFFSource extends DataTile {
requests[sourceIndex] = image[this.readMethod_]({
window: pixelBounds,
width: size[0],
height: size[1],
width: sourceTileSize[0],
height: sourceTileSize[1],
samples: samples,
fillValue: fillValue,
pool: getWorkerPool(),
@@ -680,7 +704,7 @@ class GeoTIFFSource extends DataTile {
});
}
const pixelCount = size[0] * size[1];
const pixelCount = sourceTileSize[0] * sourceTileSize[1];
const dataLength = pixelCount * bandCount;
const normalize = this.normalize_;
const metadata = this.metadata_;