上一篇是绘制多边形,这一篇来说绘制矩形,但又因为只说绘制矩形太短了,所以就结合一下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实体,并且这些实体的顶点高度是基于地形数据的。