diff --git a/src/ol/source/ogcTileUtil.js b/src/ol/source/ogcTileUtil.js index ba4eaacb84..f4216d8760 100644 --- a/src/ol/source/ogcTileUtil.js +++ b/src/ol/source/ogcTileUtil.js @@ -165,205 +165,212 @@ export function getVectorTileUrlTemplate(links, mediaType) { return tileUrlTemplate; } +/** + * @param {SourceInfo} sourceInfo The source info. + * @param {TileMatrixSet} tileMatrixSet Tile matrix set. + * @param {string} tileUrlTemplate Tile URL template. + * @param {Array} [tileMatrixSetLimits] Tile matrix set limits. + * @return {TileSetInfo} Tile set info. + */ +function parseTileMatrixSet( + sourceInfo, + tileMatrixSet, + tileUrlTemplate, + tileMatrixSetLimits +) { + let projection = sourceInfo.projection; + if (!projection) { + projection = getProjection(tileMatrixSet.crs); + if (!projection) { + throw new Error(`Unsupported CRS: ${tileMatrixSet.crs}`); + } + } + const backwards = projection.getAxisOrientation().substr(0, 2) !== 'en'; + + const matrices = tileMatrixSet.tileMatrices; + + /** + * @type {Object} + */ + const matrixLookup = {}; + for (let i = 0; i < matrices.length; ++i) { + const matrix = matrices[i]; + matrixLookup[matrix.id] = matrix; + } + + /** + * @type {Object} + */ + const limitLookup = {}; + + /** + * @type {Array} + */ + const matrixIds = []; + + if (tileMatrixSetLimits) { + for (let i = 0; i < tileMatrixSetLimits.length; ++i) { + const limit = tileMatrixSetLimits[i]; + const id = limit.tileMatrix; + matrixIds.push(id); + limitLookup[id] = limit; + } + } else { + for (let i = 0; i < matrices.length; ++i) { + const id = matrices[i].id; + matrixIds.push(id); + } + } + + const length = matrixIds.length; + const origins = new Array(length); + const resolutions = new Array(length); + const sizes = new Array(length); + const tileSizes = new Array(length); + const extent = [-Infinity, -Infinity, Infinity, Infinity]; + + for (let i = 0; i < length; ++i) { + const id = matrixIds[i]; + const matrix = matrixLookup[id]; + const origin = matrix.pointOfOrigin; + if (backwards) { + origins[i] = [origin[1], origin[0]]; + } else { + origins[i] = origin; + } + resolutions[i] = matrix.cellSize; + sizes[i] = [matrix.matrixWidth, matrix.matrixHeight]; + tileSizes[i] = [matrix.tileWidth, matrix.tileHeight]; + const limit = limitLookup[id]; + if (limit) { + const tileMapWidth = matrix.cellSize * matrix.tileWidth; + const minX = origins[i][0] + limit.minTileCol * tileMapWidth; + const maxX = origins[i][0] + (limit.maxTileCol + 1) * tileMapWidth; + + const tileMapHeight = matrix.cellSize * matrix.tileHeight; + const upsideDown = matrix.cornerOfOrigin === BOTTOM_LEFT_ORIGIN; + + let minY; + let maxY; + if (upsideDown) { + minY = origins[i][1] + limit.minTileRow * tileMapHeight; + maxY = origins[i][1] + (limit.maxTileRow + 1) * tileMapHeight; + } else { + minY = origins[i][1] - (limit.maxTileRow + 1) * tileMapHeight; + maxY = origins[i][1] - limit.minTileRow * tileMapHeight; + } + + intersectExtents(extent, [minX, minY, maxX, maxY], extent); + } + } + + const tileGrid = new TileGrid({ + origins: origins, + resolutions: resolutions, + sizes: sizes, + tileSizes: tileSizes, + extent: tileMatrixSetLimits ? extent : undefined, + }); + + const context = sourceInfo.context; + const base = sourceInfo.url; + + function tileUrlFunction(tileCoord, pixelRatio, projection) { + if (!tileCoord) { + return undefined; + } + + const id = matrixIds[tileCoord[0]]; + const matrix = matrixLookup[id]; + const upsideDown = matrix.cornerOfOrigin === BOTTOM_LEFT_ORIGIN; + + const localContext = { + tileMatrix: id, + tileCol: tileCoord[1], + tileRow: upsideDown ? -tileCoord[2] - 1 : tileCoord[2], + }; + + if (tileMatrixSetLimits) { + const limit = limitLookup[matrix.id]; + if ( + localContext.tileCol < limit.minTileCol || + localContext.tileCol > limit.maxTileCol || + localContext.tileRow < limit.minTileRow || + localContext.tileRow > limit.maxTileRow + ) { + return undefined; + } + } + + assign(localContext, context); + + const url = tileUrlTemplate.replace(/\{(\w+?)\}/g, function (m, p) { + return localContext[p]; + }); + + return resolveUrl(base, url); + } + + return { + grid: tileGrid, + urlTemplate: tileUrlTemplate, + urlFunction: tileUrlFunction, + }; +} + +/** + * @param {SourceInfo} sourceInfo The source info. + * @param {TileSet} tileSet Tile set. + * @return {TileSetInfo|Promise} Tile set info. + */ +function parseTileSetMetadata(sourceInfo, tileSet) { + const tileMatrixSetLimits = tileSet.tileMatrixSetLimits; + let tileUrlTemplate; + + if (tileSet.dataType === TileType.MAP) { + tileUrlTemplate = getMapTileUrlTemplate( + tileSet.links, + sourceInfo.mediaType + ); + } else if (tileSet.dataType === TileType.VECTOR) { + tileUrlTemplate = getVectorTileUrlTemplate( + tileSet.links, + sourceInfo.mediaType + ); + } else { + throw new Error('Expected tileset data type to be "map" or "vector"'); + } + + if (tileSet.tileMatrixSet) { + return parseTileMatrixSet( + sourceInfo, + tileSet.tileMatrixSet, + tileUrlTemplate, + tileMatrixSetLimits + ); + } + + if (!tileSet.tileMatrixSetDefinition) { + throw new Error('Expected tileMatrixSetDefinition or tileMatrixSet'); + } + + const url = resolveUrl(sourceInfo.url, tileSet.tileMatrixSetDefinition); + return getJSON(url).then(function (tileMatrixSet) { + return parseTileMatrixSet( + sourceInfo, + tileMatrixSet, + tileUrlTemplate, + tileMatrixSetLimits + ); + }); +} + /** * @param {SourceInfo} sourceInfo Source info. * @return {Promise} Tile set info. */ export function getTileSetInfo(sourceInfo) { - /** - * @param {TileMatrixSet} tileMatrixSet Tile matrix set. - * @param {string} tileUrlTemplate Tile URL template. - * @param {Array} [tileMatrixSetLimits] Tile matrix set limits. - * @return {TileSetInfo} Tile set info. - */ - function parseTileMatrixSet( - tileMatrixSet, - tileUrlTemplate, - tileMatrixSetLimits - ) { - let projection = sourceInfo.projection; - if (!projection) { - projection = getProjection(tileMatrixSet.crs); - if (!projection) { - throw new Error(`Unsupported CRS: ${tileMatrixSet.crs}`); - } - } - const backwards = projection.getAxisOrientation().substr(0, 2) !== 'en'; - - const matrices = tileMatrixSet.tileMatrices; - - /** - * @type {Object} - */ - const matrixLookup = {}; - for (let i = 0; i < matrices.length; ++i) { - const matrix = matrices[i]; - matrixLookup[matrix.id] = matrix; - } - - /** - * @type {Object} - */ - const limitLookup = {}; - - /** - * @type {Array} - */ - const matrixIds = []; - - if (tileMatrixSetLimits) { - for (let i = 0; i < tileMatrixSetLimits.length; ++i) { - const limit = tileMatrixSetLimits[i]; - const id = limit.tileMatrix; - matrixIds.push(id); - limitLookup[id] = limit; - } - } else { - for (let i = 0; i < matrices.length; ++i) { - const id = matrices[i].id; - matrixIds.push(id); - } - } - - const length = matrixIds.length; - const origins = new Array(length); - const resolutions = new Array(length); - const sizes = new Array(length); - const tileSizes = new Array(length); - const extent = [-Infinity, -Infinity, Infinity, Infinity]; - - for (let i = 0; i < length; ++i) { - const id = matrixIds[i]; - const matrix = matrixLookup[id]; - const origin = matrix.pointOfOrigin; - if (backwards) { - origins[i] = [origin[1], origin[0]]; - } else { - origins[i] = origin; - } - resolutions[i] = matrix.cellSize; - sizes[i] = [matrix.matrixWidth, matrix.matrixHeight]; - tileSizes[i] = [matrix.tileWidth, matrix.tileHeight]; - const limit = limitLookup[id]; - if (limit) { - const tileMapWidth = matrix.cellSize * matrix.tileWidth; - const minX = origins[i][0] + limit.minTileCol * tileMapWidth; - const maxX = origins[i][0] + (limit.maxTileCol + 1) * tileMapWidth; - - const tileMapHeight = matrix.cellSize * matrix.tileHeight; - const upsideDown = matrix.cornerOfOrigin === BOTTOM_LEFT_ORIGIN; - - let minY; - let maxY; - if (upsideDown) { - minY = origins[i][1] + limit.minTileRow * tileMapHeight; - maxY = origins[i][1] + (limit.maxTileRow + 1) * tileMapHeight; - } else { - minY = origins[i][1] - (limit.maxTileRow + 1) * tileMapHeight; - maxY = origins[i][1] - limit.minTileRow * tileMapHeight; - } - - intersectExtents(extent, [minX, minY, maxX, maxY], extent); - } - } - - const tileGrid = new TileGrid({ - origins: origins, - resolutions: resolutions, - sizes: sizes, - tileSizes: tileSizes, - extent: tileMatrixSetLimits ? extent : undefined, - }); - - const context = sourceInfo.context; - const base = sourceInfo.url; - - function tileUrlFunction(tileCoord, pixelRatio, projection) { - if (!tileCoord) { - return undefined; - } - - const id = matrixIds[tileCoord[0]]; - const matrix = matrixLookup[id]; - const upsideDown = matrix.cornerOfOrigin === BOTTOM_LEFT_ORIGIN; - - const localContext = { - tileMatrix: id, - tileCol: tileCoord[1], - tileRow: upsideDown ? -tileCoord[2] - 1 : tileCoord[2], - }; - - if (tileMatrixSetLimits) { - const limit = limitLookup[matrix.id]; - if ( - localContext.tileCol < limit.minTileCol || - localContext.tileCol > limit.maxTileCol || - localContext.tileRow < limit.minTileRow || - localContext.tileRow > limit.maxTileRow - ) { - return undefined; - } - } - - assign(localContext, context); - - const url = tileUrlTemplate.replace(/\{(\w+?)\}/g, function (m, p) { - return localContext[p]; - }); - - return resolveUrl(base, url); - } - - return { - grid: tileGrid, - urlTemplate: tileUrlTemplate, - urlFunction: tileUrlFunction, - }; - } - - /** - * @param {TileSet} tileSet Tile set. - * @return {TileSetInfo|Promise} Tile set info. - */ - function parseTileSetMetadata(tileSet) { - const tileMatrixSetLimits = tileSet.tileMatrixSetLimits; - let tileUrlTemplate; - - if (tileSet.dataType === TileType.MAP) { - tileUrlTemplate = getMapTileUrlTemplate( - tileSet.links, - sourceInfo.mediaType - ); - } else if (tileSet.dataType === TileType.VECTOR) { - tileUrlTemplate = getVectorTileUrlTemplate( - tileSet.links, - sourceInfo.mediaType - ); - } else { - throw new Error('Expected tileset data type to be "map" or "vector"'); - } - - if (tileSet.tileMatrixSet) { - return parseTileMatrixSet( - tileSet.tileMatrixSet, - tileUrlTemplate, - tileMatrixSetLimits - ); - } - - if (!tileSet.tileMatrixSetDefinition) { - throw new Error('Expected tileMatrixSetDefinition or tileMatrixSet'); - } - - const url = resolveUrl(sourceInfo.url, tileSet.tileMatrixSetDefinition); - return getJSON(url).then(function (tileMatrixSet) { - return parseTileMatrixSet( - tileMatrixSet, - tileUrlTemplate, - tileMatrixSetLimits - ); - }); - } - - return getJSON(sourceInfo.url).then(parseTileSetMetadata); + return getJSON(sourceInfo.url).then(function (tileSet) { + return parseTileSetMetadata(sourceInfo, tileSet); + }); }