QGCMapPolygonVisuals.qml 23.1 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

Don Gagne's avatar
Don Gagne committed
10 11 12 13 14 15
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
16

17 18 19 20 21 22
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
23 24 25 26 27

/// QGCMapPolygon map visuals
Item {
    id: _root

DonLakeFlyer's avatar
DonLakeFlyer committed
28 29
    property var    mapControl                                  ///< Map control to place item in
    property var    mapPolygon                                  ///< QGCMapPolygon object
30
    property bool   interactive:        mapPolygon.interactive
31
    property color  interiorColor:      "transparent"
32
    property color  altColor:           "transparent"
33 34 35
    property real   interiorOpacity:    1
    property int    borderWidth:        0
    property color  borderColor:        "black"
36

Don Gagne's avatar
Don Gagne committed
37
    property bool   _circleMode:                false
38
    property real   _circleRadius
Don Gagne's avatar
Don Gagne committed
39 40
    property bool   _circleRadiusDrag:          false
    property var    _circleRadiusDragCoord:     QtPositioning.coordinate()
41
    property bool   _editCircleRadius:          false
Don Gagne's avatar
Don Gagne committed
42 43 44
    property string _instructionText:           _polygonToolsText
    property var    _savedVertices:             [ ]
    property bool   _savedCircleMode
45

Don Gagne's avatar
Don Gagne committed
46 47 48
    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
49

Don Gagne's avatar
Don Gagne committed
50 51 52 53 54 55 56
    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)
        }
57 58
    }

Don Gagne's avatar
Don Gagne committed
59 60
    function removeCommonVisuals() {
        _objMgrCommonVisuals.destroyObjects()
61 62
    }

Don Gagne's avatar
Don Gagne committed
63 64 65
    function addEditingVisuals() {
        if (_objMgrEditingVisuals.empty) {
            _objMgrEditingVisuals.createObjects([ dragHandlesComponent, splitHandlesComponent, centerDragHandleComponent ], mapControl, false /* addToMap */)
66
        }
67 68
    }

Don Gagne's avatar
Don Gagne committed
69 70 71 72
    function removeEditingVisuals() {
        _objMgrEditingVisuals.destroyObjects()
    }

Don Gagne's avatar
Don Gagne committed
73
    function addToolbarVisuals() {
Don Gagne's avatar
Don Gagne committed
74
        if (_objMgrToolVisuals.empty) {
75 76
            var toolbar = _objMgrToolVisuals.createObject(toolbarComponent, mapControl)
            toolbar.z = QGroundControl.zOrderWidgets
77
        }
Don Gagne's avatar
Don Gagne committed
78 79 80 81 82 83 84 85 86
    }

    function removeToolVisuals() {
        _objMgrToolVisuals.destroyObjects()
    }

    function addCircleVisuals() {
        if (_objMgrCircleVisuals.empty) {
            _objMgrCircleVisuals.createObject(radiusVisualsComponent, mapControl)
87 88 89
        }
    }

90 91 92
    /// Calculate the default/initial 4 sided polygon
    function defaultPolygonVertices() {
        // Initial polygon is inset to take 2/3rds space
Don Gagne's avatar
Don Gagne committed
93
        var rect = Qt.rect(mapControl.centerViewport.x, mapControl.centerViewport.y, mapControl.centerViewport.width, mapControl.centerViewport.height)
94 95 96 97 98
        rect.x += (rect.width * 0.25) / 2
        rect.y += (rect.height * 0.25) / 2
        rect.width *= 0.75
        rect.height *= 0.75

Don Gagne's avatar
Don Gagne committed
99 100 101 102 103
        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 */)
104 105 106 107 108 109 110 111 112

        // 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)

113
        return [ topLeftCoord, topRightCoord, bottomRightCoord, bottomLeftCoord  ]
114 115 116
    }

    /// Reset polygon back to initial default
Don Gagne's avatar
Don Gagne committed
117 118
    function _resetPolygon() {
        mapPolygon.beginReset()
119
        mapPolygon.clear()
120
        mapPolygon.appendVertices(defaultPolygonVertices())
Don Gagne's avatar
Don Gagne committed
121 122
        mapPolygon.endReset()
        _circleMode = false
123 124
    }

Don Gagne's avatar
Don Gagne committed
125
    function _createCircularPolygon(center, radius) {
126 127 128 129
        var unboundCenter = center.atDistanceAndAzimuth(0, 0)
        var segments = 16
        var angleIncrement = 360 / segments
        var angle = 0
Don Gagne's avatar
Don Gagne committed
130
        mapPolygon.beginReset()
131
        mapPolygon.clear()
Don Gagne's avatar
Don Gagne committed
132
        _circleRadius = radius
133
        for (var i=0; i<segments; i++) {
Don Gagne's avatar
Don Gagne committed
134
            var vertex = unboundCenter.atDistanceAndAzimuth(radius, angle)
135 136
            mapPolygon.appendVertex(vertex)
            angle += angleIncrement
137
        }
Don Gagne's avatar
Don Gagne committed
138 139
        mapPolygon.endReset()
        _circleMode = true
140 141 142
    }

    /// Reset polygon to a circle which fits within initial polygon
Don Gagne's avatar
Don Gagne committed
143
    function _resetCircle() {
144 145 146 147
        var initialVertices = defaultPolygonVertices()
        var width = initialVertices[0].distanceTo(initialVertices[1])
        var height = initialVertices[1].distanceTo(initialVertices[2])
        var radius = Math.min(width, height) / 2
Don Gagne's avatar
Don Gagne committed
148
        var center = initialVertices[0].atDistanceAndAzimuth(width / 2, 90).atDistanceAndAzimuth(height / 2, 180)
Don Gagne's avatar
Don Gagne committed
149
        _createCircularPolygon(center, radius)
150 151
    }

Don Gagne's avatar
Don Gagne committed
152
    function _handleInteractiveChanged() {
153
        if (interactive) {
Don Gagne's avatar
Don Gagne committed
154
            addEditingVisuals()
Don Gagne's avatar
Don Gagne committed
155
            addToolbarVisuals()
156
        } else {
157
            mapPolygon.traceMode = false
Don Gagne's avatar
Don Gagne committed
158 159
            removeEditingVisuals()
            removeToolVisuals()
160 161 162
        }
    }

Don Gagne's avatar
Don Gagne committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    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_CircleModeChanged: {
        if (_circleMode) {
            addCircleVisuals()
        } else {
            _objMgrCircleVisuals.destroyObjects()
188 189 190
        }
    }

191 192 193 194 195 196 197 198 199 200 201 202 203
    Connections {
        target: mapPolygon
        onTraceModeChanged: {
            if (mapPolygon.traceMode) {
                _instructionText = _traceText
                _objMgrTraceVisuals.createObject(traceMouseAreaComponent, mapControl, false)
            } else {
                _instructionText = _polygonToolsText
                _objMgrTraceVisuals.destroyObjects()
            }
        }
    }

Don Gagne's avatar
Don Gagne committed
204 205 206
    Component.onCompleted: {
        addCommonVisuals()
        _handleInteractiveChanged()
207
    }
DoinLakeFlyer's avatar
DoinLakeFlyer committed
208
    Component.onDestruction: mapPolygon.traceMode = false
209

Don Gagne's avatar
Don Gagne committed
210 211 212 213 214 215
    QGCDynamicObjectManager { id: _objMgrCommonVisuals }
    QGCDynamicObjectManager { id: _objMgrToolVisuals }
    QGCDynamicObjectManager { id: _objMgrEditingVisuals }
    QGCDynamicObjectManager { id: _objMgrTraceVisuals }
    QGCDynamicObjectManager { id: _objMgrCircleVisuals }

216 217
    QGCPalette { id: qgcPal }

Don Gagne's avatar
Don Gagne committed
218
    KMLOrSHPFileDialog {
219 220
        id:             kmlOrSHPLoadDialog
        title:          qsTr("Select Polygon File")
DonLakeFlyer's avatar
DonLakeFlyer committed
221 222 223
        selectExisting: true

        onAcceptedForLoad: {
224
            mapPolygon.loadKMLOrSHPFile(file)
225
            mapFitFunctions.fitMapViewportToMissionItems()
DonLakeFlyer's avatar
DonLakeFlyer committed
226 227 228 229
            close()
        }
    }

230
    QGCMenu {
231 232
        id: menu

233
        property int _editingVertexIndex: -1
234

235 236 237 238 239 240 241
        function popupVertex(curIndex) {
            menu._editingVertexIndex = curIndex
            removeVertexItem.visible = (mapPolygon.count > 3 && menu._editingVertexIndex >= 0)
            menu.popup()
        }

        function popupCenter() {
242 243 244
            menu.popup()
        }

245
        QGCMenuItem {
246
            id:             removeVertexItem
Don Gagne's avatar
Don Gagne committed
247
            visible:        !_circleMode
248 249
            text:           qsTr("Remove vertex")
            onTriggered: {
250 251
                if (menu._editingVertexIndex >= 0) {
                    mapPolygon.removeVertex(menu._editingVertexIndex)
252 253 254 255
                }
            }
        }

256
        QGCMenuSeparator {
257 258 259
            visible:        removeVertexItem.visible
        }

260
        QGCMenuItem {
261
            text:           qsTr("Set radius..." )
Don Gagne's avatar
Don Gagne committed
262
            visible:        _circleMode
263
            onTriggered:    _editCircleRadius = true
264 265
        }

266
        QGCMenuItem {
267
            text:           qsTr("Edit position..." )
Don Gagne's avatar
Don Gagne committed
268
            visible:        _circleMode
269
            onTriggered:    mainWindow.showComponentDialog(editCenterPositionDialog, qsTr("Edit Center Position"), mainWindow.showDialogDefaultWidth, StandardButton.Close)
270 271
        }

272
        QGCMenuItem {
273
            text:           qsTr("Edit position..." )
Don Gagne's avatar
Don Gagne committed
274
            visible:        !_circleMode && menu._editingVertexIndex >= 0
275
            onTriggered:    mainWindow.showComponentDialog(editVertexPositionDialog, qsTr("Edit Vertex Position"), mainWindow.showDialogDefaultWidth, StandardButton.Close)
276 277 278
        }
    }

279 280 281 282
    Component {
        id: polygonComponent

        MapPolygon {
283
            color:          mapPolygon.showAltColor ? altColor : interiorColor
284 285 286 287
            opacity:        interiorOpacity
            border.color:   borderColor
            border.width:   borderWidth
            path:           mapPolygon.path
288 289 290 291 292 293 294 295
        }
    }

    Component {
        id: splitHandleComponent

        MapQuickItem {
            id:             mapQuickItem
296 297
            anchorPoint.x:  sourceItem.width / 2
            anchorPoint.y:  sourceItem.height / 2
Don Gagne's avatar
Don Gagne committed
298
            visible:        !_circleMode
299 300 301

            property int vertexIndex

302
            sourceItem: SplitIndicator {
303
                z:          _zorderSplitHandle
304
                onClicked:  if(_root.interactive) mapPolygon.splitPolygonSegment(mapQuickItem.vertexIndex)
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
            }
        }
    }

    Component {
        id: splitHandlesComponent

        Repeater {
            model: mapPolygon.path

            delegate: Item {
                property var _splitHandle
                property var _vertices:     mapPolygon.path

                function _setHandlePosition() {
                    var nextIndex = index + 1
                    if (nextIndex > _vertices.length - 1) {
                        nextIndex = 0
                    }
                    var distance = _vertices[index].distanceTo(_vertices[nextIndex])
                    var azimuth = _vertices[index].azimuthTo(_vertices[nextIndex])
                    _splitHandle.coordinate = _vertices[index].atDistanceAndAzimuth(distance / 2, azimuth)
                }

                Component.onCompleted: {
                    _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 {
350
            id:         dragArea
351
            mapControl: _root.mapControl
352
            z:          _zorderDragHandle
Don Gagne's avatar
Don Gagne committed
353
            visible:    !_circleMode
354
            onDragStop: mapPolygon.verifyClockwiseWinding()
355 356 357 358 359 360 361 362 363

            property int polygonVertex

            property bool _creationComplete: false

            Component.onCompleted: _creationComplete = true

            onItemCoordinateChanged: {
                if (_creationComplete) {
364
                    // During component creation some bad coordinate values got through which screws up draw
365 366 367 368
                    mapPolygon.adjustVertex(polygonVertex, itemCoordinate)
                }
            }

369
            onClicked: if(_root.interactive) menu.popupVertex(polygonVertex)
370 371 372
        }
    }

373 374 375 376
    Component {
        id: centerDragHandle
        MapQuickItem {
            id:             mapQuickItem
377 378
            anchorPoint.x:  dragHandle.width  * 0.5
            anchorPoint.y:  dragHandle.height * 0.5
379 380
            z:              _zorderDragHandle
            sourceItem: Rectangle {
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
                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
                QGCColoredImage {
                    width:      parent.width
                    height:     width
                    color:      Qt.rgba(0,0,0,1)
                    mipmap:     true
                    fillMode:   Image.PreserveAspectFit
                    source:     "/qmlimages/MapCenter.svg"
                    sourceSize.height:  height
                    anchors.centerIn:   parent
397 398 399 400 401
                }
            }
        }
    }

402 403 404 405 406
    Component {
        id: dragHandleComponent

        MapQuickItem {
            id:             mapQuickItem
407
            anchorPoint.x:  dragHandle.width  / 2
408
            anchorPoint.y:  dragHandle.height / 2
409
            z:              _zorderDragHandle
Don Gagne's avatar
Don Gagne committed
410
            visible:        !_circleMode
411 412

            property int polygonVertex
413 414

            sourceItem: Rectangle {
415 416 417 418 419 420 421
                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
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
            }
        }
    }

    // Add all polygon vertex drag handles to the map
    Component {
        id: dragHandlesComponent

        Repeater {
            model: mapPolygon.pathModel

            delegate: Item {
                property var _visuals: [ ]

                Component.onCompleted: {
                    var dragHandle = dragHandleComponent.createObject(mapControl)
                    dragHandle.coordinate = Qt.binding(function() { return object.coordinate })
439
                    dragHandle.polygonVertex = Qt.binding(function() { return index })
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
                    mapControl.addMapItem(dragHandle)
                    var dragArea = dragAreaComponent.createObject(mapControl, { "itemIndicator": dragHandle, "itemCoordinate": object.coordinate })
                    dragArea.polygonVertex = 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 = [ ]
                }
            }
        }
    }

457
    Component {
458
        id: editCenterPositionDialog
459 460 461

        EditPositionDialog {
            coordinate: mapPolygon.center
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
            onCoordinateChanged: {
                // Prevent spamming signals on vertex changes by setting centerDrag = true when changing center position.
                // This also fixes a bug where Qt gets confused by all the signalling and draws a bad visual.
                mapPolygon.centerDrag = true
                mapPolygon.center = coordinate
                mapPolygon.centerDrag = false
            }
        }
    }

    Component {
        id: editVertexPositionDialog

        EditPositionDialog {
            coordinate:             mapPolygon.vertexCoordinate(menu._editingVertexIndex)
477 478 479 480
            onCoordinateChanged: {
                mapPolygon.adjustVertex(menu._editingVertexIndex, coordinate)
                mapPolygon.verifyClockwiseWinding()
            }
481 482 483
        }
    }

484 485 486 487
    Component {
        id: centerDragAreaComponent

        MissionItemIndicatorDrag {
488
            mapControl:                 _root.mapControl
Don Gagne's avatar
Don Gagne committed
489
            z:                          _zorderCenterHandle
DonLakeFlyer's avatar
DonLakeFlyer committed
490 491 492
            onItemCoordinateChanged:    mapPolygon.center = itemCoordinate
            onDragStart:                mapPolygon.centerDrag = true
            onDragStop:                 mapPolygon.centerDrag = false
Don Gagne's avatar
Don Gagne committed
493 494
        }
    }
495

Don Gagne's avatar
Don Gagne committed
496 497
    Component {
        id: centerDragHandleComponent
498

Don Gagne's avatar
Don Gagne committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512
        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()
513
            }
Don Gagne's avatar
Don Gagne committed
514 515 516 517
        }
    }

    Component {
Don Gagne's avatar
Don Gagne committed
518
        id: toolbarComponent
Don Gagne's avatar
Don Gagne committed
519

Don Gagne's avatar
Don Gagne committed
520
        PlanEditToolbar {
521 522 523 524
            anchors.horizontalCenter:       mapControl.left
            anchors.horizontalCenterOffset: mapControl.centerViewport.left + (mapControl.centerViewport.width / 2)
            y:                              mapControl.centerViewport.top
            availableWidth:                 mapControl.centerViewport.width
Don Gagne's avatar
Don Gagne committed
525

Don Gagne's avatar
Don Gagne committed
526 527
            QGCButton {
                _horizontalPadding: 0
DonLakeFlyer's avatar
DonLakeFlyer committed
528
                text:               qsTr("Basic")
529
                visible:            !mapPolygon.traceMode
Don Gagne's avatar
Don Gagne committed
530
                onClicked:          _resetPolygon()
Don Gagne's avatar
Don Gagne committed
531 532
            }

Don Gagne's avatar
Don Gagne committed
533 534
            QGCButton {
                _horizontalPadding: 0
DonLakeFlyer's avatar
DonLakeFlyer committed
535
                text:               qsTr("Circular")
536
                visible:            !mapPolygon.traceMode
Don Gagne's avatar
Don Gagne committed
537 538
                onClicked:          _resetCircle()
            }
Don Gagne's avatar
Don Gagne committed
539

Don Gagne's avatar
Don Gagne committed
540 541
            QGCButton {
                _horizontalPadding: 0
542
                text:               mapPolygon.traceMode ? qsTr("Done Tracing") : qsTr("Trace")
Don Gagne's avatar
Don Gagne committed
543
                onClicked: {
544
                    if (mapPolygon.traceMode) {
Don Gagne's avatar
Don Gagne committed
545 546
                        if (mapPolygon.count < 3) {
                            _restorePreviousVertices()
Don Gagne's avatar
Don Gagne committed
547
                        }
548
                        mapPolygon.traceMode = false
Don Gagne's avatar
Don Gagne committed
549 550 551
                    } else {
                        _saveCurrentVertices()
                        _circleMode = false
552
                        mapPolygon.traceMode = true
Don Gagne's avatar
Don Gagne committed
553
                        mapPolygon.clear();
554 555
                    }
                }
Don Gagne's avatar
Don Gagne committed
556
            }
557

Don Gagne's avatar
Don Gagne committed
558 559 560 561
            QGCButton {
                _horizontalPadding: 0
                text:               qsTr("Load KML/SHP...")
                onClicked:          kmlOrSHPLoadDialog.openForLoad()
562
                visible:            !mapPolygon.traceMode
Don Gagne's avatar
Don Gagne committed
563 564 565 566 567 568 569 570 571
            }
        }
    }

    // Mouse area to capture clicks for tracing a polygon
    Component {
        id:  traceMouseAreaComponent

        MouseArea {
Don Gagne's avatar
Don Gagne committed
572
            anchors.fill:       mapControl
Don Gagne's avatar
Don Gagne committed
573 574 575 576
            preventStealing:    true
            z:                  QGroundControl.zOrderMapItems + 1   // Over item indicators

            onClicked: {
577
                if (mouse.button === Qt.LeftButton && _root.interactive) {
Don Gagne's avatar
Don Gagne committed
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
                    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"
599
                opacity:    interiorOpacity * .90
Don Gagne's avatar
Don Gagne committed
600 601 602
            }
        }
    }
603

Don Gagne's avatar
Don Gagne committed
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
    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
                }
            }
623 624 625 626
        }
    }

    Component {
Don Gagne's avatar
Don Gagne committed
627
        id: radiusVisualsComponent
628 629

        Item {
Don Gagne's avatar
Don Gagne committed
630
            property var    circleCenterCoord:  mapPolygon.center
631

Don Gagne's avatar
Don Gagne committed
632 633
            function _calcRadiusDragCoord() {
                _circleRadiusDragCoord = circleCenterCoord.atDistanceAndAzimuth(_circleRadius, 90)
634 635
            }

Don Gagne's avatar
Don Gagne committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
            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)
652 653 654 655 656
            }
        }
    }
}