cesium 实现测距离测面积 (划线画面 跟随鼠标位置 )

article/2025/9/21 12:05:04

效果图
在这里插入图片描述
在这里插入图片描述
方法一:使用插件

cesium_measure.js
下载地址:https://github.com/zhangti0708/cesium-measure/blob/master/src/cesium-measure.js

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Cesium.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Widgets/widgets.css"><title>测距&面积</title>
</head>
<style>.btn {z-index: 999;width: 100px;height: 30px;background-color: #fff;position: absolute;top: 30px;right: 40px;line-height: 30px;text-align: center;user-select: none;}.change {z-index: 999;width: 100px;height: 30px;position: absolute;top: 30px;right: 40px;line-height: 30px;text-align: center;color: #fff;background-color: #007acc;user-select: none;}.pointInfo {z-index: 999;position: absolute;/* top: 50%;left: 50%;transform: translate(-50%, -50%); */width: 80px;height: 40px;background-color: #fff;}
</style><body style="margin: 0;"><div id="app"><div class="pointInfo" v-show="open" ref="pointinfo" id="point"></div><div :class="change?'btn':'change'" @click="signPlace(window.viewer)">{{change?"测距":"测面积"}}</div><div id="mapcontainer"></div></div>
</body>
<script src="../js/cesium_measure.js"></script>
<script>var app = new Vue({el: '#app',data: {plane: [], //存面实例pointId: 0,change: true,open: false,openimg: false,labelname: '',objpoint: {},imgs: ["../img/0.png","../img/1.png","../img/2.png",],urlimg: "../img/0.png",point: [], //测距的点arr: [], //存放划线的点measure: null},methods: {initMap() {var viewer = new Cesium.Viewer('mapcontainer', {animation: false, //是否显示动画控件shouldAnimate: true,homeButton: false, //是否显示Home按钮fullscreenButton: true, //是否显示全屏按钮baseLayerPicker: false, //是否显示图层选择控件geocoder: false, //是否显示地名查找控件timeline: false, //是否显示时间线控件sceneModePicker: false, //是否显示投影方式控件navigationHelpButton: false, //是否显示帮助信息控件requestRenderMode: false, //启用请求渲染模式scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneModeselectionIndicator: false,skyAtmosphere: false,infoBox: false});viewer._cesiumWidget._creditContainer.style.display = "none";this.measure = new Cesium.Measure(viewer);return viewer},mapFlyTo(viewer) {viewer.camera.flyTo({destination: new Cesium.Cartesian3.fromDegrees(132.02294829, 53.323929, 180000),duration: 3})},signPlace(viewer) {if (this.change) {this.change = false;this.measure.drawLineMeasureGraphics({clampToGround: true,callback: () => {},});} else {this.change = true;this.measure.drawAreaMeasureGraphics({clampToGround: true,callback: (e) => {}});}},},mounted() {window.viewer = this.initMap();this.mapFlyTo(window.viewer);// this.mapEvent(window.viewer)}})
</script></html>

方法二:自己实现

测面积没实现 ,可以参考方法一插件里的实现方法

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Cesium.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cesium@1.86.0/Build/Cesium/Widgets/widgets.css"><title>测距&面积</title>
</head>
<style>.btn {z-index: 999;width: 100px;height: 30px;background-color: #fff;position: absolute;top: 30px;right: 40px;line-height: 30px;text-align: center;user-select: none;}.change {z-index: 999;width: 100px;height: 30px;position: absolute;top: 30px;right: 40px;line-height: 30px;text-align: center;color: #fff;background-color: #007acc;user-select: none;}.pointInfo {z-index: 999;position: absolute;/* top: 50%;left: 50%;transform: translate(-50%, -50%); */width: 80px;height: 40px;background-color: #fff;}
</style><body style="margin: 0;"><div id="app"><div class="pointInfo" v-show="open" ref="pointinfo" id="point"></div><div :class="change?'btn':'change'" @click="signPlace(window.viewer)">{{change?"测距":"测面积"}}</div><div id="mapcontainer"></div></div>
</body>
<script src="../js/cesium_measure.js"></script>
<script>var app = new Vue({el: '#app',data: {plane: [], //存面实例pointId: 0,change: true,open: false,openimg: false,labelname: '',objpoint: {},imgs: ["../img/0.png","../img/1.png","../img/2.png",],urlimg: "../img/0.png",point: [], //测距的点arr: [], //存放划线的点measure: null,timeline: null},methods: {drawLineMeasureGraphics(viewer) {window.that = thisvar draw = new Cesium.CustomDataSource('measureLayer')viewer.dataSources.add(draw)var positions = [],positions_mian = [],polygon = new Cesium.PolygonHierarchy(),_lineEntity = new Cesium.Entity(),$this = this,lineObj,_handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);// left_handlers.setInputAction((movement) => {var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);// console.log("cli" + cartesian);var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());var lat = Cesium.Math.toDegrees(cartographic.latitude);var lng = Cesium.Math.toDegrees(cartographic.longitude);var height = cartographic.height;var objpoint = {longitude: lng,latitude: lat}this.point.push(cartesian)if (this.point.length > 1) {var distance = this.disTance(this.point)this.labelname = distance;// this.creatLine(this.arr, viewer)}if (cartesian && cartesian.x) {if (positions.length == 0) {positions.push(cartesian.clone());}this.addpoint(objpoint, viewer)positions.push(cartesian);// 测距}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);_handlers.setInputAction((movement) => {// console.log(positions);var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);if (positions.length >= 2) {if (cartesian && cartesian.x) {positions.pop();positions.push(cartesian);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// right_handlers.setInputAction((movement) => {_handlers.destroy()_handlers = nulllet cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());var lat = Cesium.Math.toDegrees(cartographic.latitude);var lng = Cesium.Math.toDegrees(cartographic.longitude);var height = cartographic.height;var objpoint = {longitude: lng,latitude: lat}this.addpoint(objpoint, viewer)}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);_lineEntity.polyline = {width: 5,material: Cesium.Color.BLUE.withAlpha(0.8),clampToGround: false}_lineEntity.polyline.positions = new Cesium.CallbackProperty(function() {return positions}, false)lineObj = draw.entities.add(_lineEntity)},// 测面drawplane(viewer) {var draw = new Cesium.CustomDataSource('measureLayer1')viewer.dataSources.add(draw)var positions = [],polygon = new Cesium.PolygonHierarchy(),_polygonEntity = new Cesium.Entity(),polyObj = null,_label = '',_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);// left_handler.setInputAction((movement) => {var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);if (cartesian && cartesian.x) {if (positions.length == 0) {polygon.positions.push(cartesian.clone())positions.push(cartesian.clone());}positions.push(cartesian.clone());polygon.positions.push(cartesian.clone())// var cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());var lat = Cesium.Math.toDegrees(cartographic.latitude);var lng = Cesium.Math.toDegrees(cartographic.longitude);var height = cartographic.height;var objpoint = {longitude: lng,latitude: lat}this.addpoint(objpoint, viewer)if (!polyObj) {_polygonEntity.polyline = {width: 3,material: Cesium.Color.BLUE.withAlpha(0.8),clampToGround: false}_polygonEntity.polyline.positions = new Cesium.CallbackProperty(function() {return positions}, false)_polygonEntity.polygon = {hierarchy: new Cesium.CallbackProperty(function() {return polygon}, false),material: Cesium.Color.WHITE.withAlpha(0.8),clampToGround: false}polyObj = draw.entities.add(_polygonEntity)}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// mouse_handler.setInputAction((movement) => {var cartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid);// var cartesian = $this._viewer.scene.camera.pickEllipsoid(movement.endPosition, $this._viewer.scene.globe.ellipsoid);if (positions.length >= 2) {if (cartesian && cartesian.x) {positions.pop()positions.push(cartesian);polygon.positions.pop()polygon.positions.push(cartesian);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// right_handler.setInputAction((movement) => {let cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);_handler.destroy();positions.push(positions[0]);// let cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);var cartographic = Cesium.Cartographic.fromCartesian(cartesian, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());var lat = Cesium.Math.toDegrees(cartographic.latitude);var lng = Cesium.Math.toDegrees(cartographic.longitude);var height = cartographic.height;var objpoint = {longitude: lng,latitude: lat}this.addpoint(objpoint, viewer)// if (typeof options.callback === 'function') {//     options.callback($this.transformCartesianArrayToWGS84Array(positions), polyObj);// }}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);},initMap() {var viewer = new Cesium.Viewer('mapcontainer', {animation: false, //是否显示动画控件shouldAnimate: true,homeButton: false, //是否显示Home按钮fullscreenButton: true, //是否显示全屏按钮baseLayerPicker: false, //是否显示图层选择控件geocoder: false, //是否显示地名查找控件timeline: false, //是否显示时间线控件sceneModePicker: false, //是否显示投影方式控件navigationHelpButton: false, //是否显示帮助信息控件requestRenderMode: false, //启用请求渲染模式scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存sceneMode: 3, //初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneModeselectionIndicator: false,skyAtmosphere: false,infoBox: false});viewer._cesiumWidget._creditContainer.style.display = "none";this.measure = new Cesium.Measure(viewer);return viewer},mapFlyTo(viewer) {viewer.camera.flyTo({destination: new Cesium.Cartesian3.fromDegrees(132.02294829, 53.323929, 180000),duration: 3})},signPlace(viewer) {viewer.screenSpaceEventHandler.destroy()this.point = [];this.labelname = ""if (this.change) {this.change = false;this.drawLineMeasureGraphics(viewer)} else {this.change = true;this.drawplane(viewer)}},// 两点距离//positions 包含两个点的数组disTance(positions) {var distance = 0;for (var i = 0; i < positions.length - 1; i++) {var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);// console.log(point1cartographic, point2cartographic);var geodesic = new Cesium.EllipsoidGeodesic();geodesic.setEndPoints(point1cartographic, point2cartographic);var s = geodesic.surfaceDistance;distance = distance + s;}return distance.toFixed(0);},/*** 计算一组坐标组成多边形的面积* @param {*} positions */getPositionsArea: function(positions) {let result = 0if (positions) {let h = 0let ellipsoid = Cesium.Ellipsoid.WGS84positions.push(positions[0])for (let i = 1; i < positions.length; i++) {let oel = ellipsoid.cartographicToCartesian(this.transformWGS84ToCartographic(positions[i - 1]))let el = ellipsoid.cartographicToCartesian(this.transformWGS84ToCartographic(positions[i]))h += oel.x * el.y - el.x * oel.y}result = Math.abs(h).toFixed(2)}return result},// 添加点//添加图标点addpoint(pointData, viewer) {var billboards = viewer.scene.primitives.add(new Cesium.BillboardCollection());window.billboards = billboards;var labels = viewer.scene.primitives.add(new Cesium.LabelCollection());window.labels = labelsposition = Cesium.Cartesian3.fromDegrees(pointData.longitude, pointData.latitude,0);billboards.add({id: this.pointId,position: position,image: this.urlimg,verticalOrigin: Cesium.VerticalOrigin.BOTTOM,});labels.add({show: !this.change,position: position,text: this.labelname,id: this.pointId,font: '10px',pixelOffset: new Cesium.Cartesian2(-20, -30),})this.pointId++;},//面creatplane(polylineData, viewer) {var entit = this.plane[0]this.plane = [];viewer.entities.remove(entit);var polyon = viewer.entities.add({polygon: {// 获取指定属性(positions,holes(图形内需要挖空的区域))hierarchy: {positions: Cesium.Cartesian3.fromDegreesArray(polylineData)},// 边框outline: true,// 边框颜色outlineColor: Cesium.Color.WHITE,// 边框尺寸outlineWidth: 2,// 填充的颜色,withAlpha透明度material: Cesium.Color.GREEN.withAlpha(0.5),// 是否被提供的材质填充fill: true,// 显示在距相机的距离处的属性,多少区间内是可以显示的distanceDisplayCondition: new Cesium.DistanceDisplayCondition(1000, 10000000),// 是否显示show: true,// 顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。zIndex: 10}})this.plane.push(polyon)},mapEvent(viewer) {// var mapEvent = new Cesium.ScreenSpaceEventHandler(cesiumScene.canvas);viewer.screenSpaceEventHandler.setInputAction((click) => {var pick = viewer.scene.pick(click.endPosition);if (pick && typeof(pick.id) == "number") {document.body.style = "cursor: pointer;";this.infobox(viewer.scene, viewer)} else {document.body.style = "cursor: default;";}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);},//弹框位置htmlFixed(cesiumView, htmlOverlay, lng, lat) {const domHeight = htmlOverlay.offsetHeight; // DOM的高度const domWidth = htmlOverlay.offsetWidth; // DOM的宽度const heightOffset = 20; // Y轴偏移量const widthOffset = -9; // X轴偏移量const scratch = new Cesium.Cartesian2();cesiumView.scene.preRender.addEventListener(function() {var las = lat - 0.0009;let position = Cesium.Cartesian3.fromDegrees(lng, las, 2);let canvasPosition = cesiumView.scene.cartesianToCanvasCoordinates(position,scratch);if (Cesium.defined(canvasPosition)) {htmlOverlay.style.top = canvasPosition.y -domHeight -heightOffset + 'px';htmlOverlay.style.left = canvasPosition.x -domWidth / 2 -widthOffset + 'px';}});},},mounted() {window.viewer = this.initMap();this.mapFlyTo(window.viewer);// this.mapEvent(window.viewer)}})
</script></html>

http://chatgpt.dhexx.cn/article/oYXhQGgC.shtml

相关文章

平方面积怎么测量?教你快速学会这个方法

平方面积怎么测量&#xff1f;我们平常可能很少会需要测量平方面积的&#xff0c;但是当我们装修屋子的时候&#xff0c;不可避免地需要计算各种物品的面积。只有精准的计算&#xff0c;才能减少不必要的浪费。我们可以手工测量&#xff0c;然后进行计算。我们也可以借助手机上…

QML QtLocation地图应用学习-3:实现面积测量

1.实现思路 参照网上的测面积功能&#xff0c;界面效果和测距差不多&#xff0c;在点和线的基础上多了一个填充区域。 点和线参照上一篇博客&#xff1a;https://blog.csdn.net/gongjianbo1992/article/details/103674047 填充区域使用 MapPolygon &#xff0c;但是这个类接口…

手机怎么测量物品面积?测试原理是什么?

在我们的日常生活中&#xff0c;我们常常需要测量物品的面积&#xff0c;比如房间的面积、墙壁的面积、家具的面积等等。传统的测量方法需要使用量尺或计算公式&#xff0c;不仅繁琐而且容易出现误差。而现在&#xff0c;我们可以利用手机的功能来快速、准确地测量物品的面积。…

NMF(非负矩阵分解)

NMF 1.算法概述2. 损失函数python代码 1.算法概述 NMF(Non-negative matrix factorization)&#xff0c;即对于任意给定的一个非负矩阵V&#xff0c;其能够寻找到一个非负矩阵W和一个非负矩阵H&#xff0c;满足条件VW*H,从而将一个非负的矩阵分解为左右两个非负矩阵的乘积。 …

CAUCHY NMF FOR HYPERSPECTRAL UNMIXING

J. Peng, F. Jiang, W. Sun and Y. Zhou, "Cauchy NMF for Hyperspectral Unmixing," IGARSS 2020 - 2020 IEEE International Geoscience and Remote Sensing Symposium, 2020, pp. 2384-2387, doi: 10.1109/IGARSS39084.2020.9323950. 摘要&#xff1a; 非负矩阵…

【降维之NMF】NMF(非负矩阵分解)实例

数据介绍&#xff1a;NMF人脸数据特征提取目标&#xff1a;已知 Olivetti 人脸数据共400个&#xff0c;每个数据是 64*64 大小。由于NMF分解得到的 W 矩阵相当于从原始矩阵中提取的特征&#xff0c;那么就可以使用NMF对400个人脸数据进行特征提取。 NMF 非负矩阵分解是在矩阵中…

ADMM求解优化NMF

本文拟对文章&#xff1a;“An Alternating Direction Algorithm for Matrix Completion with Nonnegative Factors”中利用ADMM进行非负矩阵分解部分进行推导。 他的 augmented Lagrangian 可写成如下形式&#xff1a; (1) (1)优化W (2)优化H: &#xff08;3&#xff09;优化…

NMF降维算法与聚类模型的综合运用

NMF降维算法与聚类模型的综合运用 前言一&#xff1a;NMF算法二&#xff1a;NMF算法的使用三&#xff1a;NMF算法与层次聚类的综合使用四&#xff1a;总结 前言 这一章&#xff0c;我们讨论下另一个比较有效的降维手段&#xff1a;NMF&#xff08;非负矩阵分解&#xff09;。N…

NMF(非负矩阵分解)分子分型

<~生~信~交~流~与~合~作~请~关~注~公~众~号生信探索> Non-Negative Matrix Factorization (NMF). Find two non-negative matrices, i.e. matrices with all non-negative elements, (W, H) whose product approximates the non-negative matrix X. This factorization c…

LSA、pLSA、LDA、NMF、BERTopic、Top2Vec进行主题建模

在自然语言处理(NLP)中,主题建模是一种技术,用于从文本数据中发现隐藏的语义主题(或主题)。这是一个无监督机器学习问题,即在没有标签或标签的情况下学习模式。主题建模的应用非常广泛,可用于搜索引擎、情感分析、新闻聚类和摘要生成等许多任务。 在这里将探讨主题建模…

NMF通俗理解及python实现

一、通俗理解概念 NMF(Non-negative matrix factorization)&#xff0c;即对于任意给定的一个非负矩阵 V&#xff0c;其能够寻找到一个非负矩阵 W 和一个非负矩阵 H&#xff0c;满足条件 V W H VW \times H VWH&#xff0c;即将一个非负的矩阵分解为左右两个非负矩阵的乘积…

NMF-CC

题目&#xff1a;Multi-view clustering by non-negative matrix factorization with co-orthogonal constraints 一、创新点 和其他使用NMF的方法一样&#xff0c;这篇文章也是加约束&#xff0c;使创造出来的representation matrices更好。这篇文章加的约束叫做co-orthogon…

用python实现NMF降维

非负矩阵分解(Non-negative Matrix Factorization) NMF简介 NMF用于文本降维 NMF的可解释性 NMF用于归纳单篇文章主题 NMF用于推荐多篇相似文章 NMF简介 NMF也是一种降维方法&#xff0c;相比PCA具有以下特点&#xff1a; 1&#xff0c;可解释性 2&#xff0c;可以用于所…

nmf java_NMF pLSA

今天在围脖中看到自动化所刘康的围脖中给了一个关于NMF和pLSA对比分析的链接http://ezcodesample.com/plsaidiots/NMFPLSA.html&#xff0c;大体读了一下&#xff0c;下面用中文对文中的思想重新解释&#xff0c;版权归原作者Andrew Polar。 一、名词解释 (1)NMF, nonnegative …

nmf java_NMF的算法原理

NMF(Non-negative matrix factorization&#xff0c;非负矩阵分解)&#xff0c;即对于任意给定的一个非负矩阵V&#xff0c;其能够寻找到一个非负矩阵W和一个非负矩阵H&#xff0c;满足条件VW*H,从而将一个非负的矩阵分解为左右两个非负矩阵的乘积。其中&#xff0c;V矩阵中每一…

NMF降维的本质,NMF和PCA的区别

一、NMF的本质 1.当数据完全一样时 # 将如下数据的行向量用NMF降到3维&#xff0c;初始化策略全部用nndsvd&#xff0c;不能用random&#xff0c;下同 Xnp.array([[5,5,5,5],[5,5,5,5],[5,5,5,5],[5,5,5,5]])结果是这样的&#xff1a; 2.当数据分布全部递增时 # 原数据 Xn…

非负矩阵分解NMF简介

本文整理NMF相关知识。 简介 非负矩阵分解(Nonnegative Matrix Factorization)&#xff0c;简称NMF&#xff0c;是由Lee和Seung于1999年在自然杂志上提出的一种矩阵分解方法&#xff0c;它使分解后的所有分量均为非负值(要求纯加性的描述)&#xff0c;并且同时实现非线性的维数…

NMF

计算机是人类解决难题、探索未知以及提供娱乐的绝佳工具。在高效运行着的各种计算机应用背后&#xff0c;融汇了人类在物理、电子和数学等多门学科的高超智慧。严密的数学使得计算机能高效执行人类指令&#xff0c;控制内部各种数据流的走向&#xff0c;因此在现代计算机科学研…

无监督学习——非负矩阵分解(NMF)

序 非负矩阵分解&#xff08;NMF&#xff09;是一种无监督学习算法&#xff0c;其目的在于提取有用的特征。它的工作原理类似于PCA&#xff0c;也可以用于降维。与PCA相同&#xff0c;我们试图将每个数据点写成一些分量的加权求和。但在PCA中&#xff0c;我们想要的是正负分量…

非负矩阵分解NMF

http://blog.csdn.net/pipisorry/article/details/52098864 非负矩阵分解(NMF,Non-negative matrix factorization) NMF的发展及原理 著名的科学杂志《Nature》于1999年刊登了两位科学家D.D.Lee和H.S.Seung对数学中非负矩阵研究的突出成果。该文提出了一种新的矩阵分解思想—…