|
@@ -5,6 +5,7 @@
|
|
|
* 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
|
|
|
*/
|
|
|
|
|
|
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
|
|
|
Date.prototype.Format = function(fmt) { // author: meizz
|
|
|
var o = {
|
|
|
"M+": this.getMonth() + 1, // 月份
|
|
@@ -24,8 +25,7 @@ Date.prototype.Format = function(fmt) { // author: meizz
|
|
|
|
|
|
/* 引入Cesium */
|
|
|
import * as Cesium from 'cesium';
|
|
|
-
|
|
|
-import CrImageMaterialProperty from './CrImageMaterialProperty.js'
|
|
|
+// import Worker from '../../../public/worker/download.js?worker';
|
|
|
|
|
|
/* 创建类 */
|
|
|
class CrImageServerLayer {
|
|
@@ -33,29 +33,35 @@ class CrImageServerLayer {
|
|
|
* 构造函数
|
|
|
* @param {Cesium.Viewer} options.viewer 地图视图容器
|
|
|
* @param {String} options.url 服务地址
|
|
|
- * @param {Number} options.opacity 图层透明度 [默认0.3]
|
|
|
+ * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]
|
|
|
*/
|
|
|
constructor({
|
|
|
viewer,
|
|
|
url,
|
|
|
- opacity = 0.3
|
|
|
+ opacity = 0.75,
|
|
|
+ show = true,
|
|
|
} = {}) {
|
|
|
+ /* 地图视图 外部传入 必须参数 */
|
|
|
this._viewer = viewer;
|
|
|
+ /* 服务地址 外部传入 */
|
|
|
this._url = url;
|
|
|
+ /* 透明度 外部传入 */
|
|
|
this._opacity = opacity;
|
|
|
- this._renderName = 'suiji'; //后期要改成随机字符串
|
|
|
- this._entities = this._viewer.entities;
|
|
|
+ /* 图层随机标识 */
|
|
|
+ this._renderName = this._guid();
|
|
|
+ /* 实体集合 */
|
|
|
+ /* 用DataSource 方式 以便进行多图层管理 */
|
|
|
+ let dataSource = new Cesium.CustomDataSource(this._renderName);
|
|
|
+ this._viewer.dataSources.add(dataSource);
|
|
|
+ this._entities = dataSource.entities;
|
|
|
+ /* 渲染集合 */
|
|
|
+ this._renderEntities = new Map();
|
|
|
+ /* 是否渲染标志 */
|
|
|
+ this._isUpdateTile = show;
|
|
|
+ /* 是否输出测试信息 */
|
|
|
+ this._isDebug = false;
|
|
|
+ /* 初始化 */
|
|
|
this._init();
|
|
|
- this._isUpdateTile = true;
|
|
|
- this._updateTiles = new Map();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 控制台输出
|
|
|
- * @param {Object} params 参数集合
|
|
|
- */
|
|
|
- _console(params) {
|
|
|
- console.log('CrImageServerLayer', params);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -63,365 +69,440 @@ class CrImageServerLayer {
|
|
|
*/
|
|
|
_init() {
|
|
|
let _self = this;
|
|
|
- //http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_YX_102100_202112/MapServer/WMTS
|
|
|
- //http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer/wmts
|
|
|
- let baseUrl =
|
|
|
- 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer';
|
|
|
+ /* 创建服务提供者 */
|
|
|
this._provider = new Cesium.ArcGisMapServerImageryProvider({
|
|
|
- url: baseUrl,
|
|
|
+ url: _self._url,
|
|
|
})
|
|
|
-
|
|
|
+ /* 激活服务提供者 注册刷帧事件 */
|
|
|
this._provider.readyPromise.then(function(result) {
|
|
|
+ /* 服务提供者的数据范围 */
|
|
|
+ _self._rectangle = _self._provider.rectangle;
|
|
|
+ /* 输出调试信息 */
|
|
|
+ if (_self._isDebug) _self._printDebug();
|
|
|
/* 注册事件 */
|
|
|
_self._viewer.scene.postRender.addEventListener(() => {
|
|
|
- if (_self._isUpdateTile === true) {
|
|
|
- _self._updateRenderTile();
|
|
|
+ if (_self._isUpdateTile) {
|
|
|
+ /* 设置运行标志为false 等待计算完成 */
|
|
|
+ _self._isUpdateTile = false;
|
|
|
+ /* 投影瓦片集合 */
|
|
|
+ _self._renderTiles();
|
|
|
}
|
|
|
});
|
|
|
- _self._viewer.camera.moveEnd.addEventListener(function(event) {
|
|
|
-
|
|
|
- });
|
|
|
})
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 生成GUID随机数
|
|
|
+ */
|
|
|
+ _guid() {
|
|
|
+ function S4() {
|
|
|
+ return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
|
+ }
|
|
|
+ return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 输出调试信息
|
|
|
+ */
|
|
|
+ _printDebug() {
|
|
|
+ /* 数据提供者的切片方案 */
|
|
|
+ let tiling = this._provider.tilingScheme;
|
|
|
+ /* WGS84坐标系的切片方案 */
|
|
|
+ let tiling84 = new Cesium.GeographicTilingScheme();
|
|
|
+ /* 绘制数据提供者的数据范围 */
|
|
|
+ this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
|
|
|
+ /* 根据行列号和等级创建调试矩形 */
|
|
|
+ let rect = tiling84.tileXYToRectangle(1696, 312, 10);
|
|
|
+ /* 绘制调试矩形 */
|
|
|
+ // this._drawDebugRectangle(rect, Cesium.Color.YELLOW);
|
|
|
+
|
|
|
+ // let rect11 = Cesium.Rectangle.subsection(rect, 0, 0, 0.5, 0.5);
|
|
|
+ // let rect12 = Cesium.Rectangle.subsection(rect, 0.5, 0, 1.0, 0.5);
|
|
|
+ // let rect21 = Cesium.Rectangle.subsection(rect, 0, 0.5, 0.5, 1.0);
|
|
|
+ // let rect22 = Cesium.Rectangle.subsection(rect, 0.5, 0.5, 1.0, 1.0);
|
|
|
+ // this._drawDebugRectangle(rect11, Cesium.Color.RED);
|
|
|
+ // this._drawDebugRectangle(rect12, Cesium.Color.GREEN);
|
|
|
+ // this._drawDebugRectangle(rect21, Cesium.Color.BLUE);
|
|
|
+ // this._drawDebugRectangle(rect22, Cesium.Color.WHITE);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 绘制调试矩形
|
|
|
+ * @param {Cesium.Rectangle} rectangle 绘制的矩形
|
|
|
+ * @param {Cesium.Color} color 矩形边框颜色
|
|
|
+ */
|
|
|
+ _drawDebugRectangle(rectangle, color) {
|
|
|
+ /* 计算矩形的外包范围 */
|
|
|
+ let positions = this._calculateRectangleOutlineCoordinates(rectangle);
|
|
|
+ /* 创建矩形实体 */
|
|
|
+ let rectEntity = new Cesium.Entity({
|
|
|
+ name: this._renderName,
|
|
|
+ polyline: {
|
|
|
+ positions: positions,
|
|
|
+ material: color,
|
|
|
+ width: 10,
|
|
|
+ clampToGround: true, //开启贴地 如果有模型则贴模型
|
|
|
+ }
|
|
|
+ });
|
|
|
+ /* 加入数据集 */
|
|
|
+ this._entities.add(rectEntity);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 输出消息
|
|
|
* @param {Object} res
|
|
|
*/
|
|
|
- _console(res) {
|
|
|
- console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', res);
|
|
|
+ _console(...rest) {
|
|
|
+ if (this._isDebug)
|
|
|
+ console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 更新渲染的Tile集合
|
|
|
+ * 渲染瓦片集合
|
|
|
*/
|
|
|
- _updateRenderTile() {
|
|
|
+ _renderTiles() {
|
|
|
let _self = this;
|
|
|
- /* 同步 */
|
|
|
- let promise = new Promise((resolve, reject) => {
|
|
|
- _self._isUpdateTile = false;
|
|
|
- let tilesToRender = _self._viewer.scene.globe._surface._tilesToRender;
|
|
|
- _self._console(tilesToRender.length);
|
|
|
- if (tilesToRender.length !== undefined && tilesToRender.length > 0) {
|
|
|
- let renderTiles = [];
|
|
|
- for (let i = 0; i < tilesToRender.length; i++) {
|
|
|
- let renderTile = tilesToRender[i];
|
|
|
- renderTiles.push(renderTile);
|
|
|
- }
|
|
|
- resolve(renderTiles);
|
|
|
- } else {
|
|
|
- _self._isUpdateTile = true;
|
|
|
- reject();
|
|
|
- }
|
|
|
- });
|
|
|
- /* 异步 */
|
|
|
- promise.then(renderTiles => {
|
|
|
- _self._calculateRenderTiles(renderTiles);
|
|
|
- }).catch(error => {
|
|
|
- _self._console(error);
|
|
|
- }).finally(() => {
|
|
|
- _self._console('执行结束');
|
|
|
- });
|
|
|
+ /* 获取当前视图渲染的瓦片集合 */
|
|
|
+ let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
|
|
|
+ if (tilesToRender === undefined || tilesToRender.length === 0) {
|
|
|
+ this._isUpdateTile = true;
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ new Promise((resolve, reject) => {
|
|
|
+ /* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
|
|
|
+ tilesToRender.sort(function(obj1, obj2) {
|
|
|
+ let level1 = parseInt(obj1.level);
|
|
|
+ let level2 = parseInt(obj2.level);
|
|
|
+ return level1 - level2;
|
|
|
+ })
|
|
|
+ /* 返回排序后的渲染瓦片数据集 开始异步计算 */
|
|
|
+ resolve(tilesToRender);
|
|
|
+ }).then(tiles => {
|
|
|
+ /* 异步重投影瓦片数据集 */
|
|
|
+ _self._asyncProjectionTiles(tiles);
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据行列和等级生成key
|
|
|
+ * @param {Number} x 行
|
|
|
+ * @param {Number} y 列
|
|
|
+ * @param {Number} level 等级
|
|
|
+ */
|
|
|
+ _createKey(x, y, level) {
|
|
|
+ let key = `${this._renderName}_${x}_${y}_${level}`;
|
|
|
+ return key;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 计算渲染的瓦片集合
|
|
|
- * @param {JSON} renderTiles 渲染的瓦片集合
|
|
|
+ * 投影瓦片集合
|
|
|
+ * @param {Object} tiles 原始渲染瓦片集合
|
|
|
*/
|
|
|
- _calculateRenderTiles(renderTiles) {
|
|
|
- let keys = [];
|
|
|
- for (let i = 0; i < renderTiles.length; i++) {
|
|
|
- let renderTile = renderTiles[i];
|
|
|
- /* 计算重投影后的Tiles */
|
|
|
- let tiles = this._calculateTile(renderTile);
|
|
|
- for (let tile of tiles) {
|
|
|
- let key = tile.x + '_' + tile.y + '_' + tile.level;
|
|
|
- if (!this._updateTiles.has(key)) {
|
|
|
- this._updateTiles.set(key, {
|
|
|
- key: key,
|
|
|
- x: tile.x,
|
|
|
- y: tile.y,
|
|
|
- level: tile.level,
|
|
|
- rectangle: tile.rectangle,
|
|
|
- state: 1,
|
|
|
- });
|
|
|
- this._console('添加动作', key);
|
|
|
+ _asyncProjectionTiles(tiles) {
|
|
|
+ let renderTiles = [];
|
|
|
+ /* 循环投影 */
|
|
|
+ for (let tile of tiles) {
|
|
|
+ /* 对单个瓦片进行重投影 */
|
|
|
+ let proTiles = this._projectionTile(tile);
|
|
|
+ for (let proTile of proTiles) {
|
|
|
+ /* 瓦片实体唯一标识 */
|
|
|
+ let key = this._createKey(proTile.x, proTile.y, proTile.level);
|
|
|
+ /* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
|
|
|
+ let subTile = renderTiles.find(obj => {
|
|
|
+ return obj.x === proTile.x && obj.y === proTile.y;
|
|
|
+ })
|
|
|
+ if (subTile === undefined) {
|
|
|
+ /* 重投影瓦片范围与数据范围的叠合计算 */
|
|
|
+ let isExists = false;
|
|
|
+ for (let eTile of renderTiles) {
|
|
|
+ if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
|
|
|
+ /* 追加子集 方便后期进行层级处理 */
|
|
|
+ eTile.childTiles.push(key);
|
|
|
+ isExists = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 加入渲染集合 */
|
|
|
+ if (!isExists) {
|
|
|
+ renderTiles.push({
|
|
|
+ key: key,
|
|
|
+ x: proTile.x,
|
|
|
+ y: proTile.y,
|
|
|
+ level: proTile.level,
|
|
|
+ rectangle: proTile.rectangle,
|
|
|
+ childTiles: [],
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
- keys.push(key);
|
|
|
}
|
|
|
}
|
|
|
- /* 循环剔除 */
|
|
|
- for (let [key, value] of this._updateTiles) {
|
|
|
- if (keys.indexOf(key) === -1) {
|
|
|
- value.state = -1;
|
|
|
- this._updateTiles.set(key, value);
|
|
|
- this._console('移除动作', key);
|
|
|
+ /* 清理低层级元素 */
|
|
|
+ let i = renderTiles.length;
|
|
|
+ let appendTiles = [];
|
|
|
+ while (i--) {
|
|
|
+ let findTile = renderTiles[i];
|
|
|
+ if (findTile.childTiles.length >= 1) {
|
|
|
+ /* 创建高层级的瓦片 */
|
|
|
+ let tiles = this._createFourTiles(findTile);
|
|
|
+ for (let tile of tiles) {
|
|
|
+ appendTiles.push(tile);
|
|
|
+ }
|
|
|
+ /* 如果存在高层级 则删除低层级 */
|
|
|
+ renderTiles.splice(i, 1);
|
|
|
}
|
|
|
}
|
|
|
- this._isUpdateTile = true;
|
|
|
- this._render(this._updateTiles);
|
|
|
- this._console('本次计算结束');
|
|
|
+ /* 将四叉树追加的层级数据加入到渲染集合中 */
|
|
|
+ for (let appendTile of appendTiles) {
|
|
|
+ renderTiles.push(appendTile);
|
|
|
+ }
|
|
|
+ /* 对数组进行排序 */
|
|
|
+ renderTiles.sort(function(obj1, obj2) {
|
|
|
+ let level1 = parseInt(obj1.level);
|
|
|
+ let level2 = parseInt(obj2.level);
|
|
|
+ return level1 - level2;
|
|
|
+ })
|
|
|
+ /* 渲染数据到视图中 */
|
|
|
+ this._renderTilesToViewer(renderTiles);
|
|
|
}
|
|
|
|
|
|
- _render(tiles) {
|
|
|
- let _self = this;
|
|
|
- for (let [key, tile] of tiles) {
|
|
|
- this._console('渲染', tile);
|
|
|
- if (tile.state === 1) {
|
|
|
- let promise = _self._provider.requestImage(tile.x, tile.y, tile.level);
|
|
|
- promise.then(function(image) {
|
|
|
- let canvas = document.createElement("canvas");
|
|
|
- canvas.width = 256;
|
|
|
- canvas.height = 256;
|
|
|
- let context = canvas.getContext("2d");
|
|
|
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
|
- let bjPositions = _self._calculateRectangleOutlineCoordinates(tile.rectangle);
|
|
|
- let tileEntity = new Cesium.Entity({
|
|
|
- name: 'AAA',
|
|
|
- id: tile.key,
|
|
|
- // rectangle: {
|
|
|
- // coordinates: tileJson.rectangle,
|
|
|
- // material: material, //Cesium.Color.RED.withAlpha(0.9),
|
|
|
- // },
|
|
|
- polyline: {
|
|
|
- positions: bjPositions,
|
|
|
- material: Cesium.Color.YELLOW,
|
|
|
- // width: 2,
|
|
|
- clampToGround: true, //开启贴地 如果有模型则贴模型
|
|
|
- },
|
|
|
- });
|
|
|
- _self._entities.add(tileEntity);
|
|
|
- image.close();
|
|
|
- tile.state = 0;
|
|
|
- tiles.set(key, value);
|
|
|
- });
|
|
|
- } else if (tile.state === -1) {
|
|
|
- this._entities.removeById(tile.key);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 根据矩形和登记查询高一等级的行列号
|
|
|
+ * @param {Cesium.Rectangle} rectangle
|
|
|
+ */
|
|
|
+ _createTileByRectangleAndLevel(rectangle, level) {
|
|
|
+ /* 获取矩形中心点 */
|
|
|
+ let center = Cesium.Rectangle.center(rectangle);
|
|
|
+ /* 新层级 */
|
|
|
+ let nLevel = parseInt(level) + 1;
|
|
|
+ /* 查询高一层级的行列号 */
|
|
|
+ let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
|
|
|
+ if (query === undefined) return undefined;
|
|
|
+ /* 返回结果 */
|
|
|
+ return {
|
|
|
+ key: this._createKey(query.x, query.y, nLevel),
|
|
|
+ x: query.x,
|
|
|
+ y: query.y,
|
|
|
+ level: nLevel,
|
|
|
+ rectangle: rectangle,
|
|
|
+ childTiles: [],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- _calculateTile(render) {
|
|
|
- let tiles = [];
|
|
|
- /* 定义坐标系统参数 */
|
|
|
- let mercatorTilingScheme = this._provider.tilingScheme;
|
|
|
- let imageryLevel = render.level;
|
|
|
- /* 获取矩形 */
|
|
|
- let rectangle = render._rectangle;
|
|
|
- /* 判断北西角点的墨卡托投影瓦片信息 */
|
|
|
- let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
- Cesium.Rectangle.northwest(rectangle),
|
|
|
- imageryLevel
|
|
|
- );
|
|
|
- if (northwestTileCoordinates !== undefined) {
|
|
|
- let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
|
|
|
- northwestTileCoordinates.y,
|
|
|
- imageryLevel);
|
|
|
- tiles.push({
|
|
|
- x: northwestTileCoordinates.x,
|
|
|
- y: northwestTileCoordinates.y,
|
|
|
- level: imageryLevel,
|
|
|
- rectangle: _webRectangle,
|
|
|
- });
|
|
|
- }
|
|
|
- /* 判断南东角点的墨卡托投影瓦片信息 */
|
|
|
- let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
- Cesium.Rectangle.southeast(rectangle),
|
|
|
- imageryLevel
|
|
|
- );
|
|
|
- if (southeastTileCoordinates !== undefined) {
|
|
|
- let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
|
|
|
- southeastTileCoordinates.y,
|
|
|
- imageryLevel);
|
|
|
- tiles.push({
|
|
|
- x: southeastTileCoordinates.x,
|
|
|
- y: southeastTileCoordinates.y,
|
|
|
- level: imageryLevel,
|
|
|
- rectangle: _webRectangle,
|
|
|
- });
|
|
|
+ /**
|
|
|
+ * 创建四个高层级的瓦片
|
|
|
+ * @param {Object} tile 当前瓦片
|
|
|
+ */
|
|
|
+ _createFourTiles(tile) {
|
|
|
+ let rects = [];
|
|
|
+ let results = [];
|
|
|
+ let rectangle = tile.rectangle;
|
|
|
+ /* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
|
|
|
+ rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
|
|
|
+ rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
|
|
|
+ rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
|
|
|
+ rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
|
|
|
+ for (let rect of rects) {
|
|
|
+ /* 判断高层级的矩形是否与谁范围存在交集 */
|
|
|
+ if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
|
|
|
+ /* 查询高一层级的Tile */
|
|
|
+ let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
|
|
|
+ /* 如果存在加入到返回集合中 */
|
|
|
+ if (newTile !== undefined) results.push(newTile);
|
|
|
+ }
|
|
|
}
|
|
|
- return tiles;
|
|
|
+ return results;
|
|
|
}
|
|
|
|
|
|
- _initTileGrid() {
|
|
|
+ /**
|
|
|
+ * 渲染瓦片到视图中
|
|
|
+ * @param {Object} tiles
|
|
|
+ */
|
|
|
+ _renderTilesToViewer(tiles) {
|
|
|
let _self = this;
|
|
|
- /* 获取当前渲染的瓦片集合 */
|
|
|
- let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
|
|
|
- /* 定义渲染的矩形集合 */
|
|
|
- let renderRectangles = {};
|
|
|
- /* 定义坐标系统参数 */
|
|
|
- let mercatorTilingScheme = this._provider.tilingScheme;
|
|
|
- /* 循环处理 */
|
|
|
- for (let i = 0; i < tilesToRender.length; i++) {
|
|
|
- let render = tilesToRender[i];
|
|
|
- let imageryLevel = render.level;
|
|
|
- /* 获取矩形 */
|
|
|
- let rectangle = render._rectangle;
|
|
|
- /* 判断北西角点的墨卡托投影瓦片信息 */
|
|
|
- let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
- Cesium.Rectangle.northwest(rectangle),
|
|
|
- imageryLevel
|
|
|
- );
|
|
|
- if (northwestTileCoordinates !== undefined) {
|
|
|
- let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
|
|
|
- northwestTileCoordinates.y,
|
|
|
- imageryLevel);
|
|
|
- let jsonIndex = '[' + northwestTileCoordinates.x + ',' + northwestTileCoordinates.y + ',' +
|
|
|
- imageryLevel + ']';
|
|
|
- if (renderRectangles[jsonIndex] === undefined) {
|
|
|
- renderRectangles[jsonIndex] = {
|
|
|
- x: northwestTileCoordinates.x,
|
|
|
- y: northwestTileCoordinates.y,
|
|
|
- level: imageryLevel,
|
|
|
- rectangle: _webRectangle,
|
|
|
- lineColor: Cesium.Color.YELLOW,
|
|
|
- }
|
|
|
- }
|
|
|
+ /* 确定哪些渲染实体已失效 对失效的实体进行清理 */
|
|
|
+ let deleteKeys = [];
|
|
|
+ for (let [key, tile] of this._renderEntities) {
|
|
|
+ let findTile = tiles.find(obj => {
|
|
|
+ return obj.key === key;
|
|
|
+ })
|
|
|
+ if (findTile === undefined) {
|
|
|
+ deleteKeys.push(key);
|
|
|
}
|
|
|
- /* 判断南东角点的墨卡托投影瓦片信息 */
|
|
|
- let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
- Cesium.Rectangle.southeast(rectangle),
|
|
|
- imageryLevel
|
|
|
- );
|
|
|
- if (southeastTileCoordinates !== undefined) {
|
|
|
- let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
|
|
|
- southeastTileCoordinates.y,
|
|
|
- imageryLevel);
|
|
|
- let jsonIndex = '[' + southeastTileCoordinates.x + ',' + southeastTileCoordinates.y + ',' +
|
|
|
- imageryLevel +
|
|
|
- ']';
|
|
|
- if (renderRectangles[jsonIndex] === undefined) {
|
|
|
- renderRectangles[jsonIndex] = {
|
|
|
- x: southeastTileCoordinates.x,
|
|
|
- y: southeastTileCoordinates.y,
|
|
|
- level: imageryLevel,
|
|
|
- rectangle: _webRectangle,
|
|
|
- lineColor: Cesium.Color.YELLOW,
|
|
|
+ }
|
|
|
+ for (let key of deleteKeys) {
|
|
|
+ /* 移除元素 */
|
|
|
+ this._renderEntities.delete(key);
|
|
|
+ /* 移除渲染元素 */
|
|
|
+ this._entities.removeById(key);
|
|
|
+ }
|
|
|
+ /* 对过滤后的数据集进行渲染 */
|
|
|
+ for (let tile of tiles) {
|
|
|
+ /* 判断当前渲染的数据是否已经渲染且有效 */
|
|
|
+ if (!this._renderEntities.has(tile.key)) {
|
|
|
+ /* 将数据渲染到视图中 */
|
|
|
+ let entity = this._renderSimpleTileToViewer(tile);
|
|
|
+ /* 将渲染的数据加入到集合中 */
|
|
|
+ this._renderEntities.set(tile.key, entity);
|
|
|
+ /* 创建下载线程 */
|
|
|
+ let workBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
|
|
|
+ // let workBlob = new Blob([downloadWorker.toLocaleString().match(
|
|
|
+ // /(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/)[1]]) // 把函数的主体内容拿出来进行转换
|
|
|
+ let worker = new Worker(URL.createObjectURL(workBlob));
|
|
|
+ /* 发送下载任务 */
|
|
|
+ worker.postMessage({
|
|
|
+ key: tile.key,
|
|
|
+ url: this._url,
|
|
|
+ x: tile.x,
|
|
|
+ y: tile.y,
|
|
|
+ level: tile.level,
|
|
|
+ })
|
|
|
+ /* 接收下载任务 */
|
|
|
+ worker.onmessage = function(event) {
|
|
|
+ _self._console(`render x:${event.data.x} y:${event.data.y} level:${event.data.level}`);
|
|
|
+ /* 判断是否存在 */
|
|
|
+ let renderEntity = _self._entities.getById(event.data.key);
|
|
|
+ if (renderEntity !== undefined) {
|
|
|
+ let key = event.data.key;
|
|
|
+ const canvas = _self._createCanvas(event.data, event.data.image, _self._isDebug);
|
|
|
+ renderEntity.rectangle.material = canvas;
|
|
|
}
|
|
|
+ worker.terminate();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if (JSON.stringify(renderRectangles) !== '{}') {
|
|
|
- _self._renderImageToRectangle(renderRectangles);
|
|
|
- }
|
|
|
+ /* 重启计算标志 */
|
|
|
+ this._isUpdateTile = true;
|
|
|
}
|
|
|
|
|
|
- _renderImageToRectangle(tilesJson) {
|
|
|
- let _self = this;
|
|
|
- this._removeEntityByName(this._renderName);
|
|
|
- for (let tile in tilesJson) {
|
|
|
- let tileJson = tilesJson[tile];
|
|
|
- let tileRow = tileJson.x;
|
|
|
- let tileColumn = tileJson.y;
|
|
|
- let tileLevel = tileJson.level;
|
|
|
- let entityId = this._renderName + "_" + tileRow + "_" + tileColumn + "_" + tileLevel;
|
|
|
- /* 查询实体是否存在 */
|
|
|
- if (_self._entities.getById(entityId) === undefined) {
|
|
|
- let promise = _self._provider.requestImage(tileRow, tileColumn, tileLevel);
|
|
|
- promise.then(function(image) {
|
|
|
- // let data = Cesium.getImagePixels(image, 256, 256);
|
|
|
- // console.log('===dataAAA>>>', data);
|
|
|
- let canvas = document.createElement("canvas");
|
|
|
- canvas.width = 256;
|
|
|
- canvas.height = 256;
|
|
|
- let context = canvas.getContext("2d");
|
|
|
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
|
- // context.font = "bold 25px Arial";
|
|
|
- // context.textAlign = "center";
|
|
|
- // context.fillStyle = 'rgba(255,255,255,1.0)';
|
|
|
- // context.fillText(`L: ${tileLevel}`, 124, 86);
|
|
|
- // context.fillText(`X: ${tileRow}`, 124, 136);
|
|
|
- // context.fillText(`Y: ${tileColumn}`, 124, 186);
|
|
|
-
|
|
|
- let imageData = context.getImageData(0, 0, 256, 256);
|
|
|
- console.log('===dataAAA>>>', imageData);
|
|
|
- // let newImageData = _self._imageDataVRevert({
|
|
|
- // width: 256,
|
|
|
- // height: 256,
|
|
|
- // data: data,
|
|
|
- // });
|
|
|
- // console.log('===data>>>', newImageData);
|
|
|
- // let newImageData = context.getImageData(0, 0, 256, 256);
|
|
|
- // context.putImageData(_self._imageDataVRevert(newImageData, imageData), 0, 0);
|
|
|
-
|
|
|
- // context.putImageData(newImageData, 256, 256);
|
|
|
- // let material = new Cesium.ImageMaterialProperty({
|
|
|
- // image: canvas,
|
|
|
- // transparent: true,
|
|
|
- // });
|
|
|
- // let bjPositions = _self._calculateRectangleOutlineCoordinates(tileJson
|
|
|
- // .rectangle);
|
|
|
- // /* 计算矩形的中心点 */
|
|
|
- // let center = Cesium.Rectangle.center(tileJson.rectangle);
|
|
|
- // let centerPosition = Cesium.Cartesian3.fromRadians(center.longitude, center
|
|
|
- // .latitude,
|
|
|
- // center.height);
|
|
|
- // let tileEntity = new Cesium.Entity({
|
|
|
- // name: _self._renderName,
|
|
|
- // id: entityId,
|
|
|
- // // position: centerPosition,
|
|
|
- // rectangle: {
|
|
|
- // coordinates: tileJson.rectangle,
|
|
|
- // material: material, //Cesium.Color.RED.withAlpha(0.9),
|
|
|
- // },
|
|
|
- // polyline: {
|
|
|
- // positions: bjPositions,
|
|
|
- // material: Cesium.Color.BLUE,
|
|
|
- // // width: 2,
|
|
|
- // clampToGround: true, //开启贴地 如果有模型则贴模型
|
|
|
- // },
|
|
|
- // });
|
|
|
- // _self._entities.add(tileEntity);
|
|
|
- image.close();
|
|
|
- })
|
|
|
+ /**
|
|
|
+ * 渲染单个瓦片到视图中
|
|
|
+ * @param {Object} tile
|
|
|
+ */
|
|
|
+ _renderSimpleTileToViewer(tile) {
|
|
|
+ /* 创建画布 */
|
|
|
+ const canvas = this._createCanvas(tile, undefined, this._isDebug);
|
|
|
+ let bjPositions = this._calculateRectangleOutlineCoordinates(tile
|
|
|
+ .rectangle);
|
|
|
+ let tileEntity = new Cesium.Entity({
|
|
|
+ name: this._renderName,
|
|
|
+ id: tile.key,
|
|
|
+ rectangle: {
|
|
|
+ coordinates: tile.rectangle,
|
|
|
+ material: canvas,
|
|
|
+ },
|
|
|
+ polyline: {
|
|
|
+ positions: bjPositions,
|
|
|
+ material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
|
|
|
+ width: 1,
|
|
|
+ clampToGround: true, //开启贴地 如果有模型则贴模型
|
|
|
}
|
|
|
- }
|
|
|
+ });
|
|
|
+ return this._entities.add(tileEntity);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 竖向翻转
|
|
|
- * @param {Array[]} sourceData
|
|
|
+ * 根据瓦片创建画布
|
|
|
+ * @param {Object} tile 瓦片
|
|
|
+ * @param {Object} image 绘制的图片
|
|
|
+ * @param {boolean} islabel 是否绘制标签
|
|
|
*/
|
|
|
- _imageDataVRevert(sourceData) {
|
|
|
- let newData = {
|
|
|
- width: sourceData.width,
|
|
|
- height: sourceData.height,
|
|
|
- data: new Uint8ClampedArray(sourceData.data.length)
|
|
|
+ _createCanvas(tile, image, islabel) {
|
|
|
+ /* 获取服务提供者的切片方案 */
|
|
|
+ let provider = this._provider;
|
|
|
+ const canvas = document.createElement("canvas");
|
|
|
+ canvas.width = provider.tileWidth;
|
|
|
+ canvas.height = provider.tileHeight;
|
|
|
+ const context = canvas.getContext("2d");
|
|
|
+ if (image !== undefined) {
|
|
|
+ context.globalAlpha = this._opacity;
|
|
|
+ context.drawImage(event.data.image, 0, 0, canvas.width, canvas.height);
|
|
|
}
|
|
|
- for (var i = 0, h = sourceData.height; i < h; i++) {
|
|
|
- for (var j = 0, w = sourceData.width; j < w; j++) {
|
|
|
- newData.data[i * w * 4 + j * 4 + 0] =
|
|
|
- sourceData.data[(h - i) * w * 4 + j * 4 + 0];
|
|
|
- newData.data[i * w * 4 + j * 4 + 1] =
|
|
|
- sourceData.data[(h - i) * w * 4 + j * 4 + 1];
|
|
|
- newData.data[i * w * 4 + j * 4 + 2] =
|
|
|
- sourceData.data[(h - i) * w * 4 + j * 4 + 2];
|
|
|
- newData.data[i * w * 4 + j * 4 + 3] =
|
|
|
- sourceData.data[(h - i) * w * 4 + j * 4 + 3] - 100;
|
|
|
- }
|
|
|
+ if (islabel !== undefined && islabel === true) {
|
|
|
+ context.globalAlpha = 1.0;
|
|
|
+ /* 创建标签 */
|
|
|
+ context.font = "20px Arial";
|
|
|
+ context.textAlign = "center";
|
|
|
+ context.fillStyle = 'rgba(255,255,0)';
|
|
|
+ context.strokeStyle = 'rgba(255,255,255,1)';
|
|
|
+ context.lineWidth = 2;
|
|
|
+ context.strokeText(`L: ${tile.level}`, 126, 86);
|
|
|
+ context.fillText(`L: ${tile.level}`, 126, 86);
|
|
|
+ context.strokeText(`X: ${tile.x}`, 126, 136);
|
|
|
+ context.fillText(`X: ${tile.x}`, 126, 136);
|
|
|
+ context.strokeText(`Y: ${tile.y}`, 126, 186);
|
|
|
+ context.fillText(`Y: ${tile.y}`, 126, 186);
|
|
|
}
|
|
|
- return newData;
|
|
|
+ /* 返回画布 */
|
|
|
+ return canvas;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 横向翻转
|
|
|
- * @param {Array[]} sourceData
|
|
|
- * @param {Array[]} newData
|
|
|
+ * 投影当前瓦片
|
|
|
+ * @param {Object} tile
|
|
|
*/
|
|
|
- _imageDataHRevert(sourceData, newData) {
|
|
|
- for (var i = 0, h = sourceData.height; i < h; i++) {
|
|
|
- for (j = 0, w = sourceData.width; j < w; j++) {
|
|
|
- newData.data[i * w * 4 + j * 4 + 0] =
|
|
|
- sourceData.data[i * w * 4 + (w - j) * 4 + 0];
|
|
|
- newData.data[i * w * 4 + j * 4 + 1] =
|
|
|
- sourceData.data[i * w * 4 + (w - j) * 4 + 1];
|
|
|
- newData.data[i * w * 4 + j * 4 + 2] =
|
|
|
- sourceData.data[i * w * 4 + (w - j) * 4 + 2];
|
|
|
- newData.data[i * w * 4 + j * 4 + 3] =
|
|
|
- sourceData.data[i * w * 4 + (w - j) * 4 + 3];
|
|
|
+ _projectionTile(tile) {
|
|
|
+ /* 获取矩形 */
|
|
|
+ let rectangle = tile._rectangle;
|
|
|
+ // let imageryLevel = parseInt(tile.level) + 1;
|
|
|
+ let imageryLevel = parseInt(tile.level);
|
|
|
+ let mercatorTilingScheme = this._provider.tilingScheme;
|
|
|
+ let res = [];
|
|
|
+ /* 先判断当前的切片范围是否与提供者的数据范围有交集 */
|
|
|
+ let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
|
|
|
+ /* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
|
|
|
+ if (interRectangle === undefined) return res;
|
|
|
+ /* 判断北西角点的墨卡托投影瓦片信息 */
|
|
|
+ let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
+ Cesium.Rectangle.northwest(rectangle),
|
|
|
+ imageryLevel
|
|
|
+ );
|
|
|
+ /* 判断南东角点的墨卡托投影瓦片信息 */
|
|
|
+ let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
|
|
|
+ Cesium.Rectangle.southeast(rectangle),
|
|
|
+ imageryLevel
|
|
|
+ );
|
|
|
+ /* 根据不同类型分别进行计算 */
|
|
|
+ if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
|
|
|
+ for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
|
|
|
+ for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
|
|
|
+ let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
|
|
|
+ if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
|
|
|
+ res.push({
|
|
|
+ x: i,
|
|
|
+ y: j,
|
|
|
+ level: imageryLevel,
|
|
|
+ rectangle: _webRectangle,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (northwestTileCoordinates !== undefined) {
|
|
|
+ let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
|
|
|
+ northwestTileCoordinates.y,
|
|
|
+ imageryLevel);
|
|
|
+ if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
|
|
|
+ res.push({
|
|
|
+ x: northwestTileCoordinates.x,
|
|
|
+ y: northwestTileCoordinates.y,
|
|
|
+ level: imageryLevel,
|
|
|
+ rectangle: _webRectangle,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else if (southeastTileCoordinates !== undefined) {
|
|
|
+ let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
|
|
|
+ southeastTileCoordinates.y,
|
|
|
+ imageryLevel);
|
|
|
+ if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
|
|
|
+ res.push({
|
|
|
+ x: southeastTileCoordinates.x,
|
|
|
+ y: southeastTileCoordinates.y,
|
|
|
+ level: imageryLevel,
|
|
|
+ rectangle: _webRectangle,
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
- return newData;
|
|
|
+ return res;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -451,7 +532,7 @@ class CrImageServerLayer {
|
|
|
*/
|
|
|
_removeEntityByName(entityName) {
|
|
|
/* 获取实体集合 */
|
|
|
- var entities = this._viewer.entities;
|
|
|
+ var entities = this._entities;
|
|
|
/* 如果不存在实体集合或集合中没有数据 则返回 */
|
|
|
if (!entities || !entities.values) return;
|
|
|
var delEntitys = [];
|
|
@@ -468,5 +549,79 @@ class CrImageServerLayer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* 对外方法 */
|
|
|
+Object.assign(CrImageServerLayer.prototype, {
|
|
|
+ /**
|
|
|
+ * 隐藏
|
|
|
+ */
|
|
|
+ hide: function() {
|
|
|
+ this._console('隐藏');
|
|
|
+ this._isUpdateTile = false;
|
|
|
+ /* 清理资源 */
|
|
|
+ this._removeEntityByName(this._renderName);
|
|
|
+ /* 清理渲染 */
|
|
|
+ this._renderEntities.clear();
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 显示
|
|
|
+ */
|
|
|
+ show: function() {
|
|
|
+ this._console('显示');
|
|
|
+ this._isUpdateTile = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置透明度
|
|
|
+ * @param {Number} opacity [0-1]
|
|
|
+ */
|
|
|
+ setOpacity: function(opacity) {
|
|
|
+ if (opacity === undefined || typeof opacity !== 'number') return;
|
|
|
+ if (opacity >= 1) this._opacity = 1.0;
|
|
|
+ if (opacity <= 0) this._opacity = 0.0;
|
|
|
+ this._opacity = parseFloat(opacity);
|
|
|
+ }
|
|
|
+
|
|
|
+})
|
|
|
+
|
|
|
+/* 下载线程函数 */
|
|
|
+function downloadWorker() {
|
|
|
+ /* 接收主线程发送的文件下载请求 */
|
|
|
+ onmessage = function(event) {
|
|
|
+ let data = event.data;
|
|
|
+ /* 创建下载数据链接 */
|
|
|
+ let url = data.url + '/tile/' + data.level + '/' + data.y + '/' + data.x;
|
|
|
+ /* 创建下载相关 并下载 */
|
|
|
+ let xhr = new XMLHttpRequest();
|
|
|
+ xhr.open('get', url, true);
|
|
|
+ xhr.responseType = "blob"; //设置返回类型,此处我用于下载文件 所以返回blob
|
|
|
+ xhr.onload = function() {
|
|
|
+ // 请求完成
|
|
|
+ if (this.status === 200) {
|
|
|
+ var blob = this.response;
|
|
|
+ var bmpPromise = createImageBitmap(blob, {
|
|
|
+ imageOrientation: "none",
|
|
|
+ premultiplyAlpha: "none",
|
|
|
+ colorSpaceConversion: "default",
|
|
|
+ });
|
|
|
+ bmpPromise.then(function(image) {
|
|
|
+ let outObj = {
|
|
|
+ key: data.key,
|
|
|
+ x: data.x,
|
|
|
+ y: data.y,
|
|
|
+ level: data.level,
|
|
|
+ image: image,
|
|
|
+ }
|
|
|
+ postMessage(outObj);
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ console.log('===>>>', url + ' Not found');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 发送请求 */
|
|
|
+ xhr.send();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* 输出类 */
|
|
|
export default CrImageServerLayer
|