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

news2024/9/20 20:25:32

        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.9

import MapPainter 1.0

Window {
    id:window
    width: 640
    height: 480
    visible: true
    title: qsTr("Map Painter Path")

    Plugin {
        id: mapPlugin
        name: "osm" // "mapboxgl", "esri", ...

        PluginParameter{//自定义地图瓦片路径
            name:"osm.mapping.offline.directory"
            value: "G:/Map/"
        }

        PluginParameter{
            name:"osm.mapping.offline.maptiledir"
            value:true
        }

    }

    Map {
        id: myMap
        center: QtPositioning.coordinate(24,104)
        anchors.fill: parent
        plugin: mapPlugin

        zoomLevel: 8
        color: "#00000000"
        copyrightsVisible: false
        activeMapType: supportedMapTypes[2]

//        onVisibleRegionChanged: {//Qt 5.15以上使用
//            mapPainter.mapRegionChanged()
//        }

        onCenterChanged: {//Qt 5.15以下使用
            mapPainter.mapRegionChanged()
        }

        onZoomLevelChanged: {//Qt 5.15以下使用
            mapPainter.mapRegionChanged()
        }

        MapPainter{
            id:mapPainter
            anchors.fill: parent
        }

        MapQuickItem{
            id: anchorMarker
            width: 50
            height: 36
            anchorPoint.x: image.width/2
            anchorPoint.y: image.height
            coordinate: myMap.center

            sourceItem: Item{
                Image {
                    id:image
                    source: "qrc:/anchor.png"
                    sourceSize.height: 36
                    sourceSize.width: 50
                }
                Text {
                    id: label
                    y:-15
                    color: "#00ffff"
                    text: qsTr("")
                    font.bold: true
                    font.pointSize: 11
                    font.family: "微软雅黑"
                }
            }
        }
        MouseArea {
            id: mouseArea_measure
            anchors.fill: parent
            onClicked: {
                var coordinate = myMap.toCoordinate(Qt.point(mouse.x, mouse.y))
                mapPainter.addPathPoint(mouse.x, mouse.y,coordinate)
                anchorMarker.coordinate = coordinate
            }
        }
    }

    Slider {
        id: slider
        x: 430
        y: 10
        stepSize: 0.01
        value: 1
        onValueChanged: {
            var coordinate = mapPainter.mapPathData(value)
            anchorMarker.coordinate = coordinate
            label.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 <QQuickPaintedItem>
#include <QObject>
#include <QPainter>
#include <QPainterPath>
#include <QGeoCoordinate>

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<PainterType> typeList;
    QList<QGeoCoordinate> 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;i<size;i++){
            QGeoCoordinate coordinate = mGeoPainterPath.coordinate(i);
            QVariant mapPointVar;
            QMetaObject::invokeMethod(qmlObject,"transGeoToPoint",Qt::DirectConnection,
                                      Q_RETURN_ARG(QVariant,mapPointVar),
                                      Q_ARG(QVariant,QVariant::fromValue(coordinate))
                                      );
            GeoPainterPath::PainterType painterType = mGeoPainterPath.painterType(i);
            QPointF mapPoint = mapPointVar.toPointF();
            switch (painterType) {
            case GeoPainterPath::MoveTo:
                testPath->moveTo(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<QGeoCoordinate>();
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/13263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macOS 的「预览」有几种用法

如果要评选 macOS 最低调的 App &#xff0c;「预览」可能就会位列其中之一。「预览」和 macOS 结合异常紧密&#xff0c;甚至让人都会遗忘它还是个 App。毕竟大多数的时候&#xff0c;提到「预览」就会想到操作系统的一部分。而实际上&#xff0c;「预览」那「瘦小」的身躯之内…

Unity3D赛车游戏+脚本基础

前言 游戏对象实例化 Scenes游戏场景 GameObject游戏对象 Component组件 Component使用方法 预制体 Unity事件函数 Instantiate():实例化对象 什么是Time.deltaTime Transform的移动&#xff0c;旋转和缩放 实战:赛车游戏 运行演示 具体步骤 游戏打包流程 前言 …

智慧教育解决方案-最新全套文件

智慧教育解决方案-最新全套文件一、建设背景二、思路架构三、建设方案四、获取 - 智慧教育全套最新解决方案合集一、建设背景 目前数字化校园现状&#xff1a; 各自为政 分散建设 各个学校组成的业务系统、网站五花八门&#xff0c;形式多样。形式单一 功能简单 学校网站主要…

为什么同一表情‘‘.length==5但‘‘.length==4?本文带你深入理解 String Unicode UTF8 UTF16

背景 为什么同样是男人&#xff0c;但有的男人&#x1f9d4;‍♂️.length 5&#xff0c;有的男人&#x1f9d4;‍♂.length 4呢&#xff1f; 这二者都是JS中的字符串&#xff0c;要理解本质原因&#xff0c;你需要明白JS中字符串的本质&#xff0c;你需要理解 String Unic…

vlan trunk stp攻防

目录 一、VLAN、Trunk面临的安全风险 trunk干道攻击DTP攻击&#xff08;思科特有&#xff09; VLAN跳跃攻击 STP根桥攻击 二、攻击防护 一、VLAN、Trunk面临的安全风险 trunk干道攻击DTP攻击&#xff08;思科特有&#xff09; 在华为设备中trunk链路是手工指定的&#xf…

A-LEVEL Chemistry考点分析

A-LEVEL化学其实不是一门很难的科目&#xff0c;并没有太多的内容&#xff0c;虽说包含十几章的内容但其实每章都是相互关联&#xff0c;一通百通&#xff0c;掌握元素周期表的实质&#xff0c;基本上就没有什么问题了&#xff0c;重在理解&#xff01;知识点多而不碎&#xff…

如何一站式管理固定资产的全生命周期?

目前很多企业还在沿用之前传统的Excel表格来管理和盘点固定资产&#xff0c;不但加大了企业固定资产管理员的工作量&#xff0c;而且在实际的操作过程中容易出现错登记、漏盘点、无法查询操作履历等各种小插曲。而且随着企业固定资产数量、种类、分支机构以及人员的不断增加&am…

juc之常用4大并发工具类 (四)

CountDownLatch: 减少计数CyclicBarrier: 循环栅栏Semaphore: 信号量ExChanger: 交换器 文章目录1.CountDownLatch2.CyclicBarrier3.Semaphore4.Exchanger1.CountDownLatch CountDownLatch,俗称闭锁,作用是类似加强版的 Join,是让一组线程等待其他的线程完成工作以后才执行 就…

数仓开发之DWD层(四)

目录 十一&#xff1a;工具域优惠券领取事务事实表 11.1 主要任务&#xff1a; 11.2 思路分析&#xff1a; 11.3 图解&#xff1a; 十二&#xff1a;工具域优惠券使用&#xff08;下单&#xff09;事务事实表 12.1 主要任务&#xff1a; 12.2 思路分析&#xff1a; 12.3…

[附源码]Python计算机毕业设计 社区老人健康服务跟踪系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Java项目实战【超级详细】

软件开发流程 角色分工 开发环境搭建 创建普通Maven项目编写pom.xml导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instanc…

【MQ简单模式】

14天阅读挑战赛 MQ简单模式 1、模式介绍 需求&#xff1a;使用简单模式完成消息传递 步骤&#xff1a; ① 创建工程&#xff08;生成者、消费者&#xff09; ② 分别添加依赖 ③ 编写生产者发送消息 ④ 编写消费者接收消息 在上图的模型中&#xff0c;有以下概念&#xff1a; ⚫…

数据库索引的基本操作(sql语句)

表索引的增删改查&#xff08;sql语句&#xff09; 概念&#xff1a; 索引由表中的一列或多列组合而成&#xff0c;目的是优化数据库的查询速度。向索引表中插入数据时&#xff0c;数据库系统需要按照索引进行排序。有时&#xff0c;可以先将索引删除&#xff0c;然后向表插入…

Docker学习(1)—— 安装Docker

一. 安装Docker 1. 查看CentOS是否是7以上的版本 cat /etc/redhat-release 2. 安装gcc yum -y install gcc yum -y install gcc-c 3. 安装需要的软件包 yum install -y yum-utils 4. 设置stable镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/doc…

p38 MAPK调控酶及转录因子

MAPK 与 p38 MAPK 作为对外界物理和化学性质变化的响应&#xff0c;哺乳动物细胞激活有丝分裂原激活蛋白激酶 (MAPK) 的四个特征性亚家族&#xff1a;ERK1/2、JNK、p38 和 ERK5。其中 p38 MAPKs 是一类保守的丝氨酸-苏氨酸蛋白激酶&#xff0c;可被多种细胞外炎症因子 (如TNF-α…

语义分割及DeeplabV3+模型

一、基本概念 将视觉输入分为不同的语义可解释类别&#xff1b;通俗点说就是区分不同部分。 分类&#xff1a; b)语义分割 c)实例分割 d)全景分割 语义分割一般以平均IOU(Intersection Over Union,并交比)来评价性能&#xff0c;其公式如下&#xff1a; 目的是使…

Python学习----Demo(pyecharts)

PyEcharts 就是百度的Echarts&#xff0c;针对Python有一款专门的&#xff0c;所以就叫PyEcharts 官方网站&#xff1a; 文档&#xff1a; https://pyecharts.org/#/zh-cn/ 示例&#xff1a; https://gallery.pyecharts.org/#/README 通过pip安装 pip install pyecharts 或者…

关于Docker中容器之间互相访问问题

背景&#xff1a; 在学习 Docker 过程中&#xff0c;自己先开启了一个 mysql 容器&#xff0c;并且通过端口映射Navicat可以远程连接 后来在部署 nacos 过程中&#xff0c;对于其中参数 MYSQL_SERVICE_HOST 配置 mysql 的 IP 时 首先配置的是 localhost&#xff0c;结果 nacos…

Opencv项目实战:16 虚拟拖拽系统

0、项目介绍 这次使用cvzone模块&#xff0c;制作一个虚拟拖拽系统&#xff0c;我们根据索引可以知道食指与中指的索引为8和12&#xff0c;当两指间合并时可以对虚拟方块进行拖拽&#xff0c;张开时解除拖拽&#xff0c;方块停在此处。虽然目前仍然存在一定的bug&#xff0c;即…

网站seo怎么优化?

一、网站搭建 1、选择合适的建站软件。 2、网站模板的选择。 3、title的选择至关重要。 4、长尾关键词的选择。 二、站内优化 1、首页title keywords description等布局好要优化的关键词&#xff0c;页面中间和底部也要布局关键词且用标签加粗&#xff01; 2、网站 URL静态。…