// 物体状态 var EntityState = { FAILED: 0, UNLOADED: 1, RECEIVING: 2, RECEIVED: 3, TRANSFORMING: 4, TRANSFORMED: 5, READY: 6 }; /** * 物体瓦片,负责管理瓦片内物体的加载过程。 * @param provider * @constructor */ function TileEntity(provider) { if (!Cesium.defined(provider)) { throw new DeveloperError('provider is required.'); } this.provider = provider; this.state = EntityState.UNLOADED; this.buffers = []; this.dataList = []; } /** * Processes the load state machine for this instance. * */ TileEntity.prototype.processStateMachine = function (frameState, entityProvider, x, y, level, priorityFunction) { if (this.state === EntityState.UNLOADED) { requestEntityData(this, entityProvider, x, y, level, priorityFunction); } if (this.state === EntityState.RECEIVED) { transform(this, frameState, entityProvider, x, y, level); } if (this.state === EntityState.TRANSFORMED) { createResources(this, frameState.context, entityProvider, x, y, level); } if (this.state === EntityState.READY) { return true; // done loading } // 没有加载完成也应该使用父节点的,不能四个子节点都使用父节点显示那样就重复了;可以给节点增加计数,确保每个节点只显示一次。 // 目前所有父节点都是可见,后期再完善。 // Find some ancestor imagery we can use while this imagery is still loading. // var ancestor = this.parent; // var closestAncestorThatNeedsLoading; // while (defined(ancestor) && (ancestor.state !== ImageryState.READY || (!this.useWebMercatorT && !defined(ancestor.texture)))) { // if (ancestor.state !== ImageryState.FAILED && ancestor.state !== ImageryState.INVALID) { // // ancestor is still loading // closestAncestorThatNeedsLoading = closestAncestorThatNeedsLoading || ancestor; // } // ancestor = ancestor.parent; // } // // if (this.readyImagery !== ancestor) { // if (defined(this.readyImagery)) { // this.readyImagery.releaseReference(); // } // // this.readyImagery = ancestor; // // if (defined(ancestor)) { // ancestor.addReference(); // this.textureTranslationAndScale = imageryLayer._calculateTextureTranslationAndScale(tile, this); // } // } if (this.state === EntityState.FAILED) { // The imagery tile is failed or invalid, so we'd like to use an ancestor instead. // if (defined(closestAncestorThatNeedsLoading)) { // // Push the ancestor's load process along a bit. This is necessary because some ancestor imagery // // tiles may not be attached directly to a terrain tile. Such tiles will never load if // // we don't do it here. // closestAncestorThatNeedsLoading.processStateMachine(frameState, !this.useWebMercatorT, tile._priorityFunction); // return false; // not done loading // } // This imagery tile is failed or invalid, and we have the "best available" substitute. return true; // done loading } return false; // not done loading } function requestEntityData(tileEntity, entityProvider, x, y, level, priorityFunction) { function success(buffers) { if (!Cesium.defined(buffers)) { tileEntity.state = EntityState.UNLOADED; tileEntity.request = undefined; return; } tileEntity.buffers = buffers; tileEntity.state = EntityState.RECEIVED; tileEntity.request = undefined; } function failure() { if (tileEntity.request.state === RequestState.CANCELLED) { // Cancelled due to low priority - try again later. tileEntity.state = EntityState.UNLOADED; tileEntity.request = undefined; return; } // Initially assume failure. handleError may retry, in which case the state will // change to RECEIVING or UNLOADED. tileEntity.state = EntityState.FAILED; tileEntity.request = undefined; var message = 'Failed to obtain entity tile X: ' + x + ' Y: ' + y + ' Level: ' + level + '.'; entityProvider._requestError = Cesium.TileProviderError.handleError( entityProvider._requestError, entityProvider, entityProvider.errorEvent, message, x, y, level, doRequest); } function doRequest() { // Request the entity data from the entity provider. var request = new Cesium.Request({ throttle: true, throttleByServer: true, type: Cesium.RequestType.TILES3D, priorityFunction: priorityFunction }); tileEntity.request = request; var data = entityProvider.requestEntityData(x, y, level, request); // If the request method returns undefined (instead of a promise), the request // has been deferred. if (Cesium.defined(data)) { tileEntity.state = tileEntity.RECEIVING; Cesium.when(data, success, failure); } else { // Deferred - try again later. //tileEntity.state = EntityState.UNLOADED; tileEntity.request = undefined; tileEntity.state = EntityState.FAILED; } } doRequest(); } function transform(tileEntity, frameState, provider, x, y, level) { if (!Cesium.defined(tileEntity.buffers)) { return null; } // 解析数据(也可以放在分支线程) for (var i = 0, len = tileEntity.buffers.length; i < len; ++i) { var stream = new MemStream(tileEntity.buffers[i]); var version = stream.readInt32(); var count = stream.readInt32(); for (var j = 0; j < count; ++j) { var lon = stream.readFloat(); var lat = stream.readFloat(); var h = stream.readFloat(); var text = ''; var textLen = stream.readUChar8(); if (textLen > 0) { var strData = stream.readUChar8Array2(textLen); text = new TextDecoder("utf-8").decode(strData); text = text.replace(/\|/g, ''); // 替换掉所有的|字符 } var useFont = provider.fontSize * 2 + "px " + provider.fontFamily; var entity = provider.viewer.entities.add({ parent: provider.fatherGroup, position: Cesium.Cartesian3.fromDegrees(lon, lat, h), label: { text: text, font: useFont, fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 6, style: Cesium.LabelStyle.FILL_AND_OUTLINE, scale: 0.5 } }); tileEntity.dataList.push(entity.id); // 保留id供移除时使用 } } tileEntity.buffers.length = 0; tileEntity.state = EntityState.TRANSFORMING; // 如果是在其他线程做,完成后再改变状态 // when(meshPromise, function(mesh) { // tileTerrain.mesh = mesh; // tileTerrain.state = TerrainState.TRANSFORMED; // }, function() { // tileTerrain.state = TerrainState.FAILED; // }); tileEntity.state = EntityState.TRANSFORMED; } function createResources(tileEntity, context) { // 使用现有的结构就不手动构建渲染单元了 // tileTerrain.vertexArray = new VertexArray({ // context : context, // attributes : attributes, // indexBuffer : indexBuffer // }); tileEntity.state = EntityState.READY; } TileEntity.prototype.freeResources = function () { for (var i = 0, len = this.dataList.length; i < len; ++i) { this.provider.viewer.entities.removeById(this.dataList[i]); } this.dataList.length = 0; this.buffers.length = 0; };