Cesium官网给出的api貌似只能加载.terrain格式的dem数据,这里我将简单介绍一下如何自定义加载bil格式的dem数据。
首先在自定义实现加载bil格式的js类,这个很简单,就是复制源码CesiumTerrainProvider.js,将名字改掉就好。
(改名字的时候最好用替换)
构造方法里面配置bil格式的数据信息。
如:
this._url = options.url;
this._proxy = options.proxy;
this._tilingScheme = new GeographicTilingScheme({
numberOfLevelZeroTilesX : 18,
numberOfLevelZeroTilesY : 9,
ellipsoid : options.ellipsoid
});
this._heightmapWidth = 150;
this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0));
this._heightmapStructure = undefined;
this._hasWaterMask = false;
。。。。。
具体每个参数什么含义就不解释了,可以自行去看官网原文。
了解清楚下面代码意义
that._heightmapStructure = {
heightScale : 2.0,
heightOffset : -1000.0,
elementsPerHeight : 1,
stride : 1,
elementMultiplier : 512.0,
isBigEndian : false,
lowestEncodedHeight : 0,
highestEncodedHeight : 512 * 512 - 1
};
该代码主要用于设置高程信息和偏移量等,详细看官网。
索引信息读取方法requestMetadata();这个主要用于请求.terrain格式中的layer.json文件,其中
tiles: [
'{z}/{x}/{y}.terrain?v={version}'
]
是用来遍历加载所有dem文件的。
接着在requestTileGeometry方法中控制自己的文件加载顺序逻辑。
加载bil格式高程几乎完成一大半了,现在告诉大家两个参数,就是.terrain数据内容除了有高程数据,最后还有两个标志数据,分别是有无子文件和有没有水印,水印没有研究,暂时都设置的为false,子节点根据切片最小级数而定。如果当前级数等于最小级数代表没有子文件了。
注意:bil高程数据会有负值,在做数据读取时注意转换。
最后上传个代码大家参考下
1 /*global define*/ 2 define([ 3 '../ThirdParty/Uri', 4 '../ThirdParty/when', 5 './BoundingSphere', 6 './Cartesian3', 7 './Credit', 8 './defaultValue', 9 './defined', 10 './defineProperties', 11 './DeveloperError', 12 './Event', 13 './GeographicTilingScheme', 14 './HeightmapTerrainData', 15 './IndexDatatype', 16 './joinUrls', 17 './loadArrayBuffer', 18 './loadJson', 19 './Math', 20 './Matrix3', 21 './OrientedBoundingBox', 22 './QuantizedMeshTerrainData', 23 './RuntimeError', 24 './TerrainProvider', 25 './throttleRequestByServer', 26 './TileProviderError' 27 ], function ( 28 Uri, 29 when, 30 BoundingSphere, 31 Cartesian3, 32 Credit, 33 defaultValue, 34 defined, 35 defineProperties, 36 DeveloperError, 37 Event, 38 GeographicTilingScheme, 39 HeightmapTerrainData, 40 IndexDatatype, 41 joinUrls, 42 loadArrayBuffer, 43 loadJson, 44 CesiumMath, 45 Matrix3, 46 OrientedBoundingBox, 47 QuantizedMeshTerrainData, 48 RuntimeError, 49 TerrainProvider, 50 throttleRequestByServer, 51 TileProviderError) { 52 'use strict'; 53 54 /** 55 * A {@link TerrainProvider} that access terrain data in a Cesium terrain format. 56 * The format is described on the 57 * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Cesium-Terrain-Server|Cesium wiki}. 58 * 59 * @alias CesiumTerrainProvider 60 * @constructor 61 * 62 * @param {Object} options Object with the following properties: 63 * @param {String} options.url The URL of the Cesium terrain server. 64 * @param {Proxy} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed. 65 * @param {Boolean} [options.requestVertexNormals=false] Flag that indicates if the client should request additional lighting information from the server, in the form of per vertex normals if available. 66 * @param {Boolean} [options.requestWaterMask=false] Flag that indicates if the client should request per tile water masks from the server, if available. 67 * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used. 68 * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas. 69 * 70 * 71 * @example 72 * // Construct a terrain provider that uses per vertex normals for lighting 73 * // to add shading detail to an imagery provider. 74 * var terrainProvider = new Cesium.CesiumTerrainProvider({ 75 * url : 'https://assets.agi.com/stk-terrain/world', 76 * requestVertexNormals : true 77 * }); 78 * 79 * // Terrain geometry near the surface of the globe is difficult to view when using NaturalEarthII imagery, 80 * // unless the TerrainProvider provides additional lighting information to shade the terrain (as shown above). 81 * var imageryProvider = Cesium.createTileMapServiceImageryProvider({ 82 * url : 'http://localhost:8080/Source/Assets/Textures/NaturalEarthII', 83 * fileExtension : 'jpg' 84 * }); 85 * 86 * var viewer = new Cesium.Viewer('cesiumContainer', { 87 * imageryProvider : imageryProvider, 88 * baseLayerPicker : false, 89 * terrainProvider : terrainProvider 90 * }); 91 * 92 * // The globe must enable lighting to make use of the terrain's vertex normals 93 * viewer.scene.globe.enableLighting = true; 94 * 95 * @see TerrainProvider 96 */ 97 function InfoCesiumTerrainProvider(options) { 98 //>>includeStart('debug', pragmas.debug) 99 if (!defined(options) || !defined(options.url)) { 100 throw new DeveloperError('options.url is required.'); 101 } 102 //>>includeEnd('debug'); 103 104 this.maxLevel = defaultValue(options.maxLevel, 0); 105 this._url = options.url; 106 this._proxy = options.proxy; 107 108 this._tilingScheme = new GeographicTilingScheme({ 109 numberOfLevelZeroTilesX: 18, 110 numberOfLevelZeroTilesY: 9, 111 ellipsoid: options.ellipsoid 112 }); 113 114 this._heightmapWidth = 150; 115 this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0)); 116 117 this._heightmapStructure = undefined; 118 this._hasWaterMask = false; 119 120 /** 121 * Boolean flag that indicates if the Terrain Server can provide vertex normals. 122 * @type {Boolean} 123 * @default false 124 * @private 125 */ 126 this._hasVertexNormals = false; 127 /** 128 * Boolean flag that indicates if the client should request vertex normals from the server. 129 * @type {Boolean} 130 * @default false 131 * @private 132 */ 133 this._requestVertexNormals = defaultValue(options.requestVertexNormals, false); 134 this._littleEndianExtensionSize = true; 135 /** 136 * Boolean flag that indicates if the client should request tile watermasks from the server. 137 * @type {Boolean} 138 * @default false 139 * @private 140 */ 141 this._requestWaterMask = defaultValue(options.requestWaterMask, false); 142 143 this._errorEvent = new Event(); 144 145 var credit = options.credit; 146 if (typeof credit === 'string') { 147 credit = new Credit(credit); 148 } 149 this._credit = credit; 150 151 this._ready = false; 152 this._readyPromise = when.defer(); 153 154 var metadataUrl = this._url; 155 if (defined(this._proxy)) { 156 metadataUrl = this._proxy.getURL(metadataUrl); 157 } 158 159 var that = this; 160 var metadataError; 161 162 function metadataSuccess(data) { 163 var message; 164 165 if (!data.format) { 166 message = 'The tile format is not specified in the layer.json file.'; 167 metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); 168 return; 169 } 170 171 if (!data.tiles || data.tiles.length === 0) { 172 message = 'The layer.json file does not specify any tile URL templates.'; 173 metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); 174 return; 175 } 176 177 if (data.format === 'heightmap-1.0') { 178 that._heightmapStructure = { 179 heightScale: 1.0, 180 heightOffset: 0, 181 elementsPerHeight: 1, 182 stride: 1, 183 elementMultiplier: 512.0, 184 isBigEndian: false, 185 lowestEncodedHeight: 0, 186 highestEncodedHeight: 512 * 512 - 1 187 }; 188 that._hasWaterMask = true; 189 that._requestWaterMask = true; 190 } else if (data.format.indexOf('quantized-mesh-1.') !== 0) { 191 message = 'The tile format "' + data.format + '" is invalid or not supported.'; 192 metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); 193 return; 194 } 195 196 that._tileUrlTemplates = that._url;//已更改 by wanghui 197 198 that._availableTiles = data.available; 199 200 if (!defined(that._credit) && defined(data.attribution) && data.attribution !== null) { 201 that._credit = new Credit(data.attribution); 202 } 203 204 // The vertex normals defined in the 'octvertexnormals' extension is identical to the original 205 // contents of the original 'vertexnormals' extension. 'vertexnormals' extension is now 206 // deprecated, as the extensionLength for this extension was incorrectly using big endian. 207 // We maintain backwards compatibility with the legacy 'vertexnormal' implementation 208 // by setting the _littleEndianExtensionSize to false. Always prefer 'octvertexnormals' 209 // over 'vertexnormals' if both extensions are supported by the server. 210 if (defined(data.extensions) && data.extensions.indexOf('octvertexnormals') !== -1) { 211 that._hasVertexNormals = true; 212 } else if (defined(data.extensions) && data.extensions.indexOf('vertexnormals') !== -1) { 213 that._hasVertexNormals = true; 214 that._littleEndianExtensionSize = false; 215 } 216 if (defined(data.extensions) && data.extensions.indexOf('watermask') !== -1) { 217 that._hasWaterMask = true; 218 } 219 220 that._ready = true; 221 that._readyPromise.resolve(true); 222 } 223 224 /****源码更改,不读配置文件,直接初始数据***/ 225 function metadataIni() { 226 metadataSuccess({ 227 tilejson: '2.1.0', 228 format: 'heightmap-1.0', 229 version: '1.0.0', 230 scheme: 'tms', 231 tiles: [ 232 '?' 233 ] 234 }); 235 return; 236 } 237 /* 238 function metadataFailure(data) { 239 // If the metadata is not found, assume this is a pre-metadata heightmap tileset. 240 if (defined(data) && data.statusCode === 404) { 241 metadataSuccess({ 242 tilejson: '2.1.0', 243 format: 'heightmap-1.0', 244 version: '1.0.0', 245 scheme: 'tms', 246 tiles: [ 247 '{z}/{x}/{y}.terrain?v={version}' 248 ] 249 }); 250 return; 251 } 252 var message = 'An error occurred while accessing ' + metadataUrl + '.'; 253 metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); 254 } 255 256 function requestMetadata() { 257 var metadata = loadJson(metadataUrl); 258 when(metadata, metadataSuccess, metadataFailure); 259 } 260 261 requestMetadata();*/ 262 metadataIni(); 263 } 264 265 /** 266 * When using the Quantized-Mesh format, a tile may be returned that includes additional extensions, such as PerVertexNormals, watermask, etc. 267 * This enumeration defines the unique identifiers for each type of extension data that has been appended to the standard mesh data. 268 * 269 * @exports QuantizedMeshExtensionIds 270 * @see CesiumTerrainProvider 271 * @private 272 */ 273 var QuantizedMeshExtensionIds = { 274 /** 275 * Oct-Encoded Per-Vertex Normals are included as an extension to the tile mesh 276 * 277 * @type {Number} 278 * @constant 279 * @default 1 280 */ 281 OCT_VERTEX_NORMALS: 1, 282 /** 283 * A watermask is included as an extension to the tile mesh 284 * 285 * @type {Number} 286 * @constant 287 * @default 2 288 */ 289 WATER_MASK: 2 290 }; 291 292 function getRequestHeader(extensionsList) { 293 if (!defined(extensionsList) || extensionsList.length === 0) { 294 return { 295 Accept: 'application/vnd.quantized-mesh,application/octet-stream;q=0.9,*/*;q=0.01' 296 }; 297 } else { 298 var extensions = extensionsList.join('-'); 299 return { 300 Accept: 'application/vnd.quantized-mesh;extensions=' + extensions + ',application/octet-stream;q=0.9,*/*;q=0.01' 301 }; 302 } 303 } 304 305 function createHeightmapTerrainData(provider, buffer, level, x, y, tmsY) { 306 var hasChildOrNot; 307 if (level < provider.maxLevel) { 308 hasChildOrNot = new Uint8Array([15])[0]; 309 } 310 else { 311 hasChildOrNot = new Uint8Array([0])[0]; 312 } 313 if (buffer.byteLength > 0) { 314 var intBuffer = new Int16Array(buffer, 0, provider._heightmapWidth * provider._heightmapWidth); 315 var temp = 0; 316 for (var i = 0; i < intBuffer.length; i++) { 317 if (temp > intBuffer[i]) { 318 temp = intBuffer[i]; 319 } 320 if (intBuffer[i] < 0) { 321 console.log(temp); 322 } 323 } 324 var heightBuffer = new Uint16Array(intBuffer.length); 325 for (var i = 0; i < intBuffer.length; i++) { 326 heightBuffer[i] = intBuffer[i] - temp; 327 } 328 var heightmapStructure = { 329 heightScale: 3.0, 330 heightOffset: temp*3, 331 elementsPerHeight: 1, 332 stride: 1, 333 elementMultiplier: 512.0, 334 isBigEndian: false, 335 lowestEncodedHeight: 0, 336 highestEncodedHeight: 512 * 512 - 1 337 }; 338 //console.log(temp); 339 340 return new HeightmapTerrainData({ 341 buffer: heightBuffer, 342 childTileMask: hasChildOrNot, 343 waterMask: new Uint8Array([0]), 344 width: provider._heightmapWidth, 345 height: provider._heightmapWidth, 346 structure: heightmapStructure 347 }); 348 } 349 else { 350 var heightBuffer = new Uint16Array(provider._heightmapWidth * provider._heightmapWidth); 351 for (var i = 0; i < heightBuffer.byteLength; i++) { 352 heightBuffer[i] = 0; 353 } 354 return new HeightmapTerrainData({ 355 buffer: heightBuffer, 356 childTileMask: hasChildOrNot, 357 waterMask: new Uint8Array([0]), 358 width: provider._heightmapWidth, 359 height: provider._heightmapWidth, 360 structure: provider._heightmapStructure 361 }); 362 } 363 } 364 365 function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY) { 366 var pos = 0; 367 var cartesian3Elements = 3; 368 var boundingSphereElements = cartesian3Elements + 1; 369 var cartesian3Length = Float64Array.BYTES_PER_ELEMENT * cartesian3Elements; 370 var boundingSphereLength = Float64Array.BYTES_PER_ELEMENT * boundingSphereElements; 371 var encodedVertexElements = 3; 372 var encodedVertexLength = Uint16Array.BYTES_PER_ELEMENT * encodedVertexElements; 373 var triangleElements = 3; 374 var bytesPerIndex = Uint16Array.BYTES_PER_ELEMENT; 375 var triangleLength = bytesPerIndex * triangleElements; 376 377 var view = new DataView(buffer); 378 var center = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)); 379 pos += cartesian3Length; 380 381 var minimumHeight = view.getFloat32(pos, true); 382 pos += Float32Array.BYTES_PER_ELEMENT; 383 var maximumHeight = view.getFloat32(pos, true); 384 pos += Float32Array.BYTES_PER_ELEMENT; 385 386 var boundingSphere = new BoundingSphere( 387 new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)), 388 view.getFloat64(pos + cartesian3Length, true)); 389 pos += boundingSphereLength; 390 391 var horizonOcclusionPoint = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)); 392 pos += cartesian3Length; 393 394 var vertexCount = view.getUint32(pos, true); 395 pos += Uint32Array.BYTES_PER_ELEMENT; 396 var encodedVertexBuffer = new Uint16Array(buffer, pos, vertexCount * 3); 397 pos += vertexCount * encodedVertexLength; 398 399 if (vertexCount > 64 * 1024) { 400 // More than 64k vertices, so indices are 32-bit. 401 bytesPerIndex = Uint32Array.BYTES_PER_ELEMENT; 402 triangleLength = bytesPerIndex * triangleElements; 403 } 404 405 // Decode the vertex buffer. 406 var uBuffer = encodedVertexBuffer.subarray(0, vertexCount); 407 var vBuffer = encodedVertexBuffer.subarray(vertexCount, 2 * vertexCount); 408 var heightBuffer = encodedVertexBuffer.subarray(vertexCount * 2, 3 * vertexCount); 409 410 var i; 411 var u = 0; 412 var v = 0; 413 var height = 0; 414 415 function zigZagDecode(value) { 416 return (value >> 1) ^ (-(value & 1)); 417 } 418 419 for (i = 0; i < vertexCount; ++i) { 420 u += zigZagDecode(uBuffer[i]); 421 v += zigZagDecode(vBuffer[i]); 422 height += zigZagDecode(heightBuffer[i]); 423 424 uBuffer[i] = u; 425 vBuffer[i] = v; 426 heightBuffer[i] = height; 427 } 428 429 // skip over any additional padding that was added for 2/4 byte alignment 430 if (pos % bytesPerIndex !== 0) { 431 pos += (bytesPerIndex - (pos % bytesPerIndex)); 432 } 433 434 var triangleCount = view.getUint32(pos, true); 435 pos += Uint32Array.BYTES_PER_ELEMENT; 436 var indices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, triangleCount * triangleElements); 437 pos += triangleCount * triangleLength; 438 439 // High water mark decoding based on decompressIndices_ in webgl-loader's loader.js. 440 // https://code.google.com/p/webgl-loader/source/browse/trunk/samples/loader.js?r=99#55 441 // Copyright 2012 Google Inc., Apache 2.0 license. 442 var highest = 0; 443 for (i = 0; i < indices.length; ++i) { 444 var code = indices[i]; 445 indices[i] = highest - code; 446 if (code === 0) { 447 ++highest; 448 } 449 } 450 451 var westVertexCount = view.getUint32(pos, true); 452 pos += Uint32Array.BYTES_PER_ELEMENT; 453 var westIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, westVertexCount); 454 pos += westVertexCount * bytesPerIndex; 455 456 var southVertexCount = view.getUint32(pos, true); 457 pos += Uint32Array.BYTES_PER_ELEMENT; 458 var southIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, southVertexCount); 459 pos += southVertexCount * bytesPerIndex; 460 461 var eastVertexCount = view.getUint32(pos, true); 462 pos += Uint32Array.BYTES_PER_ELEMENT; 463 var eastIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, eastVertexCount); 464 pos += eastVertexCount * bytesPerIndex; 465 466 var northVertexCount = view.getUint32(pos, true); 467 pos += Uint32Array.BYTES_PER_ELEMENT; 468 var northIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, northVertexCount); 469 pos += northVertexCount * bytesPerIndex; 470 471 var encodedNormalBuffer; 472 var waterMaskBuffer; 473 while (pos < view.byteLength) { 474 var extensionId = view.getUint8(pos, true); 475 pos += Uint8Array.BYTES_PER_ELEMENT; 476 var extensionLength = view.getUint32(pos, provider._littleEndianExtensionSize); 477 pos += Uint32Array.BYTES_PER_ELEMENT; 478 479 if (extensionId === QuantizedMeshExtensionIds.OCT_VERTEX_NORMALS && provider._requestVertexNormals) { 480 encodedNormalBuffer = new Uint8Array(buffer, pos, vertexCount * 2); 481 } else if (extensionId === QuantizedMeshExtensionIds.WATER_MASK && provider._requestWaterMask) { 482 waterMaskBuffer = new Uint8Array(buffer, pos, extensionLength); 483 } 484 pos += extensionLength; 485 } 486 487 var skirtHeight = provider.getLevelMaximumGeometricError(level) * 5.0; 488 489 var rectangle = provider._tilingScheme.tileXYToRectangle(x, y, level); 490 var orientedBoundingBox; 491 if (rectangle.width < CesiumMath.PI_OVER_TWO + CesiumMath.EPSILON5) { 492 // Here, rectangle.width < pi/2, and rectangle.height < pi 493 // (though it would still work with rectangle.width up to pi) 494 495 // The skirt is not included in the OBB computation. If this ever 496 // causes any rendering artifacts (cracks), they are expected to be 497 // minor and in the corners of the screen. It's possible that this 498 // might need to be changed - just change to `minimumHeight - skirtHeight` 499 // A similar change might also be needed in `upsampleQuantizedTerrainMesh.js`. 500 orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, provider._tilingScheme.ellipsoid); 501 } 502 503 return new QuantizedMeshTerrainData({ 504 center: center, 505 minimumHeight: minimumHeight, 506 maximumHeight: maximumHeight, 507 boundingSphere: boundingSphere, 508 orientedBoundingBox: orientedBoundingBox, 509 horizonOcclusionPoint: horizonOcclusionPoint, 510 quantizedVertices: encodedVertexBuffer, 511 encodedNormals: encodedNormalBuffer, 512 indices: indices, 513 westIndices: westIndices, 514 southIndices: southIndices, 515 eastIndices: eastIndices, 516 northIndices: northIndices, 517 westSkirtHeight: skirtHeight, 518 southSkirtHeight: skirtHeight, 519 eastSkirtHeight: skirtHeight, 520 northSkirtHeight: skirtHeight, 521 childTileMask: getChildMaskForTile(provider, level, x, tmsY), 522 waterMask: waterMaskBuffer 523 }); 524 } 525 526 /** 527 * Requests the geometry for a given tile. This function should not be called before 528 * {@link CesiumTerrainProvider#ready} returns true. The result must include terrain data and 529 * may optionally include a water mask and an indication of which child tiles are available. 530 * 531 * @param {Number} x The X coordinate of the tile for which to request geometry. 532 * @param {Number} y The Y coordinate of the tile for which to request geometry. 533 * @param {Number} level The level of the tile for which to request geometry. 534 * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited, 535 * or false if the request should be initiated regardless of the number of requests 536 * already in progress. 537 * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry. If this method 538 * returns undefined instead of a promise, it is an indication that too many requests are already 539 * pending and the request will be retried later. 540 * 541 * @exception {DeveloperError} This function must not be called before {@link CesiumTerrainProvider#ready} 542 * returns true. 543 */ 544 InfoCesiumTerrainProvider.prototype.requestTileGeometry = function (x, y, level, throttleRequests) { 545 //>>includeStart('debug', pragmas.debug) 546 if (!this._ready) { 547 throw new DeveloperError('requestTileGeometry must not be called before the terrain provider is ready.'); 548 } 549 //>>includeEnd('debug'); 550 551 var urlTemplates = this._tileUrlTemplates; 552 if (urlTemplates.length === 0) { 553 return undefined; 554 } 555 556 var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level); 557 558 var tmsY = (yTiles - y - 1); 559 560 //var url = urlTemplates[(x + tmsY + level) % urlTemplates.length].replace('{z}', level).replace('{x}', x).replace('{y}', x+"_"+tmsY); 561 var url = urlTemplates + '?T=30mDEMS&L=' + level + '&X=' + x + '&Y=' + tmsY + '&UserToken=' 562 563 var proxy = this._proxy; 564 if (defined(proxy)) { 565 url = proxy.getURL(url); 566 } 567 568 var promise; 569 570 var extensionList = []; 571 if (this._requestVertexNormals && this._hasVertexNormals) { 572 extensionList.push(this._littleEndianExtensionSize ? "octvertexnormals" : "vertexnormals"); 573 } 574 if (this._requestWaterMask && this._hasWaterMask) { 575 extensionList.push("watermask"); 576 } 577 578 function tileLoader(tileUrl) { 579 return loadArrayBuffer(tileUrl, getRequestHeader(extensionList)); 580 } 581 throttleRequests = defaultValue(throttleRequests, true); 582 if (throttleRequests) { 583 promise = throttleRequestByServer(url, tileLoader); 584 if (!defined(promise)) { 585 return undefined; 586 } 587 } else { 588 promise = tileLoader(url); 589 } 590 591 var that = this; 592 return when(promise, function (buffer) { 593 if (defined(that._heightmapStructure)) { 594 return createHeightmapTerrainData(that, buffer, level, x, y, tmsY); 595 } else { 596 return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY); 597 } 598 }); 599 }; 600 601 defineProperties(InfoCesiumTerrainProvider.prototype, { 602 /** 603 * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing 604 * to the event, you will be notified of the error and can potentially recover from it. Event listeners 605 * are passed an instance of {@link TileProviderError}. 606 * @memberof CesiumTerrainProvider.prototype 607 * @type {Event} 608 */ 609 errorEvent: { 610 get: function () { 611 return this._errorEvent; 612 } 613 }, 614 615 /** 616 * Gets the credit to display when this terrain provider is active. Typically this is used to credit 617 * the source of the terrain. This function should not be called before {@link CesiumTerrainProvider#ready} returns true. 618 * @memberof CesiumTerrainProvider.prototype 619 * @type {Credit} 620 */ 621 credit: { 622 get: function () { 623 //>>includeStart('debug', pragmas.debug) 624 if (!this._ready) { 625 throw new DeveloperError('credit must not be called before the terrain provider is ready.'); 626 } 627 //>>includeEnd('debug'); 628 629 return this._credit; 630 } 631 }, 632 633 /** 634 * Gets the tiling scheme used by this provider. This function should 635 * not be called before {@link CesiumTerrainProvider#ready} returns true. 636 * @memberof CesiumTerrainProvider.prototype 637 * @type {GeographicTilingScheme} 638 */ 639 tilingScheme: { 640 get: function () { 641 //>>includeStart('debug', pragmas.debug) 642 if (!this._ready) { 643 throw new DeveloperError('tilingScheme must not be called before the terrain provider is ready.'); 644 } 645 //>>includeEnd('debug'); 646 647 return this._tilingScheme; 648 } 649 }, 650 651 /** 652 * Gets a value indicating whether or not the provider is ready for use. 653 * @memberof CesiumTerrainProvider.prototype 654 * @type {Boolean} 655 */ 656 ready: { 657 get: function () { 658 return this._ready; 659 } 660 }, 661 662 /** 663 * Gets a promise that resolves to true when the provider is ready for use. 664 * @memberof CesiumTerrainProvider.prototype 665 * @type {Promise.<Boolean>} 666 * @readonly 667 */ 668 readyPromise: { 669 get: function () { 670 return this._readyPromise.promise; 671 } 672 }, 673 674 /** 675 * Gets a value indicating whether or not the provider includes a water mask. The water mask 676 * indicates which areas of the globe are water rather than land, so they can be rendered 677 * as a reflective surface with animated waves. This function should not be 678 * called before {@link CesiumTerrainProvider#ready} returns true. 679 * @memberof CesiumTerrainProvider.prototype 680 * @type {Boolean} 681 * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready} 682 */ 683 hasWaterMask: { 684 get: function () { 685 //>>includeStart('debug', pragmas.debug) 686 if (!this._ready) { 687 throw new DeveloperError('hasWaterMask must not be called before the terrain provider is ready.'); 688 } 689 //>>includeEnd('debug'); 690 691 return this._hasWaterMask && this._requestWaterMask; 692 } 693 }, 694 695 /** 696 * Gets a value indicating whether or not the requested tiles include vertex normals. 697 * This function should not be called before {@link CesiumTerrainProvider#ready} returns true. 698 * @memberof CesiumTerrainProvider.prototype 699 * @type {Boolean} 700 * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready} 701 */ 702 hasVertexNormals: { 703 get: function () { 704 //>>includeStart('debug', pragmas.debug) 705 if (!this._ready) { 706 throw new DeveloperError('hasVertexNormals must not be called before the terrain provider is ready.'); 707 } 708 //>>includeEnd('debug'); 709 710 // returns true if we can request vertex normals from the server 711 return this._hasVertexNormals && this._requestVertexNormals; 712 } 713 }, 714 715 /** 716 * Boolean flag that indicates if the client should request vertex normals from the server. 717 * Vertex normals data is appended to the standard tile mesh data only if the client requests the vertex normals and 718 * if the server provides vertex normals. 719 * @memberof CesiumTerrainProvider.prototype 720 * @type {Boolean} 721 */ 722 requestVertexNormals: { 723 get: function () { 724 return this._requestVertexNormals; 725 } 726 }, 727 728 /** 729 * Boolean flag that indicates if the client should request a watermask from the server. 730 * Watermask data is appended to the standard tile mesh data only if the client requests the watermask and 731 * if the server provides a watermask. 732 * @memberof CesiumTerrainProvider.prototype 733 * @type {Boolean} 734 */ 735 requestWaterMask: { 736 get: function () { 737 return this._requestWaterMask; 738 } 739 } 740 }); 741 742 /** 743 * Gets the maximum geometric error allowed in a tile at a given level. 744 * 745 * @param {Number} level The tile level for which to get the maximum geometric error. 746 * @returns {Number} The maximum geometric error. 747 */ 748 InfoCesiumTerrainProvider.prototype.getLevelMaximumGeometricError = function (level) { 749 return this._levelZeroMaximumGeometricError / (1 << level); 750 }; 751 752 function getChildMaskForTile(terrainProvider, level, x, y) { 753 var available = terrainProvider._availableTiles; 754 if (!available || available.length === 0) { 755 return 15; 756 } 757 758 var childLevel = level + 1; 759 if (childLevel >= available.length) { 760 return 0; 761 } 762 763 var levelAvailable = available[childLevel]; 764 765 var mask = 0; 766 767 mask |= isTileInRange(levelAvailable, 2 * x, 2 * y) ? 1 : 0; 768 mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y) ? 2 : 0; 769 mask |= isTileInRange(levelAvailable, 2 * x, 2 * y + 1) ? 4 : 0; 770 mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y + 1) ? 8 : 0; 771 772 return mask; 773 } 774 775 function isTileInRange(levelAvailable, x, y) { 776 for (var i = 0, len = levelAvailable.length; i < len; ++i) { 777 var range = levelAvailable[i]; 778 if (x >= range.startX && x <= range.endX && y >= range.startY && y <= range.endY) { 779 return true; 780 } 781 } 782 783 return false; 784 } 785 786 /** 787 * Determines whether data for a tile is available to be loaded. 788 * 789 * @param {Number} x The X coordinate of the tile for which to request geometry. 790 * @param {Number} y The Y coordinate of the tile for which to request geometry. 791 * @param {Number} level The level of the tile for which to request geometry. 792 * @returns {Boolean} Undefined if not supported, otherwise true or false. 793 */ 794 InfoCesiumTerrainProvider.prototype.getTileDataAvailable = function (x, y, level) { 795 var available = this._availableTiles; 796 797 if (!available || available.length === 0) { 798 return undefined; 799 } else { 800 if (level >= available.length) { 801 return false; 802 } 803 var levelAvailable = available[level]; 804 var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level); 805 var tmsY = (yTiles - y - 1); 806 return isTileInRange(levelAvailable, x, tmsY); 807 } 808 }; 809 810 return InfoCesiumTerrainProvider; 811 });