天天看點

QGC 增加測距功能

一,參照百度地圖,在QGC上實作測距功能,效果如下:

QGC 增加測距功能

二,實作思路

QGC 增加測距功能

三,主要代碼實作

(1),C++ 控制類

#ifndef GFMEASURECONTROLLERNEW_H
#define GFMEASURECONTROLLERNEW_H


#include "PlanElementController.h"
#include "QmlObjectListModel.h"
#include "Vehicle.h"
#include "QGCLoggingCategory.h"
#include "MavlinkQmlSingleton.h"
#include "VisualMissionItem.h"
#include "MultiVehicleManager.h"
#include "MissionManager.h"
#include "CoordinateVector.h"
#include "FirmwarePlugin.h"
#include "QGCApplication.h"
#include "SimpleMissionItem.h"
#include "SurveyMissionItem.h"
#include "QGCMapPolygon.h"
#include <QHash>
#include <QList>
#include <QObject>

class CoordinateVector;

typedef QPair<VisualMissionItem*,VisualMissionItem*> VisualItemPair;
typedef QHash<VisualItemPair, CoordinateVector*> CoordVectHashTable;

class GFMeasureController : public QObject
{
    Q_OBJECT

public:
    GFMeasureController(QObject* parent = NULL);
    ~GFMeasureController();

    Q_PROPERTY(QmlObjectListModel*  visualItems         READ visualItems                                NOTIFY visualItemsChanged)
    Q_PROPERTY(QmlObjectListModel*  waypointLines       READ waypointLines                              NOTIFY waypointLinesChanged)


    Q_INVOKABLE void addCoordinate(QGeoCoordinate coordinate);
    Q_INVOKABLE void clearCoordinate();
    Q_INVOKABLE double totalDistance();

    QmlObjectListModel* visualItems         (void) { return _visualItems; }
    QmlObjectListModel* waypointLines       (void) { return &_waypointLines; }

private:
    QmlObjectListModel* _visualItems;
    QmlObjectListModel  _waypointLines;
    CoordVectHashTable  _linesTable;

    void _recalcWaypointLines(void);

signals:
    void visualItemsChanged(void);
    void waypointLinesChanged(void);
};

#endif
           
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/


#include <QtAlgorithms>
#include "RallyPoint.h"
#include "GFMeasureController.h"
#include "MultiVehicleManager.h"
#include "MissionManager.h"
#include "CoordinateVector.h"
#include "FirmwarePlugin.h"
#include "QGCApplication.h"
#include "SimpleMissionItem.h"
#include "SurveyMissionItem.h"
#include "PlantProtectionMissionItem.h"
#include "JsonHelper.h"
#include "ParameterManager.h"
#include "QGroundControlQmlGlobal.h"
#include "ObstaclePolygon.h"
#include "QGCGeo.h"
#ifndef __mobile__
#include "MainWindow.h"
#include "QGCFileDialog.h"
#endif

GFMeasureController::GFMeasureController(QObject *parent)
    : QObject(parent)
    ,_visualItems(NULL)
{
    _visualItems = new QmlObjectListModel(this);
}

GFMeasureController::~GFMeasureController()
{

}

void GFMeasureController::addCoordinate(QGeoCoordinate coordinate)
{
    SimpleMissionItem * newItem = new SimpleMissionItem(NULL,this);
    newItem->setCoordinate(coordinate);
    _visualItems->append(newItem);
    emit visualItemsChanged();


    _recalcWaypointLines();
}

void GFMeasureController::clearCoordinate()
{
    if (_visualItems) {
        _visualItems->deleteListAndContents();
    }
    QmlObjectListModel* newVisualItems = new QmlObjectListModel(this);
    _visualItems = newVisualItems;
    _waypointLines.clear();

    emit visualItemsChanged();
    emit waypointLinesChanged();
}

double GFMeasureController::totalDistance()
{
    double distance = 0.0;
    if(_visualItems->count()>=0)
    {
        QGeoCoordinate item1 = qobject_cast<VisualMissionItem*>(_visualItems->get(0))->coordinate();
        for(int i=1;i<_visualItems->count();i++)
        {
            QGeoCoordinate item2 = qobject_cast<VisualMissionItem*>(_visualItems->get(i))->coordinate();
            distance+=item2.distanceTo(item1);
            item1=item2;
        }
    }
    QString distanceStr = QString::number(distance,'f',2);
    return distanceStr.toDouble();
}

void GFMeasureController::_recalcWaypointLines()
{
    VisualMissionItem*  lastCoordinateItem =    qobject_cast<VisualMissionItem*>(_visualItems->get(0));

    CoordVectHashTable old_table = _linesTable;
    _linesTable.clear();
    _waypointLines.clear();
    for(int i=0;i<_visualItems->count();i++)
    {
        VisualMissionItem* item = qobject_cast<VisualMissionItem*>(_visualItems->get(i));//第一點
        VisualItemPair pair(lastCoordinateItem, item);

        auto linevect       = new CoordinateVector( lastCoordinateItem->coordinate(),item->coordinate(), this);
        _linesTable[pair] = linevect;
        lastCoordinateItem = item;

    }
    QObjectList objs;
    objs.reserve(_linesTable.count());
    foreach(CoordinateVector *vect, _linesTable.values()) {
        objs.append(vect);
    }

    // We don't delete here because many links may still be valid
    _waypointLines.swapObjectList(objs);
    qDeleteAll(old_table);
    emit waypointLinesChanged();

}
           

(2),QML 顯示

//标尺
    GFMeasureController{
        id:measureController
    }



                //測距
                MapItemView {
                    id:measureCoordinateList
                    model: measureController.visualItems
                    delegate: measureComponent
                }
                Component {
                    id: measureComponent
                    MapQuickItem {
                        id:measureMapItem
                        anchorPoint:    Qt.point(sourceItem.width/2 , sourceItem.height / 2)
                        coordinate:     object.coordinate
                        visible:        true
                        sourceItem:Rectangle {
                            id:rect
                            width:          _width
                            height:         _width
                            radius:         _width / 2
                            border.width:    1
                            border.color:   "red"
                            color:          "white"

                            property real _width: ScreenTools.defaultFontPixelHeight * ScreenTools.smallFontPointRatio * 1

                        }
                        z:              QGroundControl.zOrderMapItems
                    }
                }

                //标簽
                MapItemView {
                    id:measureLabelMapItem
                    model: measureController.visualItems
                    delegate:   measureLabelComponent
                }
                Component {
                    id: measureLabelComponent

                    MapQuickItem {
                        id:measureLabelItem
                        anchorPoint:    Qt.point(-10 , 25)
                        coordinate:     object.coordinate
                        visible:        true

                        property int preIndex: measureController.visualItems.count>0?measureController.visualItems.indexOf(object)-1:-1
                        property int lastIndex: measureController.visualItems.count-1
                        property var preCoor: preIndex>=0?measureController.visualItems.get(preIndex).coordinate:null
                        property real distance:preIndex>=0?(object.coordinate.distanceTo(preCoor)):0
                        sourceItem: Rectangle {
                            border.width:    1
                            border.color:   "gray"
                            color:          "white"
                            radius: 2
                            width: lab.contentWidth+10
                            height: measureColumn.height+3
                            Column{
                                id:measureColumn
                                anchors.left: parent.left
                                anchors.right: parent.right
                                anchors.leftMargin: 5
                                anchors.rightMargin: 5
                                spacing:    ScreenTools.defaultFontPixelHeight
                                width: lab.contentWidth
                                height: lab.contentHeight
                                Text{
                                    id:lab
                                    text: preIndex==-1?qsTr("起點"):(preIndex== lastIndex-1&&!isMeasureDistance?qsTr("總長:")+measureController.totalDistance()+qsTr("米"):measureLabelItem.distance.toFixed(1)+qsTr(" 米"))
                                    horizontalAlignment:Text.AlignHCenter

                                }
                            }

                        }
                        z:   QGroundControl.zOrderMapItems
                    }
                }

                //連線
                MissionLineView {
                    model:       measureController.waypointLines
                }

                //結束點
                MapQuickItem {
                    id:measureExitItem
                    anchorPoint:    Qt.point(-10 , 5)
                    property int lastIndex: measureController.visualItems.count-1
                    property var lastCoor: lastIndex>=0?measureController.visualItems.get(lastIndex).coordinate:null
                    coordinate:     lastCoor
                    z:              QGroundControl.zOrderMapItems
                    visible:        lastIndex>=0&&!isMeasureDistance
                    sourceItem: Rectangle {
                        border.width:    2
                        border.color:   "red"
                        color:          "white"
                        radius: 1
                        width: measureExitColumn.width+10
                        height: measureExitColumn.height
                        Column{
                            id:measureExitColumn
                            anchors.left: parent.left
                            anchors.right: parent.right
                            anchors.leftMargin: 5
                            anchors.rightMargin: 5
                            width: labExit.contentWidth
                            height: labExit.contentHeight
                            Text{
                                id:labExit
                                text:"X"
                                color:"red"
                            }
                        }
                        QGCMouseArea {
                            fillItem:   parent
                            onClicked:
                            {
                                measureController.clearCoordinate()
                            }
                        }
                    }
                }

                //滑鼠移動點
                MapQuickItem {
                    id:measureMoveMapItem
                    visible:        true
                    coordinate :null
                    anchorPoint:    Qt.point(-10 , 5)
                    property real distance: 0
                    sourceItem:Rectangle {
                        id:rect
                        border.width:    1
                        border.color:   "red"
                        color:          "white"
                        width: measureColumn.width+6
                        height: measureColumn.height+3
                        Column{
                            id:measureColumn
                            anchors.left: parent.left
                            anchors.right: parent.right
                            anchors.leftMargin: 3
                            anchors.rightMargin: 3
                            width: lab2.contentWidth
                            height: lab.contentHeight+lab2.contentHeight+5
                            Text{
                                id:lab
                                text: measureMoveMapItem.distance.toFixed(1)+qsTr(" 米")
                                horizontalAlignment:Text.AlignHCenter
                                verticalAlignment:Text.verticalCenter
                            }
                            Text{
                                id:lab2
                                text: qsTr("單擊确定地點,輕按兩下結束")
                                horizontalAlignment:Text.AlignHCenter
                                verticalAlignment:Text.verticalCenter
                            }
                        }

                    }
                    z:              QGroundControl.zOrderMapItems
                }

                //移動線
                MapPolyline {
                    id:measureMoveLine
                    line.width: 2
                    line.color: 'orange'
                    path: [
                        measureMoveMapItem.coordinate,measureController.visualItems.get(measureController.visualItems.count-1).coordinate
                    ]
                }
           

QML 滑鼠事件

MouseArea {
                    anchors.fill:   parent
                    enabled:        true
                    hoverEnabled:true
                    cursorShape: isMeasureDistance?Qt.PointingHandCursor:Qt.ArrowCursor
                    onPositionChanged: {//測距
                        var coordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y))
                        if(isMeasureDistance)
                        {
                            measureMoveMapItem.coordinate=coordinate
                            measureMoveMapItem.visible=true
                            measureMoveLine.visible=true

                            var coor1 = measureController.visualItems.get(measureController.visualItems.count-1).coordinate
                            var distance = coordinate.distanceTo(coor1)
                            measureMoveMapItem.distance=distance
                        }else{
                            measureMoveMapItem.visible=false
                            measureMoveLine.visible=false
                        }
                    }
                    onClicked: {//測距
                        if(isMeasureDistance){
                            qgcView.mouseX = mouseX
                            qgcView.mouseY = mouseY
                            var clickCoordinate = editorMap.toCoordinate(Qt.point(mouse.x, mouse.y))
                            measureController.addCoordinate(clickCoordinate)
                        }
                    }