diff --git a/ChangeLog.md b/ChangeLog.md
index 91b287b92efed2288fe62a7b693f61552078f4ef..9933569615e73cb9caab3b580e1a65b4a03dc259 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -6,6 +6,7 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build
+* New Polygon editing tools ui. Includes ability to trace polygon by clicking.
* ArduCopter/Rover: Follow Me setup page
* More performant flight path display algorithm. Mobile builds no longer show limited path length.
* ArduCopter/Rover: Add support for Follow Me
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 566974b776b91b5df5a93dd536f406cb4a1519b3..9972edaea638801cdb4d1fc00ff242ad6cc9ef0c 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -85,6 +85,7 @@
src/QmlControls/HeightIndicator.qml
src/QmlControls/IndicatorButton.qml
src/QmlControls/JoystickThumbPad.qml
+ src/QmlControls/KMLOrSHPFileDialog.qml
src/QmlControls/LogReplayStatusBar.qml
src/QmlControls/MainWindowSavedState.qml
src/QmlControls/MAVLinkMessageButton.qml
diff --git a/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml b/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml
index bcdef05afc84f15c26260d9f42dc984fbb1855f4..1b91c6af1935439149ae00b5670e5dbc9295c008 100644
--- a/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml
+++ b/src/FlightMap/MapItems/MissionItemIndicatorDrag.qml
@@ -23,6 +23,7 @@ Rectangle {
height: _itemIndicatorHeight + (_touchMarginVertical * 2)
color: "transparent"
z: QGroundControl.zOrderMapItems + 1 // Above item icons
+ visible: itemCoordinate.isValid
// Properties which must be specific by consumer
property var mapControl ///< Map control which contains this item
diff --git a/src/FlightMap/MapItems/MissionLineView.qml b/src/FlightMap/MapItems/MissionLineView.qml
index 4f9fe11d68a6b4813530050cbbc38066eae12b73..0d98659036c4b40a84f93a77d1cb615593123ed4 100644
--- a/src/FlightMap/MapItems/MissionLineView.qml
+++ b/src/FlightMap/MapItems/MissionLineView.qml
@@ -24,6 +24,6 @@ MapItemView {
line.color: "#be781c" // Hack, can't get palette to work in here
z: QGroundControl.zOrderWaypointLines
- path: object ? [ object.coordinate1, object.coordinate2 ] : [ ]
+ path: object && object.coordinate1.isValid && object.coordinate2.isValid ? [ object.coordinate1, object.coordinate2 ] : []
}
}
diff --git a/src/MissionManager/QGCMapPolygon.cc b/src/MissionManager/QGCMapPolygon.cc
index d3111ac123ba9e758a532a5267865319b10cca15..f1ec6cafc835964a990b054eb4bbe859531b6859 100644
--- a/src/MissionManager/QGCMapPolygon.cc
+++ b/src/MissionManager/QGCMapPolygon.cc
@@ -29,6 +29,7 @@ QGCMapPolygon::QGCMapPolygon(QObject* parent)
, _centerDrag (false)
, _ignoreCenterUpdates (false)
, _interactive (false)
+ , _resetActive (false)
{
_init();
}
@@ -39,6 +40,7 @@ QGCMapPolygon::QGCMapPolygon(const QGCMapPolygon& other, QObject* parent)
, _centerDrag (false)
, _ignoreCenterUpdates (false)
, _interactive (false)
+ , _resetActive (false)
{
*this = other;
@@ -265,11 +267,14 @@ void QGCMapPolygon::appendVertices(const QList& coordinates)
{
QList objects;
+ _beginResetIfNotActive();
for (const QGeoCoordinate& coordinate: coordinates) {
objects.append(new QGCQGeoCoordinate(coordinate, this));
_polygonPath.append(QVariant::fromValue(coordinate));
}
_polygonModel.append(objects);
+ _endResetIfNotActive();
+
emit pathChanged();
}
@@ -448,8 +453,10 @@ void QGCMapPolygon::offset(double distance)
}
// Update internals
+ _beginResetIfNotActive();
clear();
appendVertices(rgNewPolygon);
+ _endResetIfNotActive();
}
bool QGCMapPolygon::loadKMLOrSHPFile(const QString& file)
@@ -461,8 +468,10 @@ bool QGCMapPolygon::loadKMLOrSHPFile(const QString& file)
return false;
}
+ _beginResetIfNotActive();
clear();
appendVertices(rgCoords);
+ _endResetIfNotActive();
return true;
}
@@ -509,7 +518,37 @@ void QGCMapPolygon::verifyClockwiseWinding(void)
rgReversed.prepend(varCoord.value());
}
+ _beginResetIfNotActive();
clear();
appendVertices(rgReversed);
+ _endResetIfNotActive();
+ }
+}
+
+void QGCMapPolygon::beginReset(void)
+{
+ _resetActive = true;
+ _polygonModel.beginReset();
+}
+
+void QGCMapPolygon::endReset(void)
+{
+ _resetActive = false;
+ _polygonModel.endReset();
+ emit pathChanged();
+ emit centerChanged(_center);
+}
+
+void QGCMapPolygon::_beginResetIfNotActive(void)
+{
+ if (!_resetActive) {
+ beginReset();
+ }
+}
+
+void QGCMapPolygon::_endResetIfNotActive(void)
+{
+ if (!_resetActive) {
+ endReset();
}
}
diff --git a/src/MissionManager/QGCMapPolygon.h b/src/MissionManager/QGCMapPolygon.h
index d112a58d2ef0f86c35ae55783a33a0d1d7a54023..4a023eb4a6ae0d8666abf8ee392a7fd4f5894581 100644
--- a/src/MissionManager/QGCMapPolygon.h
+++ b/src/MissionManager/QGCMapPolygon.h
@@ -36,6 +36,8 @@ public:
Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
Q_PROPERTY(bool centerDrag READ centerDrag WRITE setCenterDrag NOTIFY centerDragChanged)
Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged)
+ Q_PROPERTY(bool isValid READ isValid NOTIFY countChanged)
+ Q_PROPERTY(bool empty READ empty NOTIFY countChanged)
Q_INVOKABLE void clear(void);
Q_INVOKABLE void appendVertex(const QGeoCoordinate& coordinate);
@@ -69,6 +71,9 @@ public:
/// Adjust polygon winding order to be clockwise (if needed)
Q_INVOKABLE void verifyClockwiseWinding(void);
+ Q_INVOKABLE void beginReset (void);
+ Q_INVOKABLE void endReset (void);
+
/// Saves the polygon to the json object.
/// @param json Json object to save to
void saveToJson(QJsonObject& json);
@@ -94,6 +99,8 @@ public:
QGeoCoordinate center (void) const { return _center; }
bool centerDrag (void) const { return _centerDrag; }
bool interactive (void) const { return _interactive; }
+ bool isValid (void) const { return _polygonModel.count() >= 3; }
+ bool empty (void) const { return _polygonModel.count() == 0; }
QVariantList path (void) const { return _polygonPath; }
QmlObjectListModel* qmlPathModel(void) { return &_polygonModel; }
@@ -122,10 +129,12 @@ private slots:
void _updateCenter(void);
private:
- void _init(void);
- QPolygonF _toPolygonF(void) const;
- QGeoCoordinate _coordFromPointF(const QPointF& point) const;
- QPointF _pointFFromCoord(const QGeoCoordinate& coordinate) const;
+ void _init (void);
+ QPolygonF _toPolygonF (void) const;
+ QGeoCoordinate _coordFromPointF (const QPointF& point) const;
+ QPointF _pointFFromCoord (const QGeoCoordinate& coordinate) const;
+ void _beginResetIfNotActive (void);
+ void _endResetIfNotActive (void);
QVariantList _polygonPath;
QmlObjectListModel _polygonModel;
@@ -134,6 +143,7 @@ private:
bool _centerDrag;
bool _ignoreCenterUpdates;
bool _interactive;
+ bool _resetActive;
};
#endif
diff --git a/src/MissionManager/QGCMapPolygonVisuals.qml b/src/MissionManager/QGCMapPolygonVisuals.qml
index 898d146fceaabf23152b7a7bd4fe652018408a22..3841bec8a2ed78e7ef8b63753b5f2194bdb14ec8 100644
--- a/src/MissionManager/QGCMapPolygonVisuals.qml
+++ b/src/MissionManager/QGCMapPolygonVisuals.qml
@@ -7,11 +7,12 @@
*
****************************************************************************/
-import QtQuick 2.11
-import QtQuick.Controls 2.4
-import QtLocation 5.3
-import QtPositioning 5.3
-import QtQuick.Dialogs 1.2
+import QtQuick 2.11
+import QtQuick.Controls 2.4
+import QtLocation 5.3
+import QtPositioning 5.3
+import QtQuick.Dialogs 1.2
+import QtQuick.Layouts 1.11
import QGroundControl 1.0
import QGroundControl.ScreenTools 1.0
@@ -32,64 +33,74 @@ Item {
property int borderWidth: 0
property color borderColor: "black"
- property var _polygonComponent
- property var _dragHandlesComponent
- property var _splitHandlesComponent
- property var _centerDragHandleComponent
- property bool _circle: false
+ property bool _circleMode: false
property real _circleRadius
+ property bool _circleRadiusDrag: false
+ property var _circleRadiusDragCoord: QtPositioning.coordinate()
property bool _editCircleRadius: false
+ property bool _traceMode: false
+ property string _instructionText: _polygonToolsText
+ property var _savedVertices: [ ]
+ property bool _savedCircleMode
property real _zorderDragHandle: QGroundControl.zOrderMapItems + 3 // Highest to prevent splitting when items overlap
property real _zorderSplitHandle: QGroundControl.zOrderMapItems + 2
property real _zorderCenterHandle: QGroundControl.zOrderMapItems + 1 // Lowest such that drag or split takes precedence
- function addVisuals() {
- _polygonComponent = polygonComponent.createObject(mapControl)
- mapControl.addMapItem(_polygonComponent)
+ readonly property string _polygonToolsText: qsTr("Polygon 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(polygonComponent, mapControl, true)
+ }
}
- function removeVisuals() {
- _polygonComponent.destroy()
+ function removeCommonVisuals() {
+ _objMgrCommonVisuals.destroyObjects()
}
- function addHandles() {
- if (!_dragHandlesComponent) {
- _dragHandlesComponent = dragHandlesComponent.createObject(mapControl)
- _splitHandlesComponent = splitHandlesComponent.createObject(mapControl)
- _centerDragHandleComponent = centerDragHandleComponent.createObject(mapControl)
+ function addEditingVisuals() {
+ if (_objMgrEditingVisuals.empty) {
+ _objMgrEditingVisuals.createObjects([ dragHandlesComponent, splitHandlesComponent, centerDragHandleComponent ], mapControl, false /* addToMap */)
}
}
- function removeHandles() {
- if (_dragHandlesComponent) {
- _dragHandlesComponent.destroy()
- _dragHandlesComponent = undefined
- }
- if (_splitHandlesComponent) {
- _splitHandlesComponent.destroy()
- _splitHandlesComponent = undefined
+ function removeEditingVisuals() {
+ _objMgrEditingVisuals.destroyObjects()
+ }
+
+
+ function addToolVisuals() {
+ if (_objMgrToolVisuals.empty) {
+ _objMgrToolVisuals.createObject(editHeaderComponent, mapControl)
}
- if (_centerDragHandleComponent) {
- _centerDragHandleComponent.destroy()
- _centerDragHandleComponent = undefined
+ }
+
+ function removeToolVisuals() {
+ _objMgrToolVisuals.destroyObjects()
+ }
+
+ function addCircleVisuals() {
+ if (_objMgrCircleVisuals.empty) {
+ _objMgrCircleVisuals.createObject(radiusVisualsComponent, mapControl)
}
}
/// Calculate the default/initial 4 sided polygon
function defaultPolygonVertices() {
// Initial polygon is inset to take 2/3rds space
- var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height)
+ var rect = Qt.rect(mapControl.centerViewport.x, mapControl.centerViewport.y, mapControl.centerViewport.width, mapControl.centerViewport.height)
rect.x += (rect.width * 0.25) / 2
rect.y += (rect.height * 0.25) / 2
rect.width *= 0.75
rect.height *= 0.75
- var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */)
- var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */)
- var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */)
- var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */)
- var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */)
+ var centerCoord = mapControl.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */)
+ var topLeftCoord = mapControl.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */)
+ var topRightCoord = mapControl.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */)
+ var bottomLeftCoord = mapControl.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */)
+ var bottomRightCoord = mapControl.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */)
// Initial polygon has max width and height of 3000 meters
var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), 3000) / 2
@@ -102,82 +113,111 @@ Item {
return [ topLeftCoord, topRightCoord, bottomRightCoord, bottomLeftCoord, centerCoord ]
}
- /// Add an initial 4 sided polygon
- function addInitialPolygon() {
- if (mapPolygon.count < 3) {
- initialVertices = defaultPolygonVertices()
- mapPolygon.appendVertex(initialVertices[0])
- mapPolygon.appendVertex(initialVertices[1])
- mapPolygon.appendVertex(initialVertices[2])
- mapPolygon.appendVertex(initialVertices[3])
- }
- }
-
/// Reset polygon back to initial default
- function resetPolygon() {
- var initialVertices = defaultPolygonVertices()
+ function _resetPolygon() {
+ mapPolygon.beginReset()
mapPolygon.clear()
+ var initialVertices = defaultPolygonVertices()
for (var i=0; i<4; i++) {
mapPolygon.appendVertex(initialVertices[i])
}
- _circle = false
+ mapPolygon.endReset()
+ _circleMode = false
}
- function setCircleRadius(center, radius) {
+ function _createCircularPolygon(center, radius) {
var unboundCenter = center.atDistanceAndAzimuth(0, 0)
- _circleRadius = radius
var segments = 16
var angleIncrement = 360 / segments
var angle = 0
+ mapPolygon.beginReset()
mapPolygon.clear()
+ _circleRadius = radius
for (var i=0; i= 0) {
@@ -216,38 +256,23 @@ Item {
visible: removeVertexItem.visible
}
- QGCMenuItem {
- text: qsTr("Circle" )
- onTriggered: resetCircle()
- }
-
- QGCMenuItem {
- text: qsTr("Polygon")
- onTriggered: resetPolygon()
- }
-
QGCMenuItem {
text: qsTr("Set radius..." )
- visible: _circle
+ visible: _circleMode
onTriggered: _editCircleRadius = true
}
QGCMenuItem {
text: qsTr("Edit position..." )
- visible: _circle
+ visible: _circleMode
onTriggered: mainWindow.showComponentDialog(editCenterPositionDialog, qsTr("Edit Center Position"), mainWindow.showDialogDefaultWidth, StandardButton.Close)
}
QGCMenuItem {
text: qsTr("Edit position..." )
- visible: !_circle && menu._editingVertexIndex >= 0
+ visible: !_circleMode && menu._editingVertexIndex >= 0
onTriggered: mainWindow.showComponentDialog(editVertexPositionDialog, qsTr("Edit Vertex Position"), mainWindow.showDialogDefaultWidth, StandardButton.Close)
}
-
- QGCMenuItem {
- text: qsTr("Load KML/SHP...")
- onTriggered: kmlOrSHPLoadDialog.openForLoad()
- }
}
Component {
@@ -269,7 +294,7 @@ Item {
id: mapQuickItem
anchorPoint.x: sourceItem.width / 2
anchorPoint.y: sourceItem.height / 2
- visible: !_circle
+ visible: !_circleMode
property int vertexIndex
@@ -323,7 +348,7 @@ Item {
id: dragArea
mapControl: _root.mapControl
z: _zorderDragHandle
- visible: !_circle
+ visible: !_circleMode
onDragStop: mapPolygon.verifyClockwiseWinding()
property int polygonVertex
@@ -380,7 +405,7 @@ Item {
anchorPoint.x: dragHandle.width / 2
anchorPoint.y: dragHandle.height / 2
z: _zorderDragHandle
- visible: !_circle
+ visible: !_circleMode
property int polygonVertex
@@ -463,74 +488,219 @@ Item {
onItemCoordinateChanged: mapPolygon.center = itemCoordinate
onDragStart: mapPolygon.centerDrag = true
onDragStop: mapPolygon.centerDrag = false
+ }
+ }
- onClicked: menu.popupCenter()
+ Component {
+ id: centerDragHandleComponent
- function setRadiusFromDialog() {
- var radius = QGroundControl.appSettingsDistanceUnitsToMeters(radiusField.text)
- setCircleRadius(mapPolygon.center, radius)
- _editCircleRadius = false
+ Item {
+ property var dragHandle
+ property var dragArea
+
+ Component.onCompleted: {
+ dragHandle = centerDragHandle.createObject(mapControl)
+ dragHandle.coordinate = Qt.binding(function() { return mapPolygon.center })
+ mapControl.addMapItem(dragHandle)
+ dragArea = centerDragAreaComponent.createObject(mapControl, { "itemIndicator": dragHandle, "itemCoordinate": mapPolygon.center })
+ }
+
+ Component.onDestruction: {
+ dragHandle.destroy()
+ dragArea.destroy()
}
+ }
+ }
+
+ Component {
+ id: editHeaderComponent
+
+ Item {
+ x: mapControl.centerViewport.left + _viewportMargins
+ y: mapControl.centerViewport.top + _viewportMargins
+ width: mapControl.centerViewport.width - (_viewportMargins * 2)
+ height: editHeaderRowLayout.y + editHeaderRowLayout.height + _viewportMargins
+ z: QGroundControl.zOrderMapItems + 2
+
+ property real _radius: ScreenTools.defaultFontPixelWidth / 2
+ property real _viewportMargins: ScreenTools.defaultFontPixelWidth
Rectangle {
- anchors.margins: _margin
- anchors.left: parent.right
- width: radiusColumn.width + (_margin *2)
- height: radiusColumn.height + (_margin *2)
- color: qgcPal.window
- border.color: qgcPal.text
- visible: _editCircleRadius
-
- Column {
- id: radiusColumn
- anchors.margins: _margin
- anchors.left: parent.left
- anchors.top: parent.top
- spacing: _margin
-
- QGCLabel { text: qsTr("Radius:") }
-
- QGCTextField {
- id: radiusField
- showUnits: true
- unitsLabel: QGroundControl.appSettingsDistanceUnitsString
- text: QGroundControl.metersToAppSettingsDistanceUnits(_circleRadius).toFixed(2)
- onEditingFinished: setRadiusFromDialog()
- inputMethodHints: Qt.ImhFormattedNumbersOnly
+ anchors.fill: parent
+ radius: _radius
+ color: "white"
+ opacity: 0.75
+ }
+
+ RowLayout {
+ id: editHeaderRowLayout
+ anchors.margins: _viewportMargins
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ QGCButton {
+ text: qsTr("Basic Polygon")
+ visible: !_traceMode
+ onClicked: _resetPolygon()
+ }
+
+ QGCButton {
+ text: qsTr("Circular Polygon")
+ visible: !_traceMode
+ onClicked: _resetCircle()
+ }
+
+ QGCButton {
+ text: _traceMode ? qsTr("Done Tracing") : qsTr("Trace Polygon")
+ onClicked: {
+ if (_traceMode) {
+ if (mapPolygon.count < 3) {
+ _restorePreviousVertices()
+ }
+ _traceMode = false
+ } else {
+ _saveCurrentVertices()
+ _circleMode = false
+ _traceMode = true
+ mapPolygon.clear();
+ }
}
}
+ QGCButton {
+ text: qsTr("Load KML/SHP...")
+ onClicked: kmlOrSHPLoadDialog.openForLoad()
+ visible: !_traceMode
+ }
+
QGCLabel {
- anchors.right: radiusColumn.right
- anchors.top: radiusColumn.top
- text: "X"
+ id: instructionLabel
+ color: "black"
+ text: _instructionText
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ // Mouse area to capture clicks for tracing a polygon
+ Component {
+ id: traceMouseAreaComponent
+
+ MouseArea {
+ anchors.fill: map
+ preventStealing: true
+ z: QGroundControl.zOrderMapItems + 1 // Over item indicators
+
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ mapPolygon.appendVertex(mapControl.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */))
+ }
+ }
+ }
+ }
+
+ Component {
+ id: radiusDragHandleComponent
+
+ MapQuickItem {
+ id: mapQuickItem
+ anchorPoint.x: dragHandle.width / 2
+ anchorPoint.y: dragHandle.height / 2
+ z: QGroundControl.zOrderMapItems + 2
+
+ sourceItem: Rectangle {
+ id: dragHandle
+ width: ScreenTools.defaultFontPixelHeight * 1.5
+ height: width
+ radius: width / 2
+ color: "white"
+ opacity: .90
+ }
+ }
+ }
- QGCMouseArea {
- fillItem: parent
- onClicked: setRadiusFromDialog()
+ Component {
+ id: radiusDragAreaComponent
+
+ MissionItemIndicatorDrag {
+ mapControl: _root.mapControl
+
+ property real _lastRadius
+
+ onItemCoordinateChanged: {
+ var radius = mapPolygon.center.distanceTo(itemCoordinate)
+ // Prevent signalling re-entrancy
+ if (!_circleRadiusDrag && Math.abs(radius - _lastRadius) > 0.1) {
+ _circleRadiusDrag = true
+ _createCircularPolygon(mapPolygon.center, radius)
+ _circleRadiusDragCoord = itemCoordinate
+ _circleRadiusDrag = false
+ _lastRadius = radius
+ }
+ }
+
+ /*
+ onItemCoordinateChanged: delayTimer.radius = mapPolygon.center.distanceTo(itemCoordinate)
+
+ onDragStart: delayTimer.start()
+ onDragStop: { delayTimer.stop(); delayTimer.update() }
+
+ // Use a delayed update to increase performance of redraw while dragging
+ Timer {
+ id: delayTimer
+ interval: 100
+ repeat: true
+
+ property real radius
+ property real _lastRadius
+
+ onRadiusChanged: console.log(radius)
+
+ function update() {
+ // Prevent signalling re-entrancy
+ if (!_circleRadiusDrag && radius != _lastRadius) {
+ _circleRadiusDrag = true
+ _createCircularPolygon(mapPolygon.center, radius)
+ _circleRadiusDragCoord = itemCoordinate
+ _circleRadiusDrag = false
+ _lastRadius = radius
}
}
+
+ onTriggered: update()
}
+ */
}
}
Component {
- id: centerDragHandleComponent
+ id: radiusVisualsComponent
Item {
- property var dragHandle
- property var dragArea
+ property var circleCenterCoord: mapPolygon.center
- Component.onCompleted: {
- dragHandle = centerDragHandle.createObject(mapControl)
- dragHandle.coordinate = Qt.binding(function() { return mapPolygon.center })
- mapControl.addMapItem(dragHandle)
- dragArea = centerDragAreaComponent.createObject(mapControl, { "itemIndicator": dragHandle, "itemCoordinate": mapPolygon.center })
+ function _calcRadiusDragCoord() {
+ _circleRadiusDragCoord = circleCenterCoord.atDistanceAndAzimuth(_circleRadius, 90)
}
- Component.onDestruction: {
- dragHandle.destroy()
- dragArea.destroy()
+ onCircleCenterCoordChanged: {
+ if (!_circleRadiusDrag) {
+ _calcRadiusDragCoord()
+ }
+ }
+
+ QGCDynamicObjectManager {
+ id: _objMgr
+ }
+
+ Component.onCompleted: {
+ _calcRadiusDragCoord()
+ var radiusDragHandle = _objMgr.createObject(radiusDragHandleComponent, mapControl, true)
+ radiusDragHandle.coordinate = Qt.binding(function() { return _circleRadiusDragCoord })
+ var radiusDragIndicator = radiusDragAreaComponent.createObject(mapControl, { "itemIndicator": radiusDragHandle, "itemCoordinate": _circleRadiusDragCoord })
+ _objMgr.addObject(radiusDragIndicator)
}
}
}
diff --git a/src/PlanView/PlanView.qml b/src/PlanView/PlanView.qml
index a7105f132521b08e418118fa01c3837516bb7d29..7ff8650397b6bb11e9a88fc803ff1db8fa28fc13 100644
--- a/src/PlanView/PlanView.qml
+++ b/src/PlanView/PlanView.qml
@@ -405,10 +405,10 @@ Item {
planView: true
// This is the center rectangle of the map which is not obscured by tools
- property rect centerViewport: Qt.rect(_leftToolWidth, 0, editorMap.width - _leftToolWidth - _rightPanelWidth, editorMap.height - _statusHeight)
+ property rect centerViewport: Qt.rect(_leftToolWidth, 0, editorMap.width - _leftToolWidth - _rightToolWidth, mapScale.y)
- property real _leftToolWidth: toolStrip.x + toolStrip.width
- property real _statusHeight: waypointValuesDisplay.visible ? editorMap.height - waypointValuesDisplay.y : 0
+ property real _leftToolWidth: toolStrip.x + toolStrip.width
+ property real _rightToolWidth: rightPanel.width + rightPanel.anchors.rightMargin
readonly property real animationDuration: 500
diff --git a/src/PlanView/SurveyItemEditor.qml b/src/PlanView/SurveyItemEditor.qml
index 6a91934ce245c7512bf20d9523949574a0579477..92f41a0b27f0d227bdd01c22bd99ccb2dc6cbef5 100644
--- a/src/PlanView/SurveyItemEditor.qml
+++ b/src/PlanView/SurveyItemEditor.qml
@@ -54,101 +54,119 @@ Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
- spacing: _margin
- QGCTabBar {
- id: tabBar
+ ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
+ spacing: _margin
+ visible: !missionItem.surveyAreaPolygon.isValid
- Component.onCompleted: currentIndex = QGroundControl.settingsManager.planViewSettings.displayPresetsTabFirst.rawValue ? 2 : 0
-
- QGCTabButton { text: qsTr("Grid") }
- QGCTabButton { text: qsTr("Camera") }
- QGCTabButton { text: qsTr("Presets") }
+ QGCLabel {
+ Layout.fillWidth: true
+ wrapMode: Text.WordWrap
+ text: qsTr("Use the Polygon Tools to create the polygon which outlines your survey area.")
+ }
}
Column {
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
- visible: tabBar.currentIndex == 0
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: missionItem.surveyAreaPolygon.isValid
- QGCLabel {
+ QGCTabBar {
+ id: tabBar
anchors.left: parent.left
anchors.right: parent.right
- text: qsTr("WARNING: Photo interval is below minimum interval (%1 secs) supported by camera.").arg(_cameraMinTriggerInterval.toFixed(1))
- wrapMode: Text.WordWrap
- color: qgcPal.warningText
- visible: missionItem.cameraShots > 0 && _cameraMinTriggerInterval !== 0 && _cameraMinTriggerInterval > missionItem.timeBetweenShots
- }
- CameraCalcGrid {
- cameraCalc: missionItem.cameraCalc
- vehicleFlightIsFrontal: true
- distanceToSurfaceLabel: qsTr("Altitude")
- distanceToSurfaceAltitudeMode: missionItem.followTerrain ?
- QGroundControl.AltitudeModeAboveTerrain :
- missionItem.cameraCalc.distanceToSurfaceRelative
- frontalDistanceLabel: qsTr("Trigger Dist")
- sideDistanceLabel: qsTr("Spacing")
- }
+ Component.onCompleted: currentIndex = QGroundControl.settingsManager.planViewSettings.displayPresetsTabFirst.rawValue ? 2 : 0
- SectionHeader {
- id: transectsHeader
- text: qsTr("Transects")
+ QGCTabButton { text: qsTr("Grid") }
+ QGCTabButton { text: qsTr("Camera") }
+ QGCTabButton { text: qsTr("Presets") }
}
- GridLayout {
- anchors.left: parent.left
- anchors.right: parent.right
- columnSpacing: _margin
- rowSpacing: _margin
- columns: 2
- visible: transectsHeader.checked
-
- QGCLabel { text: qsTr("Angle") }
- FactTextField {
- fact: missionItem.gridAngle
- Layout.fillWidth: true
- onUpdated: angleSlider.value = missionItem.gridAngle.value
+ Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: tabBar.currentIndex == 0
+
+ QGCLabel {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: qsTr("WARNING: Photo interval is below minimum interval (%1 secs) supported by camera.").arg(_cameraMinTriggerInterval.toFixed(1))
+ wrapMode: Text.WordWrap
+ color: qgcPal.warningText
+ visible: missionItem.cameraShots > 0 && _cameraMinTriggerInterval !== 0 && _cameraMinTriggerInterval > missionItem.timeBetweenShots
}
- QGCSlider {
- id: angleSlider
- minimumValue: 0
- maximumValue: 359
- stepSize: 1
- tickmarksEnabled: false
- Layout.fillWidth: true
- Layout.columnSpan: 2
- Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
- onValueChanged: missionItem.gridAngle.value = value
- Component.onCompleted: value = missionItem.gridAngle.value
- updateValueWhileDragging: true
+ CameraCalcGrid {
+ cameraCalc: missionItem.cameraCalc
+ vehicleFlightIsFrontal: true
+ distanceToSurfaceLabel: qsTr("Altitude")
+ distanceToSurfaceAltitudeMode: missionItem.followTerrain ?
+ QGroundControl.AltitudeModeAboveTerrain :
+ missionItem.cameraCalc.distanceToSurfaceRelative
+ frontalDistanceLabel: qsTr("Trigger Dist")
+ sideDistanceLabel: qsTr("Spacing")
}
- QGCLabel {
- text: qsTr("Turnaround dist")
+ SectionHeader {
+ id: transectsHeader
+ text: qsTr("Transects")
}
- FactTextField {
- fact: missionItem.turnAroundDistance
- Layout.fillWidth: true
+
+ GridLayout {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ columnSpacing: _margin
+ rowSpacing: _margin
+ columns: 2
+ visible: transectsHeader.checked
+
+ QGCLabel { text: qsTr("Angle") }
+ FactTextField {
+ fact: missionItem.gridAngle
+ Layout.fillWidth: true
+ onUpdated: angleSlider.value = missionItem.gridAngle.value
+ }
+
+ QGCSlider {
+ id: angleSlider
+ minimumValue: 0
+ maximumValue: 359
+ stepSize: 1
+ tickmarksEnabled: false
+ Layout.fillWidth: true
+ Layout.columnSpan: 2
+ Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
+ onValueChanged: missionItem.gridAngle.value = value
+ Component.onCompleted: value = missionItem.gridAngle.value
+ updateValueWhileDragging: true
+ }
+
+ QGCLabel {
+ text: qsTr("Turnaround dist")
+ }
+ FactTextField {
+ fact: missionItem.turnAroundDistance
+ Layout.fillWidth: true
+ }
}
- }
- QGCButton {
- text: qsTr("Rotate Entry Point")
- onClicked: missionItem.rotateEntryPoint();
- }
+ QGCButton {
+ text: qsTr("Rotate Entry Point")
+ onClicked: missionItem.rotateEntryPoint();
+ }
- ColumnLayout {
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
- visible: transectsHeader.checked
+ ColumnLayout {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: transectsHeader.checked
- /*
+ /*
Temporarily removed due to bug https://github.com/mavlink/qgroundcontrol/issues/7005
FactCheckBox {
text: qsTr("Split concave polygons")
@@ -158,231 +176,232 @@ Rectangle {
}
*/
- QGCOptionsComboBox {
- Layout.fillWidth: true
-
- model: [
- {
- text: qsTr("Hover and capture image"),
- fact: missionItem.hoverAndCapture,
- enabled: !missionItem.followTerrain,
- visible: missionItem.hoverAndCaptureAllowed
- },
- {
- text: qsTr("Refly at 90 deg offset"),
- fact: missionItem.refly90Degrees,
- enabled: !missionItem.followTerrain,
- visible: true
- },
- {
- text: qsTr("Images in turnarounds"),
- fact: missionItem.cameraTriggerInTurnAround,
- enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true,
- visible: true
- },
- {
- text: qsTr("Fly alternate transects"),
- fact: missionItem.flyAlternateTransects,
- enabled: true,
- visible: _vehicle ? (_vehicle.fixedWing || _vehicle.vtol) : false
- },
- {
- text: qsTr("Relative altitude"),
- enabled: missionItem.cameraCalc.isManualCamera && !missionItem.followTerrain,
- visible: QGroundControl.corePlugin.options.showMissionAbsoluteAltitude || (!missionItem.cameraCalc.distanceToSurfaceRelative && !missionItem.followTerrain),
- checked: missionItem.cameraCalc.distanceToSurfaceRelative
+ QGCOptionsComboBox {
+ Layout.fillWidth: true
+
+ model: [
+ {
+ text: qsTr("Hover and capture image"),
+ fact: missionItem.hoverAndCapture,
+ enabled: !missionItem.followTerrain,
+ visible: missionItem.hoverAndCaptureAllowed
+ },
+ {
+ text: qsTr("Refly at 90 deg offset"),
+ fact: missionItem.refly90Degrees,
+ enabled: !missionItem.followTerrain,
+ visible: true
+ },
+ {
+ text: qsTr("Images in turnarounds"),
+ fact: missionItem.cameraTriggerInTurnAround,
+ enabled: missionItem.hoverAndCaptureAllowed ? !missionItem.hoverAndCapture.rawValue : true,
+ visible: true
+ },
+ {
+ text: qsTr("Fly alternate transects"),
+ fact: missionItem.flyAlternateTransects,
+ enabled: true,
+ visible: _vehicle ? (_vehicle.fixedWing || _vehicle.vtol) : false
+ },
+ {
+ text: qsTr("Relative altitude"),
+ enabled: missionItem.cameraCalc.isManualCamera && !missionItem.followTerrain,
+ visible: QGroundControl.corePlugin.options.showMissionAbsoluteAltitude || (!missionItem.cameraCalc.distanceToSurfaceRelative && !missionItem.followTerrain),
+ checked: missionItem.cameraCalc.distanceToSurfaceRelative
+ }
+ ]
+
+ onItemClicked: {
+ if (index == 4) {
+ missionItem.cameraCalc.distanceToSurfaceRelative = !missionItem.cameraCalc.distanceToSurfaceRelative
+ console.log(missionItem.cameraCalc.distanceToSurfaceRelative)
+ }
}
- ]
+ }
+ }
- onItemClicked: {
- if (index == 4) {
- missionItem.cameraCalc.distanceToSurfaceRelative = !missionItem.cameraCalc.distanceToSurfaceRelative
- console.log(missionItem.cameraCalc.distanceToSurfaceRelative)
+ SectionHeader {
+ id: terrainHeader
+ text: qsTr("Terrain")
+ checked: missionItem.followTerrain
+ }
+
+ ColumnLayout {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: terrainHeader.checked
+
+
+ QGCCheckBox {
+ id: followsTerrainCheckBox
+ text: qsTr("Vehicle follows terrain")
+ checked: missionItem.followTerrain
+ onClicked: missionItem.followTerrain = checked
+ }
+
+ GridLayout {
+ Layout.fillWidth: true
+ columnSpacing: _margin
+ rowSpacing: _margin
+ columns: 2
+ visible: followsTerrainCheckBox.checked
+
+ QGCLabel { text: qsTr("Tolerance") }
+ FactTextField {
+ fact: missionItem.terrainAdjustTolerance
+ Layout.fillWidth: true
+ }
+
+ QGCLabel { text: qsTr("Max Climb Rate") }
+ FactTextField {
+ fact: missionItem.terrainAdjustMaxClimbRate
+ Layout.fillWidth: true
+ }
+
+ QGCLabel { text: qsTr("Max Descent Rate") }
+ FactTextField {
+ fact: missionItem.terrainAdjustMaxDescentRate
+ Layout.fillWidth: true
}
}
}
- }
- SectionHeader {
- id: terrainHeader
- text: qsTr("Terrain")
- checked: missionItem.followTerrain
- }
+ SectionHeader {
+ id: statsHeader
+ text: qsTr("Statistics")
+ }
+
+ TransectStyleComplexItemStats {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ visible: statsHeader.checked
+ }
+ } // Grid Column
+
+ Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: tabBar.currentIndex == 1
+
+ CameraCalcCamera {
+ cameraCalc: missionItem.cameraCalc
+ vehicleFlightIsFrontal: true
+ distanceToSurfaceLabel: qsTr("Altitude")
+ distanceToSurfaceAltitudeMode: missionItem.followTerrain ?
+ QGroundControl.AltitudeModeAboveTerrain :
+ missionItem.cameraCalc.distanceToSurfaceRelative
+ frontalDistanceLabel: qsTr("Trigger Dist")
+ sideDistanceLabel: qsTr("Spacing")
+ }
+ } // Camera Column
ColumnLayout {
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
- visible: terrainHeader.checked
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: _margin
+ visible: tabBar.currentIndex == 2
+ QGCLabel {
+ Layout.fillWidth: true
+ text: qsTr("Presets")
+ wrapMode: Text.WordWrap
+ }
- QGCCheckBox {
- id: followsTerrainCheckBox
- text: qsTr("Vehicle follows terrain")
- checked: missionItem.followTerrain
- onClicked: missionItem.followTerrain = checked
+ QGCComboBox {
+ id: presetCombo
+ Layout.fillWidth: true
+ model: missionItem.presetNames
}
- GridLayout {
+ RowLayout {
Layout.fillWidth: true
- columnSpacing: _margin
- rowSpacing: _margin
- columns: 2
- visible: followsTerrainCheckBox.checked
- QGCLabel { text: qsTr("Tolerance") }
- FactTextField {
- fact: missionItem.terrainAdjustTolerance
+ QGCButton {
Layout.fillWidth: true
+ text: qsTr("Apply Preset")
+ enabled: missionItem.presetNames.length != 0
+ onClicked: missionItem.loadPreset(presetCombo.textAt(presetCombo.currentIndex))
}
- QGCLabel { text: qsTr("Max Climb Rate") }
- FactTextField {
- fact: missionItem.terrainAdjustMaxClimbRate
+ QGCButton {
Layout.fillWidth: true
+ text: qsTr("Delete Preset")
+ enabled: missionItem.presetNames.length != 0
+ onClicked: missionItem.deletePreset(presetCombo.textAt(presetCombo.currentIndex))
}
- QGCLabel { text: qsTr("Max Descent Rate") }
- FactTextField {
- fact: missionItem.terrainAdjustMaxDescentRate
- Layout.fillWidth: true
- }
}
- }
-
- SectionHeader {
- id: statsHeader
- text: qsTr("Statistics")
- }
-
- TransectStyleComplexItemStats {
- anchors.left: parent.left
- anchors.right: parent.right
- visible: statsHeader.checked
- }
- } // Grid Column
-
- Column {
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
- visible: tabBar.currentIndex == 1
-
- CameraCalcCamera {
- cameraCalc: missionItem.cameraCalc
- vehicleFlightIsFrontal: true
- distanceToSurfaceLabel: qsTr("Altitude")
- distanceToSurfaceAltitudeMode: missionItem.followTerrain ?
- QGroundControl.AltitudeModeAboveTerrain :
- missionItem.cameraCalc.distanceToSurfaceRelative
- frontalDistanceLabel: qsTr("Trigger Dist")
- sideDistanceLabel: qsTr("Spacing")
- }
- } // Camera Column
-
- ColumnLayout {
- anchors.left: parent.left
- anchors.right: parent.right
- spacing: _margin
- visible: tabBar.currentIndex == 2
-
- QGCLabel {
- Layout.fillWidth: true
- text: qsTr("Presets")
- wrapMode: Text.WordWrap
- }
-
- QGCComboBox {
- id: presetCombo
- Layout.fillWidth: true
- model: missionItem.presetNames
- }
- RowLayout {
- Layout.fillWidth: true
+ Item { height: ScreenTools.defaultFontPixelHeight; width: 1 }
QGCButton {
+ Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
- text: qsTr("Apply Preset")
- enabled: missionItem.presetNames.length != 0
- onClicked: missionItem.loadPreset(presetCombo.textAt(presetCombo.currentIndex))
+ text: qsTr("Save Settings As New Preset")
+ onClicked: mainWindow.showComponentDialog(savePresetDialog, qsTr("Save Preset"), mainWindow.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
}
- QGCButton {
+ SectionHeader {
+ id: presectsTransectsHeader
+ anchors.left: undefined
+ anchors.right: undefined
Layout.fillWidth: true
- text: qsTr("Delete Preset")
- enabled: missionItem.presetNames.length != 0
- onClicked: missionItem.deletePreset(presetCombo.textAt(presetCombo.currentIndex))
+ text: qsTr("Transects")
}
- }
-
- Item { height: ScreenTools.defaultFontPixelHeight; width: 1 }
+ GridLayout {
+ Layout.fillWidth: true
+ columnSpacing: _margin
+ rowSpacing: _margin
+ columns: 2
+ visible: presectsTransectsHeader.checked
- QGCButton {
- Layout.alignment: Qt.AlignCenter
- Layout.fillWidth: true
- text: qsTr("Save Settings As New Preset")
- onClicked: mainWindow.showComponentDialog(savePresetDialog, qsTr("Save Preset"), mainWindow.showDialogDefaultWidth, StandardButton.Save | StandardButton.Cancel)
- }
+ QGCLabel { text: qsTr("Angle") }
+ FactTextField {
+ fact: missionItem.gridAngle
+ Layout.fillWidth: true
+ onUpdated: presetsAngleSlider.value = missionItem.gridAngle.value
+ }
- SectionHeader {
- id: presectsTransectsHeader
- anchors.left: undefined
- anchors.right: undefined
- Layout.fillWidth: true
- text: qsTr("Transects")
- }
+ QGCSlider {
+ id: presetsAngleSlider
+ minimumValue: 0
+ maximumValue: 359
+ stepSize: 1
+ tickmarksEnabled: false
+ Layout.fillWidth: true
+ Layout.columnSpan: 2
+ Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
+ onValueChanged: missionItem.gridAngle.value = value
+ Component.onCompleted: value = missionItem.gridAngle.value
+ updateValueWhileDragging: true
+ }
- GridLayout {
- Layout.fillWidth: true
- columnSpacing: _margin
- rowSpacing: _margin
- columns: 2
- visible: presectsTransectsHeader.checked
-
- QGCLabel { text: qsTr("Angle") }
- FactTextField {
- fact: missionItem.gridAngle
- Layout.fillWidth: true
- onUpdated: presetsAngleSlider.value = missionItem.gridAngle.value
+ QGCButton {
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ text: qsTr("Rotate Entry Point")
+ onClicked: missionItem.rotateEntryPoint();
+ }
}
- QGCSlider {
- id: presetsAngleSlider
- minimumValue: 0
- maximumValue: 359
- stepSize: 1
- tickmarksEnabled: false
- Layout.fillWidth: true
- Layout.columnSpan: 2
- Layout.preferredHeight: ScreenTools.defaultFontPixelHeight * 1.5
- onValueChanged: missionItem.gridAngle.value = value
- Component.onCompleted: value = missionItem.gridAngle.value
- updateValueWhileDragging: true
+ SectionHeader {
+ id: presetsStatsHeader
+ anchors.left: undefined
+ anchors.right: undefined
+ Layout.fillWidth: true
+ text: qsTr("Statistics")
}
- QGCButton {
- Layout.columnSpan: 2
+ TransectStyleComplexItemStats {
Layout.fillWidth: true
- text: qsTr("Rotate Entry Point")
- onClicked: missionItem.rotateEntryPoint();
+ visible: presetsStatsHeader.checked
}
- }
-
- SectionHeader {
- id: presetsStatsHeader
- anchors.left: undefined
- anchors.right: undefined
- Layout.fillWidth: true
- text: qsTr("Statistics")
- }
-
- TransectStyleComplexItemStats {
- Layout.fillWidth: true
- visible: presetsStatsHeader.checked
- }
- } // Camera Column
+ } // Main editing column
+ } // Top level Column
Component {
id: savePresetDialog
@@ -418,4 +437,17 @@ Rectangle {
}
}
}
+
+ KMLOrSHPFileDialog {
+ id: kmlOrSHPLoadDialog
+ title: qsTr("Select Polygon File")
+ selectExisting: true
+
+ onAcceptedForLoad: {
+ missionItem.surveyAreaPolygon.loadKMLOrSHPFile(file)
+ missionItem.resetState = false
+ //editorMap.mapFitFunctions.fitMapViewportToMissionItems()
+ close()
+ }
+ }
} // Rectangle
diff --git a/src/PlanView/SurveyMapVisual.qml b/src/PlanView/SurveyMapVisual.qml
index 6315223c4e2cee07296d014fcc8803d2bbe3c743..50c13686d68d6e259472d1c3c002ebd40cc7c118 100644
--- a/src/PlanView/SurveyMapVisual.qml
+++ b/src/PlanView/SurveyMapVisual.qml
@@ -21,39 +21,4 @@ import QGroundControl.FlightMap 1.0
/// Survey Complex Mission Item visuals
TransectStyleMapVisuals {
polygonInteractive: true
-
- property var _mapPolygon: object.surveyAreaPolygon
-
- /// Add an initial 4 sided polygon if there is none
- function _addInitialPolygon() {
- if (_mapPolygon.count < 3) {
- // Initial polygon is inset to take 2/3rds space
- var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height)
- rect.x += (rect.width * 0.25) / 2
- rect.y += (rect.height * 0.25) / 2
- rect.width *= 0.75
- rect.height *= 0.75
-
- var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */)
- var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */)
- var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */)
- var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */)
- var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */)
-
- // Initial polygon has max width and height of 3000 meters
- var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), 3000) / 2
- var halfHeightMeters = Math.min(topLeftCoord.distanceTo(bottomLeftCoord), 3000) / 2
- topLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 0)
- topRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 0)
- bottomLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 180)
- bottomRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 180)
-
- _mapPolygon.appendVertex(topLeftCoord)
- _mapPolygon.appendVertex(topRightCoord)
- _mapPolygon.appendVertex(bottomRightCoord)
- _mapPolygon.appendVertex(bottomLeftCoord)
- }
- }
-
- Component.onCompleted: _addInitialPolygon()
}
diff --git a/src/QmlControls/KMLOrSHPFileDialog.qml b/src/QmlControls/KMLOrSHPFileDialog.qml
new file mode 100644
index 0000000000000000000000000000000000000000..272fe6ee68bec7d23828b95a7824c483bd20d5ca
--- /dev/null
+++ b/src/QmlControls/KMLOrSHPFileDialog.qml
@@ -0,0 +1,24 @@
+/****************************************************************************
+ *
+ * (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.11
+
+import QGroundControl 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.ShapeFileHelper 1.0
+
+QGCFileDialog {
+ id: kmlOrSHPLoadDialog
+ folder: QGroundControl.settingsManager.appSettings.missionSavePath
+ title: qsTr("Select Polygon File")
+ selectExisting: true
+ nameFilters: ShapeFileHelper.fileDialogKMLOrSHPFilters
+ fileExtension: QGroundControl.settingsManager.appSettings.kmlFileExtension
+ fileExtension2: QGroundControl.settingsManager.appSettings.shpFileExtension
+}
diff --git a/src/QmlControls/QGCDynamicObjectManager.qml b/src/QmlControls/QGCDynamicObjectManager.qml
index 5eb47ff20da39d192e2e056098840ce901bcef05..e29bd346244909a98ad8e67d8c53aa8740182194 100644
--- a/src/QmlControls/QGCDynamicObjectManager.qml
+++ b/src/QmlControls/QGCDynamicObjectManager.qml
@@ -9,30 +9,42 @@ import QGroundControl.ScreenTools 1.0
Item {
visible: false
- property var rgDynamicObjects: [ ]
+ property var rgDynamicObjects: [ ]
+ property bool empty: rgDynamicObjects.length === 0
- function createObject(sourceComponent, parentObject, parentObjectIsMap) {
+ Component.onDestruction: destroyObjects()
+
+ function createObject(sourceComponent, parentObject, addMapItem) {
var obj = sourceComponent.createObject(parentObject)
if (obj.status === Component.Error) {
console.log(obj.errorString())
}
rgDynamicObjects.push(obj)
if (arguments.length < 3) {
- parentObjectIsMap = false
+ addMapItem = false
}
- if (parentObjectIsMap) {
- map.addMapItem(obj)
+ if (addMapItem) {
+ parentObject.addMapItem(obj)
}
return obj
}
- function createObjects(rgSourceComponents, parentObject, parentObjectIsMap) {
+ function createObjects(rgSourceComponents, parentObject, addMapItem) {
if (arguments.length < 3) {
- parentObjectIsMap = false
+ addMapItem = false
}
for (var i=0; i