Merge pull request #12464 from mike-000/zDirection

Make zDirection option available for all tile sources
This commit is contained in:
Andreas Hocevar
2021-07-09 23:04:42 +02:00
committed by GitHub
21 changed files with 216 additions and 38 deletions

View File

@@ -60,11 +60,26 @@ export function includes(arr, obj) {
}
/**
* @param {Array<number>} arr Array.
* {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution} can use a function
* of this type to determine which nearest resolution to use.
*
* This function takes a `{number}` representing a value between two array entries,
* a `{number}` representing the value of the nearest higher entry and
* a `{number}` representing the value of the nearest lower entry
* as arguments and returns a `{number}`. If a negative number or zero is returned
* the lower value will be used, if a positive number is returned the higher value
* will be used.
* @typedef {function(number, number, number): number} NearestDirectionFunction
* @api
*/
/**
* @param {Array<number>} arr Array in desccending order.
* @param {number} target Target.
* @param {number} direction 0 means return the nearest, > 0
* means return the largest nearest, < 0 means return the
* smallest nearest.
* @param {number|NearestDirectionFunction} direction
* 0 means return the nearest,
* > 0 means return the largest nearest,
* < 0 means return the smallest nearest.
* @return {number} Index.
*/
export function linearFindNearest(arr, target, direction) {
@@ -92,7 +107,13 @@ export function linearFindNearest(arr, target, direction) {
if (arr[i] == target) {
return i;
} else if (arr[i] < target) {
if (arr[i - 1] - target < target - arr[i]) {
if (typeof direction === 'function') {
if (direction(target, arr[i - 1], arr[i]) > 0) {
return i - 1;
} else {
return i;
}
} else if (arr[i - 1] - target < target - arr[i]) {
return i - 1;
} else {
return i;

View File

@@ -66,6 +66,9 @@ const TOS_ATTRIBUTION =
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -129,6 +132,7 @@ class BingMaps extends TileImage {
tilePixelRatio: hidpi ? 2 : 1,
wrapX: options.wrapX !== undefined ? options.wrapX : true,
transition: options.transition,
zDirection: options.zDirection,
});
/**

View File

@@ -29,6 +29,9 @@ import {assign} from '../obj.js';
* @property {string} [account] Username as used to access public Carto dashboard at https://{username}.carto.com/.
* @property {number} [transition=250] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -56,6 +59,7 @@ class CartoDB extends XYZ {
projection: options.projection,
transition: options.transition,
wrapX: options.wrapX,
zDirection: options.zDirection,
});
/**

View File

@@ -43,10 +43,9 @@ import {toSize} from '../size.js';
* @property {string} [url] Base URL of the IIIF Image service.
* This should be the same as the IIIF Image ID.
* @property {import("../format/IIIFInfo.js").Versions} [version=Versions.VERSION2] Service's IIIF Image API version.
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
function formatPercentage(percentage) {
@@ -346,7 +345,7 @@ class IIIF extends TileImage {
});
/**
* @type {number}
* @type {number|import("../array.js").NearestDirectionFunction}
*/
this.zDirection = options.zDirection;
}

View File

@@ -39,6 +39,9 @@ export const ATTRIBUTION =
* @property {string} [url='https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'] URL template.
* Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -81,6 +84,7 @@ class OSM extends XYZ {
transition: options.transition,
url: url,
wrapX: options.wrapX,
zDirection: options.zDirection,
});
}
}

View File

@@ -104,6 +104,9 @@ const ProviderConfig = {
* To disable the opacity transition, pass `transition: 0`.
* @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -145,6 +148,7 @@ class Stamen extends XYZ {
transition: options.transition,
url: url,
wrapX: options.wrapX,
zDirection: options.zDirection,
});
}
}

View File

@@ -28,7 +28,7 @@ import {scale as scaleSize, toSize} from '../size.js';
* @property {boolean} [wrapX=true] WrapX.
* @property {number} [transition] Transition.
* @property {string} [key] Key.
* @property {number} [zDirection=0] ZDirection.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
*/
/**
@@ -108,7 +108,7 @@ class TileSource extends Source {
* by a renderer if the views resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @type {number}
* @type {number|import("../array.js").NearestDirectionFunction}
*/
this.zDirection = options.zDirection ? options.zDirection : 0;
}

View File

@@ -51,6 +51,9 @@ import {hash as tileCoordHash} from '../tilecoord.js';
* transition, pass `transition: 0`.
* @property {Array<string>} [urls] ArcGIS Rest service urls. Use this instead of `url` when the ArcGIS
* Service supports multiple urls for export requests.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -82,6 +85,7 @@ class TileArcGISRest extends TileImage {
urls: options.urls,
wrapX: options.wrapX !== undefined ? options.wrapX : true,
transition: options.transition,
zDirection: options.zDirection,
});
/**

View File

@@ -11,11 +11,10 @@ import {toSize} from '../size.js';
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Optional projection.
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [zDirection=0] Set to `1` when debugging `VectorTile` sources with
* a default configuration. Indicates which resolution should be used by a renderer if
* the view resolution does not match any resolution of the tile source. If 0, the nearest
* resolution will be used. If 1, the nearest lower resolution will be used. If -1, the
* nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Set to `1` when debugging `VectorTile` sources with a default configuration.
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
* @property {string} [template='z:{z} x:{x} y:{y}'] Template for labeling the tiles.
* Should include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.
*/

View File

@@ -53,10 +53,9 @@ import {getUid} from '../util.js';
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {string} [key] Optional tile key for proper cache fetching
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**

View File

@@ -59,6 +59,9 @@ import {jsonp as requestJSONP} from '../net.js';
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -82,6 +85,7 @@ class TileJSON extends TileImage {
tileLoadFunction: options.tileLoadFunction,
wrapX: options.wrapX !== undefined ? options.wrapX : true,
transition: options.transition,
zDirection: options.zDirection,
});
/**

View File

@@ -69,6 +69,9 @@ import {hash as tileCoordHash} from '../tilecoord.js';
* but they will be wrapped horizontally to render multiple worlds.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -103,6 +106,7 @@ class TileWMS extends TileImage {
urls: options.urls,
wrapX: options.wrapX !== undefined ? options.wrapX : true,
transition: options.transition,
zDirection: options.zDirection,
});
/**

View File

@@ -268,6 +268,9 @@ export class CustomTile extends Tile {
* If not provided, `url` must be configured.
* @property {string} [url] TileJSON endpoint that provides the configuration for this source.
* Request will be made through JSONP. If not provided, `tileJSON` must be configured.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -283,6 +286,7 @@ class UTFGrid extends TileSource {
super({
projection: getProjection('EPSG:3857'),
state: SourceState.LOADING,
zDirection: options.zDirection,
});
/**

View File

@@ -25,7 +25,7 @@ import {getUid} from '../util.js';
* @property {boolean} [wrapX=true] WrapX.
* @property {number} [transition] Transition.
* @property {string} [key] Key.
* @property {number} [zDirection=0] ZDirection.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection.
*/
/**

View File

@@ -83,10 +83,9 @@ import {toSize} from '../size.js';
* When set to `false`, only one world
* will be rendered. When set to `true`, tiles will be wrapped horizontally to
* render multiple worlds.
* @property {number} [zDirection=1] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=1]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**

View File

@@ -54,6 +54,9 @@ import {find, findIndex, includes} from '../array.js';
* @property {boolean} [wrapX=false] Whether to wrap the world horizontally.
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -99,6 +102,7 @@ class WMTS extends TileImage {
urls: urls,
wrapX: options.wrapX !== undefined ? options.wrapX : false,
transition: options.transition,
zDirection: options.zDirection,
});
/**

View File

@@ -44,10 +44,9 @@ import {createXYZ, extentFromProjection} from '../tilegrid.js';
* @property {boolean} [wrapX=true] Whether to wrap the world horizontally.
* @property {number} [transition=250] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number} [zDirection=0] Indicate which resolution should be used
* by a renderer if the view resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**

View File

@@ -113,10 +113,9 @@ export class CustomTile extends ImageTile {
* @property {number} [transition] Duration of the opacity transition for rendering.
* To disable the opacity transition, pass `transition: 0`.
* @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
* @property {number} [zDirection] Indicate which resolution should be used
* by a renderer if the views resolution does not match any resolution of the tile source.
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
* will be used. If -1, the nearest higher resolution will be used.
* @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0]
* Choose whether to use tiles with a higher or lower zoom level when between integer
* zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.
*/
/**
@@ -272,7 +271,7 @@ class Zoomify extends TileImage {
});
/**
* @type {number}
* @type {number|import("../array.js").NearestDirectionFunction}
*/
this.zDirection = options.zDirection;

View File

@@ -634,9 +634,18 @@ class TileGrid {
/**
* @param {number} resolution Resolution.
* @param {number} [opt_direction] If 0, the nearest resolution will be used.
* If 1, the nearest lower resolution will be used. If -1, the nearest
* higher resolution will be used. Default is 0.
* @param {number|import("../array.js").NearestDirectionFunction} [opt_direction]
* If 0, the nearest resolution will be used.
* If 1, the nearest higher resolution (lower Z) will be used. If -1, the
* nearest lower resolution (higher Z) will be used. Default is 0.
* Use a {@link module:ol/array~NearestDirectionFunction} for more precise control.
*
* For example to change tile Z at the midpoint of zoom levels
* ```js
* function(value, high, low) {
* return value - low * Math.sqrt(high / low);
* }
* ```
* @return {number} Z.
* @api
*/

View File

@@ -475,34 +475,94 @@ describe('ol/array.js', function () {
expect(linearFindNearest(arr, 1000, 1)).to.eql(0);
expect(linearFindNearest(arr, 1000, -1)).to.eql(0);
expect(linearFindNearest(arr, 999, -1)).to.eql(1);
expect(
linearFindNearest(arr, 901, function (value, high, low) {
return value - (low + (high - low) * 0.8);
})
).to.eql(0);
expect(
linearFindNearest(arr, 900, function (value, high, low) {
return value - (low + (high - low) * 0.8);
})
).to.eql(1);
expect(linearFindNearest(arr, 900, 0)).to.eql(0);
expect(linearFindNearest(arr, 900, 1)).to.eql(0);
expect(linearFindNearest(arr, 900, -1)).to.eql(1);
expect(linearFindNearest(arr, 751, 0)).to.eql(0);
expect(linearFindNearest(arr, 750, 0)).to.eql(1);
expect(linearFindNearest(arr, 750, 1)).to.eql(0);
expect(linearFindNearest(arr, 750, -1)).to.eql(1);
expect(
linearFindNearest(arr, 551, function (value, high, low) {
return value - (low + (high - low) * 0.1);
})
).to.eql(0);
expect(
linearFindNearest(arr, 550, function (value, high, low) {
return value - (low + (high - low) * 0.1);
})
).to.eql(1);
expect(linearFindNearest(arr, 550, 0)).to.eql(1);
expect(linearFindNearest(arr, 550, 1)).to.eql(0);
expect(linearFindNearest(arr, 550, -1)).to.eql(1);
expect(linearFindNearest(arr, 501, 1)).to.eql(0);
expect(linearFindNearest(arr, 500, 0)).to.eql(1);
expect(linearFindNearest(arr, 500, 1)).to.eql(1);
expect(linearFindNearest(arr, 500, -1)).to.eql(1);
expect(linearFindNearest(arr, 499, -1)).to.eql(2);
expect(
linearFindNearest(arr, 451, function (value, high, low) {
return value - (low + (high - low) * 0.875);
})
).to.eql(1);
expect(
linearFindNearest(arr, 450, function (value, high, low) {
return value - (low + (high - low) * 0.875);
})
).to.eql(2);
expect(linearFindNearest(arr, 450, 0)).to.eql(1);
expect(linearFindNearest(arr, 450, 1)).to.eql(1);
expect(linearFindNearest(arr, 450, -1)).to.eql(2);
expect(linearFindNearest(arr, 301, 0)).to.eql(1);
expect(linearFindNearest(arr, 300, 0)).to.eql(2);
expect(linearFindNearest(arr, 300, 1)).to.eql(1);
expect(linearFindNearest(arr, 300, -1)).to.eql(2);
expect(
linearFindNearest(arr, 201, function (value, high, low) {
return value - (low + (high - low) * 0.25);
})
).to.eql(1);
expect(
linearFindNearest(arr, 200, function (value, high, low) {
return value - (low + (high - low) * 0.25);
})
).to.eql(2);
expect(linearFindNearest(arr, 200, 0)).to.eql(2);
expect(linearFindNearest(arr, 200, 1)).to.eql(1);
expect(linearFindNearest(arr, 200, -1)).to.eql(2);
expect(linearFindNearest(arr, 101, 1)).to.eql(1);
expect(linearFindNearest(arr, 100, 0)).to.eql(2);
expect(linearFindNearest(arr, 100, 1)).to.eql(2);
expect(linearFindNearest(arr, 100, -1)).to.eql(2);

View File

@@ -1177,6 +1177,64 @@ describe('ol/tilegrid/TileGrid.js', function () {
});
});
describe('getZForResolution (NearestDirectionFunction)', function () {
it('returns the expected z value', function () {
const tileGrid = new TileGrid({
resolutions: resolutions,
origin: origin,
tileSize: tileSize,
});
expect(
tileGrid.getZForResolution(626, function (value, high, low) {
return value - (low + (high - low) * 0.25);
})
).to.eql(0);
expect(
tileGrid.getZForResolution(625, function (value, high, low) {
return value - (low + (high - low) * 0.25);
})
).to.eql(1);
expect(
tileGrid.getZForResolution(476, function (value, high, low) {
return value - (low + (high - low) * 0.9);
})
).to.eql(1);
expect(
tileGrid.getZForResolution(475, function (value, high, low) {
return value - (low + (high - low) * 0.9);
})
).to.eql(2);
expect(
tileGrid.getZForResolution(201, function (value, high, low) {
return value - (low + (high - low) * 0.666666667);
})
).to.eql(2);
expect(
tileGrid.getZForResolution(200, function (value, high, low) {
return value - (low + (high - low) * 0.666666667);
})
).to.eql(3);
expect(
tileGrid.getZForResolution(126, function (value, high, low) {
return value - (low + (high - low) * 0.166666667);
})
).to.eql(2);
expect(
tileGrid.getZForResolution(125, function (value, high, low) {
return value - (low + (high - low) * 0.166666667);
})
).to.eql(3);
});
});
describe('getTileRangeForTileCoordAndZ()', function () {
const tileGrid = createForExtent(
getProjection('EPSG:3857').getExtent(),