• QML地图Map中使用QPainterPath,并显示任意点经纬度位置


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

     

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

    Demo项目地址:

    https://download.csdn.net/download/zjgo007/87259998icon-default.png?t=M85Bhttps://download.csdn.net/download/zjgo007/87259998https://github.com/zjgo007/QmlDemo/tree/master/MapPainterhttps://github.com/zjgo007/QmlDemo/tree/master/MapPainter

     

    main.qml

    1. import QtQuick 2.9
    2. import QtQuick.Window 2.2
    3. import QtLocation 5.9
    4. import QtPositioning 5.9
    5. import QtQuick.Controls 2.9
    6. import MapPainter 1.0
    7. Window {
    8. id:window
    9. width: 640
    10. height: 480
    11. visible: true
    12. title: qsTr("Map Painter Path")
    13. Plugin {
    14. id: mapPlugin
    15. name: "osm" // "mapboxgl", "esri", ...
    16. PluginParameter{//自定义地图瓦片路径
    17. name:"osm.mapping.offline.directory"
    18. value: "G:/Map/"
    19. }
    20. PluginParameter{
    21. name:"osm.mapping.offline.maptiledir"
    22. value:true
    23. }
    24. }
    25. Map {
    26. id: myMap
    27. center: QtPositioning.coordinate(24,104)
    28. anchors.fill: parent
    29. plugin: mapPlugin
    30. zoomLevel: 8
    31. color: "#00000000"
    32. copyrightsVisible: false
    33. activeMapType: supportedMapTypes[2]
    34. // onVisibleRegionChanged: {//Qt 5.15以上使用
    35. // mapPainter.mapRegionChanged()
    36. // }
    37. onCenterChanged: {//Qt 5.15以下使用
    38. mapPainter.mapRegionChanged()
    39. }
    40. onZoomLevelChanged: {//Qt 5.15以下使用
    41. mapPainter.mapRegionChanged()
    42. }
    43. MapPainter{
    44. id:mapPainter
    45. anchors.fill: parent
    46. }
    47. MapQuickItem{
    48. id: anchorMarker
    49. width: 50
    50. height: 36
    51. anchorPoint.x: image.width/2
    52. anchorPoint.y: image.height
    53. coordinate: myMap.center
    54. sourceItem: Item{
    55. Image {
    56. id:image
    57. source: "qrc:/anchor.png"
    58. sourceSize.height: 36
    59. sourceSize.width: 50
    60. }
    61. Text {
    62. id: label
    63. y:-15
    64. color: "#00ffff"
    65. text: qsTr("")
    66. font.bold: true
    67. font.pointSize: 11
    68. font.family: "微软雅黑"
    69. }
    70. }
    71. }
    72. MouseArea {
    73. id: mouseArea_measure
    74. anchors.fill: parent
    75. onClicked: {
    76. var coordinate = myMap.toCoordinate(Qt.point(mouse.x, mouse.y))
    77. mapPainter.addPathPoint(mouse.x, mouse.y,coordinate)
    78. anchorMarker.coordinate = coordinate
    79. }
    80. }
    81. }
    82. Slider {
    83. id: slider
    84. x: 430
    85. y: 10
    86. stepSize: 0.01
    87. value: 1
    88. onValueChanged: {
    89. var coordinate = mapPainter.mapPathData(value)
    90. anchorMarker.coordinate = coordinate
    91. label.text = "("+coordinate.latitude.toFixed(4)+","+coordinate.longitude.toFixed(4)+")"
    92. }
    93. }
    94. Component.onCompleted: {
    95. mapPainter.setQmlObject(window)
    96. }
    97. function transGeoToPoint(coordinate){
    98. return myMap.fromCoordinate(coordinate,false)
    99. }
    100. function transPointToGeo(pointf){
    101. return myMap.toCoordinate(pointf,false)
    102. }
    103. }

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

    1. Component.onCompleted: {
    2. mapPainter.setQmlObject(window)
    3. }
    4. function transGeoToPoint(coordinate){
    5. return myMap.fromCoordinate(coordinate,false)
    6. }
    7. function transPointToGeo(pointf){
    8. return myMap.toCoordinate(pointf,false)
    9. }

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

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

    mappainter.h

    1. #ifndef MAPPAINTER_H
    2. #define MAPPAINTER_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. class GeoPainterPath
    9. {
    10. public:
    11. GeoPainterPath() {}
    12. ~GeoPainterPath(){}
    13. enum PainterType{
    14. None,
    15. MoveTo,
    16. LineTo
    17. };
    18. void addGeoPath(PainterType type,QGeoCoordinate coordinate);
    19. PainterType painterType(int index);
    20. QGeoCoordinate coordinate(int index);
    21. int size();
    22. void clear();
    23. private:
    24. QList typeList;
    25. QList geoList;
    26. };
    27. class MapPainter : public QQuickPaintedItem
    28. {
    29. Q_OBJECT
    30. public:
    31. MapPainter(QQuickItem *parent = nullptr);
    32. ~MapPainter();
    33. virtual void paint(QPainter *painter) Q_DECL_OVERRIDE;
    34. Q_INVOKABLE void setQmlObject(QObject* object);
    35. public slots:
    36. void addPathPoint(qreal x,qreal y,QGeoCoordinate coordinate);
    37. void updatePainterPath();
    38. void mapRegionChanged();
    39. QGeoCoordinate mapPathData(qreal percent);
    40. private:
    41. QPainterPath* testPath;
    42. bool pathDirty;
    43. GeoPainterPath mGeoPainterPath;
    44. QObject* qmlObject;
    45. };
    46. #endif // MAPPAINTER_H

    mappainter.cpp

    1. #include "mappainter.h"
    2. MapPainter::MapPainter(QQuickItem *parent):QQuickPaintedItem(parent),pathDirty(false)
    3. {
    4. testPath = new QPainterPath();
    5. connect(this,&QQuickPaintedItem::widthChanged,this,&MapPainter::mapRegionChanged);
    6. connect(this,&QQuickPaintedItem::heightChanged,this,&MapPainter::mapRegionChanged);
    7. }
    8. MapPainter::~MapPainter()
    9. {
    10. delete testPath;
    11. }
    12. void MapPainter::paint(QPainter *painter)
    13. {
    14. if(pathDirty)
    15. updatePainterPath();
    16. painter->setPen(QPen(QColor("red"), 2, Qt::SolidLine,
    17. Qt::RoundCap, Qt::RoundJoin));
    18. painter->drawPath(*testPath);
    19. }
    20. void MapPainter::setQmlObject(QObject *object)
    21. {
    22. qmlObject = object;
    23. }
    24. void MapPainter::addPathPoint(qreal x, qreal y, QGeoCoordinate coordinate)
    25. {
    26. if(testPath->elementCount()==0){
    27. testPath->moveTo(x,y);
    28. mGeoPainterPath.addGeoPath(GeoPainterPath::MoveTo,coordinate);
    29. }else{
    30. testPath->lineTo(x,y);
    31. mGeoPainterPath.addGeoPath(GeoPainterPath::LineTo,coordinate);
    32. }
    33. update();
    34. }
    35. void MapPainter::updatePainterPath()
    36. {
    37. if(qmlObject){
    38. testPath->clear();
    39. int size = mGeoPainterPath.size();
    40. for(int i=0;i
    41. QGeoCoordinate coordinate = mGeoPainterPath.coordinate(i);
    42. QVariant mapPointVar;
    43. QMetaObject::invokeMethod(qmlObject,"transGeoToPoint",Qt::DirectConnection,
    44. Q_RETURN_ARG(QVariant,mapPointVar),
    45. Q_ARG(QVariant,QVariant::fromValue(coordinate))
    46. );
    47. GeoPainterPath::PainterType painterType = mGeoPainterPath.painterType(i);
    48. QPointF mapPoint = mapPointVar.toPointF();
    49. switch (painterType) {
    50. case GeoPainterPath::MoveTo:
    51. testPath->moveTo(mapPoint);
    52. break;
    53. case GeoPainterPath::LineTo:
    54. testPath->lineTo(mapPoint);
    55. break;
    56. default:
    57. break;
    58. }
    59. }
    60. pathDirty = false;
    61. }
    62. }
    63. void MapPainter::mapRegionChanged()
    64. {
    65. pathDirty = true;
    66. update();
    67. }
    68. QGeoCoordinate MapPainter::mapPathData(qreal percent)
    69. {
    70. QPointF pointf = testPath->pointAtPercent(percent);
    71. QVariant coordinateVar;
    72. QMetaObject::invokeMethod(qmlObject,"transPointToGeo",Qt::DirectConnection,
    73. Q_RETURN_ARG(QVariant,coordinateVar),
    74. Q_ARG(QVariant,QVariant::fromValue(pointf)));
    75. return coordinateVar.value();
    76. }
    77. void GeoPainterPath::addGeoPath(PainterType type, QGeoCoordinate coordinate)
    78. {
    79. typeList.append(type);
    80. geoList.append(coordinate);
    81. }
    82. GeoPainterPath::PainterType GeoPainterPath::painterType(int index)
    83. {
    84. if(index>=typeList.size()){
    85. return PainterType::None;
    86. }
    87. return typeList.at(index);
    88. }
    89. QGeoCoordinate GeoPainterPath::coordinate(int index)
    90. {
    91. if(index>=geoList.size()){
    92. return QGeoCoordinate();
    93. }
    94. return geoList.at(index);
    95. }
    96. int GeoPainterPath::size()
    97. {
    98. return geoList.size();
    99. }
    100. void GeoPainterPath::clear()
    101. {
    102. typeList.clear();
    103. geoList.clear();
    104. }

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

  • 相关阅读:
    软件工程经济学期末复习
    科教兴国 | 拓世集团携手中国航天广电集团,打造《AI+教育平台》
    搜索——最短路模型,多源bfs
    IIs部署发布vue项目测试环境
    【算法刷题日记之本手篇】最难的问题与因子个数
    【面试普通人VS高手】Kafka的零拷贝原理?
    基于低代码平台打造新时代的OA系统
    怎样在应用中实现自助报表功能?
    android开发电子书,android基础编程
    文心一言(ERNIE Bot)初体验
  • 原文地址:https://blog.csdn.net/zjgo007/article/details/127911714