Skip to content

Commit

Permalink
Merge pull request #5864 from AnalyticalGraphicsInc/terrain-ancestor-…
Browse files Browse the repository at this point in the history
…layers

Added support of parentUrl property in layer.json
  • Loading branch information
kring authored Oct 13, 2017
2 parents 7e96f5f + e6e45b5 commit 2862c99
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Change Log
==========
### 1.39 - 2017-11-01
* Added support for the layer.json `parentUrl` property in `CesiumTerrainProvider` to allow for compositing of tilesets.

### 1.38 - 2017-10-02

* Breaking changes
Expand Down
187 changes: 146 additions & 41 deletions Source/Core/CesiumTerrainProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ define([
'./QuantizedMeshTerrainData',
'./Request',
'./RequestType',
'./RuntimeError',
'./TerrainProvider',
'./TileAvailability',
'./TileProviderError'
Expand All @@ -45,11 +46,21 @@ define([
QuantizedMeshTerrainData,
Request,
RequestType,
RuntimeError,
TerrainProvider,
TileAvailability,
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
Expand Down Expand Up @@ -114,22 +125,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}
Expand All @@ -139,17 +144,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);
Expand All @@ -158,7 +165,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) {
Expand All @@ -173,8 +184,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,
Expand All @@ -184,63 +201,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) {
Expand All @@ -257,8 +342,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() {
Expand Down Expand Up @@ -320,7 +404,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;
Expand Down Expand Up @@ -431,7 +515,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) {
Expand Down Expand Up @@ -505,7 +589,27 @@ define([
}
//>>includeEnd('debug');

var urlTemplates = this._tileUrlTemplates;
var layers = this._layers;
var layerToUse;
var layerCount = layers.length;

if (layerCount === 1) { // Optimized path for single layers
layerToUse = layers[0];
} else {
for (var i = 0; i < layerCount; ++i) {
var layer = layers[i];
if (!defined(layer.availability) || layer.availability.isTileAvailable(level, x, y)) {
layerToUse = layer;
break;
}
}
}

if (!defined(layerToUse)) {
return when.reject(new RuntimeError('Terrain tile doesn\'t exist'));
}

var urlTemplates = layerToUse.tileUrlTemplates;
if (urlTemplates.length === 0) {
return undefined;
}
Expand All @@ -522,10 +626,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');
}

Expand All @@ -540,7 +644,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);
});
};

Expand Down Expand Up @@ -723,10 +827,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;
Expand Down
Loading

0 comments on commit 2862c99

Please sign in to comment.