377 lines
13 KiB
QML
377 lines
13 KiB
QML
/****************************************************************************
|
|
*
|
|
* (c) 2009-2020 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
import QtQuick 2.11
|
|
import QtQuick.Controls 2.4
|
|
import QtLocation 5.3
|
|
import QtPositioning 5.3
|
|
import QtQuick.Dialogs 1.2
|
|
|
|
import QGroundControl 1.0
|
|
import QGroundControl.ScreenTools 1.0
|
|
import QGroundControl.Palette 1.0
|
|
import QGroundControl.Controls 1.0
|
|
import QGroundControl.FlightMap 1.0
|
|
import QGroundControl.ShapeFileHelper 1.0
|
|
|
|
/// QGCMapPolyline map visuals
|
|
Item {
|
|
id: _root
|
|
|
|
property var mapControl ///< Map control to place item in
|
|
property var mapPolyline ///< QGCMapPolyline object
|
|
property bool interactive: mapPolyline.interactive
|
|
property int lineWidth: 3
|
|
property color lineColor: "#be781c"
|
|
|
|
property var _dragHandlesComponent
|
|
property var _splitHandlesComponent
|
|
property string _instructionText: _corridorToolsText
|
|
property real _zorderDragHandle: QGroundControl.zOrderMapItems + 3 // Highest to prevent splitting when items overlap
|
|
property real _zorderSplitHandle: QGroundControl.zOrderMapItems + 2
|
|
property var _savedVertices: [ ]
|
|
|
|
readonly property string _corridorToolsText: qsTr("Polyline Tools")
|
|
readonly property string _traceText: qsTr("Click in the map to add vertices. Click 'Done Tracing' when finished.")
|
|
|
|
function _addCommonVisuals() {
|
|
if (_objMgrCommonVisuals.empty) {
|
|
_objMgrCommonVisuals.createObject(polylineComponent, mapControl, true)
|
|
}
|
|
}
|
|
|
|
function _addInteractiveVisuals() {
|
|
if (_objMgrInteractiveVisuals.empty) {
|
|
_objMgrInteractiveVisuals.createObjects([ dragHandlesComponent, splitHandlesComponent, toolbarComponent ], mapControl)
|
|
}
|
|
}
|
|
|
|
/// Calculate the default/initial polyline
|
|
function _defaultPolylineVertices() {
|
|
var x = mapControl.centerViewport.x + (mapControl.centerViewport.width / 2)
|
|
var yInset = mapControl.centerViewport.height / 4
|
|
var topPointCoord = mapControl.toCoordinate(Qt.point(x, mapControl.centerViewport.y + yInset), false /* clipToViewPort */)
|
|
var bottomPointCoord = mapControl.toCoordinate(Qt.point(x, mapControl.centerViewport.y + mapControl.centerViewport.height - yInset), false /* clipToViewPort */)
|
|
return [ topPointCoord, bottomPointCoord ]
|
|
}
|
|
|
|
/// Reset polyline back to initial default
|
|
function _resetPolyline() {
|
|
mapPolyline.beginReset()
|
|
mapPolyline.clear()
|
|
var initialVertices = _defaultPolylineVertices()
|
|
mapPolyline.appendVertex(initialVertices[0])
|
|
mapPolyline.appendVertex(initialVertices[1])
|
|
mapPolyline.endReset()
|
|
}
|
|
|
|
function _saveCurrentVertices() {
|
|
_savedVertices = [ ]
|
|
for (var i=0; i<mapPolyline.count; i++) {
|
|
_savedVertices.push(mapPolyline.vertexCoordinate(i))
|
|
}
|
|
}
|
|
|
|
function _restorePreviousVertices() {
|
|
mapPolyline.beginReset()
|
|
mapPolyline.clear()
|
|
for (var i=0; i<_savedVertices.length; i++) {
|
|
mapPolyline.appendVertex(_savedVertices[i])
|
|
}
|
|
mapPolyline.endReset()
|
|
}
|
|
|
|
onInteractiveChanged: {
|
|
if (interactive) {
|
|
_addInteractiveVisuals()
|
|
} else {
|
|
_objMgrInteractiveVisuals.destroyObjects()
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: mapPolyline
|
|
onTraceModeChanged: {
|
|
if (mapPolyline.traceMode) {
|
|
_instructionText = _traceText
|
|
_objMgrTraceVisuals.createObject(traceMouseAreaComponent, mapControl, false)
|
|
} else {
|
|
_instructionText = _corridorToolsText
|
|
_objMgrTraceVisuals.destroyObjects()
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
_addCommonVisuals()
|
|
if (interactive) {
|
|
_addInteractiveVisuals()
|
|
}
|
|
}
|
|
Component.onDestruction: mapPolyline.traceMode = false
|
|
|
|
QGCDynamicObjectManager { id: _objMgrCommonVisuals }
|
|
QGCDynamicObjectManager { id: _objMgrInteractiveVisuals }
|
|
QGCDynamicObjectManager { id: _objMgrTraceVisuals }
|
|
|
|
QGCPalette { id: qgcPal }
|
|
|
|
QGCFileDialog {
|
|
id: kmlLoadDialog
|
|
folder: QGroundControl.settingsManager.appSettings.missionSavePath
|
|
title: qsTr("Select KML File")
|
|
selectExisting: true
|
|
nameFilters: ShapeFileHelper.fileDialogKMLFilters
|
|
fileExtension: QGroundControl.settingsManager.appSettings.kmlFileExtension
|
|
|
|
onAcceptedForLoad: {
|
|
mapPolyline.loadKMLFile(file)
|
|
close()
|
|
}
|
|
}
|
|
|
|
QGCMenu {
|
|
id: menu
|
|
property int _removeVertexIndex
|
|
|
|
function popUpWithIndex(curIndex) {
|
|
_removeVertexIndex = curIndex
|
|
removeVertexItem.visible = mapPolyline.count > 2
|
|
menu.popup()
|
|
}
|
|
|
|
QGCMenuItem {
|
|
id: removeVertexItem
|
|
text: qsTr("Remove vertex" )
|
|
onTriggered: mapPolyline.removeVertex(menu._removeVertexIndex)
|
|
}
|
|
|
|
QGCMenuItem {
|
|
text: qsTr("Edit position..." )
|
|
onTriggered: mainWindow.showComponentDialog(editPositionDialog, qsTr("Edit Position"), mainWindow.showDialogDefaultWidth, StandardButton.Cancel)
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: editPositionDialog
|
|
|
|
EditPositionDialog {
|
|
Component.onCompleted: coordinate = mapPolyline.path[menu._removeVertexIndex]
|
|
onCoordinateChanged: mapPolyline.adjustVertex(menu._removeVertexIndex,coordinate)
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: polylineComponent
|
|
|
|
MapPolyline {
|
|
line.width: lineWidth
|
|
line.color: lineColor
|
|
path: mapPolyline.path
|
|
visible: _root.visible
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: splitHandleComponent
|
|
|
|
MapQuickItem {
|
|
id: mapQuickItem
|
|
anchorPoint.x: sourceItem.width / 2
|
|
anchorPoint.y: sourceItem.height / 2
|
|
z: _zorderSplitHandle
|
|
|
|
property int vertexIndex
|
|
|
|
sourceItem: SplitIndicator {
|
|
onClicked: mapPolyline.splitSegment(mapQuickItem.vertexIndex)
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: splitHandlesComponent
|
|
|
|
Repeater {
|
|
model: mapPolyline.path
|
|
|
|
delegate: Item {
|
|
property var _splitHandle
|
|
property var _vertices: mapPolyline.path
|
|
|
|
function _setHandlePosition() {
|
|
var nextIndex = index + 1
|
|
var distance = _vertices[index].distanceTo(_vertices[nextIndex])
|
|
var azimuth = _vertices[index].azimuthTo(_vertices[nextIndex])
|
|
_splitHandle.coordinate = _vertices[index].atDistanceAndAzimuth(distance / 2, azimuth)
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
if (index + 1 <= _vertices.length - 1) {
|
|
_splitHandle = splitHandleComponent.createObject(mapControl)
|
|
_splitHandle.vertexIndex = index
|
|
_setHandlePosition()
|
|
mapControl.addMapItem(_splitHandle)
|
|
}
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
if (_splitHandle) {
|
|
_splitHandle.destroy()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Control which is used to drag polygon vertices
|
|
Component {
|
|
id: dragAreaComponent
|
|
|
|
MissionItemIndicatorDrag {
|
|
mapControl: _root.mapControl
|
|
id: dragArea
|
|
z: _zorderDragHandle
|
|
|
|
property int polylineVertex
|
|
|
|
property bool _creationComplete: false
|
|
|
|
Component.onCompleted: _creationComplete = true
|
|
|
|
onItemCoordinateChanged: {
|
|
if (_creationComplete) {
|
|
// During component creation some bad coordinate values got through which screws up draw
|
|
mapPolyline.adjustVertex(polylineVertex, itemCoordinate)
|
|
}
|
|
}
|
|
|
|
onClicked: {
|
|
menu.popUpWithIndex(polylineVertex)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: dragHandleComponent
|
|
|
|
MapQuickItem {
|
|
id: mapQuickItem
|
|
anchorPoint.x: dragHandle.width / 2
|
|
anchorPoint.y: dragHandle.height / 2
|
|
z: _zorderDragHandle
|
|
|
|
property int polylineVertex
|
|
|
|
sourceItem: Rectangle {
|
|
id: dragHandle
|
|
width: ScreenTools.defaultFontPixelHeight * 1.5
|
|
height: width
|
|
radius: width * 0.5
|
|
color: Qt.rgba(1,1,1,0.8)
|
|
border.color: Qt.rgba(0,0,0,0.25)
|
|
border.width: 1
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add all polygon vertex drag handles to the map
|
|
Component {
|
|
id: dragHandlesComponent
|
|
|
|
Repeater {
|
|
model: mapPolyline.pathModel
|
|
|
|
delegate: Item {
|
|
property var _visuals: [ ]
|
|
|
|
Component.onCompleted: {
|
|
var dragHandle = dragHandleComponent.createObject(mapControl)
|
|
dragHandle.coordinate = Qt.binding(function() { return object.coordinate })
|
|
dragHandle.polylineVertex = Qt.binding(function() { return index })
|
|
mapControl.addMapItem(dragHandle)
|
|
var dragArea = dragAreaComponent.createObject(mapControl, { "itemIndicator": dragHandle, "itemCoordinate": object.coordinate })
|
|
dragArea.polylineVertex = Qt.binding(function() { return index })
|
|
_visuals.push(dragHandle)
|
|
_visuals.push(dragArea)
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
for (var i=0; i<_visuals.length; i++) {
|
|
_visuals[i].destroy()
|
|
}
|
|
_visuals = [ ]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: toolbarComponent
|
|
|
|
PlanEditToolbar {
|
|
anchors.horizontalCenter: mapControl.left
|
|
anchors.horizontalCenterOffset: mapControl.centerViewport.left + (mapControl.centerViewport.width / 2)
|
|
y: mapControl.centerViewport.top
|
|
z: QGroundControl.zOrderMapItems + 2
|
|
availableWidth: mapControl.centerViewport.width
|
|
|
|
QGCButton {
|
|
_horizontalPadding: 0
|
|
text: qsTr("Basic")
|
|
visible: !mapPolyline.traceMode
|
|
onClicked: _resetPolyline()
|
|
}
|
|
|
|
QGCButton {
|
|
_horizontalPadding: 0
|
|
text: mapPolyline.traceMode ? qsTr("Done Tracing") : qsTr("Trace")
|
|
onClicked: {
|
|
if (mapPolyline.traceMode) {
|
|
if (mapPolyline.count < 2) {
|
|
_restorePreviousVertices()
|
|
}
|
|
mapPolyline.traceMode = false
|
|
} else {
|
|
_saveCurrentVertices()
|
|
mapPolyline.traceMode = true
|
|
mapPolyline.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
QGCButton {
|
|
_horizontalPadding: 0
|
|
text: qsTr("Load KML...")
|
|
onClicked: kmlLoadDialog.openForLoad()
|
|
visible: !mapPolyline.traceMode
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mouse area to capture clicks for tracing a polyline
|
|
Component {
|
|
id: traceMouseAreaComponent
|
|
|
|
MouseArea {
|
|
anchors.fill: mapControl
|
|
preventStealing: true
|
|
z: QGroundControl.zOrderMapItems + 1 // Over item indicators
|
|
|
|
onClicked: {
|
|
if (mouse.button === Qt.LeftButton) {
|
|
mapPolyline.appendVertex(mapControl.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|