cesium学习记录09-turf.js的使用(画矩形结合地形生成三角网)

上一篇是鼠标绘制,这一篇结合一下turf.js,并使用上一篇中的鼠标绘制矩形,生成一下地形三角网
Turf.js中文网

最终效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、引入Turf.js

1,下载

npm install @turf/turf

2,引入

import * as turf from "@turf/turf";

二、根据矩形区域生成点集

这里的矩形即鼠标绘制的矩形
在这里插入图片描述

(resultPoints即矩形的顶点坐标返回值,num是手动穿的参数,当然数值越大点就越多了)

// 1. 创建一个矩形区域
// var rectangle = Cesium.Rectangle.fromDegrees(117.09649937089316, 36.20673458245797, 117.11797117691083, 36.230040948473906)
var rectangle = Cesium.Rectangle.fromDegrees(resultPoints[0].lng,resultPoints[2].lat,resultPoints[2].lng,resultPoints[0].lat)
// 2. 在这个矩形区域内生成点集
var width = num;  // 横向点数
var height = num; // 纵向点数
var terrainProvider =viewer.terrainProvider
var positions = [];
for (var y = 0; y < height; y++) {for (var x = 0; x < width; x++) {var longitude = Cesium.Math.lerp(rectangle.west, rectangle.east, x / (width - 1));var latitude = Cesium.Math.lerp(rectangle.south, rectangle.north, y / (height - 1));positions.push(Cesium.Cartographic.fromRadians(longitude, latitude));}
}

三、根据地形和区域为上述点集赋高度值

(这里的terrainProvider即地图加载的地形,我这里使用了cesium默认带的地形:viewer.terrainProvider = Cesium.createWorldTerrain({ requestVertexNormals: true, requestWaterMask: true });,参数terrainProvider即这里的viewer.terrainProvider。positions即上面的positions)

Cesium.sampleTerrainMostDetailed(terrainProvider, positions).then(function(samples) {var points = samples.map(function(sample) {return turf.point([Cesium.Math.toDegrees(sample.longitude), Cesium.Math.toDegrees(sample.latitude), sample.height],{ z: sample.height })  // 将高度值保存到名为 'z' 的属性中);});
//显示点集  
var cartesianPoints = points.map(function(point) {var coord = point.geometry.coordinates;var cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1], coord[2]);return Cesium.Cartographic.toCartesian(cartographic);
});
var pointCollection = new Cesium.PointPrimitiveCollection();cartesianPoints.forEach(function(position) {
pointCollection.add({position: position,color: Cesium.Color.RED,pixelSize: 5
});
});
viewer.scene.primitives.add(pointCollection);})

(需要注意的是,//显示点集后面的添加点的代码在生成三角网是不必要的,只是我觉得看着好看一点 )
在这里插入图片描述

四、使用turf.js生成三角形网格

即将Cesium.sampleTerrainMostDetailed(terrainProvider, positions)方法里面改为:

代码:

Cesium.sampleTerrainMostDetailed(terrainProvider, positions).then(function(samples) {var points = samples.map(function(sample) {return turf.point([Cesium.Math.toDegrees(sample.longitude), Cesium.Math.toDegrees(sample.latitude), sample.height],{ z: sample.height })  // 将高度值保存到名为 'z' 的属性中);});// 创建一个FeatureCollection
var featureCollection = turf.featureCollection(points);
var tin = turf.tin(featureCollection, 'z');
var geometryInstances = [];  // 用于存放所有的三角形GeometryInstance
var instances = [];
// 遍历每个TIN三角形
tin.features.forEach(function(feature,i) {var coordinates = feature.geometry.coordinates[0];var heights = [feature.properties.a, feature.properties.b, feature.properties.c];var positions = coordinates.map(function(coord, index) {return Cesium.Cartesian3.fromDegrees(coord[0], coord[1], heights[index]);});viewer.entities.add({name: "三角面",id: "triangle"+i,polygon: {hierarchy: [positions[0], positions[1], positions[2]],heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,perPositionHeight: true,material: Cesium.Color.fromCssColorString("#23B8BA").withAlpha(1.0),//  extrudedHeight: 0,outline: true,outlineColor:  Cesium.Color.GREEN,}});
});var cartesianPoints = points.map(function(point) {var coord = point.geometry.coordinates;var cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1], coord[2]);return Cesium.Cartographic.toCartesian(cartographic);});var pointCollection = new Cesium.PointPrimitiveCollection();cartesianPoints.forEach(function(position) {pointCollection.add({position: position,color: Cesium.Color.RED,pixelSize: 5});
});
viewer.scene.primitives.add(pointCollection);
})

在这里插入图片描述

代码说明:

函数定义和参数:

GeneratingTriangulation(resultPoints,num) { … }: 这是定义GeneratingTriangulation方法的部分,它接受两个参数:resultPoints是一个包含矩形四个顶点坐标的数组;num是横向和纵向的点数。

创建一个矩形区域:

var rectangle = Cesium.Rectangle.fromDegrees(…):根据resultPoints中提供的坐标,创建一个矩形区域。

在这个矩形区域内生成点集:

var positions = [];: 初始化一个空数组,用于保存生成的点集的坐标。
通过两个嵌套循环在矩形区域内均匀地生成点集。

获取点集的高程信息:

Cesium.sampleTerrainMostDetailed(terrainProvider, positions).then(function(samples) { … }:使用Cesium的sampleTerrainMostDetailed函数获取每个点的高程信息。

转换高程采样点为Turf.js点:

将Cesium高程采样点转换为Turf.js点格式,并保存每个点的高程(Z值)。

生成TIN三角网:

var tin = turf.tin(featureCollection, ‘z’);: 使用Turf.js的tin函数,基于点集和它们的Z值生成TIN三角网。

在Cesium地图上绘制TIN三角网:

通过遍历每个TIN三角形,并为每个三角形创建一个Cesium的polygon实体。这些多边形实体有高度信息,因此它们会按照地形进行渲染。

在Cesium地图上绘制点集:

遍历cartesianPoints(点集的笛卡尔坐标),并将它们作为点实体添加到地图上,这样可以在地图上可视化这些点。

注解:

Cesium.Rectangle.fromDegrees(…):这个函数创建一个矩形,参数是矩形的西、南、东、北边界的经纬度。
Cesium.sampleTerrainMostDetailed(terrainProvider, positions):这个函数从给定的地形服务提供商中采样最详细级别的地形数据,以获取指定位置的地形高程。
turf.tin(…):这个函数是Turf.js库中的一个函数,用于根据输入的点集生成TIN三角网。Turf.js是一个JavaScript库,用于地理空间分析。
这个方法最终的结果是在Cesium地图上绘制了一个TIN三角网,该三角网是根据指定的矩形区域和点数生成的。每个三角形都是一个单独的Cesium实体,并且这些实体的顶点高度是基于地形数据的。

五、计算坡度

顺便计算一下坡度

tin.features.forEach中,添加如下代码:

 const point1 = positions[0];const point2 = positions[1];const point3 = positions[2];//使用我们新定义的函数计算每个三角形的坡度var analysisResult = that.calculateSlopeAndAspect(point1,point2,point3);

计算坡度的方法:

/*** 计算三角形的坡度* @param {*} point1 * @param {*} point2 * @param {*} point3 * @returns */calculateSlopeAndAspect(point1, point2, point3) {// 计算两个向量,它们位于三角形的两边var v1 = Cesium.Cartesian3.subtract(point1,point2,new Cesium.Cartesian3());var v2 = Cesium.Cartesian3.subtract(point2,point3,new Cesium.Cartesian3());// 计算这两个向量的叉积,得到三角形的法向量var normal = new Cesium.Cartesian3();Cesium.Cartesian3.cross(v1, v2, normal);Cesium.Cartesian3.normalize(normal, normal);// 计算三角形的中心点var centroid = new Cesium.Cartesian3((point1.x + point2.x + point3.x) / 3,(point1.y + point2.y + point3.y) / 3,(point1.z + point2.z + point3.z) / 3);// 得到从地球中心到三角形中心的单位向量(这里不应该使用垂直向量(0,0,1),如果使用(0,0,1)会导致面南的坡度大,面北的坡度小)var centerToCentroid = Cesium.Cartesian3.normalize(centroid, new Cesium.Cartesian3());// 确保法线向量指向地球外部if (Cesium.Cartesian3.dot(normal, centerToCentroid) < 0) {Cesium.Cartesian3.negate(normal, normal);}// 计算坡度:法向量和从地球中心到三角形中心的径向向量之间的夹角var slopeRadians = Math.acos(Cesium.Cartesian3.dot(normal, centerToCentroid));var slopeDegrees = Cesium.Math.toDegrees(slopeRadians);// 如果坡度大于90度,则将其减少到90度以下if (slopeDegrees > 90) {slopeDegrees = 180 - slopeDegrees;}// 返回坡度值return { slope: slopeDegrees };},

使用这个方法得到的坡度值定义三角形面的颜色:

即在 var analysisResult =...后面添加:

var slope = analysisResult.slope;var hue = slope / 90.0; // 将坡度从0到90度映射到色调从0到1var saturation = 1.0;   // 全饱和度var lightness = 0.5;    // 正常亮度var alpha = 1.0;        // 完全不透明//将HSL颜色转换为RGBA,当坡度为0度时,hue变为0,颜色是红色;当坡度为90度时,hue变为1,颜色是绿色;在0到90度之间的坡度将映射到从红色到绿色之间的颜色。var color = Cesium.Color.fromHsl(hue, saturation, lightness).withAlpha(alpha);

三角形的material修改为

material: color,

将三角网高度抬升一下,方便观察,提高个300米

var positions = coordinates.map(function(coord, index) {return Cesium.Cartesian3.fromDegrees(coord[0], coord[1], heights[index]+300);});

(越红坡度越大)
在这里插入图片描述
至于最开始的第三张图,中间的黄色体的实现就不再赘述了,无非是一个个五面体构成的(顶面就是每个三角面,然后三个四边形侧面(两个顶面点加两个底面点),再加上高度值一定的三角底面)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部