让同事用Cesium写一个测量工具并支持三角测量,他说有点难。。
大家好,我是日拱一卒的攻城师不浪,致力于技术与艺术的融合。这是2024年输出的第39/100篇文章。
可视化&Webgis交流群+V:brown_7778(备注来意)
前言
最近在开发智慧城市的项目,产品想让同事基于Cesium
开发一个测量工具,需要支持长度测量
、面积测量
以及三角测量
,但同事挠了挠头,说做这个有点费劲,还反问了产品:做这功能有啥意义?
产品经理:测量工具在智慧城市中发挥了重要的作用,通过对城市道路,地形,建筑物,场地等的精确测量,确保施工规划能够与现实场景精准吻合,节省人力以及施工成本。
对桥梁、隧道、地铁、管网等城市基础设施进行结构健康监测,安装传感器,实时监测结构体震动以及结构体偏移量
等数据,确保设施安全运行并能够提前发现问题,防患于未然。
开发同事听完,觉得还蛮有道理,看向我:浪浪,如何应对?
我:呐,拿走直接抄!下班请吃铜锅涮肉!
三角测量
先来了解下三角测量
:是一种基于三角形
几何原理的测量方法,用于确定未知点的位置。它通过已知基线(即两个已知点之间的距离)和从这两个已知点测量的角
度,计算出目标点的精确位置。
例如在建筑施工中,工程师使用三角测量法来测量楼体高度
、桥梁等结构的位置
和角度
,确保建筑的精准施工。
代码解析
接下来看下这个MeasureTool
类,主要包含以下功能:
- 坐标转换:整理了地理坐标(WGS84)与笛卡尔坐标(Cartesian)之间的转换功能。
- 拾取功能:通过屏幕坐标拾取场景中的三维位置,并判断该位置是位于模型上、地形上还是椭球体表面。
- 距离测量:绘制线段,并在场景中显示起点和终点之间的距离。
- 面积测量:通过给定的一组坐标,计算它们组成的多边形面积。
- 三角测量:绘制一个三角形来测量水平距离、直线距离和高度差。
坐标转换功能
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.fromDegrees
和Ellipsoid.WGS84.cartesianToCartographic
方法分别用于实现经纬度与笛卡尔坐标系的相互转换。
拾取功能
拾取功能允许通过屏幕像素坐标来获取3D场景中的位置。主要依赖scene.pickPosition
和scene.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