QML地图Map中使用QPainterPath,并显示任意点经纬度位置
创始人
2024-04-09 14:17:31
0

        QML地图Map中提供了供绘制图形的组件,例如MapPolyline,MapCircle等,但是这些组件在绘制复杂轨迹时就显得功能不够全面,因此我将QPainterPath在Map中进行使用并进行绘制,并使用C++和Qml中的函数进行相互调用计算获取点屏幕坐标和经纬度坐标。例子中使用了QPainterPath的QPainterPath::pointAtPercent获取绘制的轨迹全过程中的各个位置的经纬度。效果如图:

 

        QML主要功能为地图显示,其中Plugin中定义的路径为我地图瓦片存放路径,你们需要修改为自己的或者直接使用在线地图。我们自定义了一个类 MapPainter,该类继承至QQuickPaintedItem,并通过元对象系统注册至QML中,覆盖到Map上方作为画布使用。

Demo项目地址:https://github.com/zjgo007/QmlDemo/tree/master/MapPainterhttps://github.com/zjgo007/QmlDemo/tree/master/MapPainter

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtLocation 5.9
import QtPositioning 5.9
import QtQuick.Controls 2.9import MapPainter 1.0Window {id:windowwidth: 640height: 480visible: truetitle: qsTr("Map Painter Path")Plugin {id: mapPluginname: "osm" // "mapboxgl", "esri", ...PluginParameter{//自定义地图瓦片路径name:"osm.mapping.offline.directory"value: "G:/Map/"}PluginParameter{name:"osm.mapping.offline.maptiledir"value:true}}Map {id: myMapcenter: QtPositioning.coordinate(24,104)anchors.fill: parentplugin: mapPluginzoomLevel: 8color: "#00000000"copyrightsVisible: falseactiveMapType: supportedMapTypes[2]//        onVisibleRegionChanged: {//Qt 5.15以上使用
//            mapPainter.mapRegionChanged()
//        }onCenterChanged: {//Qt 5.15以下使用mapPainter.mapRegionChanged()}onZoomLevelChanged: {//Qt 5.15以下使用mapPainter.mapRegionChanged()}MapPainter{id:mapPainteranchors.fill: parent}MapQuickItem{id: anchorMarkerwidth: 50height: 36anchorPoint.x: image.width/2anchorPoint.y: image.heightcoordinate: myMap.centersourceItem: Item{Image {id:imagesource: "qrc:/anchor.png"sourceSize.height: 36sourceSize.width: 50}Text {id: labely:-15color: "#00ffff"text: qsTr("")font.bold: truefont.pointSize: 11font.family: "微软雅黑"}}}MouseArea {id: mouseArea_measureanchors.fill: parentonClicked: {var coordinate = myMap.toCoordinate(Qt.point(mouse.x, mouse.y))mapPainter.addPathPoint(mouse.x, mouse.y,coordinate)anchorMarker.coordinate = coordinate}}}Slider {id: sliderx: 430y: 10stepSize: 0.01value: 1onValueChanged: {var coordinate = mapPainter.mapPathData(value)anchorMarker.coordinate = coordinatelabel.text = "("+coordinate.latitude.toFixed(4)+","+coordinate.longitude.toFixed(4)+")"}}Component.onCompleted: {mapPainter.setQmlObject(window)}function transGeoToPoint(coordinate){return myMap.fromCoordinate(coordinate,false)}function transPointToGeo(pointf){return myMap.toCoordinate(pointf,false)}
}

        其中需要注意的是,在QML的Component.onCompleted信号发出后,需要该QML的QObject传递至MapPainter中,便于在C++中调用qml里定义的函数,这两个函数用于经纬度坐标和屏幕坐标转换。

Component.onCompleted: {mapPainter.setQmlObject(window)}function transGeoToPoint(coordinate){return myMap.fromCoordinate(coordinate,false)}function transPointToGeo(pointf){return myMap.toCoordinate(pointf,false)}

        在C++中,addPathPoint(qreal x,qreal y,QGeoCoordinate coordinate)函数用于传入鼠标点击位置的屏幕坐标和经纬度坐标。mapRegionChanged()用于标记当前地图已被平移或者缩放,需要重新绘制轨迹。

        同时自定义了类GeoPainterPath,该类记录了鼠标绘制轨迹的点位置和绘制方式,我只简单的放了MoveTo和LineTo,其他绘制方式可自行添加。

mappainter.h

#ifndef MAPPAINTER_H
#define MAPPAINTER_H#include 
#include 
#include 
#include 
#include class GeoPainterPath
{
public:GeoPainterPath() {}~GeoPainterPath(){}enum PainterType{None,MoveTo,LineTo};void addGeoPath(PainterType type,QGeoCoordinate coordinate);PainterType painterType(int index);QGeoCoordinate coordinate(int index);int size();void clear();private:QList typeList;QList geoList;
};class MapPainter : public QQuickPaintedItem
{Q_OBJECT
public:MapPainter(QQuickItem *parent = nullptr);~MapPainter();virtual void paint(QPainter *painter) Q_DECL_OVERRIDE;Q_INVOKABLE void setQmlObject(QObject* object);public slots:void addPathPoint(qreal x,qreal y,QGeoCoordinate coordinate);void updatePainterPath();void mapRegionChanged();QGeoCoordinate mapPathData(qreal percent);private:QPainterPath* testPath;bool pathDirty;GeoPainterPath mGeoPainterPath;QObject* qmlObject;
};#endif // MAPPAINTER_H

mappainter.cpp

#include "mappainter.h"MapPainter::MapPainter(QQuickItem *parent):QQuickPaintedItem(parent),pathDirty(false)
{testPath = new QPainterPath();connect(this,&QQuickPaintedItem::widthChanged,this,&MapPainter::mapRegionChanged);connect(this,&QQuickPaintedItem::heightChanged,this,&MapPainter::mapRegionChanged);
}MapPainter::~MapPainter()
{delete testPath;
}void MapPainter::paint(QPainter *painter)
{if(pathDirty)updatePainterPath();painter->setPen(QPen(QColor("red"), 2, Qt::SolidLine,Qt::RoundCap, Qt::RoundJoin));painter->drawPath(*testPath);
}void MapPainter::setQmlObject(QObject *object)
{qmlObject = object;
}void MapPainter::addPathPoint(qreal x, qreal y, QGeoCoordinate coordinate)
{if(testPath->elementCount()==0){testPath->moveTo(x,y);mGeoPainterPath.addGeoPath(GeoPainterPath::MoveTo,coordinate);}else{testPath->lineTo(x,y);mGeoPainterPath.addGeoPath(GeoPainterPath::LineTo,coordinate);}update();
}void MapPainter::updatePainterPath()
{if(qmlObject){testPath->clear();int size = mGeoPainterPath.size();for(int i=0;imoveTo(mapPoint);break;case GeoPainterPath::LineTo:testPath->lineTo(mapPoint);break;default:break;}}pathDirty = false;}
}void MapPainter::mapRegionChanged()
{pathDirty = true;update();
}QGeoCoordinate MapPainter::mapPathData(qreal percent)
{QPointF pointf = testPath->pointAtPercent(percent);QVariant coordinateVar;QMetaObject::invokeMethod(qmlObject,"transPointToGeo",Qt::DirectConnection,Q_RETURN_ARG(QVariant,coordinateVar),Q_ARG(QVariant,QVariant::fromValue(pointf)));return coordinateVar.value();
}void GeoPainterPath::addGeoPath(PainterType type, QGeoCoordinate coordinate)
{typeList.append(type);geoList.append(coordinate);
}GeoPainterPath::PainterType GeoPainterPath::painterType(int index)
{if(index>=typeList.size()){return PainterType::None;}return typeList.at(index);
}QGeoCoordinate GeoPainterPath::coordinate(int index)
{if(index>=geoList.size()){return QGeoCoordinate();}return geoList.at(index);
}int GeoPainterPath::size()
{return geoList.size();
}void GeoPainterPath::clear()
{typeList.clear();geoList.clear();
}

 Demo项目地址:https://github.com/zjgo007/QmlDemo/tree/master/MapPainterhttps://github.com/zjgo007/QmlDemo/tree/master/MapPainter

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...