-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support of parentUrl property in layer.json #5864
Changes from 4 commits
b00498d
17f9d4b
645fdd8
323cf28
ef33387
d62c765
e6e45b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,15 @@ define([ | |
TileProviderError) { | ||
'use strict'; | ||
|
||
function LayerInformation(layer) { | ||
this.isHeightmap = layer.isHeightmap; | ||
this.tileUrlTemplates = layer.tileUrlTemplates; | ||
this.availability = layer.availability; | ||
this.hasVertexNormals = layer.hasVertexNormals; | ||
this.hasWaterMask = layer.hasWaterMask; | ||
this.littleEndianExtensionSize = layer.littleEndianExtensionSize; | ||
} | ||
|
||
/** | ||
* A {@link TerrainProvider} that accesses terrain data in a Cesium terrain format. | ||
* The format is described on the | ||
|
@@ -114,22 +123,16 @@ define([ | |
|
||
this._heightmapStructure = undefined; | ||
this._hasWaterMask = false; | ||
|
||
/** | ||
* Boolean flag that indicates if the Terrain Server can provide vertex normals. | ||
* @type {Boolean} | ||
* @default false | ||
* @private | ||
*/ | ||
this._hasVertexNormals = false; | ||
|
||
/** | ||
* Boolean flag that indicates if the client should request vertex normals from the server. | ||
* @type {Boolean} | ||
* @default false | ||
* @private | ||
*/ | ||
this._requestVertexNormals = defaultValue(options.requestVertexNormals, false); | ||
this._littleEndianExtensionSize = true; | ||
|
||
/** | ||
* Boolean flag that indicates if the client should request tile watermasks from the server. | ||
* @type {Boolean} | ||
|
@@ -139,17 +142,19 @@ define([ | |
this._requestWaterMask = defaultValue(options.requestWaterMask, false); | ||
|
||
this._errorEvent = new Event(); | ||
this._availability = undefined; | ||
|
||
var credit = options.credit; | ||
if (typeof credit === 'string') { | ||
credit = new Credit(credit); | ||
} | ||
this._credit = credit; | ||
|
||
this._availability = undefined; | ||
|
||
this._ready = false; | ||
this._readyPromise = when.defer(); | ||
|
||
var lastUrl = this._url; | ||
var metadataUrl = joinUrls(this._url, 'layer.json'); | ||
if (defined(this._proxy)) { | ||
metadataUrl = this._proxy.getURL(metadataUrl); | ||
|
@@ -158,7 +163,11 @@ define([ | |
var that = this; | ||
var metadataError; | ||
|
||
function metadataSuccess(data) { | ||
var layers = this._layers = []; | ||
var attribution = ''; | ||
var overallAvailability = []; | ||
|
||
function parseMetadataSuccess(data) { | ||
var message; | ||
|
||
if (!data.format) { | ||
|
@@ -173,8 +182,14 @@ define([ | |
return; | ||
} | ||
|
||
var hasVertexNormals = false; | ||
var hasWaterMask = false; | ||
var littleEndianExtensionSize = true; | ||
var isHeightmap = false; | ||
if (data.format === 'heightmap-1.0') { | ||
that._heightmapStructure = { | ||
isHeightmap = true; | ||
if (!defined(that._heightmapStructure)) { | ||
that._heightmapStructure = { | ||
heightScale : 1.0 / 5.0, | ||
heightOffset : -1000.0, | ||
elementsPerHeight : 1, | ||
|
@@ -184,63 +199,131 @@ define([ | |
lowestEncodedHeight : 0, | ||
highestEncodedHeight : 256 * 256 - 1 | ||
}; | ||
that._hasWaterMask = true; | ||
} | ||
hasWaterMask = true; | ||
that._requestWaterMask = true; | ||
} else if (data.format.indexOf('quantized-mesh-1.') !== 0) { | ||
message = 'The tile format "' + data.format + '" is invalid or not supported.'; | ||
metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); | ||
return; | ||
} | ||
|
||
that._tileUrlTemplates = data.tiles; | ||
for (var i = 0; i < that._tileUrlTemplates.length; ++i) { | ||
var template = new Uri(that._tileUrlTemplates[i]); | ||
var baseUri = new Uri(that._url); | ||
var tileUrlTemplates = data.tiles; | ||
for (var i = 0; i < tileUrlTemplates.length; ++i) { | ||
var template = new Uri(tileUrlTemplates[i]); | ||
var baseUri = new Uri(lastUrl); | ||
if (template.authority && !baseUri.authority) { | ||
baseUri.authority = template.authority; | ||
baseUri.scheme = template.scheme; | ||
} | ||
that._tileUrlTemplates[i] = joinUrls(baseUri, template).toString().replace('{version}', data.version); | ||
tileUrlTemplates[i] = joinUrls(baseUri, template).toString().replace('{version}', data.version); | ||
} | ||
|
||
var availableTiles = data.available; | ||
|
||
var availability; | ||
if (defined(availableTiles)) { | ||
that._availability = new TileAvailability(that._tilingScheme, availableTiles.length); | ||
availability = new TileAvailability(that._tilingScheme, availableTiles.length); | ||
|
||
for (var level = 0; level < availableTiles.length; ++level) { | ||
var rangesAtLevel = availableTiles[level]; | ||
var yTiles = that._tilingScheme.getNumberOfYTilesAtLevel(level); | ||
if (!defined(overallAvailability[level])) { | ||
overallAvailability[level] = []; | ||
} | ||
|
||
for (var rangeIndex = 0; rangeIndex < rangesAtLevel.length; ++rangeIndex) { | ||
var range = rangesAtLevel[rangeIndex]; | ||
that._availability.addAvailableTileRange(level, range.startX, yTiles - range.endY - 1, range.endX, yTiles - range.startY - 1); | ||
var yStart = yTiles - range.endY - 1; | ||
var yEnd = yTiles - range.startY - 1; | ||
overallAvailability[level].push([range.startX, yStart, range.endX, yEnd]); | ||
availability.addAvailableTileRange(level, range.startX, yStart, range.endX, yEnd); | ||
} | ||
} | ||
} | ||
|
||
if (!defined(that._credit) && defined(data.attribution) && data.attribution !== null) { | ||
that._credit = new Credit(data.attribution); | ||
} | ||
|
||
// The vertex normals defined in the 'octvertexnormals' extension is identical to the original | ||
// contents of the original 'vertexnormals' extension. 'vertexnormals' extension is now | ||
// deprecated, as the extensionLength for this extension was incorrectly using big endian. | ||
// We maintain backwards compatibility with the legacy 'vertexnormal' implementation | ||
// by setting the _littleEndianExtensionSize to false. Always prefer 'octvertexnormals' | ||
// over 'vertexnormals' if both extensions are supported by the server. | ||
if (defined(data.extensions) && data.extensions.indexOf('octvertexnormals') !== -1) { | ||
that._hasVertexNormals = true; | ||
hasVertexNormals = true; | ||
} else if (defined(data.extensions) && data.extensions.indexOf('vertexnormals') !== -1) { | ||
that._hasVertexNormals = true; | ||
that._littleEndianExtensionSize = false; | ||
hasVertexNormals = true; | ||
littleEndianExtensionSize = false; | ||
} | ||
if (defined(data.extensions) && data.extensions.indexOf('watermask') !== -1) { | ||
that._hasWaterMask = true; | ||
hasWaterMask = true; | ||
} | ||
|
||
that._hasWaterMask = that._hasWaterMask || hasWaterMask; | ||
that._hasVertexNormals = that._hasVertexNormals || hasVertexNormals; | ||
if (defined(data.attribution)) { | ||
if (attribution.length > 0) { | ||
attribution += ' '; | ||
} | ||
attribution += data.attribution; | ||
} | ||
|
||
layers.push(new LayerInformation({ | ||
isHeightmap: isHeightmap, | ||
tileUrlTemplates: tileUrlTemplates, | ||
availability: availability, | ||
hasVertexNormals: hasVertexNormals, | ||
hasWaterMask: hasWaterMask, | ||
littleEndianExtensionSize: littleEndianExtensionSize | ||
})); | ||
|
||
var parentUrl = data.parentUrl; | ||
if (defined(parentUrl)) { | ||
if (!defined(availability)) { | ||
console.log('A layer.json can\'t have a parentUrl if it does\'t have an available array.'); | ||
return when.resolve(); | ||
} | ||
lastUrl = joinUrls(lastUrl, parentUrl); | ||
metadataUrl = joinUrls(lastUrl, 'layer.json'); | ||
if (defined(that._proxy)) { | ||
metadataUrl = that._proxy.getURL(metadataUrl); | ||
} | ||
var parentMetadata = loadJson(metadataUrl); | ||
return when(parentMetadata, parseMetadataSuccess, parseMetadataFailure); | ||
} | ||
|
||
that._ready = true; | ||
that._readyPromise.resolve(true); | ||
return when.resolve(); | ||
} | ||
|
||
function parseMetadataFailure(data) { | ||
var message = 'An error occurred while accessing ' + metadataUrl + '.'; | ||
metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); | ||
} | ||
|
||
function metadataSuccess(data) { | ||
parseMetadataSuccess(data) | ||
.then(function() { | ||
if (defined(metadataError)) { | ||
return; | ||
} | ||
|
||
var length = overallAvailability.length; | ||
if (length > 0) { | ||
var availability = that._availability = new TileAvailability(that._tilingScheme, length); | ||
for (var level = 0; level < length; ++level) { | ||
var levelRanges = overallAvailability[level]; | ||
for (var i = 0; i < levelRanges.length; ++i) { | ||
var range = levelRanges[i]; | ||
availability.addAvailableTileRange(level, range[0], range[1], range[2], range[3]); | ||
} | ||
} | ||
} | ||
|
||
if (!defined(that._credit) && attribution.length > 0) { | ||
that._credit = new Credit(attribution); | ||
} | ||
|
||
that._ready = true; | ||
that._readyPromise.resolve(true); | ||
}); | ||
} | ||
|
||
function metadataFailure(data) { | ||
|
@@ -257,8 +340,7 @@ define([ | |
}); | ||
return; | ||
} | ||
var message = 'An error occurred while accessing ' + metadataUrl + '.'; | ||
metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); | ||
parseMetadataFailure(data); | ||
} | ||
|
||
function requestMetadata() { | ||
|
@@ -320,7 +402,7 @@ define([ | |
}); | ||
} | ||
|
||
function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY) { | ||
function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY, littleEndianExtensionSize) { | ||
var pos = 0; | ||
var cartesian3Elements = 3; | ||
var boundingSphereElements = cartesian3Elements + 1; | ||
|
@@ -431,7 +513,7 @@ define([ | |
while (pos < view.byteLength) { | ||
var extensionId = view.getUint8(pos, true); | ||
pos += Uint8Array.BYTES_PER_ELEMENT; | ||
var extensionLength = view.getUint32(pos, provider._littleEndianExtensionSize); | ||
var extensionLength = view.getUint32(pos, littleEndianExtensionSize); | ||
pos += Uint32Array.BYTES_PER_ELEMENT; | ||
|
||
if (extensionId === QuantizedMeshExtensionIds.OCT_VERTEX_NORMALS && provider._requestVertexNormals) { | ||
|
@@ -505,7 +587,22 @@ define([ | |
} | ||
//>>includeEnd('debug'); | ||
|
||
var urlTemplates = this._tileUrlTemplates; | ||
var layers = this._layers; | ||
var layerToUse = layers[0]; | ||
var layerCount = layers.length; | ||
for (var i=0;i<layerCount;++i) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whitepace |
||
var layer = layers[i]; | ||
if (!defined(layer.availability) || layer.availability.isTileAvailable(level, x, y)) { | ||
layerToUse = layer; | ||
break; | ||
} | ||
} | ||
|
||
if (!defined(layerToUse)) { | ||
return undefined; | ||
} | ||
|
||
var urlTemplates = layerToUse.tileUrlTemplates; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't measured or anything, but there's the potential for a somewhat high performance cost here, especially on slow systems with slow internet connections. On these systems, Cesium tends to spend a lot of time traversing the quadtree to select the tiles it wishes it has, then calling Before this pull request, Cesium only had to do some string manipulations to build up a URL, and then it would hand it off to But after this pull request, Cesium now has to do a lot of tile availability checking before handing off to So two suggestions, one easy and one harder:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if 2 is possible. Even if we check the throttle status, we still need to know whether that layer contains the tile so we can return a Promise/undefined or if we should go to the next layer, which may be from a different domain and have a different throttle status. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah true you could only optimize some special cases. i.e. if all the layers are from the same host, and that host already has too many requests in flight, you can skip availability checking. Or another less useful special case: if all layers already have too many tile requests in flight, just return undefined without checking availability. Anyway, the important thing is to avoid the performance regression for the single layer case (as you've already done) and we can worry about optimizing the multi layer case if it ever really becomes an issue. |
||
if (urlTemplates.length === 0) { | ||
return undefined; | ||
} | ||
|
@@ -522,10 +619,10 @@ define([ | |
} | ||
|
||
var extensionList = []; | ||
if (this._requestVertexNormals && this._hasVertexNormals) { | ||
extensionList.push(this._littleEndianExtensionSize ? 'octvertexnormals' : 'vertexnormals'); | ||
if (this._requestVertexNormals && layerToUse.hasVertexNormals) { | ||
extensionList.push(layerToUse.littleEndianExtensionSize ? 'octvertexnormals' : 'vertexnormals'); | ||
} | ||
if (this._requestWaterMask && this._hasWaterMask) { | ||
if (this._requestWaterMask && layerToUse.hasWaterMask) { | ||
extensionList.push('watermask'); | ||
} | ||
|
||
|
@@ -540,7 +637,7 @@ define([ | |
if (defined(that._heightmapStructure)) { | ||
return createHeightmapTerrainData(that, buffer, level, x, y, tmsY); | ||
} | ||
return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY); | ||
return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY, layerToUse.littleEndianExtensionSize); | ||
}); | ||
}; | ||
|
||
|
@@ -723,10 +820,11 @@ define([ | |
* @returns {Boolean} Undefined if not supported, otherwise true or false. | ||
*/ | ||
CesiumTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) { | ||
if (!defined(this.availability)) { | ||
if (!defined(this._availability)) { | ||
return undefined; | ||
} | ||
return this.availability.isTileAvailable(level, x, y); | ||
|
||
return this._availability.isTileAvailable(level, x, y); | ||
}; | ||
|
||
return CesiumTerrainProvider; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment is not necessary.