diff --git a/CHANGES.md b/CHANGES.md index ee1ad93d5312..7f22d65d5308 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Change Log * Added `Entity.tileset` for loading a 3D Tiles tileset via the Entity API using the new `Cesium3DTilesetGraphics` class. * Added `tileset.uri`, `tileset.show`, and `tileset.maximumScreenSpaceError` properties to CZML processing for loading 3D Tiles. * Added `Color.lerp` for linearly interpolating between two RGB colors. [#8607](https://github.com/AnalyticalGraphicsInc/cesium/pull/8607) +* `CesiumTerrainProvider` now supports terrain tiles using a `WebMercatorTilingScheme` by specifying `"projection": "EPSG:3857"` in `layer.json`. It also now supports numbering tiles from the North instead of the South by specifying `"scheme": "slippyMap"` in `layer.json`. [#8563](https://github.com/AnalyticalGraphicsInc/cesium/pull/8563) ##### Fixes :wrench: diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6a1b241bc406..0d1f53cc3781 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -245,3 +245,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [André Borud](https://github.com/andreborud) * [Nathan Schulte](https://github.com/nmschulte) * [Jan Wąsak](https://github.com/jhnwsk) +* [Julian Fell](https://github.com/jtfell) diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index 4165945d63d2..3fa8aea1f484 100644 --- a/Source/Core/CesiumTerrainProvider.js +++ b/Source/Core/CesiumTerrainProvider.js @@ -9,6 +9,7 @@ import defineProperties from './defineProperties.js'; import DeveloperError from './DeveloperError.js'; import Event from './Event.js'; import GeographicTilingScheme from './GeographicTilingScheme.js'; +import WebMercatorTilingScheme from './WebMercatorTilingScheme.js'; import getStringFromTypedArray from './getStringFromTypedArray.js'; import HeightmapTerrainData from './HeightmapTerrainData.js'; import IndexDatatype from './IndexDatatype.js'; @@ -72,18 +73,11 @@ import TileProviderError from './TileProviderError.js'; } //>>includeEnd('debug'); - this._tilingScheme = new GeographicTilingScheme({ - numberOfLevelZeroTilesX : 2, - numberOfLevelZeroTilesY : 1, - ellipsoid : options.ellipsoid - }); - this._heightmapWidth = 65; - this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0)); - this._heightmapStructure = undefined; this._hasWaterMask = false; this._hasVertexNormals = false; + this._ellipsoid = options.ellipsoid; /** * Boolean flag that indicates if the client should request vertex normals from the server. @@ -198,6 +192,38 @@ import TileProviderError from './TileProviderError.js'; var maxZoom = data.maxzoom; overallMaxZoom = Math.max(overallMaxZoom, maxZoom); // Keeps track of which of the availablity containing tiles have been loaded + + if (!data.projection || data.projection === 'EPSG:4326') { + that._tilingScheme = new GeographicTilingScheme({ + numberOfLevelZeroTilesX : 2, + numberOfLevelZeroTilesY : 1, + ellipsoid : that._ellipsoid + }); + } else if (data.projection === 'EPSG:3857') { + that._tilingScheme = new WebMercatorTilingScheme({ + numberOfLevelZeroTilesX : 1, + numberOfLevelZeroTilesY : 1, + ellipsoid : that._ellipsoid + }); + } else { + message = 'The projection "' + data.projection + '" is invalid or not supported.'; + metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestLayerJson); + return; + } + + that._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap( + that._tilingScheme.ellipsoid, + that._heightmapWidth, + that._tilingScheme.getNumberOfXTilesAtLevel(0) + ); + if (!data.scheme || data.scheme === 'tms' || data.scheme === 'slippyMap') { + that._scheme = data.scheme; + } else { + message = 'The scheme "' + data.scheme + '" is invalid or not supported.'; + metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestLayerJson); + return; + } + var availabilityTilesLoaded; // The vertex normals defined in the 'octvertexnormals' extension is identical to the original @@ -402,7 +428,7 @@ import TileProviderError from './TileProviderError.js'; }; } - function createHeightmapTerrainData(provider, buffer, level, x, y, tmsY) { + function createHeightmapTerrainData(provider, buffer, level, x, y) { var heightBuffer = new Uint16Array(buffer, 0, provider._heightmapWidth * provider._heightmapWidth); return new HeightmapTerrainData({ buffer : heightBuffer, @@ -415,7 +441,7 @@ import TileProviderError from './TileProviderError.js'; }); } - function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY, layer) { + function createQuantizedMeshTerrainData(provider, buffer, level, x, y, layer) { var littleEndianExtensionSize = layer.littleEndianExtensionSize; var pos = 0; var cartesian3Elements = 3; @@ -633,9 +659,14 @@ import TileProviderError from './TileProviderError.js'; return undefined; } - var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); - - var tmsY = (yTiles - y - 1); + // The TileMapService scheme counts from the bottom left + var terrainY; + if (!provider._scheme || provider._scheme === 'tms') { + var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); + terrainY = (yTiles - y - 1); + } else { + terrainY = y; + } var extensionList = []; if (provider._requestVertexNormals && layerToUse.hasVertexNormals) { @@ -650,7 +681,8 @@ import TileProviderError from './TileProviderError.js'; var headers; var query; - var url = urlTemplates[(x + tmsY + level) % urlTemplates.length]; + var url = urlTemplates[(x + terrainY + level) % urlTemplates.length]; + var resource = layerToUse.resource; if (defined(resource._ionEndpoint) && !defined(resource._ionEndpoint.externalType)) { // ion uses query paremeters to request extensions @@ -669,7 +701,7 @@ import TileProviderError from './TileProviderError.js'; version: layerToUse.version, z: level, x: x, - y: tmsY + y: terrainY }, queryParameters: query, headers: headers, @@ -682,9 +714,9 @@ import TileProviderError from './TileProviderError.js'; return promise.then(function (buffer) { if (defined(provider._heightmapStructure)) { - return createHeightmapTerrainData(provider, buffer, level, x, y, tmsY); + return createHeightmapTerrainData(provider, buffer, level, x, y); } - return createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY, layerToUse); + return createQuantizedMeshTerrainData(provider, buffer, level, x, y, layerToUse); }); } diff --git a/Specs/Core/CesiumTerrainProviderSpec.js b/Specs/Core/CesiumTerrainProviderSpec.js index 17a267456df7..426c754400dc 100644 --- a/Specs/Core/CesiumTerrainProviderSpec.js +++ b/Specs/Core/CesiumTerrainProviderSpec.js @@ -206,13 +206,19 @@ describe('Core/CesiumTerrainProvider', function() { }); it('returns reasonable geometric error for various levels', function() { + returnQuantizedMeshTileJson(); + var provider = new CesiumTerrainProvider({ url : 'made/up/url' }); - expect(provider.getLevelMaximumGeometricError(0)).toBeGreaterThan(0.0); - expect(provider.getLevelMaximumGeometricError(0)).toEqualEpsilon(provider.getLevelMaximumGeometricError(1) * 2.0, CesiumMath.EPSILON10); - expect(provider.getLevelMaximumGeometricError(1)).toEqualEpsilon(provider.getLevelMaximumGeometricError(2) * 2.0, CesiumMath.EPSILON10); + return pollToPromise(function() { + return provider.ready; + }).then(function() { + expect(provider.getLevelMaximumGeometricError(0)).toBeGreaterThan(0.0); + expect(provider.getLevelMaximumGeometricError(0)).toEqualEpsilon(provider.getLevelMaximumGeometricError(1) * 2.0, CesiumMath.EPSILON10); + expect(provider.getLevelMaximumGeometricError(1)).toEqualEpsilon(provider.getLevelMaximumGeometricError(2) * 2.0, CesiumMath.EPSILON10); + }); }); it('logo is undefined if credit is not provided', function() {