CenterMapDropButton.qml 8.8 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.
 *
 ****************************************************************************/

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

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

    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) {
62
        if (coordList.length === 0) {
63 64 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
            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) {
116
        var i
117 118 119
        var homePosition = fitHomePosition()
        if (homePosition.isValid && geoFenceController.circleEnabled) {
            var azimuthList = [ 0, 180, 90, 270 ]
120
            for (i = 0; i < azimuthList.length; i++) {
121 122 123 124 125
                var edgeCoordinate = homePosition.atDistanceAndAzimuth(geoFenceController.circleRadius, azimuthList[i])
                coordList.push(edgeCoordinate)
            }
        }
        if (geoFenceController.polygonEnabled && geoFenceController.polygon.count() > 2) {
126
            for (i = 0; i < geoFenceController.polygon.count(); i++) {
127 128 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
                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 {
189
                text:               qsTr("Launch")
190 191 192 193 194 195 196 197 198 199 200 201
                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
202
                enabled:            map.gcsPosition ? map.gcsPosition.isValid && !followVehicleCheckBox.checked : false
203 204 205

                onClicked: {
                    dropButton.hideDropDown()
DonLakeFlyer's avatar
DonLakeFlyer committed
206
                    map.center = map.gcsPosition
207 208 209
                }
            }

210 211 212 213 214 215 216 217 218 219 220

            QGCButton {
                text:               qsTr("Specified Location")
                Layout.fillWidth:   true

                onClicked: {
                    dropButton.hideDropDown()
                    map.centerToSpecifiedLocation()
                }
            }

221 222 223
            QGCButton {
                text:               qsTr("Vehicle")
                Layout.fillWidth:   true
224
                enabled:            activeVehicle && activeVehicle.latitude != 0 && activeVehicle.longitude != 0 && !followVehicleCheckBox.checked
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

                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