From 5c7a27792cdfc3cf68800622c054cf08d8386cb5 Mon Sep 17 00:00:00 2001 From: Julian Fell Date: Thu, 23 Jan 2020 08:32:56 +1000 Subject: [PATCH 1/6] Add option to switch CesiumTerrainProvider to a WebMercator tiling scheme based on key in layer.json --- Source/Core/CesiumTerrainProvider.js | 54 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index 4165945d63d..3359cc2f6ad 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,31 @@ 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.tilingScheme || data.tilingScheme === 'GlobalGeodetic') { + that._tilingScheme = new GeographicTilingScheme({ + numberOfLevelZeroTilesX : 2, + numberOfLevelZeroTilesY : 1, + ellipsoid : that._ellipsoid + }); + } else if (data.tilingScheme === 'WebMercator') { + that._tilingScheme = new WebMercatorTilingScheme({ + numberOfLevelZeroTilesX : 1, + numberOfLevelZeroTilesY : 1, + ellipsoid : that._ellipsoid + }); + } else { + message = 'The layer.json tilingScheme "' + data.tilingScheme + '" 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) + ); + var availabilityTilesLoaded; // The vertex normals defined in the 'octvertexnormals' extension is identical to the original @@ -402,7 +421,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 +434,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 +652,10 @@ import TileProviderError from './TileProviderError.js'; return undefined; } - var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); - - var tmsY = (yTiles - y - 1); + if (provider._tilingScheme instanceof GeographicTilingScheme) { + var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); + y = (yTiles - y - 1); + } var extensionList = []; if (provider._requestVertexNormals && layerToUse.hasVertexNormals) { @@ -650,7 +670,7 @@ import TileProviderError from './TileProviderError.js'; var headers; var query; - var url = urlTemplates[(x + tmsY + level) % urlTemplates.length]; + var url = urlTemplates[(x + y + level) % urlTemplates.length]; var resource = layerToUse.resource; if (defined(resource._ionEndpoint) && !defined(resource._ionEndpoint.externalType)) { // ion uses query paremeters to request extensions @@ -669,7 +689,7 @@ import TileProviderError from './TileProviderError.js'; version: layerToUse.version, z: level, x: x, - y: tmsY + y: y }, queryParameters: query, headers: headers, @@ -682,9 +702,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); }); } From 9fddd3fbe2f7efe42f0b1578ac9805775ad7897d Mon Sep 17 00:00:00 2001 From: Julian Fell Date: Thu, 23 Jan 2020 08:48:48 +1000 Subject: [PATCH 2/6] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6346f2b35a7..9f597d22f0c 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -239,3 +239,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Tinco Andringa](https://github.com/tinco) * [André Borud](https://github.com/andreborud) * [Nathan Schulte](https://github.com/nmschulte) +* [Julian Fell](https://github.com/jtfell) From 11f36af6bdf8eaac26b7cd64a1a056926293a701 Mon Sep 17 00:00:00 2001 From: Julian Fell Date: Thu, 23 Jan 2020 13:11:42 +1000 Subject: [PATCH 3/6] Require layerjson before testing geometric error --- Specs/Core/CesiumTerrainProviderSpec.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Specs/Core/CesiumTerrainProviderSpec.js b/Specs/Core/CesiumTerrainProviderSpec.js index 17a267456df..426c754400d 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() { From a829cfd5041ce5fadf0432f8031fbcc93e7cfad0 Mon Sep 17 00:00:00 2001 From: Julian Fell Date: Thu, 30 Jan 2020 14:54:46 +1000 Subject: [PATCH 4/6] use 'scheme' and 'projection' options to modify the tiling scheme --- Source/Core/CesiumTerrainProvider.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index 3359cc2f6ad..da14a7a3d19 100644 --- a/Source/Core/CesiumTerrainProvider.js +++ b/Source/Core/CesiumTerrainProvider.js @@ -193,22 +193,22 @@ import TileProviderError from './TileProviderError.js'; overallMaxZoom = Math.max(overallMaxZoom, maxZoom); // Keeps track of which of the availablity containing tiles have been loaded - if (!data.tilingScheme || data.tilingScheme === 'GlobalGeodetic') { + if (!data.projection || data.projection === 'EPSG:4326') { that._tilingScheme = new GeographicTilingScheme({ numberOfLevelZeroTilesX : 2, numberOfLevelZeroTilesY : 1, ellipsoid : that._ellipsoid }); - } else if (data.tilingScheme === 'WebMercator') { + } else if (data.projection === 'EPSG:3857') { that._tilingScheme = new WebMercatorTilingScheme({ numberOfLevelZeroTilesX : 1, numberOfLevelZeroTilesY : 1, ellipsoid : that._ellipsoid }); } else { - message = 'The layer.json tilingScheme "' + data.tilingScheme + '" is invalid or not supported.'; - metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestLayerJson); - return; + 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( @@ -216,6 +216,13 @@ import TileProviderError from './TileProviderError.js'; 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; @@ -652,7 +659,8 @@ import TileProviderError from './TileProviderError.js'; return undefined; } - if (provider._tilingScheme instanceof GeographicTilingScheme) { + // The TileMapService scheme counts from the bottom left + if (!provider._scheme || provider._scheme === 'tms') { var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); y = (yTiles - y - 1); } From e83db9260b2241af6669e61a100ba06987cc0cdf Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Thu, 30 Jan 2020 21:11:04 +1100 Subject: [PATCH 5/6] Update CHANGES.md. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 1e2b2cc0b08..675ee7050c2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,7 @@ Change Log * Added `Globe.showSkirts` to support the ability to hide terrain skirts when viewing terrain from below the surface. [#8489](https://github.com/AnalyticalGraphicsInc/cesium/pull/8489) * Fixed `BoundingSphere.projectTo2D` when the bounding sphere’s center is at the origin. [#8482](https://github.com/AnalyticalGraphicsInc/cesium/pull/8482) * Added `minificationFilter` and `magnificationFilter` options to `Material` to control texture filtering. [#8473](https://github.com/AnalyticalGraphicsInc/cesium/pull/8473) +* `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) * Update [earcut](https://github.com/mapbox/earcut) to 2.2.1. [#8528](https://github.com/AnalyticalGraphicsInc/cesium/pull/8528) ##### Fixes :wrench: From 14f0e838ca1e9378ff006f30de8b5e6208d11501 Mon Sep 17 00:00:00 2001 From: Julian Fell Date: Fri, 31 Jan 2020 12:40:28 +1000 Subject: [PATCH 6/6] Ensure createQuantizedMeshTerrainData is called with cesium coordinates (not TMS coordinates) --- Source/Core/CesiumTerrainProvider.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index da14a7a3d19..3fa8aea1f48 100644 --- a/Source/Core/CesiumTerrainProvider.js +++ b/Source/Core/CesiumTerrainProvider.js @@ -660,9 +660,12 @@ import TileProviderError from './TileProviderError.js'; } // The TileMapService scheme counts from the bottom left + var terrainY; if (!provider._scheme || provider._scheme === 'tms') { var yTiles = provider._tilingScheme.getNumberOfYTilesAtLevel(level); - y = (yTiles - y - 1); + terrainY = (yTiles - y - 1); + } else { + terrainY = y; } var extensionList = []; @@ -678,7 +681,8 @@ import TileProviderError from './TileProviderError.js'; var headers; var query; - var url = urlTemplates[(x + y + 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 @@ -697,7 +701,7 @@ import TileProviderError from './TileProviderError.js'; version: layerToUse.version, z: level, x: x, - y: y + y: terrainY }, queryParameters: query, headers: headers,