@ -7,11 +7,12 @@
@@ -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 {
@@ -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 / / H i g h e s t t o p r e v e n t s p l i t t i n g w h e n i t e m s o v e r l a p
property real _zorderSplitHandle : QGroundControl . zOrderMapItems + 2
property real _zorderCenterHandle : QGroundControl . zOrderMapItems + 1 / / L o w e s t s u c h t h a t d r a g o r s p l i t t a k e s p r e c e d e n c e
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 removeCommon Visuals ( ) {
_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 removeHandle s ( ) {
if ( _dragHandlesComponent ) {
_dragHandlesComponent . destroy ( )
_dragHandlesComponent = undefined
}
if ( _splitHandlesComponent ) {
_splitHandlesComponent . destroy ( )
_splitHandlesComponent = undefined
function removeEditingVisual s ( ) {
_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 )
}
}
/ / / C a l c u l a t e t h e d e f a u l t / i n i t i a l 4 s i d e d p o l y g o n
function defaultPolygonVertices ( ) {
/ / I n i t i a l p o l y g o n i s i n s e t t o t a k e 2 / 3 r d s s p a c e
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 */ )
/ / I n i t i a l p o l y g o n h a s m a x w i d t h a n d h e i g h t o f 3 0 0 0 m e t e r s
var halfWidthMeters = Math . min ( topLeftCoord . distanceTo ( topRightCoord ) , 3000 ) / 2
@ -102,82 +113,111 @@ Item {
@@ -102,82 +113,111 @@ Item {
return [ topLeftCoord , topRightCoord , bottomRightCoord , bottomLeftCoord , centerCoord ]
}
/ / / A d d a n i n i t i a l 4 s i d e d p o l y g o n
function addInitialPolygon ( ) {
if ( mapPolygon . count < 3 ) {
initialVertices = defaultPolygonVertices ( )
mapPolygon . appendVertex ( initialVertices [ 0 ] )
mapPolygon . appendVertex ( initialVertices [ 1 ] )
mapPolygon . appendVertex ( initialVertices [ 2 ] )
mapPolygon . appendVertex ( initialVertices [ 3 ] )
}
}
/ / / R e s e t p o l y g o n b a c k t o i n i t i a l d e f a u l t
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 < segments ; i ++ ) {
var vertex = unboundCenter . atDistanceAndAzimuth ( _ci rcleR adius, angle )
var vertex = unboundCenter . atDistanceAndAzimuth ( radius , angle )
mapPolygon . appendVertex ( vertex )
angle += angleIncrement
}
_circle = true
mapPolygon . endReset ( )
_circleMode = true
}
/ / / R e s e t p o l y g o n t o a c i r c l e w h i c h f i t s w i t h i n i n i t i a l p o l y g o n
function resetCircle ( ) {
function _ resetCircle( ) {
var initialVertices = defaultPolygonVertices ( )
var width = initialVertices [ 0 ] . distanceTo ( initialVertices [ 1 ] )
var height = initialVertices [ 1 ] . distanceTo ( initialVertices [ 2 ] )
var radius = Math . min ( width , height ) / 2
var center = initialVertices [ 4 ]
setCircleRadius ( center , radius )
_createCircularPolygon ( center , radius )
}
onInteractiveChanged: {
function _handleInteractiveChanged ( ) {
if ( interactive ) {
addHandles ( )
addEditingVisuals ( )
addToolVisuals ( )
} else {
removeHandles ( )
_traceMode = false
removeEditingVisuals ( )
removeToolVisuals ( )
}
}
Component.onCompleted: {
addVisuals ( )
if ( interactive ) {
addHandles ( )
function _saveCurrentVertices ( ) {
_savedVertices = [ ]
_savedCircleMode = _circleMode
for ( var i = 0 ; i < mapPolygon . count ; i ++ ) {
_savedVertices . push ( mapPolygon . vertexCoordinate ( i ) )
}
}
function _restorePreviousVertices ( ) {
mapPolygon . beginReset ( )
mapPolygon . clear ( )
for ( var i = 0 ; i < _savedVertices . length ; i ++ ) {
mapPolygon . appendVertex ( _savedVertices [ i ] )
}
mapPolygon . endReset ( )
_circleMode = _savedCircleMode
}
onInteractiveChanged: _handleInteractiveChanged ( )
on_TraceModeChanged: {
if ( _traceMode ) {
_instructionText = _traceText
_objMgrTraceVisuals . createObject ( traceMouseAreaComponent , mapControl , false )
} else {
_instructionText = _polygonToolsText
_objMgrTraceVisuals . destroyObjects ( )
}
}
on_CircleModeChanged: {
if ( _circleMode ) {
addCircleVisuals ( )
} else {
_objMgrCircleVisuals . destroyObjects ( )
}
}
Component.onDestruction: {
removeVisuals ( )
removeHandles ( )
Component.onCompleted : {
addCommon Visuals( )
_handleInteractiveChanged ( )
}
QGCDynamicObjectManager { id: _objMgrCommonVisuals }
QGCDynamicObjectManager { id: _objMgrToolVisuals }
QGCDynamicObjectManager { id: _objMgrEditingVisuals }
QGCDynamicObjectManager { id: _objMgrTraceVisuals }
QGCDynamicObjectManager { id: _objMgrCircleVisuals }
QGCPalette { id: qgcPal }
QGCFileDialog {
KMLOrSHP FileDialog {
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
onAcceptedForLoad: {
mapPolygon . loadKMLOrSHPFile ( file )
@ -203,7 +243,7 @@ Item {
@@ -203,7 +243,7 @@ Item {
QGCMenuItem {
id: removeVertexItem
visible: ! _circle
visible: ! _circleMode
text: qsTr ( "Remove vertex" )
onTriggered: {
if ( menu . _editingVertexIndex >= 0 ) {
@ -217,37 +257,22 @@ Item {
@@ -217,37 +257,22 @@ Item {
}
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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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
}
}
}
}
/ / M o u s e a r e a t o c a p t u r e c l i c k s f o r t r a c i n g a p o l y g o n
Component {
id: traceMouseAreaComponent
MouseArea {
anchors.fill: map
preventStealing: true
z: QGroundControl . zOrderMapItems + 1 / / O v e r i t e m i n d i c a t o r s
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 )
/ / P r e v e n t s i g n a l l i n g r e - e n t r a n c y
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 ( ) }
/ / U s e a d e l a y e d u p d a t e t o i n c r e a s e p e r f o r m a n c e o f r e d r a w w h i l e d r a g g i n g
Timer {
id: delayTimer
interval: 100
repeat: true
property real radius
property real _lastRadius
onRadiusChanged: console . log ( radius )
function update ( ) {
/ / P r e v e n t s i g n a l l i n g r e - e n t r a n c y
if ( ! _circleRadiusDrag && radius != _lastRadius ) {
_circleRadiusDrag = true
_createCircularPolygon ( mapPolygon . center , radius )
_circleRadiusDragCoord = itemCoordinate
_circleRadiusDrag = false
_lastRadius = radius
}
}
onTriggered: update ( )
}
* /
}
}
Component {
id: centerDragHandleComponent
id: radiusVisuals Component
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 )
}
}
}