上一篇是绘制多边形,这一篇来说绘制矩形,但又因为只说绘制矩形太短了,所以就结合一下turf.js,生成一下地形三角网
Turf.js中文网
最终效果:
一、引入Turf.js
1,下载
npm install @turf/turf
2,引入
import * as turf from "@turf/turf";
二、鼠标绘制矩形区域
代码:
//画矩形DrawRectangle() {var allPoints = [];// 设置返回值return new Promise((resolve, reject) => {let viewer = this.viewer;let topLeftPoint = null;let bottomRightPoint = null;let drawingRectangle = viewer.entities.add({id: "drawingRectangle",name: "画矩形",rectangle: {coordinates: new Cesium.CallbackProperty(() => {if (topLeftPoint === null || bottomRightPoint === null) {return;}let west = topLeftPoint.longitude;let north = topLeftPoint.latitude;let east = bottomRightPoint.longitude;let south = bottomRightPoint.latitude;return new Cesium.Rectangle(west, south, east, north);}, false),material: Cesium.Color.BLUE.withAlpha(0.2),closeTop: true,closeBottom: false}});let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);handler.setInputAction(event => {var cartesian = this.getCatesian3FromPX(event.position);if (cartesian) {if (topLeftPoint === null) {topLeftPoint = Cesium.Cartographic.fromCartesian(cartesian);}viewer.entities.add({position: cartesian,point: {color: Cesium.Color.RED,pixelSize: 10}});}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);handler.setInputAction(event => {if (topLeftPoint) {bottomRightPoint = Cesium.Cartographic.fromCartesian(this.getCatesian3FromPX(event.endPosition));}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);handler.setInputAction(() => {if (topLeftPoint !== null && bottomRightPoint !== null) {handler.destroy(); // 关闭鼠标事件监听,结束绘制let west = Cesium.Math.toDegrees(topLeftPoint.longitude);let north = Cesium.Math.toDegrees(topLeftPoint.latitude);let east = Cesium.Math.toDegrees(bottomRightPoint.longitude);let south = Cesium.Math.toDegrees(bottomRightPoint.latitude);allPoints.push({ lng: west, lat: north });allPoints.push({ lng: east, lat: north });allPoints.push({ lng: east, lat: south });allPoints.push({ lng: west, lat: south });allPoints.push(allPoints[0]); // 闭合resolve(allPoints);}}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);});
},
(getCatesian3FromPX方法在上一篇)
效果:
代码说明:
函数定义和参数:
DrawRectangle() { … }: 这是定义DrawRectangle方法的部分
初始化变量:
var allPoints = [];: 初始化一个空数组,用于保存绘制的矩形的顶点坐标。
let topLeftPoint = null;: 初始化一个变量,用于存储矩形的左上角点。
let bottomRightPoint = null;: 初始化一个变量,用于存储矩形的右下角点。
Promise构造函数:
return new Promise((resolve, reject) => { … });: 返回一个新的Promise对象,用于处理异步操作。resolve和reject是两个回调函数,分别表示异步操作成功和失败的处理。
创建矩形Entity:
let drawingRectangle = viewer.entities.add({ … });: 用于在Cesium Viewer中添加一个新的矩形Entity。它使用CallbackProperty动态计算矩形的坐标。
创建事件处理器:
let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);: 初始化一个新的Cesium屏幕空间事件处理器。
监听鼠标单击事件:
当用户在Cesium Viewer上单击鼠标左键时,这个事件会被触发。
if (topLeftPoint === null) { … }: 判断是否已经设置了矩形的左上角点。如果没有,则设置。
监听鼠标移动事件:
当用户在Cesium Viewer上移动鼠标时,这个事件会被触发。
if (topLeftPoint) { … }: 当左上角点设置后,根据鼠标的当前位置设置矩形的右下角点。
监听鼠标双击事件:
当用户在Cesium Viewer上双击鼠标左键时,这个事件会被触发。
当左上角和右下角点都被设置后,结束绘制,关闭鼠标事件监听。
handler.destroy(); 用于关闭鼠标事件监听,结束绘制。
计算出矩形的四个顶点的经纬度坐标,并将这些坐标点保存到allPoints数组中。
resolve(allPoints);: 最后,通过resolve函数将allPoints数组传递出去,表示异步操作成功完成。
总结:
这个DrawRectangle方法允许用户通过以下三个步骤在Cesium地图上绘制一个矩形:
单击地图以设置矩形的左上角点。
移动鼠标以实时预览矩形的形状。
双击地图以确认矩形的右下角点,并完成矩形的绘制。
方法返回一个Promise对象,当用户完成矩形的绘制后,这个Promise对象将被resolve,返回矩形的顶点坐标。
三、根据矩形区域生成点集
(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实体,并且这些实体的顶点高度是基于地形数据的。