Skip to content
Snippets Groups Projects
FlightMap.qml 16.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • /****************************************************************************
     *
     *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
     *
     * QGroundControl is licensed according to the terms in the file
     * COPYING.md in the root of the source code directory.
     *
     ****************************************************************************/
    
    dogmaphobic's avatar
    dogmaphobic committed
    
    
    /**
     * @file
     *   @brief QGC Map Background
     *   @author Gus Grubba <mavlink@grubba.com>
     */
    
    
    import QtQuick          2.4
    
    import QtQuick.Controls 1.3
    
    import QtLocation       5.3
    import QtPositioning    5.3
    
    import QGroundControl                       1.0
    
    dogmaphobic's avatar
    dogmaphobic committed
    import QGroundControl.FactSystem            1.0
    
    import QGroundControl.Controls              1.0
    
    import QGroundControl.FlightMap             1.0
    
    import QGroundControl.ScreenTools           1.0
    import QGroundControl.MultiVehicleManager   1.0
    import QGroundControl.Vehicle               1.0
    
    import QGroundControl.Mavlink               1.0
    
    dogmaphobic's avatar
    dogmaphobic committed
    
    
        property string mapName:            'defaultMap'
    
        property bool   isSatelliteMap:     activeMapType.name.indexOf("Satellite") > -1 || activeMapType.name.indexOf("Hybrid") > -1
    
    dogmaphobic's avatar
    dogmaphobic committed
        readonly property real  maxZoomLevel: 20
        property variant        scaleLengths: [5, 10, 25, 50, 100, 150, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000]
    
        function formatDistance(meters)
        {
            var dist = Math.round(meters)
            if (dist > 1000 ){
                if (dist > 100000){
                    dist = Math.round(dist / 1000)
                }
                else{
                    dist = Math.round(dist / 100)
                    dist = dist / 10
                }
                dist = dist + " km"
            }
            else{
                dist = dist + " m"
            }
            return dist
        }
    
        function calculateScale() {
            var coord1, coord2, dist, text, f
            f = 0
            coord1 = _map.toCoordinate(Qt.point(0, scale.y))
            coord2 = _map.toCoordinate(Qt.point(0 + scaleImage.sourceSize.width, scale.y))
            dist = Math.round(coord1.distanceTo(coord2))
            if (dist === 0) {
                // not visible
            } else {
                for (var i = 0; i < scaleLengths.length - 1; i++) {
                    if (dist < (scaleLengths[i] + scaleLengths[i+1]) / 2 ) {
                        f = scaleLengths[i] / dist
                        dist = scaleLengths[i]
                        break;
                    }
                }
                if (f === 0) {
                    f = dist / scaleLengths[i]
                    dist = scaleLengths[i]
                }
            }
            text = formatDistance(dist)
            scaleImage.width = (scaleImage.sourceSize.width * f) - 2 * scaleImageLeft.sourceSize.width
            scaleText.text = text
        }
    
        function setVisibleRegion(region) {
            // This works around a bug on Qt where if you set a visibleRegion and then the user moves or zooms the map
            // and then you set the same visibleRegion the map will not move/scale appropriately since it thinks there
            // is nothing to do.
            _map.visibleRegion = QtPositioning.rectangle(QtPositioning.coordinate(0, 0), QtPositioning.coordinate(0, 0))
            _map.visibleRegion = region
        }
    
    
        zoomLevel:                  18
    
        center:                     QGroundControl.lastKnownHomePosition
    
        gesture.flickDeceleration:  3000
    
        plugin: Plugin { name: "QGroundControl" }
    
    Don Gagne's avatar
    Don Gagne committed
        ExclusiveGroup { id: mapTypeGroup }
    
        property bool _initialMapPositionSet: false
    
        Connections {
            target: mainWindow
            onGcsPositionChanged: {
                if (!_initialMapPositionSet) {
                    _initialMapPositionSet = true
    
    Don Gagne's avatar
    Don Gagne committed
                    center = mainWindow.gcsPosition
    
        function updateActiveMapType() {
            var fullMapName = QGroundControl.flightMapSettings.mapProvider + " " + QGroundControl.flightMapSettings.mapType
    
    Don Gagne's avatar
    Don Gagne committed
            for (var i = 0; i < _map.supportedMapTypes.length; i++) {
    
                if (fullMapName === _map.supportedMapTypes[i].name) {
    
    Don Gagne's avatar
    Don Gagne committed
                    _map.activeMapType = _map.supportedMapTypes[i]
    
        Component.onCompleted: updateActiveMapType()
    
        Connections {
            target:             QGroundControl.flightMapSettings
            onMapTypeChanged:   updateActiveMapType()
        }
    
    
        /// Ground Station location
    
        MapQuickItem {
            anchorPoint.x:  sourceItem.width  / 2
            anchorPoint.y:  sourceItem.height / 2
            visible:        mainWindow.gcsPosition.isValid
            coordinate:     mainWindow.gcsPosition
    
    dogmaphobic's avatar
    dogmaphobic committed
            sourceItem:     MissionItemIndexLabel {
    
    
        //---- Polygon drawing code
    
        //
        // Usage:
        //
        // Connections {
        //     target: map.polygonDraw
        //
    
        //    onPolygonCaptureStarted: {
    
        //      // Polygon creation has started
        //    }
        //
    
        //    onPolygonCaptureFinished: {
    
        //      // Polygon capture complete, coordinates signal variable contains the polygon points
        //    }
        // }
        //
        // map.polygonDraqw.startPolgyon() - begin capturing a new polygon
        // map.polygonDraqw.endPolygon() - end capture (right-click will also end capture)
    
        // Not sure why this is needed, but trying to reference polygonDrawer directly from other code doesn't work
        property alias polygonDraw: polygonDrawer
    
    
        QGCMapLabel {
            id:                     polygonHelp        
    
            anchors.topMargin:      parent.height - ScreenTools.availableHeight
            anchors.top:            parent.top
            anchors.left:           parent.left
            anchors.right:          parent.right
            horizontalAlignment:    Text.AlignHCenter
    
            map:                    _map
    
            text:                   qsTr("Click to add point %1").arg(ScreenTools.isMobile || !polygonDrawer.polygonReady ? "" : qsTr("- Right Click to end polygon"))
            visible:                polygonDrawer.drawingPolygon
    
    
            Connections {
                target: polygonDrawer
    
                onDrawingPolygonChanged: {
                    if (polygonDrawer.drawingPolygon) {
                        polygonHelp.text = qsTr("Click to add point")
                    }
                    polygonHelp.visible = polygonDrawer.drawingPolygon
                }
    
                onPolygonReadyChanged: {
                    if (polygonDrawer.polygonReady && !ScreenTools.isMobile) {
                        polygonHelp.text = qsTr("Click to add point - Right Click to end polygon")
                    }
                }
    
                onAdjustingPolygonChanged: {
                    if (polygonDrawer.adjustingPolygon) {
                        polygonHelp.text = qsTr("Adjust polygon by dragging corners")
                    }
                    polygonHelp.visible = polygonDrawer.adjustingPolygon
                }
            }
    
        }
    
        MouseArea {
            id:                 polygonDrawer
            anchors.fill:       parent
            acceptedButtons:    Qt.LeftButton | Qt.RightButton
            visible:            drawingPolygon
            z:                  1000 // Hack to fix MouseArea layering for now
    
    
            property alias  drawingPolygon:     polygonDrawer.hoverEnabled
            property bool   adjustingPolygon:   false
    
            property bool   polygonReady:       polygonDrawerPolygonSet.path.length > 2 ///< true: enough points have been captured to create a closed polygon
            property bool   justClicked: false
    
            property var _callbackObject
    
    
            property var _vertexDragList: []
    
    
            /// Begin capturing a new polygon
    
            ///     polygonCaptureStarted will be signalled
    
            function startCapturePolygon(callback) {
                polygonDrawer._callbackObject = callback
    
                polygonDrawer.drawingPolygon = true
                polygonDrawer._clearPolygon()
    
                polygonDrawer._callbackObject.polygonCaptureStarted()
    
            }
    
            /// Finish capturing the polygon
    
            ///     polygonCaptureFinished will be signalled
    
            /// @return true: polygon completed, false: not enough points to complete polygon
    
            function finishCapturePolygon() {
    
                if (!polygonDrawer.polygonReady) {
                    return false
                }
    
    
                var polygonPath = polygonDrawerPolygonSet.path
    
                _cancelCapturePolygon()
    
                polygonDrawer._callbackObject.polygonCaptureFinished(polygonPath)
    
            function startAdjustPolygon(callback, vertexCoordinates) {
                polygonDraw._callbackObject = callback
    
                polygonDrawer.adjustingPolygon = true
                for (var i=0; i<vertexCoordinates.length; i++) {
                    var mapItem = Qt.createQmlObject(
                                "import QtQuick                     2.5; " +
                                "import QtLocation                  5.3; " +
                                "import QGroundControl.ScreenTools  1.0; " +
                                "Rectangle {" +
                                "   id:     vertexDrag; " +
                                "   width:  _sideLength; " +
                                "   height: _sideLength; " +
                                "   color:  'red'; " +
                                "" +
                                "   property var coordinate; " +
                                "   property int index; " +
                                "" +
                                "   readonly property real _sideLength:     ScreenTools.defaultFontPixelWidth * 2; " +
                                "   readonly property real _halfSideLength: _sideLength / 2; " +
                                "" +
                                "   Drag.active:    dragMouseArea.drag.active; " +
                                "   Drag.hotSpot.x: _halfSideLength; " +
                                "   Drag.hotSpot.y: _halfSideLength; " +
                                "" +
                                "   onXChanged: updateCoordinate(); " +
                                "   onYChanged: updateCoordinate(); " +
                                "" +
                                "   function updateCoordinate() { " +
                                "       vertexDrag.coordinate = _map.toCoordinate(Qt.point(vertexDrag.x + _halfSideLength, vertexDrag.y + _halfSideLength), false); " +
    
                                "       polygonDrawer._callbackObject.polygonAdjustVertex(vertexDrag.index, vertexDrag.coordinate); " +
    
                                "   } " +
                                "" +
                                "   function updatePosition() { " +
                                "       var vertexPoint = _map.fromCoordinate(coordinate, false); " +
                                "       vertexDrag.x = vertexPoint.x - _halfSideLength; " +
                                "       vertexDrag.y = vertexPoint.y - _halfSideLength; " +
                                "   } " +
                                "" +
                                "   Connections { " +
                                "       target: _map; " +
                                "       onCenterChanged: updatePosition(); " +
                                "       onZoomLevelChanged: updatePosition(); " +
                                "   } " +
                                "" +
                                "   MouseArea { " +
                                "       id:             dragMouseArea; " +
                                "       anchors.fill:   parent; " +
                                "       drag.target:    parent; " +
                                "       drag.minimumX:  0; " +
                                "       drag.minimumY:  0; " +
                                "       drag.maximumX:  _map.width - parent.width; " +
                                "       drag.maximumY:  _map.height - parent.height; " +
                                "   } " +
                                "} ",
                                _map)
                    mapItem.z = QGroundControl.zOrderMapItems + 1
                    mapItem.coordinate = vertexCoordinates[i]
                    mapItem.index = i
                    mapItem.updatePosition()
                    polygonDrawer._vertexDragList.push(mapItem)
    
                    polygonDrawer._callbackObject.polygonAdjustStarted()
    
                }
            }
    
            function finishAdjustPolygon() {
    
                _cancelAdjustPolygon()
                polygonDrawer._callbackObject.polygonAdjustFinished()
            }
    
            /// Cancels an in progress draw or adjust
            function cancelPolygonEdit() {
                _cancelAdjustPolygon()
                _cancelCapturePolygon()
            }
    
            function _cancelAdjustPolygon() {
    
                polygonDrawer.adjustingPolygon = false
                for (var i=0; i<polygonDrawer._vertexDragList.length; i++) {
                    polygonDrawer._vertexDragList[i].destroy()
                }
                polygonDrawer._vertexDragList = []
    
            }
    
            function _cancelCapturePolygon() {
                polygonDrawer._clearPolygon()
                polygonDrawer.drawingPolygon = false
    
            function _clearPolygon() {
                // Simpler methods to clear the path simply don't work due to bugs. This craziness does.
                var bogusCoord = _map.toCoordinate(Qt.point(height/2, width/2))
                polygonDrawerPolygon.path = [ bogusCoord, bogusCoord ]
                polygonDrawerNextPoint.path = [ bogusCoord, bogusCoord ]
                polygonDrawerPolygon.path = [ ]
                polygonDrawerNextPoint.path = [ ]
    
                polygonDrawerPolygonSet.path = [ bogusCoord, bogusCoord ]
                polygonDrawerPolygonSet.path = [ ]
    
            }
    
            onClicked: {
                if (mouse.button == Qt.LeftButton) {
    
                    if (polygonDrawerPolygon.path.length > 2) {
                        // Make sure the new line doesn't intersect the existing polygon
                        var lastSegment = polygonDrawerPolygon.path.length - 2
                        var newLineA = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment], false /* clipToViewPort */)
                        var newLineB = _map.fromCoordinate(polygonDrawerPolygon.path[lastSegment+1], false /* clipToViewPort */)
                        for (var i=0; i<lastSegment; i++) {
                            var oldLineA = _map.fromCoordinate(polygonDrawerPolygon.path[i], false /* clipToViewPort */)
                            var oldLineB = _map.fromCoordinate(polygonDrawerPolygon.path[i+1], false /* clipToViewPort */)
                            if (QGroundControl.linesIntersect(newLineA, newLineB, oldLineA, oldLineB)) {
                                return;
                            }
                        }
                    }
    
                    var clickCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))
                    var polygonPath = polygonDrawerPolygon.path
    
    nickexists's avatar
    nickexists committed
                    if (polygonPath.length == 0) {
    
                        // Add first coordinate
                        polygonPath.push(clickCoordinate)
                    } else {
    
    Don Gagne's avatar
    Don Gagne committed
                        // Add subsequent coordinate
                        if (ScreenTools.isMobile) {
                            // Since mobile has no mouse, the onPositionChangedHandler will not fire. We have to add the coordinate
                            // here instead.
                            polygonDrawer.justClicked = false
                            polygonPath.push(clickCoordinate)
                        } else {
                            // The onPositionChanged handler for mouse movement will have already added the coordinate to the array.
                            // Just update it to the final position
                            polygonPath[polygonDrawerPolygon.path.length - 1] = clickCoordinate
                        }
    
                    polygonDrawerPolygonSet.path = polygonPath
    
                    polygonDrawerPolygon.path = polygonPath
                } else if (polygonDrawer.polygonReady) {
    
                    finishCapturePolygon()
    
    Don Gagne's avatar
    Don Gagne committed
                if (ScreenTools.isMobile) {
                    // We don't track mouse drag on mobile
                    return
                }
    
                if (polygonDrawerPolygon.path.length) {
                    var dragCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))
    
                    var polygonPath = polygonDrawerPolygon.path
                    if (polygonDrawer.justClicked){
    
    Don Gagne's avatar
    Don Gagne committed
                        // Add new drag coordinate
    
                        polygonPath.push(dragCoordinate)
                        polygonDrawer.justClicked = false
                    }
    
    
                    // Update drag line
                    polygonDrawerNextPoint.path = [ polygonDrawerPolygon.path[polygonDrawerPolygon.path.length - 2], dragCoordinate ]
    
                    polygonPath[polygonDrawerPolygon.path.length - 1] = dragCoordinate
    
        /// Polygon being drawn
    
        MapPolygon {
            id:         polygonDrawerPolygon
            color:      "blue"
            opacity:    0.5
    
            visible:    polygonDrawerPolygon.path.length > 2
        }
        MapPolygon {
            id:         polygonDrawerPolygonSet
            color:      'green'
            opacity:    0.5
            visible:    polygonDrawer.polygonReady
    
        /// Next line for polygon
    
        MapPolyline {
            id:         polygonDrawerNextPoint
            line.color: "green"
    
            visible:    polygonDrawer.drawingPolygon
        }
    
        //---- End Polygon Drawing code