CenterMapDropButton.qml 8.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
/****************************************************************************
 *
 *   (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.
 *
 ****************************************************************************/

10 11 12 13
import QtQuick          2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts  1.2
import QtPositioning    5.3
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

import QGroundControl               1.0
import QGroundControl.ScreenTools   1.0
import QGroundControl.Controls      1.0
import QGroundControl.Palette       1.0

DropButton {
    id:                 dropButton
    dropDirection:      dropRight
    buttonImage:        "/qmlimages/MapCenter.svg"
    viewportMargins:    ScreenTools.defaultFontPixelWidth / 2
    lightBorders:       map.isSatelliteMap

    property var    map
    property rect   mapFitViewport
    property bool   usePlannedHomePosition      ///< true: planned home position used for calculations, false: vehicle home position use for calculations
    property var    geoFenceController
    property var    missionController
    property var    rallyPointController
    property bool   showMission:          true
    property bool   showAllItems:         true
    property bool   showFollowVehicle:    false
    property bool   followVehicle:        false

    property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle

    function fitHomePosition() {
        var homePosition = QtPositioning.coordinate()
        var activeVehicle = QGroundControl.multiVehicleManager.activeVehicle
        if (usePlannedHomePosition) {
            homePosition = missionController.visualItems.get(0).coordinate
        } else if (activeVehicle) {
            homePosition = activeVehicle.homePosition
        }
        return homePosition
    }

    /// Normalize latitude to range: 0 to 180, S to N
    function normalizeLat(lat) {
        return lat + 90.0
    }

    /// Normalize longitude to range: 0 to 360, W to E
    function normalizeLon(lon) {
        return lon  + 180.0
    }

    /// Fits the visible region of the map to inclues all of the specified coordinates. If no coordinates
    /// are specified the map will center to fitHomePosition()
    function fitMapViewportToAllCoordinates(coordList) {
64
        if (coordList.length === 0) {
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
            map.center = fitHomePosition()
            return
        }

        // Create the normalized lat/lon corners for the coordinate bounding rect from the list of coordinates
        var north = normalizeLat(coordList[0].latitude)
        var south = north
        var east = normalizeLon(coordList[0].longitude)
        var west = east
        for (var i=1; i<coordList.length; i++) {
            var lat = normalizeLat(coordList[i].latitude)
            var lon = normalizeLon(coordList[i].longitude)

            north = Math.max(north, lat)
            south = Math.min(south, lat)
            east = Math.max(east, lon)
            west = Math.min(west, lon)
        }

        // Expand the coordinate bounding rect to make room for the tools around the edge of the map
        var latDegreesPerPixel = (north - south) / mapFitViewport.width
        var lonDegreesPerPixel = (east - west) / mapFitViewport.height
        north = Math.min(north + (mapFitViewport.y * latDegreesPerPixel), 180)
        south = Math.max(south - ((map.height - mapFitViewport.bottom) * latDegreesPerPixel), 0)
        west = Math.max(west - (mapFitViewport.x * lonDegreesPerPixel), 0)
        east = Math.min(east + ((map.width - mapFitViewport.right) * lonDegreesPerPixel), 360)

        // Fix the map region to the new bounding rect
        var topLeftCoord = QtPositioning.coordinate(north - 90.0, west - 180.0)
        var bottomRightCoord  = QtPositioning.coordinate(south - 90.0, east - 180.0)
        map.setVisibleRegion(QtPositioning.rectangle(topLeftCoord, bottomRightCoord))
    }

    function addMissionItemCoordsForFit(coordList) {
        var homePosition = fitHomePosition()
        if (homePosition.isValid) {
            coordList.push(homePosition)
        }
        for (var i=1; i<missionController.visualItems.count; i++) {
            var missionItem = missionController.visualItems.get(i)
            if (missionItem.specifiesCoordinate && !missionItem.isStandaloneCoordinate) {
                coordList.push(missionItem.coordinate)
            }
        }
    }

    function fitMapViewportToMissionItems() {
        var coordList = [ ]
        addMissionItemCoordsForFit(coordList)
        fitMapViewportToAllCoordinates(coordList)
    }

    function addFenceItemCoordsForFit(coordList) {
118
        var i
119 120 121
        var homePosition = fitHomePosition()
        if (homePosition.isValid && geoFenceController.circleEnabled) {
            var azimuthList = [ 0, 180, 90, 270 ]
122
            for (i = 0; i < azimuthList.length; i++) {
123 124 125 126 127
                var edgeCoordinate = homePosition.atDistanceAndAzimuth(geoFenceController.circleRadius, azimuthList[i])
                coordList.push(edgeCoordinate)
            }
        }
        if (geoFenceController.polygonEnabled && geoFenceController.polygon.count() > 2) {
128
            for (i = 0; i < geoFenceController.polygon.count(); i++) {
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 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 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
                coordList.push(geoFenceController.polygon.path[i])
            }
        }
    }

    function fitMapViewportToFenceItems() {
        var coordList = [ ]
        addFenceItemCoordsForFit(coordList)
        fitMapViewportToAllCoordinates(coordList)
    }

    function addRallyItemCoordsForFit(coordList) {
        for (var i=0; i<rallyPointController.points.count; i++) {
            coordList.push(rallyPointController.points.get(i).coordinate)
        }
    }

    function fitMapViewportToRallyItems() {
        var coordList = [ ]
        addRallyItemCoordsForFit(coordList)
        fitMapViewportToAllCoordinates(coordList)
    }

    function fitMapViewportToAllItems() {
        var coordList = [ ]
        addMissionItemCoordsForFit(coordList)
        addFenceItemCoordsForFit(coordList)
        addRallyItemCoordsForFit(coordList)
        fitMapViewportToAllCoordinates(coordList)
    }

    dropDownComponent: Component {
        ColumnLayout {
            spacing: ScreenTools.defaultFontPixelWidth * 0.5

            QGCLabel { text: qsTr("Center map on:") }

            QGCButton {
                text:               qsTr("Mission")
                Layout.fillWidth:   true
                visible:            showMission
                enabled:            !followVehicleCheckBox.checked

                onClicked: {
                    dropButton.hideDropDown()
                    fitMapViewportToMissionItems()
                }
            }

            QGCButton {
                text:               qsTr("All items")
                Layout.fillWidth:   true
                visible:            showAllItems
                enabled:            !followVehicleCheckBox.checked

                onClicked: {
                    dropButton.hideDropDown()
                    fitMapViewportToAllItems()
                }
            }

            QGCButton {
                text:               qsTr("Home")
                Layout.fillWidth:   true
                enabled:            !followVehicleCheckBox.checked

                onClicked: {
                    dropButton.hideDropDown()
                    map.center = fitHomePosition()
                }
            }

            QGCButton {
                text:               qsTr("Current Location")
                Layout.fillWidth:   true
DonLakeFlyer's avatar
DonLakeFlyer committed
204
                enabled:            map.gcsPosition ? map.gcsPosition.isValid && !followVehicleCheckBox.checked : false
205 206 207

                onClicked: {
                    dropButton.hideDropDown()
DonLakeFlyer's avatar
DonLakeFlyer committed
208
                    map.center = map.gcsPosition
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
                }
            }

            QGCButton {
                text:               qsTr("Vehicle")
                Layout.fillWidth:   true
                enabled:            _activeVehicle && _activeVehicle.latitude != 0 && _activeVehicle.longitude != 0 && !followVehicleCheckBox.checked

                onClicked: {
                    dropButton.hideDropDown()
                    map.center = activeVehicle.coordinate
                }
            }

            QGCCheckBox {
                id:         followVehicleCheckBox
                text:       qsTr("Follow Vehicle")
                checked:    followVehicle
                visible:    showFollowVehicle

                onClicked:  {
                    dropButton.hideDropDown()
                    dropButton.followVehicle = checked
                }
            }
        } // Column
    } // Component - dropDownComponent
} // DropButton