From fb486d9cc432959d2e7867802ccaad438175a1cc Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Thu, 2 Mar 2017 16:40:17 -0800 Subject: [PATCH] Convert polygon editing to dynamic objects --- qgroundcontrol.qrc | 2 + src/FlightMap/FlightMap.qml | 288 ---------------- .../MapItems/MissionItemIndicatorDrag.qml | 63 ++++ src/FlightMap/MapItems/PolygonEditor.qml | 307 ++++++++++++++++++ src/FlightMap/qmldir | 10 +- .../FWLandingPatternMapVisual.qml | 67 ++-- src/MissionEditor/MissionEditor.qml | 2 +- src/MissionEditor/SimpleItemMapVisual.qml | 41 +-- src/MissionEditor/SurveyItemEditor.qml | 29 +- 9 files changed, 422 insertions(+), 387 deletions(-) create mode 100644 src/FlightMap/MapItems/MissionItemIndicatorDrag.qml create mode 100644 src/FlightMap/MapItems/PolygonEditor.qml diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index a2ea31659..2869e0398 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -133,8 +133,10 @@ src/FlightMap/Widgets/InstrumentSwipeView.qml src/FlightMap/MapScale.qml src/FlightMap/MapItems/MissionItemIndicator.qml + src/FlightMap/MapItems/MissionItemIndicatorDrag.qml src/FlightMap/MapItems/MissionItemView.qml src/FlightMap/MapItems/MissionLineView.qml + src/FlightMap/MapItems/PolygonEditor.qml src/FlightMap/Widgets/QGCArtificialHorizon.qml src/FlightMap/Widgets/QGCAttitudeHUD.qml src/FlightMap/Widgets/QGCAttitudeWidget.qml diff --git a/src/FlightMap/FlightMap.qml b/src/FlightMap/FlightMap.qml index 75a5b2a37..894d1dde1 100644 --- a/src/FlightMap/FlightMap.qml +++ b/src/FlightMap/FlightMap.qml @@ -137,292 +137,4 @@ Map { label: "Q" } } - - //---- Polygon drawing code - - // - // Usage: - // - // Connections { - // target: map.polygonDraw - // - // onPolygonCaptureStarted: { - // // Polygon creation has started - // } - // - // onPolygonCaptureFinished: { - // // Polygon capture complete, coordinates signal variable contains the polygon points - // } - // } - // - // map.polygonDraqw.startPolgyon() - begin capturing a new polygon - // map.polygonDraqw.endPolygon() - end capture (right-click will also end capture) - - // Not sure why this is needed, but trying to reference polygonDrawer directly from other code doesn't work - property alias polygonDraw: polygonDrawer - - QGCMapLabel { - id: polygonHelp - anchors.topMargin: parent.height - ScreenTools.availableHeight - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - horizontalAlignment: Text.AlignHCenter - map: _map - text: qsTr("Click to add point %1").arg(ScreenTools.isMobile || !polygonDrawer.polygonReady ? "" : qsTr("- Right Click to end polygon")) - visible: polygonDrawer.drawingPolygon - - Connections { - target: polygonDrawer - - onDrawingPolygonChanged: { - if (polygonDrawer.drawingPolygon) { - polygonHelp.text = qsTr("Click to add point") - } - polygonHelp.visible = polygonDrawer.drawingPolygon - } - - onPolygonReadyChanged: { - if (polygonDrawer.polygonReady && !ScreenTools.isMobile) { - polygonHelp.text = qsTr("Click to add point - Right Click to end polygon") - } - } - - onAdjustingPolygonChanged: { - if (polygonDrawer.adjustingPolygon) { - polygonHelp.text = qsTr("Adjust polygon by dragging corners") - } - polygonHelp.visible = polygonDrawer.adjustingPolygon - } - } - } - - MouseArea { - id: polygonDrawer - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - visible: drawingPolygon - z: 1000 // Hack to fix MouseArea layering for now - - property alias drawingPolygon: polygonDrawer.hoverEnabled - property bool adjustingPolygon: false - property bool polygonReady: polygonDrawerPolygonSet.path.length > 2 ///< true: enough points have been captured to create a closed polygon - property bool justClicked: false - - property var _callbackObject - - property var _vertexDragList: [] - - /// Begin capturing a new polygon - /// polygonCaptureStarted will be signalled - function startCapturePolygon(callback) { - polygonDrawer._callbackObject = callback - polygonDrawer.drawingPolygon = true - polygonDrawer._clearPolygon() - polygonDrawer._callbackObject.polygonCaptureStarted() - } - - /// Finish capturing the polygon - /// polygonCaptureFinished will be signalled - /// @return true: polygon completed, false: not enough points to complete polygon - function finishCapturePolygon() { - if (!polygonDrawer.polygonReady) { - return false - } - - var polygonPath = polygonDrawerPolygonSet.path - _cancelCapturePolygon() - polygonDrawer._callbackObject.polygonCaptureFinished(polygonPath) - return true - } - - function startAdjustPolygon(callback, vertexCoordinates) { - polygonDraw._callbackObject = callback - polygonDrawer.adjustingPolygon = true - for (var i=0; i 2) { - // Make sure the new line doesn't intersect the existing polygon - var lastSegment = polygonDrawerPolygon.path.length - 2 - var newLineA = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment], false /* clipToViewPort */) - var newLineB = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment+1], false /* clipToViewPort */) - for (var i=0; i 2 - } - MapPolygon { - id: polygonDrawerPolygonSet - color: 'green' - opacity: 0.5 - visible: polygonDrawer.polygonReady - } - - /// Next line for polygon - MapPolyline { - id: polygonDrawerNextPoint - line.color: "green" - line.width: 3 - visible: polygonDrawer.drawingPolygon - } - - //---- End Polygon Drawing code } // Map diff --git a/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml b/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml new file mode 100644 index 000000000..345f78f94 --- /dev/null +++ b/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml @@ -0,0 +1,63 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick 2.4 +import QtLocation 5.3 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Controls 1.0 + +/// Use the drag a MissionItemIndicator +Rectangle { + id: itemDragger + x: itemIndicator.x - _expandMargin + y: itemIndicator.y - _expandMargin + width: itemIndicator.width + (_expandMargin * 2) + height: itemIndicator.height + (_expandMargin * 2) + color: "transparent" + z: QGroundControl.zOrderMapItems + 1 // Above item icons + + // These are handy for debugging so left in for now + //border.width: 1 + //border.color: "white" + + // Properties which must be specific by consumer + property var itemIndicator ///< The mission item indicator to drag around + property var itemCoordinate ///< Coordinate we are updating during drag + + property bool _preventCoordinateBindingLoop: false + property real _expandMargin: ScreenTools.isMobile ? ScreenTools.defaultFontPixelWidth : 0 + + onXChanged: liveDrag() + onYChanged: liveDrag() + + function liveDrag() { + if (!itemDragger._preventCoordinateBindingLoop && Drag.active) { + var point = Qt.point(itemDragger.x + _expandMargin + itemIndicator.anchorPoint.x, itemDragger.y + _expandMargin + itemIndicator.anchorPoint.y) + var coordinate = map.toCoordinate(point) + itemDragger._preventCoordinateBindingLoop = true + coordinate.altitude = itemCoordinate.altitude + itemCoordinate = coordinate + itemDragger._preventCoordinateBindingLoop = false + } + } + + Drag.active: itemDrag.drag.active + + MouseArea { + id: itemDrag + anchors.fill: parent + drag.target: parent + drag.minimumX: 0 + drag.minimumY: 0 + drag.maximumX: itemDragger.parent.width - parent.width + drag.maximumY: itemDragger.parent.height - parent.height + } +} diff --git a/src/FlightMap/MapItems/PolygonEditor.qml b/src/FlightMap/MapItems/PolygonEditor.qml new file mode 100644 index 000000000..15fa0d20d --- /dev/null +++ b/src/FlightMap/MapItems/PolygonEditor.qml @@ -0,0 +1,307 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick 2.4 +import QtLocation 5.3 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Controls 1.0 + + +/// Polygon drawing item. Add to your control and call methods to get support for polygon drawing and adjustment. +Item { + id: _root + + // These properties must be provided by the consumer + property var map ///< Map control + property var callbackObject ///< Callback item + + // These properties can be queried by the consumer + property bool drawingPolygon: false + property bool adjustingPolygon: false + property bool polygonReady: _currentPolygon ? _currentPolygon.path.length > 2 : false ///< true: enough points have been captured to create a closed polygon + + property var _helpLabel ///< Dynamically added help label component + property var _newPolygon ///< Dynamically added polygon which represents all polygon points including the one currently being drawn + property var _currentPolygon ///< Dynamically added polygon which represents the currently completed polygon + property var _nextPointLine ///< Dynamically added line which goes from last polygon point to the new one being drawn + property var _mouseArea ///< Dynamically added MouseArea which handles all clicking and mouse movement + property var _vertexDragList: [ ] ///< Dynamically added vertex drag points + + /// Begin capturing a new polygon + /// polygonCaptureStarted will be signalled through callbackObject + function startCapturePolygon() { + _helpLabel = helpLabelComponent.createObject (map) + _newPolygon = newPolygonComponent.createObject (map) + _currentPolygon = currentPolygonComponent.createObject(map) + _nextPointLine = nextPointComponent.createObject (map) + _mouseArea = mouseAreaComponent.createObject (map) + + map.addMapItem(_newPolygon) + map.addMapItem(_currentPolygon) + map.addMapItem(_nextPointLine) + + drawingPolygon = true + callbackObject.polygonCaptureStarted() + } + + /// Finish capturing the polygon + /// polygonCaptureFinished will be signalled through callbackObject + /// @return true: polygon completed, false: not enough points to complete polygon + function finishCapturePolygon() { + if (!polygonReady) { + return false + } + var polygonPath = _currentPolygon.path + _cancelCapturePolygon() + callbackObject.polygonCaptureFinished(polygonPath) + return true + } + + function startAdjustPolygon(vertexCoordinates) { + adjustingPolygon = true + for (var i=0; i 2) { + // Make sure the new line doesn't intersect the existing polygon + var lastSegment = _newPolygon.path.length - 2 + var newLineA = map.fromCoordinate(_newPolygon.path[lastSegment], false /* clipToViewPort */) + var newLineB = map.fromCoordinate(_newPolygon.path[lastSegment+1], false /* clipToViewPort */) + for (var i=0; i 2 + } + } + + /// Current complete polygon + Component { + id: currentPolygonComponent + + MapPolygon { + color: 'green' + opacity: 0.5 + visible: polygonReady + } + } + + /// Next line for polygon + Component { + id: nextPointComponent + + MapPolyline { + line.color: "green" + line.width: 3 + } + } +} diff --git a/src/FlightMap/qmldir b/src/FlightMap/qmldir index 8d6f8eded..e91e94d50 100644 --- a/src/FlightMap/qmldir +++ b/src/FlightMap/qmldir @@ -22,10 +22,12 @@ VehicleHealthWidget 1.0 VehicleHealthWidget.qml VibrationWidget 1.0 VibrationWidget.qml # Map items -MissionItemIndicator 1.0 MissionItemIndicator.qml -MissionItemView 1.0 MissionItemView.qml -MissionLineView 1.0 MissionLineView.qml -VehicleMapItem 1.0 VehicleMapItem.qml +MissionItemIndicator 1.0 MissionItemIndicator.qml +MissionItemIndicatorDrag 1.0 MissionItemIndicatorDrag.qml +MissionItemView 1.0 MissionItemView.qml +MissionLineView 1.0 MissionLineView.qml +PolygonEditor 1.0 PolygonEditor.qml +VehicleMapItem 1.0 VehicleMapItem.qml # Editor controls QGCMapPolygonControls 1.0 QGCMapPolygonControls.qml diff --git a/src/MissionEditor/FWLandingPatternMapVisual.qml b/src/MissionEditor/FWLandingPatternMapVisual.qml index 179fba959..81fd35e7f 100644 --- a/src/MissionEditor/FWLandingPatternMapVisual.qml +++ b/src/MissionEditor/FWLandingPatternMapVisual.qml @@ -16,6 +16,7 @@ import QGroundControl 1.0 import QGroundControl.ScreenTools 1.0 import QGroundControl.Palette 1.0 import QGroundControl.Controls 1.0 +import QGroundControl.FlightMap 1.0 /// Fixed Wing Landing Pattern map visuals Item { @@ -78,8 +79,8 @@ Item { function showDragAreas() { if (_dragAreas.length === 0) { - _dragAreas.push(dragAreaComponent.createObject(map, { "dragLoiter": true })) - _dragAreas.push(dragAreaComponent.createObject(map, { "dragLoiter": false })) + _dragAreas.push(loiterDragAreaComponent.createObject(map)) + _dragAreas.push(landDragAreaComponent.createObject(map)) } } @@ -145,53 +146,27 @@ Item { } } - // Control which is used to drag items + // Control which is used to drag the loiter point Component { - id: dragAreaComponent - - Rectangle { - id: itemDragger - x: mapQuickItem.x - y: mapQuickItem.y - width: mapQuickItem.width - height: mapQuickItem.height - color: "transparent" - z: QGroundControl.zOrderMapItems + 1 // Above item icons - - property bool dragLoiter - property var mapQuickItem: dragLoiter ? _itemVisuals[_loiterPointIndex] : _itemVisuals[_landPointIndex] - property bool _preventCoordinateBindingLoop: false - - onXChanged: liveDrag() - onYChanged: liveDrag() - - function liveDrag() { - if (!itemDragger._preventCoordinateBindingLoop && Drag.active) { - var point = Qt.point(itemDragger.x + mapQuickItem.anchorPoint.x, itemDragger.y + mapQuickItem.anchorPoint.y) - var coordinate = map.toCoordinate(point) - itemDragger._preventCoordinateBindingLoop = true - if (dragLoiter) { - coordinate.altitude = _missionItem.loiterCoordinate.altitude - _missionItem.loiterCoordinate = coordinate - } else { - coordinate.altitude = _missionItem.landingCoordinate.altitude - _missionItem.landingCoordinate = coordinate - } - itemDragger._preventCoordinateBindingLoop = false - } - } + id: loiterDragAreaComponent - Drag.active: itemDrag.drag.active + MissionItemIndicatorDrag { + itemIndicator: _itemVisuals[_loiterPointIndex] + itemCoordinate: _missionItem.loiterCoordinate - MouseArea { - id: itemDrag - anchors.fill: parent - drag.target: parent - drag.minimumX: 0 - drag.minimumY: 0 - drag.maximumX: itemDragger.parent.width - parent.width - drag.maximumY: itemDragger.parent.height - parent.height - } + onItemCoordinateChanged: _missionItem.loiterCoordinate = itemCoordinate + } + } + + // Control which is used to drag the loiter point + Component { + id: landDragAreaComponent + + MissionItemIndicatorDrag { + itemIndicator: _itemVisuals[_landPointIndex] + itemCoordinate: _missionItem.landingCoordinate + + onItemCoordinateChanged: _missionItem.landingCoordinate = itemCoordinate } } diff --git a/src/MissionEditor/MissionEditor.qml b/src/MissionEditor/MissionEditor.qml index bc05d7d22..7f3c76417 100644 --- a/src/MissionEditor/MissionEditor.qml +++ b/src/MissionEditor/MissionEditor.qml @@ -254,7 +254,7 @@ QGCView { function setCurrentItem(sequenceNumber) { if (sequenceNumber !== _currentMissionIndex) { - editorMap.polygonDraw.cancelPolygonEdit() + //editorMap.polygonDraw.cancelPolygonEdit() _currentMissionItem = undefined _currentMissionIndex = -1 for (var i=0; i<_visualItems.count; i++) { diff --git a/src/MissionEditor/SimpleItemMapVisual.qml b/src/MissionEditor/SimpleItemMapVisual.qml index a03601b4c..7146ecc0d 100644 --- a/src/MissionEditor/SimpleItemMapVisual.qml +++ b/src/MissionEditor/SimpleItemMapVisual.qml @@ -80,44 +80,11 @@ Item { Component { id: dragAreaComponent - Rectangle { - id: itemDragger - x: _itemVisual.x - _expandMargin - y: _itemVisual.y - _expandMargin - width: _itemVisual.width + (_expandMargin * 2) - height: _itemVisual.height + (_expandMargin * 2) - color: "transparent" - z: QGroundControl.zOrderMapItems + 1 // Above item icons - - property bool dragLoiter - property bool _preventCoordinateBindingLoop: false - property real _expandMargin: ScreenTools.isMobile ? ScreenTools.defaultFontPixelWidth : 0 - - onXChanged: liveDrag() - onYChanged: liveDrag() - - function liveDrag() { - if (!itemDragger._preventCoordinateBindingLoop && Drag.active) { - var point = Qt.point(itemDragger.x + _expandMargin + _itemVisual.anchorPoint.x, itemDragger.y + _expandMargin + _itemVisual.anchorPoint.y) - var coordinate = map.toCoordinate(point) - itemDragger._preventCoordinateBindingLoop = true - coordinate.altitude = _missionItem.coordinate.altitude - _missionItem.coordinate = coordinate - itemDragger._preventCoordinateBindingLoop = false - } - } + MissionItemIndicatorDrag { + itemIndicator: _itemVisual + itemCoordinate: _missionItem.coordinate - Drag.active: itemDrag.drag.active - - MouseArea { - id: itemDrag - anchors.fill: parent - drag.target: parent - drag.minimumX: 0 - drag.minimumY: 0 - drag.maximumX: itemDragger.parent.width - parent.width - drag.maximumY: itemDragger.parent.height - parent.height - } + onItemCoordinateChanged: _missionItem.coordinate = itemCoordinate } } diff --git a/src/MissionEditor/SurveyItemEditor.qml b/src/MissionEditor/SurveyItemEditor.qml index 75f952aca..0117c4221 100644 --- a/src/MissionEditor/SurveyItemEditor.qml +++ b/src/MissionEditor/SurveyItemEditor.qml @@ -9,6 +9,7 @@ import QGroundControl.Vehicle 1.0 import QGroundControl.Controls 1.0 import QGroundControl.FactControls 1.0 import QGroundControl.Palette 1.0 +import QGroundControl.FlightMap 1.0 // Editor for Survery mission items Rectangle { @@ -593,29 +594,29 @@ Rectangle { QGCButton { width: _root.width * 0.45 - text: editorMap.polygonDraw.drawingPolygon ? qsTr("Finish Draw") : qsTr("Draw") - visible: !editorMap.polygonDraw.adjustingPolygon - enabled: ((editorMap.polygonDraw.drawingPolygon && editorMap.polygonDraw.polygonReady) || !editorMap.polygonDraw.drawingPolygon) + text: polygonEditor.drawingPolygon ? qsTr("Finish Draw") : qsTr("Draw") + visible: !polygonEditor .adjustingPolygon + enabled: ((polygonEditor.drawingPolygon && polygonEditor.polygonReady) || !polygonEditor.drawingPolygon) onClicked: { - if (editorMap.polygonDraw.drawingPolygon) { - editorMap.polygonDraw.finishCapturePolygon() + if (polygonEditor.drawingPolygon) { + polygonEditor.finishCapturePolygon() } else { - editorMap.polygonDraw.startCapturePolygon(_root) + polygonEditor.startCapturePolygon() } } } QGCButton { width: _root.width * 0.4 - text: editorMap.polygonDraw.adjustingPolygon ? qsTr("Finish Adjust") : qsTr("Adjust") - visible: missionItem.polygonPath.length > 0 && !editorMap.polygonDraw.drawingPolygon + text: polygonEditor.adjustingPolygon ? qsTr("Finish Adjust") : qsTr("Adjust") + visible: missionItem.polygonPath.length > 0 && !polygonEditor.drawingPolygon onClicked: { - if (editorMap.polygonDraw.adjustingPolygon) { - editorMap.polygonDraw.finishAdjustPolygon() + if (polygonEditor.adjustingPolygon) { + polygonEditor.finishAdjustPolygon() } else { - editorMap.polygonDraw.startAdjustPolygon(_root, missionItem.polygonPath) + polygonEditor.startAdjustPolygon(missionItem.polygonPath) } } } @@ -652,4 +653,10 @@ Rectangle { } } } + + PolygonEditor { + id: polygonEditor + map: editorMap + callbackObject: parent + } } -- 2.22.0