cesium根据高程点实现简易地下水水流分析

说明

        因为公司业务需求,要在web前端做一个水流分析的功能。但是提供的数据并不像风场数据一样,带有方向和速度信息。只有坐标点和高程。所以简单做了一个根据点的流向分析动画,里边没有用什么很复杂的算法,所以效果不是很好,但希望能给读者带来一点功能实现上的思路。对于流水路径的计算,肯定有更好的方法,这里只做简单示例。

先上功能实现图:

 数据阶段

因为本功能所用的只是带高程的点的合集,所以要对点进行分析

cesium根据高程点实现简易地下水水流分析_第1张图片

 首先从提供的excel表中读取数据,也可能数据来源于其他文件,但最终得到的数据格式相同。

得到点的集合如下图所示:

cesium根据高程点实现简易地下水水流分析_第2张图片

 经过高程点坐标转换与拼接,坐标系转换可参考Proj4js转换坐标的方法,这里暂不展开讲解。

最后经过数组的抽稀与拼接获得高程点集合:

cesium根据高程点实现简易地下水水流分析_第3张图片

 后面我用了一个笨办法,其实并不好,如果路过的大佬有更好的算法请踢我一下,我要学习。

            let direction = [];
			allPoint.forEach((itema) => {
				let arr = [];
				allPoint.forEach((itemb) => {
					if (itema.value > itemb.value) {
						arr.push([itemb.lon, itemb.lat]);
					}
				});
				if (arr.length !== 0) {
					let targetPoint = turf.point([itema.lon, itema.lat]);
					let computearr = [];
					arr.forEach((item) => {
						computearr.push(turf.point(item));
					});
					let points = turf.featureCollection(computearr);
					let nearest = turf.nearestPoint(targetPoint, points);
					direction.push([[itema.lon, itema.lat], nearest.geometry.coordinates]);
				}
			});

作为测试用,上边方法并不推荐,可以优化筛选,比如添加距离限制等。大体思路就是,遍历数组中所有的点,找到离当前点最近且比当前点高程低的点,两个点拼接成一个数组对。

最后得到如下数组对:

cesium根据高程点实现简易地下水水流分析_第4张图片

流线生成

利用之前筛选出的数组对,做一个流线动画,大体思路就是,一个数组对刚好连成线,从高处往低处流。

流线动画代码参考示例如下:

要定义轨迹动态线的着色器,该部分代码可以加到创建cesium地图方法里,哪儿都可以,只要能把这个材质定义上就行。

// 定义线的轨迹动态线纹理-->
			function PolylineTrailLinkMaterialProperty(color, duration) {
				this._definitionChanged = new Cesium.Event();
				this._color = undefined;
				this._colorSubscription = undefined;
				this.color = color;
				this.duration = duration;
				this._time = new Date().getTime();
			}
			Object.defineProperties(PolylineTrailLinkMaterialProperty.prototype, {
				isConstant: {
					get: function () {
						return false;
					},
				},
				definitionChanged: {
					get: function () {
						return this._definitionChanged;
					},
				},
				color: Cesium.createPropertyDescriptor('color'),
			});
			PolylineTrailLinkMaterialProperty.prototype.getType = function (time) {
				return 'PolylineTrailLink';
			};
			PolylineTrailLinkMaterialProperty.prototype.getValue = function (time, result) {
				if (!Cesium.defined(result)) {
					result = {};
				}
				result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
				result.image = Cesium.Material.PolylineTrailLinkImage;
				result.time = ((new Date().getTime() - this._time) % this.duration) / this.duration;
				return result;
			};
			PolylineTrailLinkMaterialProperty.prototype.equals = function (other) {
				return this === other || (other instanceof PolylineTrailLinkMaterialProperty && Property.equals(this._color, other._color));
			};
			// 在Material上挂载相关的流动线纹理 可以根据自己的需要进行封装
			Cesium.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty;
			Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink';

			Cesium.Material.PolylineTrailLinkImage = './images/line.png';
			// 定义着色器源码 核心部分
			Cesium.Material.PolylineTrailLinkSource =
				'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
    {\n\
        czm_material material = czm_getDefaultMaterial(materialInput);\n\
        vec2 st = materialInput.st;\n\
        vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\
        material.alpha = colorImage.a;\n\
        material.diffuse = colorImage.rgb;\n\
        return material;\n\
    }';
			Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, {
				fabric: {
					type: Cesium.Material.PolylineTrailLinkType,
					uniforms: {
						color: new Cesium.Color(0.0, 0.0, 1.0, 0.5),
						image: Cesium.Material.PolylineTrailLinkImage,
						time: 0,
					},
					source: Cesium.Material.PolylineTrailLinkSource,
				},
				translucent: function (material) {
					return true;
				},
			});

 然后遍历数组生成流线:注意这个材质定义要放在遍历的外边,如果每次都new一个材质的话,cesium会报错。

	        let linematerial = new Cesium.PolylineTrailLinkMaterialProperty(
				Cesium.Color.ORANGE,
				3000,
				'./images/line.png'
			);
			direction.forEach((item) => {
			let position = Cesium.Cartesian3.fromDegreesArrayHeights([item[0][0], item[0][                1], 300, item[1][0], item[1][1], 300]);
				let route = Viewer.entities.add({
					// name: 'Rescue Route',
					polyline: {
						positions: position,
						width: 5,
						material: linematerial,
					},
				});
});

以上就可以生成流线分析了,我这里用的是1.78版本cesium,注意你如果使用的是高版本的cesium,这里的GLSL语法低了,需要自己该新版本的GLSL语法。

代码中所用的line.png图片就是个渐变图,文章受限并不好发。

大体长这样:

cesium根据高程点实现简易地下水水流分析_第5张图片

 这个文章里的水印不知道咋去...........如果需要图片素材可免费私信索要。

我的想法

本来我想象中应该能有个算法,把这些点根据流向连成一条条的线,这样会好看些,并且连成线后,可以用truf等算法库进行平滑处理,肯定比现在好看的多。类似风场动画那种。但是目前我水平有限,时间也比较紧张,没有做更多的优化处理。希望我的这个例子能给大家带来一点思路。

你可能感兴趣的:(cesium,javascript,前端)