QGCMapPolygonVisuals.qml 23 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 32 33 34
    property color  interiorColor:      "transparent"
    property real   interiorOpacity:    1
    property int    borderWidth:        0
    property color  borderColor:        "black"
35

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

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

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

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

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

Don Gagne's avatar
Don Gagne committed
68 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) {
Don Gagne's avatar
Don Gagne committed
75
            _objMgrToolVisuals.createObject(toolbarComponent, mapControl)
76
        }
Don Gagne's avatar
Don Gagne committed
77 78 79 80 81 82 83 84 85
    }

    function removeToolVisuals() {
        _objMgrToolVisuals.destroyObjects()
    }

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

89 90 91
    /// 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
92
        var rect = Qt.rect(mapControl.centerViewport.x, mapControl.centerViewport.y, mapControl.centerViewport.width, mapControl.centerViewport.height)
93 94 95 96 97
        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
98 99 100 101 102
        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 */)
103 104 105 106 107 108 109 110 111 112 113 114 115

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

        return [ topLeftCoord, topRightCoord, bottomRightCoord, bottomLeftCoord, centerCoord  ]
    }

    /// Reset polygon back to initial default
Don Gagne's avatar
Don Gagne committed
116 117
    function _resetPolygon() {
        mapPolygon.beginReset()
118
        mapPolygon.clear()
Don Gagne's avatar
Don Gagne committed
119
        var initialVertices = defaultPolygonVertices()
120 121 122
        for (var i=0; i<4; i++) {
            mapPolygon.appendVertex(initialVertices[i])
        }
Don Gagne's avatar
Don Gagne committed
123 124
        mapPolygon.endReset()
        _circleMode = false
125 126
    }

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

    /// Reset polygon to a circle which fits within initial polygon
Don Gagne's avatar
Don Gagne committed
145
    function _resetCircle() {
146 147 148 149 150
        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]
Don Gagne's avatar
Don Gagne committed
151
        _createCircularPolygon(center, radius)
152 153
    }

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

Don Gagne's avatar
Don Gagne committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    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()
190 191 192
        }
    }

193 194 195 196 197 198 199 200 201 202 203 204 205
    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
206 207 208
    Component.onCompleted: {
        addCommonVisuals()
        _handleInteractiveChanged()
209
    }
DoinLakeFlyer's avatar
DoinLakeFlyer committed
210
    Component.onDestruction: mapPolygon.traceMode = false
211

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

218 219
    QGCPalette { id: qgcPal }

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

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

232
    QGCMenu {
233 234
        id: menu

235
        property int _editingVertexIndex: -1
236

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

        function popupCenter() {
244 245 246
            menu.popup()
        }

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

258
        QGCMenuSeparator {
259 260 261
            visible:        removeVertexItem.visible
        }

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

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

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

281 282 283 284
    Component {
        id: polygonComponent

        MapPolygon {
285 286 287 288 289
            color:          interiorColor
            opacity:        interiorOpacity
            border.color:   borderColor
            border.width:   borderWidth
            path:           mapPolygon.path
290 291 292 293 294 295 296 297
        }
    }

    Component {
        id: splitHandleComponent

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

            property int vertexIndex

304
            sourceItem: SplitIndicator {
305 306
                z:          _zorderSplitHandle
                onClicked:  mapPolygon.splitPolygonSegment(mapQuickItem.vertexIndex)
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 350 351
            }
        }
    }

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

            property int polygonVertex

            property bool _creationComplete: false

            Component.onCompleted: _creationComplete = true

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

371
            onClicked: menu.popupVertex(polygonVertex)
372 373 374
        }
    }

375 376 377 378
    Component {
        id: centerDragHandle
        MapQuickItem {
            id:             mapQuickItem
379 380
            anchorPoint.x:  dragHandle.width  * 0.5
            anchorPoint.y:  dragHandle.height * 0.5
381 382
            z:              _zorderDragHandle
            sourceItem: Rectangle {
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
                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
399 400 401 402 403
                }
            }
        }
    }

404 405 406 407 408
    Component {
        id: dragHandleComponent

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

            property int polygonVertex
415 416

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

    // 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 })
441
                    dragHandle.polygonVertex = Qt.binding(function() { return index })
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
                    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 = [ ]
                }
            }
        }
    }

459
    Component {
460
        id: editCenterPositionDialog
461 462 463

        EditPositionDialog {
            coordinate: mapPolygon.center
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
            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)
479 480 481 482
            onCoordinateChanged: {
                mapPolygon.adjustVertex(menu._editingVertexIndex, coordinate)
                mapPolygon.verifyClockwiseWinding()
            }
483 484 485
        }
    }

486 487 488 489
    Component {
        id: centerDragAreaComponent

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

Don Gagne's avatar
Don Gagne committed
498 499
    Component {
        id: centerDragHandleComponent
500

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

    Component {
Don Gagne's avatar
Don Gagne committed
520
        id: toolbarComponent
Don Gagne's avatar
Don Gagne committed
521

Don Gagne's avatar
Don Gagne committed
522
        PlanEditToolbar {
523 524 525 526 527
            anchors.horizontalCenter:       mapControl.left
            anchors.horizontalCenterOffset: mapControl.centerViewport.left + (mapControl.centerViewport.width / 2)
            y:                              mapControl.centerViewport.top
            z:                              QGroundControl.zOrderMapItems + 2
            availableWidth:                 mapControl.centerViewport.width
Don Gagne's avatar
Don Gagne committed
528

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

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

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

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

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

        MouseArea {
Don Gagne's avatar
Don Gagne committed
575
            anchors.fill:       mapControl
Don Gagne's avatar
Don Gagne committed
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
            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
            }
        }
    }
606

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

    Component {
Don Gagne's avatar
Don Gagne committed
630
        id: radiusVisualsComponent
631 632

        Item {
Don Gagne's avatar
Don Gagne committed
633
            property var    circleCenterCoord:  mapPolygon.center
634

Don Gagne's avatar
Don Gagne committed
635 636
            function _calcRadiusDragCoord() {
                _circleRadiusDragCoord = circleCenterCoord.atDistanceAndAzimuth(_circleRadius, 90)
637 638
            }

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