Skip to content
Snippets Groups Projects
FlightMap.qml 15.2 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
        }
    
    
        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()
        }
    
    
        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
    
        QGCLabel {
            id:                     polygonHelp
            anchors.topMargin:      parent.height - ScreenTools.availableHeight
            anchors.top:            parent.top
            anchors.left:           parent.left
            anchors.right:          parent.right
            horizontalAlignment:    Text.AlignHCenter
            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:       polygonDrawerPolygon.path.length > 3 ///< true: enough points have been captured to create a closed polygon
    
    
            /// New polygon capture has started
    
            signal polygonCaptureStarted
    
    
            /// Polygon capture is complete
            ///     @param coordinates Map coordinates for the polygon points
    
            signal polygonCaptureFinished(var coordinates)
    
            /// Polygon adjustment has begun
            signal polygonAdjustStarted
    
            /// Polygon Vertex coordinate has been adjusted
            signal polygonAdjustVertex(int vertexIndex, var vertexCoordinate)
    
            /// Polygon adjustment finished
            signal polygonAdjustFinished
    
            property var _vertexDragList: []
    
    
            /// Begin capturing a new polygon
    
            ///     polygonCaptureStarted will be signalled
            function startCapturePolygon() {
    
                polygonDrawer.drawingPolygon = true
                polygonDrawer._clearPolygon()
    
                polygonDrawer.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 = polygonDrawerPolygon.path
                polygonPath.pop() // get rid of drag coordinate
                polygonDrawer._clearPolygon()
                polygonDrawer.drawingPolygon = false
    
                polygonDrawer.polygonCaptureFinished(polygonPath)
    
            function startAdjustPolygon(vertexCoordinates) {
                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.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.polygonAdjustStarted()
                }
            }
    
            function finishAdjustPolygon() {
                polygonDrawer.adjustingPolygon = false
                for (var i=0; i<polygonDrawer._vertexDragList.length; i++) {
                    polygonDrawer._vertexDragList[i].destroy()
                }
                polygonDrawer._vertexDragList = []
                polygonDrawer.polygonAdjustFinished()
            }
    
    
            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 = [ ]
            }
    
            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
                    if (polygonPath.length == 0) {
                        // Add first coordinate
                        polygonPath.push(clickCoordinate)
                    } else {
                        // Update finalized coordinate
                        polygonPath[polygonDrawerPolygon.path.length - 1] = clickCoordinate
                    }
                    // Add next drag coordinate
                    polygonPath.push(clickCoordinate)
                    polygonDrawerPolygon.path = polygonPath
                } else if (polygonDrawer.polygonReady) {
    
                    finishCapturePolygon()
    
                }
            }
    
            onPositionChanged: {
                if (polygonDrawerPolygon.path.length) {
                    var dragCoordinate = _map.toCoordinate(Qt.point(mouse.x, mouse.y))
    
                    // Update drag line
                    polygonDrawerNextPoint.path = [ polygonDrawerPolygon.path[polygonDrawerPolygon.path.length - 2], dragCoordinate ]
    
                    // Update drag coordinate
                    var polygonPath = polygonDrawerPolygon.path
                    polygonPath[polygonDrawerPolygon.path.length - 1] = dragCoordinate
                    polygonDrawerPolygon.path = polygonPath
                }
            }
        }
    
    
        /// Polygon being drawn
    
        MapPolygon {
            id:         polygonDrawerPolygon
            color:      "blue"
            opacity:    0.5
            visible:    polygonDrawer.drawingPolygon
        }
    
    
        /// Next line for polygon
    
        MapPolyline {
            id:         polygonDrawerNextPoint
            line.color: "green"
            line.width: 5
            visible:    polygonDrawer.drawingPolygon
        }
    
        //---- End Polygon Drawing code