一,參照百度地圖,在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)
}
}