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

article/2025/9/21 12:32:11

1.实现思路

参照网上的测面积功能,界面效果和测距差不多,在点和线的基础上多了一个填充区域。

点和线参照上一篇博客:https://blog.csdn.net/gongjianbo1992/article/details/103674047

填充区域使用 MapPolygon ,但是这个类接口很少,大部分操作还是借住折线 MapPolyline 来完成。

这个功能最主要的是根据坐标点的集合求面积,在网上找了很多参考代码,大部分思路是球面多边形面积计算,但是计算结果都不一样,有误差。

最后我用的是别人从高德的API里提取出来的函数。下面给出部分参考链接:

JS实现(首尾太近会算错):https://blog.csdn.net/neil89/article/details/49331641

Py实现:https://www.cnblogs.com/c-w20140301/p/10308431.html

Java参照的高德API:https://blog.csdn.net/zdb1314/article/details/80661602

根据球面面积计算公式:https://wenku.baidu.com/view/4e213e27162ded630b1c59eef8c75fbfc67d94e2.html

2.实现代码及git链接

下面是实现效果:

Area组件实现代码:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12// 计算地图连线围成面积
MapItemGroup{id: controlproperty bool _pathClose: falseproperty double areaValue: 0//MapPolygon很多方法没有,所以拿MapPolyline来记录坐标点//优化的话自定义cpp类型MapPolygon{id: item_polygoncolor: Qt.rgba(0,1,0,0.4);border.width: 0path: item_line.path}MapPolyline{id: item_lineline.width: 1line.color: "red"}MapItemView{id: item_viewadd: Transition {}remove: Transition {}model: ListModel{id: item_model}delegate: MapQuickItem{id: ietm_delegatesourceItem: Rectangle {width: 14height: 14radius: 7color: "white"border.width: 2border.color: "red"//Component.onDestruction: console.log("destory item");Loader{anchors.horizontalCenter: parent.horizontalCenteranchors.top: parent.bottomanchors.margins: 5sourceComponent: (_pathClose&&index==(item_model.count-1))?area_comp:null_comp}}//通过listmodel来设置数据coordinate{latitude: latitudevallongitude: longitudeval}anchorPoint: Qt.point(sourceItem.width/2, sourceItem.height/2)}}Component{id: null_compItem{}}Component{id: area_compRectangle{width: area_text.width+5+5+14+5height: area_text.height+10border.color: "gray"Text {id: area_textx: 5anchors.verticalCenter: parent.verticalCentertext: control.areaValue+" m^2"}Rectangle{width: 14height: 14anchors.right: parent.rightanchors.rightMargin: 5anchors.verticalCenter: parent.verticalCenterborder.color: "red"Text {color: "red"anchors.centerIn: parenttext: "+"rotation: 45}MouseArea{anchors.fill: parentonClicked: {clearPath();}}}}}function appendPoint(coord){item_model.append({"latitudeval":coord.latitude,"longitudeval":coord.longitude});item_line.addCoordinate(coord);}function followMouse(coord){if(item_line.pathLength()<=0)return;if(item_line.pathLength()===item_model.count){item_line.addCoordinate(coord);}else{item_line.replaceCoordinate(item_line.pathLength()-1,coord);}}function closePath(){control._pathClose=true;while(item_line.pathLength()>item_model.count){item_line.removeCoordinate(item_line.pathLength()-1);}if(item_line.pathLength()<3){clearPath();return;}control.areaValue=getPolygonArea(item_line.path);item_line.addCoordinate(item_line.path[0]);}function clearPath(){item_line.path=[];item_model.clear();}//计算方式1:https://www.cnblogs.com/c-w20140301/p/10308431.html//根据py代码换砖而来//转换为弧度function convertToRadian(num){return num*Math.PI/180;}//计算地图区域面积function calculatePolygonArea(path){let area_count=0;let path_len=path.length;if(path_len<3)return area_count;let data_list=[];for(let i=0;i<path_len;i++){area_count+=convertToRadian(path[(i+1)%path_len].longitude-path[(i)%path_len].longitude)*(2+Math.sin(convertToRadian(path[(i)%path_len].latitude))+Math.sin(convertToRadian(path[(i+1)%path_len].latitude)));}area_count*=6378137.0 * 6378137.0 / 2.0;return Math.abs(area_count);}//计算方式2:https://blog.csdn.net/zdb1314/article/details/80661602//应该是提取的高德api里的函数,命名应该是混淆加密之后的function getPolygonArea(path){let area_count=0;let path_len=path.length;if(path_len<3)return area_count;let data_list=[];//WGS84地球半径let sJ = 6378137;//Math.PI/180let Hq = 0.017453292519943295;let c = sJ *Hq;for(let i=0;i<path_len-1;i++){let h=path[i];let k=path[i+1];let u=h.longitude*c*Math.cos(h.latitude*Hq);let hhh=h.latitude*c;let v=k.longitude*c*Math.cos(k.latitude*Hq);area_count+=(u*k.latitude*c-v*hhh);}let eee=path[path_len-1].longitude*c*Math.cos(path[path_len-1].latitude*Hq);let g2=path[path_len-1].latitude*c;let k=path[0].longitude*c*Math.cos(path[0].latitude*Hq);area_count+=eee*path[0].latitude*c-k*g2;return Math.round(Math.abs(area_count)/2);}
}

在 Window 中调用下面组件来展示 Demo:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12//地图自定义
Item{id: control//地图的模式// 0:普通浏览// 1:测距// 2:截图// 3:面积property int mapMode: 0property MapArea currentArea: nullproperty alias map: the_mapclip: trueonMapModeChanged: {console.log("map mode",mapMode);if(control.mapMode!=3&&currentArea){currentArea.closePath();currentArea=null;}}//缩放等级,维度,精度function viewPoint(zoomLevel,latitude,longitude){the_map.zoomLevel=zoomLevel;the_map.center=QtPositioning.coordinate(latitude, longitude);}Row{RadioButton{text: "Normal"checked: trueonCheckedChanged: if(checked)control.mapMode=0;}RadioButton{text: "Area"onCheckedChanged: if(checked)control.mapMode=3;}}Map {id: the_mapanchors.fill: parentanchors.topMargin: 40minimumZoomLevel: 4maximumZoomLevel: 16zoomLevel: 10center: QtPositioning.coordinate(30.6562, 104.0657)plugin: Plugin { //这里使用了自定义plugin请忽略name: "mymap" //"esri" "mapbox" "osm" "here"PluginParameter {name: "baseUrl"// 自行指定瓦片路径value: "file:///"+applicationDirPath+"/dianzi_gaode_ArcgisServerTiles/_alllayers"}PluginParameter {name: "format"value: "png"}}//显示缩放等级与centerRectangle{anchors{left: the_map.leftbottom: the_map.bottommargins: 5}width: content.width+20height: content.height+10Text {id: contentx: 10y: 5font.pixelSize: 14text: "Zoom Level "+Math.floor(the_map.zoomLevel)+" Center:"+the_map.center.latitude+"  "+the_map.center.longitude}}MouseArea{id: map_mouseanchors.fill: parentenabled: control.mapMode!=0//画了一个点后跟随鼠标,除非双击hoverEnabled: trueonClicked: {// 3 面积if(control.mapMode===3){if(!currentArea){currentArea=area_comp.createObject(the_map);if(currentArea)the_map.addMapItemGroup(currentArea);}if(currentArea){var coord=the_map.toCoordinate(Qt.point(mouseX,mouseY),false);currentArea.appendPoint(coord);}}}onDoubleClicked: {// 3 面积if(control.mapMode===3){if(currentArea){currentArea.closePath();currentArea=null;}}}onPositionChanged: {// 3 面积if(control.mapMode===3){if(currentArea){var coord=the_map.toCoordinate(Qt.point(mouseX,mouseY),false);currentArea.followMouse(coord);}}}}}Component{id: area_compMapArea{}}
}

代码 github 链接:https://github.com/gongjianbo/MyQtLocation


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

相关文章

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

在我们的日常生活中&#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对数学中非负矩阵研究的突出成果。该文提出了一种新的矩阵分解思想—…

非负矩阵分解(NMF)的Matlab实例与说明

原理啥的到处都有&#xff0c;就直接跳过了。这里主要是NMF的基础实验。下一篇是NMF的高光谱实验总结。 1. matlab示例解说 这一节的图片来自官方文档。 这里第一和第三变量在第一行的值0.6945和0.62220对W的第一列有相当强的权重。第一个第二变量在第二行的值0.8020和0.568…

【机器学习】NMF(非负矩阵分解)

写在篇前 本篇文章主要介绍NMF算法原理以及使用sklearn中的封装方法实现该算法&#xff0c;最重要的是理解要NMF矩阵分解的实际意义&#xff0c;将其运用到自己的数据分析中&#xff01; 理论概述 NMF(Non-negative matrix factorization)&#xff0c;即对于任意给定的一个非负…