Просмотр исходного кода

瓦片通过矩形进行渲染测试

不会爬树的猴 2 лет назад
Родитель
Сommit
88b498efa4

+ 118 - 0
src/components/CrMap/CrImageMaterialProperty.js

@@ -0,0 +1,118 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2022年1月30日
+ * 描述:图片渲染
+ */
+
+/* 引入Cesium */
+import * as Cesium from 'cesium';
+
+class CrImageMaterialProperty {
+	/**
+	 * @param {JSON} options 配置项
+	 * @param {Cesium.Viewer} options.viewer 着色器运行所需的视图
+	 * @param {Cesium.Color} options.color [墙的颜色,默认蓝色] 可选
+	 * @param {String} options.image 渲染图片
+	 */
+	constructor(options) {
+		/* 着色器运行依赖的视图 */
+		this._viewer = options.viewer;
+		/* 变更事件 */
+		this._definitionChanged = new Cesium.Event();
+		this._color = undefined;
+		/* 墙的颜色 */
+		this.color = options.color || Cesium.Color.BLUE;
+		/* 墙的贴图 */
+		this.image = options.image;
+		/* 材质类型名称 */
+		this._materialTypeName = 'CrImageMaterialProperty'
+
+		/* 将材质加入缓存 以便重复利用 */
+		Cesium.Material._materialCache.addMaterial(this._materialTypeName, {
+			fabric: {
+				type: this._materialTypeName,
+				uniforms: {
+					color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
+					image: options.image,
+				},
+				source: this._getShaderSource()
+			},
+			translucent: function(material) {
+				/* 材质是否半透明 */
+				return true;
+			}
+		});
+	}
+
+	/**
+	 * 带方向的渐变墙
+	 */
+	_getShaderSource() {
+		let materail = '';
+		materail += 'czm_material czm_getMaterial(czm_materialInput materialInput){\n' +
+			'  czm_material material = czm_getDefaultMaterial(materialInput);\n' +
+			'  material.alpha = color.a;\n' +
+			'  material.diffuse = image.rgb;\n' +
+			'  return material;\n' +
+			'}';
+		return materail;
+	}
+}
+
+Object.defineProperties(CrImageMaterialProperty.prototype, {
+	/**
+	 * 重新获取类型方法
+	 * @param {Cesium.JulianDate} time 时间
+	 */
+	getType(time) {
+		return this._materialTypeName;
+	},
+
+	/**
+	 * 重写获取值方法
+	 * @param {Cesium.JulianDate} time
+	 * @param {JSON} result 
+	 */
+	getValue(time, result) {
+		if (!Cesium.defined(result)) {
+			result = {};
+		}
+		result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.BLUE, result
+			.color);
+		result.image = this.image;
+		this._viewer.scene.requestRender();
+		return result;
+	},
+
+	/**
+	 * 重写对比函数
+	 * @param {Object} other 传入对比对象
+	 */
+	equals(other) {
+		return (this === other || (other instanceof WallMaterialProperty && Cesium.Property.equals(this
+			._color, other._color)));
+	},
+
+	/**
+	 * 判断是否相等,返回false表示属性一直在变化中
+	 */
+	isConstant: {
+		get: function() {
+			return false;
+		}
+	},
+	/**
+	 * 事件变更
+	 */
+	definitionChanged: {
+		get: function() {
+			return this._definitionChanged;
+		}
+	},
+	/* 颜色属性 */
+	color: Cesium.createPropertyDescriptor('color')
+})
+
+/* 导出 */
+export default CrImageMaterialProperty;

+ 472 - 0
src/components/CrMap/CrImageServerLayer.js

@@ -0,0 +1,472 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2023年1月30日
+ * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
+ */
+
+Date.prototype.Format = function(fmt) { // author: meizz 
+	var o = {
+		"M+": this.getMonth() + 1, // 月份 
+		"d+": this.getDate(), // 日 
+		"h+": this.getHours(), // 小时 
+		"m+": this.getMinutes(), // 分 
+		"s+": this.getSeconds(), // 秒 
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 季度 
+		"S": this.getMilliseconds() // 毫秒 
+	};
+	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
+			"00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}
+
+/* 引入Cesium */
+import * as Cesium from 'cesium';
+
+import CrImageMaterialProperty from './CrImageMaterialProperty.js'
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {String} options.url 服务地址
+	 * @param {Number} options.opacity 图层透明度 [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		url,
+		opacity = 0.3
+	} = {}) {
+		this._viewer = viewer;
+		this._url = url;
+		this._opacity = opacity;
+		this._renderName = 'suiji'; //后期要改成随机字符串
+		this._entities = this._viewer.entities;
+		this._init();
+		this._isUpdateTile = true;
+		this._updateTiles = new Map();
+	}
+
+	/**
+	 * 控制台输出
+	 * @param {Object} params 参数集合
+	 */
+	_console(params) {
+		console.log('CrImageServerLayer', params);
+	}
+
+	/**
+	 * 初始化
+	 */
+	_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,
+		})
+
+		this._provider.readyPromise.then(function(result) {
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile === true) {
+					_self._updateRenderTile();
+				}
+			});
+			_self._viewer.camera.moveEnd.addEventListener(function(event) {
+
+			});
+		})
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(res) {
+		console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', res);
+	}
+
+	/**
+	 * 更新渲染的Tile集合
+	 */
+	_updateRenderTile() {
+		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('执行结束');
+		});
+	}
+
+	/**
+	 * 计算渲染的瓦片集合
+	 * @param {JSON} renderTiles 渲染的瓦片集合
+	 */
+	_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);
+				}
+				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);
+			}
+		}
+		this._isUpdateTile = true;
+		this._render(this._updateTiles);
+		this._console('本次计算结束');
+	}
+
+	_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);
+			}
+		}
+	}
+
+	_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,
+			});
+		}
+		return tiles;
+	}
+
+	_initTileGrid() {
+		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 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,
+					}
+				}
+			}
+		}
+		if (JSON.stringify(renderRectangles) !== '{}') {
+			_self._renderImageToRectangle(renderRectangles);
+		}
+	}
+
+	_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 {Array[]} sourceData 
+	 */
+	_imageDataVRevert(sourceData) {
+		let newData = {
+			width: sourceData.width,
+			height: sourceData.height,
+			data: new Uint8ClampedArray(sourceData.data.length)
+		}
+		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;
+			}
+		}
+		return newData;
+	}
+
+	/**
+	 * 横向翻转
+	 * @param {Array[]} sourceData 
+	 * @param {Array[]} newData
+	 */
+	_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];
+			}
+		}
+		return newData;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @param {Cesium.Rectangle} rectangle 矩形
+	 * @return {Array<Cesium.Cartesian3>} 坐标串集合
+	 */
+	_calculateRectangleOutlineCoordinates(rectangle) {
+		/* 计算东南角 */
+		let south_east = Cesium.Rectangle.southeast(rectangle);
+		let se = Cesium.Cartographic.toCartesian(south_east);
+		/* 计算西南角 */
+		let south_west = Cesium.Rectangle.southwest(rectangle);
+		let sw = Cesium.Cartographic.toCartesian(south_west);
+		/* 计算东北角 */
+		let north_east = Cesium.Rectangle.northeast(rectangle);
+		let ne = Cesium.Cartographic.toCartesian(north_east);
+		/* 计算西北角 */
+		let north_west = Cesium.Rectangle.northwest(rectangle);
+		let nw = Cesium.Cartographic.toCartesian(north_west);
+		return [sw, se, ne, nw, sw];
+	}
+
+	/**
+	 * 根据Entity的名称批量删除Entity
+	 * @param {String} entityName 实体名称
+	 */
+	_removeEntityByName(entityName) {
+		/* 获取实体集合 */
+		var entities = this._viewer.entities;
+		/* 如果不存在实体集合或集合中没有数据 则返回 */
+		if (!entities || !entities.values) return;
+		var delEntitys = [];
+		/* 循环获取当前集合中的所有实体 */
+		for (var i = 0; i < entities.values.length; i++) {
+			if (entities.values[i].name == entityName) {
+				delEntitys.push(entities.values[i]);
+			}
+		}
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < delEntitys.length; i++) {
+			entities.remove(delEntitys[i]);
+		}
+	}
+}
+
+/* 输出类 */
+export default CrImageServerLayer