注册
web

让同事用Cesium写一个测量工具并支持三角测量,他说有点难。。


大家好,我是日拱一卒的攻城师不浪,致力于技术与艺术的融合。这是2024年输出的第39/100篇文章。

可视化&Webgis交流群+V:brown_7778(备注来意)



前言


最近在开发智慧城市的项目,产品想让同事基于Cesium开发一个测量工具,需要支持长度测量面积测量以及三角测量,但同事挠了挠头,说做这个有点费劲,还反问了产品:做这功能有啥意义?


产品经理:测量工具在智慧城市中发挥了重要的作用,通过对城市道路,地形,建筑物,场地等的精确测量,确保施工规划能够与现实场景精准吻合,节省人力以及施工成本。


对桥梁、隧道、地铁、管网等城市基础设施进行结构健康监测,安装传感器,实时监测结构体震动以及结构体偏移量等数据,确保设施安全运行并能够提前发现问题,防患于未然。


开发同事听完,觉得还蛮有道理,看向我:浪浪,如何应对?


我:呐,拿走直接抄!下班请吃铜锅涮肉!



三角测量


先来了解下三角测量:是一种基于三角形几何原理的测量方法,用于确定未知点的位置。它通过已知基线(即两个已知点之间的距离)和从这两个已知点测量的度,计算出目标点的精确位置。


例如在建筑施工中,工程师使用三角测量法来测量楼体高度、桥梁等结构的位置角度,确保建筑的精准施工。



代码解析


接下来看下这个MeasureTool类,主要包含以下功能:



  1. 坐标转换:整理了地理坐标(WGS84)与笛卡尔坐标(Cartesian)之间的转换功能。
  2. 拾取功能:通过屏幕坐标拾取场景中的三维位置,并判断该位置是位于模型上、地形上还是椭球体表面。
  3. 距离测量:绘制线段,并在场景中显示起点和终点之间的距离。
  4. 面积测量:通过给定的一组坐标,计算它们组成的多边形面积。
  5. 三角测量:绘制一个三角形来测量水平距离、直线距离和高度差。

坐标转换功能



  • transformWGS84ToCartesian: 将WGS84坐标(经度、纬度、高度)转换为Cesium中的三维笛卡尔坐标。
  • transformCartesianToWGS84: 将Cesium的三维笛卡尔坐标转换为WGS84坐标。

核心代码:


transformWGS84ToCartesian(position, alt) {
return position
? Cesium.Cartesian3.fromDegrees(
position.lng || position.lon,
position.lat,
(position.alt = alt || position.alt),
Cesium.Ellipsoid.WGS84
)
: Cesium.Cartesian3.ZERO;
}

transformCartesianToWGS84(cartesian) {
var ellipsoid = Cesium.Ellipsoid.WGS84;
var cartographic = ellipsoid.cartesianToCartographic(cartesian);
return {
lng: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
alt: cartographic.height,
};
}

Cesium的Cartesian3.fromDegreesEllipsoid.WGS84.cartesianToCartographic方法分别用于实现经纬度与笛卡尔坐标系的相互转换。


拾取功能


拾取功能允许通过屏幕像素坐标来获取3D场景中的位置。主要依赖scene.pickPositionscene.globe.pick来实现拾取。


核心代码:


getCatesian3FromPX(px) {
var picks = this._viewer.scene.drillPick(px);
var cartesian = this._viewer.scene.pickPosition(px);
if (!cartesian) {
var ray = this._viewer.scene.camera.getPickRay(px);
cartesian = this._viewer.scene.globe.pick(ray, this._viewer.scene);
}
return cartesian;
}

这里首先尝试从3D模型或地形上拾取位置,如果未能拾取到模型或地形上的点,则尝试通过射线投射到椭球体表面。


距离测量



通过拾取点并记录每个点的坐标,计算相邻两个点的距离,并显示在Cesium场景中。通过ScreenSpaceEventHandler来捕获鼠标点击和移动事件。


核心代码:


drawLineMeasureGraphics(options = {}) {
var positions = [];
var _handlers = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
_handlers.setInputAction(function (movement) {
var cartesian = this.getCatesian3FromPX(movement.position);
positions.push(cartesian);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

_handlers.setInputAction(function (movement) {
var cartesian = this.getCatesian3FromPX(movement.endPosition);
positions.pop();
positions.push(cartesian);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

_handlers.setInputAction(function () {
_handlers.destroy();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}

测距的基本思想是通过鼠标点击获取多个点的坐标,然后计算每两个相邻点的距离。


面积测量



面积测量通过计算多个点围成的多边形的面积,基于Cesium的PolygonHierarchy实现多边形绘制。


核心代码:


getPositionsArea(positions) {
let ellipsoid = Cesium.Ellipsoid.WGS84;
let area = 0;
positions.push(positions[0]); // 闭合多边形
for (let i = 1; i < positions.length; i++) {
let p1 = ellipsoid.cartographicToCartesian(this.transformWGS84ToCartographic(positions[i - 1]));
let p2 = ellipsoid.cartographicToCartesian(this.transformWGS84ToCartographic(positions[i]));
area += p1.x * p2.y - p2.x * p1.y;
}
return Math.abs(area) / 2.0;
}

这里通过一个简单的多边形面积公式(叉乘)来计算笛卡尔坐标下的面积。


三角测量


三角测量通过拾取三个点,计算它们之间的直线距离水平距离以及高度差,构建一个三角形并在场景中显示这些信息。


核心代码:


drawTrianglesMeasureGraphics(options = {}) {
var _positions = [];
var _handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
_handler.setInputAction(function (movement) {
var position = this.getCatesian3FromPX(movement.position);
_positions.push(position);
if (_positions.length === 3) _handler.destroy();
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

该方法核心思想是获取三个点的坐标,通过高度差来构建水平线和垂线,然后显示相应的距离和高度差信息。


使用


封装好,之后,使用起来就非常简单了。


import MeasureTool from "@/utils/cesiumCtrl/measure.js";
const measure = new MeasureTool(viewer);
**
* 测距
*/
const onLineMeasure = () => {
measure.drawLineMeasureGraphics({
clampToGround: true,
callback: (e) => {
console.log("----", e);
},
});
};
/**
* 测面积
*/

const onAreaMeasure = () => {
measure.drawAreaMeasureGraphics({
clampToGround: true,
callback: () => {},
});
};
/**
* 三角量测
*/

const onTrianglesMeasure = () => {
measure.drawTrianglesMeasureGraphics({
callback: () => {},
});
};

最后


这些测量工具都是依赖于Cesium提供的坐标转换、拾取以及事件处理机制,核心思路是通过ScreenSpaceEventHandler捕捉鼠标事件,获取坐标点,并通过几何算法计算距离、面积和高度。


【完整源码地址】:github.com/tingyuxuan2…


如果认为有帮助,希望可以给我们一个免费的star,激励我们持续开源更多代码。



如果想系统学习Cesium,可以看下作者的Cesium系列教程《Cesium从入门到实战》,将Cesium的知识点进行串联,让不了解Cesium的小伙伴拥有一个完整的学习路线,学完后直接上手做项目,+作者:brown_7778(备注来意)了解课程细节。




另外有需要进可视化&Webgis交流群可以加我:brown_7778(备注来意),也欢迎数字孪生可视化领域的交流合作。



作者:攻城师不浪
来源:juejin.cn/post/7424902468243669029

0 个评论

要回复文章请先登录注册