QML Map中测距——QtLocation轻量级地图应用学习


本文转载于:QML QtLocation轻量级地图应用学习:实现测距功能


所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!

QML其它文章请点击这里:     QT QUICK QML 学习笔记


1. 实现思路

参照百度or高德地图的测距功能,主要由两种元素组成,标记点和连线。
在这里插入图片描述
其中连线很好解决,Qt 提供了 MapPolyline 类型,可以用来绘制折线,并且提供了增删的便捷函数:
在这里插入图片描述
对于标记点,我们可以用 MapQuickItem 来实现,里面包含一个标记圆圈、长度Text、删除按钮。对于一组 MapQuickItem,我使用 MapItemView 来管理。而求两个坐标点的距离,直接调用的 coordinate 类型的 distanceTo 函数,总长直接遍历求距离就行了。

接下来就是封装一个 Ruler 的组件,实现多次测距的绘制。每次开始测距时,通过 createObject 动态创建一个 Ruler 组件,然后往里面添加坐标点。坐标点我是在 Map 上放了一个 MouseArea ,然后用 Map 的 toCoordinate 方法把 point 转换成坐标点。

此外,如果要自己计算两点距离,可以参考网上球面两点距离的公式,如:
在这里插入图片描述
在这里插入图片描述
上面参考的表示法应该是十进制的,如果是度分秒的形式,可以先转化下:
在这里插入图片描述

2. 实现代码及git链接

下面是实现效果:
在这里插入图片描述
有一点还没解决,那就是 MapPolyline 这种图元设置 layer 实现平滑效果的话,放大之后很卡。另外就是,一个 Ruler 所有元素被删之后我也没有析构它。

Ruler组件的实现代码:

//MapRuler.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12
 
// 一次测距里包含多个标记点以及连线
MapItemGroup{
    id: control
 
    MapPolyline {
        id: item_line
        line.color: "red"
        line.width: 2
        //平滑后放大有点卡
        //layer.enabled: true
        //layer.smooth: true
        //layer.samples: 8
        function getDistanceCount(){
            var distance_count=0;
            for(var i=1;i<pathLength();i++){
                distance_count+=item_line.coordinateAt(i).distanceTo(item_line.coordinateAt(i-1));
            }
            return Math.round(distance_count);
        }
    }
 
    MapItemView{
        id: item_view
        add: Transition {}
        remove: Transition {}
        model: ListModel{
            id: item_model
        }
        delegate: MapQuickItem{
            id: ietm_delegate
            sourceItem: Rectangle {
                width: 14
                height: 14
                radius: 7
                color: "white"
                border.width: 2
                border.color: "red"
                Rectangle{
                    anchors.left: parent.right
                    anchors.top: parent.bottom
                    width: item_text.width+5+5+14+5
                    height: item_text.height+10
                    border.color: "gray"
                    Text {
                        id: item_text
                        x: 5
                        anchors.verticalCenter: parent.verticalCenter
                        text: index<=0
                              ? "起点"
                              : (index==item_model.count-1)
                                ? ("总长 "+item_line.getDistanceCount()/1000+" km")
                                :(Math.round(ietm_delegate.coordinate.distanceTo(item_line.coordinateAt(index-1)))/1000+" km")
                    }
                    Rectangle{
                        width: 14
                        height: 14
                        anchors.right: parent.right
                        anchors.rightMargin: 5
                        anchors.verticalCenter: parent.verticalCenter
                        border.color: "red"
                        Text {
                            color: "red"
                            anchors.centerIn: parent
                            text: "+"
                            rotation: 45
                        }
                        MouseArea{
                            anchors.fill: parent
                            onClicked: {
                                //最后一个全部删除,否则一个一个的删除
                                //为0的时候发送信号给group请求删除
                                if(index==item_model.count-1){
                                    item_line.path=[];
                                    item_model.clear();
                                    //control.destroy();
                                }else{
                                    item_line.removeCoordinate(index);
                                    item_model.remove(index);
                                }
                            }
                        }
                    }
                }
 
                //Component.onDestruction: console.log("destory item");
            }
            //通过listmodel来设置数据
            coordinate{
                latitude: latitudeval
                longitude: longitudeval
            }
            anchorPoint: Qt.point(sourceItem.width/2, sourceItem.height/2)
        }
    }
 
    function appendPoint(coord){
        //var coord=the_map.toCoordinate(Qt.point(mouseX,mouseY),false);
        //console.log("area",coord.latitude,coord.longitude);
        item_model.append({"latitudeval":coord.latitude,"longitudeval":coord.longitude});
        item_line.addCoordinate(coord);
        //mouse_area._closePath=false;
        //console.log("ruler append",item_model.count,item_line.pathLength())
    }
 
    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(){
        while(item_line.pathLength()>item_model.count){
            item_line.removeCoordinate(item_line.pathLength()-1);
        }
    }
}

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

 //Demo.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtLocation 5.12
import QtPositioning 5.12
 
//地图自定义
Item{
    id: control
    //地图的模式
    // 0:普通浏览
    // 1:测距
    property int mapMode: 0
    property MapRuler currentRuler: null
 
    property alias map: the_map
    clip: true
 
    onMapModeChanged: {
        console.log("map mode",mapMode);
        if(control.mapMode!=1&&currentRuler){
            currentRuler.closePath();
            currentRuler=null;
        }
    }
 
    //缩放等级,维度,精度
    function viewPoint(zoomLevel,latitude,longitude){
        the_map.zoomLevel=zoomLevel;
        the_map.center=QtPositioning.coordinate(latitude, longitude);
    }
 
 
    Row{
        RadioButton{
            text: "Normal"
            checked: true
            onCheckedChanged: if(checked)control.mapMode=0;
        }
        RadioButton{
            text: "Ruler"
            onCheckedChanged: if(checked)control.mapMode=1;
        }
    }
 
    Map {
        id: the_map
        anchors.fill: parent
        anchors.topMargin: 40
        minimumZoomLevel: 4
        maximumZoomLevel: 16
        zoomLevel: 10
        center: QtPositioning.coordinate(30.6562, 104.0657)
 
        plugin: Plugin {
            name: "esri" //"esri" "mapbox" "osm" "here"
        }
 
        //显示缩放等级与center
        Rectangle{
            anchors{
                left: the_map.left
                bottom: the_map.bottom
                margins: 5
            }
 
            width: content.width+20
            height: content.height+10
            Text {
                id: content
                x: 10
                y: 5
                font.pixelSize: 14
                text: "Zoom Level "+Math.floor(the_map.zoomLevel)+" Center:"+the_map.center.latitude+"  "+the_map.center.longitude
 
            }
        }
 
        MouseArea{
            id: map_mouse
            anchors.fill: parent
            enabled: control.mapMode!=0
 
            //画了一个点后跟随鼠标,除非双击
            hoverEnabled: true
            onClicked: {
                // 1 测距
                if(control.mapMode===1){
                    if(!currentRuler){
                        currentRuler=ruler_comp.createObject(the_map);
                        if(currentRuler)
                            the_map.addMapItemGroup(currentRuler);
                    }
                    if(currentRuler){
                        var coord=the_map.toCoordinate(Qt.point(mouseX,mouseY),false);
                        currentRuler.appendPoint(coord);
                    }
                }
            }
            onDoubleClicked: {
                // 1 测距
                if(control.mapMode===1){
                    if(currentRuler){
                        currentRuler.closePath();
                        currentRuler=null;
                    }
                }
            }
            onPositionChanged: {
                // 1 测距
                if(control.mapMode===1){
                    if(currentRuler){
                        var coord=the_map.toCoordinate(Qt.point(mouseX,mouseY),false);
                        currentRuler.followMouse(coord);
                    }
                }
            }
        }
    }
 
    Component{
        id: ruler_comp
        MapRuler{
 
        }
    }
}

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

  • 10
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
你好!对于学习QtLocation地图应用,我可以为你提供一些指导。首先,QtLocationQt框架的一个模块,用于集成地图和位置服务功能。它提供了一组API和工具,使开发者能够在他们的应用程序使用地图功能。 要开始学习QtLocation地图应用,你可以按照以下步骤进行: 1. 安装Qt:首先,确保你已经安装了Qt开发环境。你可以从Qt官方网站下载并安装Qt Creator和Qt框架。 2. 导入QtLocation模块:在Qt Creator创建一个新的Qt项目,并在项目设置添加QtLocation模块。这将确保你可以使用该模块的功能。 3. 获取地图提供商的API密钥:大多数地图提供商(如Google Maps、Mapbox等)需要API密钥才能使用他们的服务。注册一个开发人员账户并获取API密钥。 4. 配置地图提供商:在代码设置地图提供商和API密钥。根据你选择的地图提供商和Qt版本,具体的设置方法会有所不同。你可以查阅QtLocation的文档和示例代码来了解如何配置。 5. 在应用程序添加地图功能:使用QtLocation提供的API,你可以添加地图、标记点、路径等功能到你的应用程序。可以通过创建QML文件或者使用C++代码来实现。 6. 处理位置信息:QtLocation还提供了一些API来处理设备的位置信息。你可以使用这些API获取设备的当前位置、监听位置变化等。 7. 运行和调试:完成代码编写后,你可以在Qt Creator运行和调试你的应用程序。确保你的API密钥正确配置,并能够正常显示地图。 以上是一个简单的学习QtLocation地图应用的步骤。当然,在实际开发可能会涉及到更多的细节和特定需求。我建议你查阅QtLocation的官方文档、示例代码和教程,以便更全面地学习和理解相关知识。祝你学习愉快!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值