diff --git a/src/FlightDisplay/FlightDisplayViewMap.qml b/src/FlightDisplay/FlightDisplayViewMap.qml index c8a7f213e3d8c9d7d4b483be2db4997f59c24b77..5c714a8f90a1f2280937200d23030f58e45e94cb 100644 --- a/src/FlightDisplay/FlightDisplayViewMap.qml +++ b/src/FlightDisplay/FlightDisplayViewMap.qml @@ -223,21 +223,21 @@ FlightMap { missionItems: wimaController.missionItems path: wimaController.waypointPath showItems: _wimaEnabled && _showAllWimaItems - zOrderWP: QGroundControl.zOrderWaypointIndicators-3 - zOrderLines: QGroundControl.zOrderWaypointLines-1 + zOrderWP: QGroundControl.zOrderWaypointIndicators-2 + zOrderLines: QGroundControl.zOrderWaypointLines-2 color: "gray" } // current Items - /*WimaPlanMapItems { + WimaPlanMapItems { map: flightMap largeMapView: _mainIsMap missionItems: wimaController.currentMissionItems path: wimaController.currentWaypointPath showItems: _wimaEnabled && _showCurrentWimaItems zOrderWP: QGroundControl.zOrderWaypointIndicators-1 - zOrderLines: QGroundControl.zOrderWaypointIndicators-2 - color: "green" // gray with alpha 0.7 - }*/ + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "green" + } // Add trajectory points to the map MapItemView { diff --git a/src/FlightDisplay/FlightDisplayViewMap.qml.orig b/src/FlightDisplay/FlightDisplayViewMap.qml.orig new file mode 100644 index 0000000000000000000000000000000000000000..d9456d5452feb1351cacd52916986a1f4a358d34 --- /dev/null +++ b/src/FlightDisplay/FlightDisplayViewMap.qml.orig @@ -0,0 +1,578 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.FlightMap 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Vehicle 1.0 + +FlightMap { + id: flightMap + anchors.fill: parent + mapName: _mapName + allowGCSLocationCenter: !userPanned + allowVehicleLocationCenter: !_keepVehicleCentered + planView: false + + + property alias scaleState: mapScale.state + + // The following properties must be set by the consumer + property var planMasterController + property var wimaController + property var guidedActionsController + property var flightWidgets + property var rightPanelWidth + property var qgcView ///< QGCView control which contains this map + property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view + + property rect centerViewport: Qt.rect(0, 0, width, height) + + property var _planMasterController: planMasterController + property var _missionController: _planMasterController.missionController + property var _geoFenceController: _planMasterController.geoFenceController + property var _rallyPointController: _planMasterController.rallyPointController + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() + property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) + property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + + property bool _disableVehicleTracking: false + property bool _keepVehicleCentered: _mainIsMap ? false : true + + property bool _wimaEnabled: wimaController.enableWimaController.value + property bool _showAllWimaItems: wimaController.showAllMissionItems.value + property bool _showCurrentWimaItems: wimaController.showCurrentMissionItems.value + + function updateAirspace(reset) { + if(_airspaceEnabled) { + var coordinateNW = flightMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */) + var coordinateSE = flightMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */) + if(coordinateNW.isValid && coordinateSE.isValid) { + QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset) + } + } + } + + // Track last known map position and zoom from Fly view in settings + + onZoomLevelChanged: { + QGroundControl.flightMapZoom = zoomLevel + updateAirspace(false) + } + onCenterChanged: { + QGroundControl.flightMapPosition = center + updateAirspace(false) + } + + // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires + onUserPannedChanged: { + if (userPanned) { + console.log("user panned") + userPanned = false + _disableVehicleTracking = true + panRecenterTimer.restart() + } + } + + on_AirspaceEnabledChanged: { + updateAirspace(true) + } + + function pointInRect(point, rect) { + return point.x > rect.x && + point.x < rect.x + rect.width && + point.y > rect.y && + point.y < rect.y + rect.height; + } + + property real _animatedLatitudeStart + property real _animatedLatitudeStop + property real _animatedLongitudeStart + property real _animatedLongitudeStop + property real animatedLatitude + property real animatedLongitude + + onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + + NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 } + NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 } + + function animatedMapRecenter(fromCoord, toCoord) { + _animatedLatitudeStart = fromCoord.latitude + _animatedLongitudeStart = fromCoord.longitude + _animatedLatitudeStop = toCoord.latitude + _animatedLongitudeStop = toCoord.longitude + animateLat.start() + animateLong.start() + } + + function recenterNeeded() { + var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */) + var toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width + var instrumentsWidth = 0 + if (QGroundControl.corePlugin.options.instrumentWidget && QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) { + // Assume standard instruments + instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth() + } + var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height) + return !pointInRect(vehiclePoint, centerViewport) + } + + function updateMapToVehiclePosition() { + // We let FlightMap handle first vehicle position + if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) { + if (_keepVehicleCentered) { + flightMap.center = _activeVehicleCoordinate + } else { + if (firstVehiclePositionReceived && recenterNeeded()) { + animatedMapRecenter(flightMap.center, _activeVehicleCoordinate) + } + } + } + } + + Timer { + id: panRecenterTimer + interval: 10000 + running: false + + onTriggered: { + _disableVehicleTracking = false + updateMapToVehiclePosition() + } + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: updateMapToVehiclePosition() + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } + + Connections { + target: _missionController + + onNewItemsFromVehicle: { + var visualItems = _missionController.visualItems + if (visualItems && visualItems.count !== 1) { + mapFitFunctions.fitMapViewportToMissionItems() + firstVehiclePositionReceived = true + } + } + } + + ExclusiveGroup { + id: _mapTypeButtonsExclusiveGroup + } + + MapFitFunctions { + id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! + map: _flightMap + usePlannedHomePosition: false + planMasterController: _planMasterController + + property real leftToolWidth: toolStrip.x + toolStrip.width + } + + // Add wima Areas to the Map + MapItemView { + property bool _enableWima: wimaController.enableWimaController.value + + model: _enableWima ? wimaController.visualItems : 0 + + delegate: MapPolygon{ + path: object.path; + border.color: "black" + color: object.type === "WimaJoinedAreaData" ? "gray" + : object.type === "WimaServiceAreaData" ? "yellow" + : object.type === "WimaMeasurementAreaData" ? "green" + : "transparent" + opacity: 0.25 + z: 0 + } + } + + // Add mission items generated by wima planer to the map + // all Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.missionItems + path: wimaController.waypointPath + showItems: _wimaEnabled && _showAllWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-2 + zOrderLines: QGroundControl.zOrderWaypointLines-2 + color: "gray" + } + // current Items + /*WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.currentMissionItems + path: wimaController.currentWaypointPath + showItems: _wimaEnabled && _showCurrentWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-1 +<<<<<<< HEAD + zOrderLines: QGroundControl.zOrderWaypointIndicators-2 + color: "green" // gray with alpha 0.7 + }*/ +======= + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "green" + } +>>>>>>> temp + + // Add trajectory points to the map + MapItemView { + model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0 + + delegate: MapPolyline { + line.width: 3 + line.color: "red" + z: QGroundControl.zOrderTrajectoryLines + path: [ + object.coordinate1, + object.coordinate2, + ] + } + } + + // Add the vehicles to the map + MapItemView { + model: QGroundControl.multiVehicleManager.vehicles + + delegate: VehicleMapItem { + vehicle: object + coordinate: object.coordinate + map: flightMap + size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight + z: QGroundControl.zOrderVehicles + } + } + + // Add ADSB vehicles to the map + MapItemView { + model: _activeVehicle ? _activeVehicle.adsbVehicles : [] + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + delegate: VehicleMapItem { + coordinate: object.coordinate + altitude: object.altitude + callsign: object.callsign + heading: object.heading + alert: object.alert + map: flightMap + z: QGroundControl.zOrderVehicles + } + } + + // Add the items associated with each vehicles flight plan to the map + Repeater { + model: QGroundControl.multiVehicleManager.vehicles + + PlanMapItems { + map: flightMap + largeMapView: _mainIsMap + masterController: masterController + isActiveVehicle: _vehicle.active + + property var _vehicle: object + + PlanMasterController { + id: masterController + Component.onCompleted: startStaticActiveVehicle(object) + } + } + } + + // Allow custom builds to add map items + CustomMapItems { + map: flightMap + largeMapView: _mainIsMap + } + + GeoFenceMapVisuals { + map: flightMap + myGeoFenceController: _geoFenceController + interactive: false + planView: false + homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate() + } + + // Rally points on map + MapItemView { + model: _rallyPointController.points + + delegate: MapQuickItem { + id: itemIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: object.coordinate + z: QGroundControl.zOrderMapItems + + sourceItem: MissionItemIndexLabel { + id: itemIndexLabel + label: qsTr("R", "rally point map item label") + } + } + } + + // Camera trigger points + MapItemView { + model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0 + + delegate: CameraTriggerIndicator { + coordinate: object.coordinate + z: QGroundControl.zOrderTopMost + } + } + + // GoTo Location visuals + MapQuickItem { + id: gotoLocationItem + visible: false + z: QGroundControl.zOrderMapItems + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Goto here", "Goto here waypoint") + } + + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + gotoLocationItem.coordinate = coord + gotoLocationItem.visible = true + } + + function hide() { + gotoLocationItem.visible = false + } + + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + + // Orbit editing visuals + QGCMapCircleVisuals { + id: orbitMapCircle + mapControl: parent + mapCircle: _mapCircle + visible: false + + property alias center: _mapCircle.center + property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle + + readonly property real defaultRadius: 30 + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + _mapCircle.radius.rawValue = defaultRadius + orbitMapCircle.center = coord + orbitMapCircle.visible = true + } + + function hide() { + orbitMapCircle.visible = false + } + + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + + function radius() { + return _mapCircle.radius.rawValue + } + + Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle + + QGCMapCircle { + id: _mapCircle + interactive: true + radius.rawValue: 30 + showRotation: true + clockwiseRotation: true + } + } + + // Orbit telemetry visuals + QGCMapCircleVisuals { + id: orbitTelemetryCircle + mapControl: parent + mapCircle: _activeVehicle ? _activeVehicle.orbitMapCircle : null + visible: _activeVehicle ? _activeVehicle.orbitActive : false + } + + MapQuickItem { + id: orbitCenterIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate() + visible: orbitTelemetryCircle.visible + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Orbit", "Orbit waypoint") + } + } + + // Handle guided mode clicks + MouseArea { + anchors.fill: parent + + Menu { + id: clickMenu + + property var coord + + MenuItem { + text: qsTr("Go to location") + visible: guidedActionsController.showGotoLocation + + onTriggered: { + gotoLocationItem.show(clickMenu.coord) + orbitMapCircle.hide() + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) + } + } + + MenuItem { + text: qsTr("Orbit at location") + visible: guidedActionsController.showOrbit + + onTriggered: { + orbitMapCircle.show(clickMenu.coord) + gotoLocationItem.hide() + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) + } + } + } + + onClicked: { + if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) { + return + } + orbitMapCircle.hide() + gotoLocationItem.hide() + var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */) + if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) { + clickMenu.coord = clickCoord + clickMenu.popup() + } else if (guidedActionsController.showGotoLocation) { + gotoLocationItem.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord) + } else if (guidedActionsController.showOrbit) { + orbitMapCircle.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord) + } + } + } + + MapScale { + id: mapScale + anchors.right: parent.right + anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33) + anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight + anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33) + mapControl: flightMap + visible: !ScreenTools.isTinyScreen + state: "bottomMode" + states: [ + State { + name: "topMode" + AnchorChanges { + target: mapScale + anchors.top: parent.top + anchors.bottom: undefined + } + }, + State { + name: "bottomMode" + AnchorChanges { + target: mapScale + anchors.top: undefined + anchors.bottom: parent.bottom + } + } + ] + } + + // Airspace overlap support + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : [] + delegate: MapCircle { + center: object.center + radius: object.radius + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : [] + delegate: MapPolygon { + path: object.polygon + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + +} diff --git a/src/FlightDisplay/FlightDisplayViewMap_BACKUP_16429.qml b/src/FlightDisplay/FlightDisplayViewMap_BACKUP_16429.qml new file mode 100644 index 0000000000000000000000000000000000000000..d9456d5452feb1351cacd52916986a1f4a358d34 --- /dev/null +++ b/src/FlightDisplay/FlightDisplayViewMap_BACKUP_16429.qml @@ -0,0 +1,578 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.FlightMap 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Vehicle 1.0 + +FlightMap { + id: flightMap + anchors.fill: parent + mapName: _mapName + allowGCSLocationCenter: !userPanned + allowVehicleLocationCenter: !_keepVehicleCentered + planView: false + + + property alias scaleState: mapScale.state + + // The following properties must be set by the consumer + property var planMasterController + property var wimaController + property var guidedActionsController + property var flightWidgets + property var rightPanelWidth + property var qgcView ///< QGCView control which contains this map + property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view + + property rect centerViewport: Qt.rect(0, 0, width, height) + + property var _planMasterController: planMasterController + property var _missionController: _planMasterController.missionController + property var _geoFenceController: _planMasterController.geoFenceController + property var _rallyPointController: _planMasterController.rallyPointController + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() + property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) + property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + + property bool _disableVehicleTracking: false + property bool _keepVehicleCentered: _mainIsMap ? false : true + + property bool _wimaEnabled: wimaController.enableWimaController.value + property bool _showAllWimaItems: wimaController.showAllMissionItems.value + property bool _showCurrentWimaItems: wimaController.showCurrentMissionItems.value + + function updateAirspace(reset) { + if(_airspaceEnabled) { + var coordinateNW = flightMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */) + var coordinateSE = flightMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */) + if(coordinateNW.isValid && coordinateSE.isValid) { + QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset) + } + } + } + + // Track last known map position and zoom from Fly view in settings + + onZoomLevelChanged: { + QGroundControl.flightMapZoom = zoomLevel + updateAirspace(false) + } + onCenterChanged: { + QGroundControl.flightMapPosition = center + updateAirspace(false) + } + + // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires + onUserPannedChanged: { + if (userPanned) { + console.log("user panned") + userPanned = false + _disableVehicleTracking = true + panRecenterTimer.restart() + } + } + + on_AirspaceEnabledChanged: { + updateAirspace(true) + } + + function pointInRect(point, rect) { + return point.x > rect.x && + point.x < rect.x + rect.width && + point.y > rect.y && + point.y < rect.y + rect.height; + } + + property real _animatedLatitudeStart + property real _animatedLatitudeStop + property real _animatedLongitudeStart + property real _animatedLongitudeStop + property real animatedLatitude + property real animatedLongitude + + onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + + NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 } + NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 } + + function animatedMapRecenter(fromCoord, toCoord) { + _animatedLatitudeStart = fromCoord.latitude + _animatedLongitudeStart = fromCoord.longitude + _animatedLatitudeStop = toCoord.latitude + _animatedLongitudeStop = toCoord.longitude + animateLat.start() + animateLong.start() + } + + function recenterNeeded() { + var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */) + var toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width + var instrumentsWidth = 0 + if (QGroundControl.corePlugin.options.instrumentWidget && QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) { + // Assume standard instruments + instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth() + } + var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height) + return !pointInRect(vehiclePoint, centerViewport) + } + + function updateMapToVehiclePosition() { + // We let FlightMap handle first vehicle position + if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) { + if (_keepVehicleCentered) { + flightMap.center = _activeVehicleCoordinate + } else { + if (firstVehiclePositionReceived && recenterNeeded()) { + animatedMapRecenter(flightMap.center, _activeVehicleCoordinate) + } + } + } + } + + Timer { + id: panRecenterTimer + interval: 10000 + running: false + + onTriggered: { + _disableVehicleTracking = false + updateMapToVehiclePosition() + } + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: updateMapToVehiclePosition() + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } + + Connections { + target: _missionController + + onNewItemsFromVehicle: { + var visualItems = _missionController.visualItems + if (visualItems && visualItems.count !== 1) { + mapFitFunctions.fitMapViewportToMissionItems() + firstVehiclePositionReceived = true + } + } + } + + ExclusiveGroup { + id: _mapTypeButtonsExclusiveGroup + } + + MapFitFunctions { + id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! + map: _flightMap + usePlannedHomePosition: false + planMasterController: _planMasterController + + property real leftToolWidth: toolStrip.x + toolStrip.width + } + + // Add wima Areas to the Map + MapItemView { + property bool _enableWima: wimaController.enableWimaController.value + + model: _enableWima ? wimaController.visualItems : 0 + + delegate: MapPolygon{ + path: object.path; + border.color: "black" + color: object.type === "WimaJoinedAreaData" ? "gray" + : object.type === "WimaServiceAreaData" ? "yellow" + : object.type === "WimaMeasurementAreaData" ? "green" + : "transparent" + opacity: 0.25 + z: 0 + } + } + + // Add mission items generated by wima planer to the map + // all Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.missionItems + path: wimaController.waypointPath + showItems: _wimaEnabled && _showAllWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-2 + zOrderLines: QGroundControl.zOrderWaypointLines-2 + color: "gray" + } + // current Items + /*WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.currentMissionItems + path: wimaController.currentWaypointPath + showItems: _wimaEnabled && _showCurrentWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-1 +<<<<<<< HEAD + zOrderLines: QGroundControl.zOrderWaypointIndicators-2 + color: "green" // gray with alpha 0.7 + }*/ +======= + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "green" + } +>>>>>>> temp + + // Add trajectory points to the map + MapItemView { + model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0 + + delegate: MapPolyline { + line.width: 3 + line.color: "red" + z: QGroundControl.zOrderTrajectoryLines + path: [ + object.coordinate1, + object.coordinate2, + ] + } + } + + // Add the vehicles to the map + MapItemView { + model: QGroundControl.multiVehicleManager.vehicles + + delegate: VehicleMapItem { + vehicle: object + coordinate: object.coordinate + map: flightMap + size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight + z: QGroundControl.zOrderVehicles + } + } + + // Add ADSB vehicles to the map + MapItemView { + model: _activeVehicle ? _activeVehicle.adsbVehicles : [] + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + delegate: VehicleMapItem { + coordinate: object.coordinate + altitude: object.altitude + callsign: object.callsign + heading: object.heading + alert: object.alert + map: flightMap + z: QGroundControl.zOrderVehicles + } + } + + // Add the items associated with each vehicles flight plan to the map + Repeater { + model: QGroundControl.multiVehicleManager.vehicles + + PlanMapItems { + map: flightMap + largeMapView: _mainIsMap + masterController: masterController + isActiveVehicle: _vehicle.active + + property var _vehicle: object + + PlanMasterController { + id: masterController + Component.onCompleted: startStaticActiveVehicle(object) + } + } + } + + // Allow custom builds to add map items + CustomMapItems { + map: flightMap + largeMapView: _mainIsMap + } + + GeoFenceMapVisuals { + map: flightMap + myGeoFenceController: _geoFenceController + interactive: false + planView: false + homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate() + } + + // Rally points on map + MapItemView { + model: _rallyPointController.points + + delegate: MapQuickItem { + id: itemIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: object.coordinate + z: QGroundControl.zOrderMapItems + + sourceItem: MissionItemIndexLabel { + id: itemIndexLabel + label: qsTr("R", "rally point map item label") + } + } + } + + // Camera trigger points + MapItemView { + model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0 + + delegate: CameraTriggerIndicator { + coordinate: object.coordinate + z: QGroundControl.zOrderTopMost + } + } + + // GoTo Location visuals + MapQuickItem { + id: gotoLocationItem + visible: false + z: QGroundControl.zOrderMapItems + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Goto here", "Goto here waypoint") + } + + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + gotoLocationItem.coordinate = coord + gotoLocationItem.visible = true + } + + function hide() { + gotoLocationItem.visible = false + } + + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + + // Orbit editing visuals + QGCMapCircleVisuals { + id: orbitMapCircle + mapControl: parent + mapCircle: _mapCircle + visible: false + + property alias center: _mapCircle.center + property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle + + readonly property real defaultRadius: 30 + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + _mapCircle.radius.rawValue = defaultRadius + orbitMapCircle.center = coord + orbitMapCircle.visible = true + } + + function hide() { + orbitMapCircle.visible = false + } + + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + + function radius() { + return _mapCircle.radius.rawValue + } + + Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle + + QGCMapCircle { + id: _mapCircle + interactive: true + radius.rawValue: 30 + showRotation: true + clockwiseRotation: true + } + } + + // Orbit telemetry visuals + QGCMapCircleVisuals { + id: orbitTelemetryCircle + mapControl: parent + mapCircle: _activeVehicle ? _activeVehicle.orbitMapCircle : null + visible: _activeVehicle ? _activeVehicle.orbitActive : false + } + + MapQuickItem { + id: orbitCenterIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate() + visible: orbitTelemetryCircle.visible + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Orbit", "Orbit waypoint") + } + } + + // Handle guided mode clicks + MouseArea { + anchors.fill: parent + + Menu { + id: clickMenu + + property var coord + + MenuItem { + text: qsTr("Go to location") + visible: guidedActionsController.showGotoLocation + + onTriggered: { + gotoLocationItem.show(clickMenu.coord) + orbitMapCircle.hide() + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) + } + } + + MenuItem { + text: qsTr("Orbit at location") + visible: guidedActionsController.showOrbit + + onTriggered: { + orbitMapCircle.show(clickMenu.coord) + gotoLocationItem.hide() + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) + } + } + } + + onClicked: { + if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) { + return + } + orbitMapCircle.hide() + gotoLocationItem.hide() + var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */) + if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) { + clickMenu.coord = clickCoord + clickMenu.popup() + } else if (guidedActionsController.showGotoLocation) { + gotoLocationItem.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord) + } else if (guidedActionsController.showOrbit) { + orbitMapCircle.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord) + } + } + } + + MapScale { + id: mapScale + anchors.right: parent.right + anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33) + anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight + anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33) + mapControl: flightMap + visible: !ScreenTools.isTinyScreen + state: "bottomMode" + states: [ + State { + name: "topMode" + AnchorChanges { + target: mapScale + anchors.top: parent.top + anchors.bottom: undefined + } + }, + State { + name: "bottomMode" + AnchorChanges { + target: mapScale + anchors.top: undefined + anchors.bottom: parent.bottom + } + } + ] + } + + // Airspace overlap support + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : [] + delegate: MapCircle { + center: object.center + radius: object.radius + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : [] + delegate: MapPolygon { + path: object.polygon + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + +} diff --git a/src/FlightDisplay/FlightDisplayViewMap_BASE_16429.qml b/src/FlightDisplay/FlightDisplayViewMap_BASE_16429.qml new file mode 100644 index 0000000000000000000000000000000000000000..452420ee6b4ac6386565191d743786436786987e --- /dev/null +++ b/src/FlightDisplay/FlightDisplayViewMap_BASE_16429.qml @@ -0,0 +1,572 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.FlightMap 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Vehicle 1.0 + +FlightMap { + id: flightMap + anchors.fill: parent + mapName: _mapName + allowGCSLocationCenter: !userPanned + allowVehicleLocationCenter: !_keepVehicleCentered + planView: false + + + property alias scaleState: mapScale.state + + // The following properties must be set by the consumer + property var planMasterController + property var wimaController + property var guidedActionsController + property var flightWidgets + property var rightPanelWidth + property var qgcView ///< QGCView control which contains this map + property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view + + property rect centerViewport: Qt.rect(0, 0, width, height) + + property var _planMasterController: planMasterController + property var _missionController: _planMasterController.missionController + property var _geoFenceController: _planMasterController.geoFenceController + property var _rallyPointController: _planMasterController.rallyPointController + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() + property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) + property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + + property bool _disableVehicleTracking: false + property bool _keepVehicleCentered: _mainIsMap ? false : true + + property bool _wimaEnabled: wimaController.enableWimaController.value + property bool _showAllWimaItems: wimaController.showAllMissionItems.value + property bool _showCurrentWimaItems: wimaController.showCurrentMissionItems.value + + function updateAirspace(reset) { + if(_airspaceEnabled) { + var coordinateNW = flightMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */) + var coordinateSE = flightMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */) + if(coordinateNW.isValid && coordinateSE.isValid) { + QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset) + } + } + } + + // Track last known map position and zoom from Fly view in settings + + onZoomLevelChanged: { + QGroundControl.flightMapZoom = zoomLevel + updateAirspace(false) + } + onCenterChanged: { + QGroundControl.flightMapPosition = center + updateAirspace(false) + } + + // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires + onUserPannedChanged: { + if (userPanned) { + console.log("user panned") + userPanned = false + _disableVehicleTracking = true + panRecenterTimer.restart() + } + } + + on_AirspaceEnabledChanged: { + updateAirspace(true) + } + + function pointInRect(point, rect) { + return point.x > rect.x && + point.x < rect.x + rect.width && + point.y > rect.y && + point.y < rect.y + rect.height; + } + + property real _animatedLatitudeStart + property real _animatedLatitudeStop + property real _animatedLongitudeStart + property real _animatedLongitudeStop + property real animatedLatitude + property real animatedLongitude + + onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + + NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 } + NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 } + + function animatedMapRecenter(fromCoord, toCoord) { + _animatedLatitudeStart = fromCoord.latitude + _animatedLongitudeStart = fromCoord.longitude + _animatedLatitudeStop = toCoord.latitude + _animatedLongitudeStop = toCoord.longitude + animateLat.start() + animateLong.start() + } + + function recenterNeeded() { + var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */) + var toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width + var instrumentsWidth = 0 + if (QGroundControl.corePlugin.options.instrumentWidget && QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) { + // Assume standard instruments + instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth() + } + var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height) + return !pointInRect(vehiclePoint, centerViewport) + } + + function updateMapToVehiclePosition() { + // We let FlightMap handle first vehicle position + if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) { + if (_keepVehicleCentered) { + flightMap.center = _activeVehicleCoordinate + } else { + if (firstVehiclePositionReceived && recenterNeeded()) { + animatedMapRecenter(flightMap.center, _activeVehicleCoordinate) + } + } + } + } + + Timer { + id: panRecenterTimer + interval: 10000 + running: false + + onTriggered: { + _disableVehicleTracking = false + updateMapToVehiclePosition() + } + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: updateMapToVehiclePosition() + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } + + Connections { + target: _missionController + + onNewItemsFromVehicle: { + var visualItems = _missionController.visualItems + if (visualItems && visualItems.count !== 1) { + mapFitFunctions.fitMapViewportToMissionItems() + firstVehiclePositionReceived = true + } + } + } + + ExclusiveGroup { + id: _mapTypeButtonsExclusiveGroup + } + + MapFitFunctions { + id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! + map: _flightMap + usePlannedHomePosition: false + planMasterController: _planMasterController + + property real leftToolWidth: toolStrip.x + toolStrip.width + } + + // Add wima Areas to the Map + MapItemView { + property bool _enableWima: wimaController.enableWimaController.value + + model: _enableWima ? wimaController.visualItems : 0 + + delegate: MapPolygon{ + path: object.path; + border.color: "black" + color: object.type === "WimaJoinedAreaData" ? "gray" + : object.type === "WimaServiceAreaData" ? "yellow" + : object.type === "WimaMeasurementAreaData" ? "green" + : "transparent" + opacity: 0.25 + z: 0 + } + } + + // Add mission items generated by wima planer to the map + // all Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.missionItems + path: wimaController.waypointPath + showItems: _wimaEnabled && _showAllWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-3 + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "gray" + } + // current Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.currentMissionItems + path: wimaController.currentWaypointPath + showItems: _wimaEnabled && _showCurrentWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-1 + zOrderLines: QGroundControl.zOrderWaypointIndicators-2 + color: "green" // gray with alpha 0.7 + } + + // Add trajectory points to the map + MapItemView { + model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0 + + delegate: MapPolyline { + line.width: 3 + line.color: "red" + z: QGroundControl.zOrderTrajectoryLines + path: [ + object.coordinate1, + object.coordinate2, + ] + } + } + + // Add the vehicles to the map + MapItemView { + model: QGroundControl.multiVehicleManager.vehicles + + delegate: VehicleMapItem { + vehicle: object + coordinate: object.coordinate + map: flightMap + size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight + z: QGroundControl.zOrderVehicles + } + } + + // Add ADSB vehicles to the map + MapItemView { + model: _activeVehicle ? _activeVehicle.adsbVehicles : [] + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + delegate: VehicleMapItem { + coordinate: object.coordinate + altitude: object.altitude + callsign: object.callsign + heading: object.heading + alert: object.alert + map: flightMap + z: QGroundControl.zOrderVehicles + } + } + + // Add the items associated with each vehicles flight plan to the map + Repeater { + model: QGroundControl.multiVehicleManager.vehicles + + PlanMapItems { + map: flightMap + largeMapView: _mainIsMap + masterController: masterController + isActiveVehicle: _vehicle.active + + property var _vehicle: object + + PlanMasterController { + id: masterController + Component.onCompleted: startStaticActiveVehicle(object) + } + } + } + + // Allow custom builds to add map items + CustomMapItems { + map: flightMap + largeMapView: _mainIsMap + } + + GeoFenceMapVisuals { + map: flightMap + myGeoFenceController: _geoFenceController + interactive: false + planView: false + homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate() + } + + // Rally points on map + MapItemView { + model: _rallyPointController.points + + delegate: MapQuickItem { + id: itemIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: object.coordinate + z: QGroundControl.zOrderMapItems + + sourceItem: MissionItemIndexLabel { + id: itemIndexLabel + label: qsTr("R", "rally point map item label") + } + } + } + + // Camera trigger points + MapItemView { + model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0 + + delegate: CameraTriggerIndicator { + coordinate: object.coordinate + z: QGroundControl.zOrderTopMost + } + } + + // GoTo Location visuals + MapQuickItem { + id: gotoLocationItem + visible: false + z: QGroundControl.zOrderMapItems + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Goto here", "Goto here waypoint") + } + + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + gotoLocationItem.coordinate = coord + gotoLocationItem.visible = true + } + + function hide() { + gotoLocationItem.visible = false + } + + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + + // Orbit editing visuals + QGCMapCircleVisuals { + id: orbitMapCircle + mapControl: parent + mapCircle: _mapCircle + visible: false + + property alias center: _mapCircle.center + property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle + + readonly property real defaultRadius: 30 + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + _mapCircle.radius.rawValue = defaultRadius + orbitMapCircle.center = coord + orbitMapCircle.visible = true + } + + function hide() { + orbitMapCircle.visible = false + } + + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + + function radius() { + return _mapCircle.radius.rawValue + } + + Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle + + QGCMapCircle { + id: _mapCircle + interactive: true + radius.rawValue: 30 + showRotation: true + clockwiseRotation: true + } + } + + // Orbit telemetry visuals + QGCMapCircleVisuals { + id: orbitTelemetryCircle + mapControl: parent + mapCircle: _activeVehicle ? _activeVehicle.orbitMapCircle : null + visible: _activeVehicle ? _activeVehicle.orbitActive : false + } + + MapQuickItem { + id: orbitCenterIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate() + visible: orbitTelemetryCircle.visible + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Orbit", "Orbit waypoint") + } + } + + // Handle guided mode clicks + MouseArea { + anchors.fill: parent + + Menu { + id: clickMenu + + property var coord + + MenuItem { + text: qsTr("Go to location") + visible: guidedActionsController.showGotoLocation + + onTriggered: { + gotoLocationItem.show(clickMenu.coord) + orbitMapCircle.hide() + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) + } + } + + MenuItem { + text: qsTr("Orbit at location") + visible: guidedActionsController.showOrbit + + onTriggered: { + orbitMapCircle.show(clickMenu.coord) + gotoLocationItem.hide() + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) + } + } + } + + onClicked: { + if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) { + return + } + orbitMapCircle.hide() + gotoLocationItem.hide() + var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */) + if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) { + clickMenu.coord = clickCoord + clickMenu.popup() + } else if (guidedActionsController.showGotoLocation) { + gotoLocationItem.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord) + } else if (guidedActionsController.showOrbit) { + orbitMapCircle.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord) + } + } + } + + MapScale { + id: mapScale + anchors.right: parent.right + anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33) + anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight + anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33) + mapControl: flightMap + visible: !ScreenTools.isTinyScreen + state: "bottomMode" + states: [ + State { + name: "topMode" + AnchorChanges { + target: mapScale + anchors.top: parent.top + anchors.bottom: undefined + } + }, + State { + name: "bottomMode" + AnchorChanges { + target: mapScale + anchors.top: undefined + anchors.bottom: parent.bottom + } + } + ] + } + + // Airspace overlap support + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : [] + delegate: MapCircle { + center: object.center + radius: object.radius + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : [] + delegate: MapPolygon { + path: object.polygon + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + +} diff --git a/src/FlightDisplay/FlightDisplayViewMap_LOCAL_16429.qml b/src/FlightDisplay/FlightDisplayViewMap_LOCAL_16429.qml new file mode 100644 index 0000000000000000000000000000000000000000..c8a7f213e3d8c9d7d4b483be2db4997f59c24b77 --- /dev/null +++ b/src/FlightDisplay/FlightDisplayViewMap_LOCAL_16429.qml @@ -0,0 +1,572 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.FlightMap 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Vehicle 1.0 + +FlightMap { + id: flightMap + anchors.fill: parent + mapName: _mapName + allowGCSLocationCenter: !userPanned + allowVehicleLocationCenter: !_keepVehicleCentered + planView: false + + + property alias scaleState: mapScale.state + + // The following properties must be set by the consumer + property var planMasterController + property var wimaController + property var guidedActionsController + property var flightWidgets + property var rightPanelWidth + property var qgcView ///< QGCView control which contains this map + property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view + + property rect centerViewport: Qt.rect(0, 0, width, height) + + property var _planMasterController: planMasterController + property var _missionController: _planMasterController.missionController + property var _geoFenceController: _planMasterController.geoFenceController + property var _rallyPointController: _planMasterController.rallyPointController + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() + property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) + property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + + property bool _disableVehicleTracking: false + property bool _keepVehicleCentered: _mainIsMap ? false : true + + property bool _wimaEnabled: wimaController.enableWimaController.value + property bool _showAllWimaItems: wimaController.showAllMissionItems.value + property bool _showCurrentWimaItems: wimaController.showCurrentMissionItems.value + + function updateAirspace(reset) { + if(_airspaceEnabled) { + var coordinateNW = flightMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */) + var coordinateSE = flightMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */) + if(coordinateNW.isValid && coordinateSE.isValid) { + QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset) + } + } + } + + // Track last known map position and zoom from Fly view in settings + + onZoomLevelChanged: { + QGroundControl.flightMapZoom = zoomLevel + updateAirspace(false) + } + onCenterChanged: { + QGroundControl.flightMapPosition = center + updateAirspace(false) + } + + // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires + onUserPannedChanged: { + if (userPanned) { + console.log("user panned") + userPanned = false + _disableVehicleTracking = true + panRecenterTimer.restart() + } + } + + on_AirspaceEnabledChanged: { + updateAirspace(true) + } + + function pointInRect(point, rect) { + return point.x > rect.x && + point.x < rect.x + rect.width && + point.y > rect.y && + point.y < rect.y + rect.height; + } + + property real _animatedLatitudeStart + property real _animatedLatitudeStop + property real _animatedLongitudeStart + property real _animatedLongitudeStop + property real animatedLatitude + property real animatedLongitude + + onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + + NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 } + NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 } + + function animatedMapRecenter(fromCoord, toCoord) { + _animatedLatitudeStart = fromCoord.latitude + _animatedLongitudeStart = fromCoord.longitude + _animatedLatitudeStop = toCoord.latitude + _animatedLongitudeStop = toCoord.longitude + animateLat.start() + animateLong.start() + } + + function recenterNeeded() { + var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */) + var toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width + var instrumentsWidth = 0 + if (QGroundControl.corePlugin.options.instrumentWidget && QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) { + // Assume standard instruments + instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth() + } + var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height) + return !pointInRect(vehiclePoint, centerViewport) + } + + function updateMapToVehiclePosition() { + // We let FlightMap handle first vehicle position + if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) { + if (_keepVehicleCentered) { + flightMap.center = _activeVehicleCoordinate + } else { + if (firstVehiclePositionReceived && recenterNeeded()) { + animatedMapRecenter(flightMap.center, _activeVehicleCoordinate) + } + } + } + } + + Timer { + id: panRecenterTimer + interval: 10000 + running: false + + onTriggered: { + _disableVehicleTracking = false + updateMapToVehiclePosition() + } + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: updateMapToVehiclePosition() + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } + + Connections { + target: _missionController + + onNewItemsFromVehicle: { + var visualItems = _missionController.visualItems + if (visualItems && visualItems.count !== 1) { + mapFitFunctions.fitMapViewportToMissionItems() + firstVehiclePositionReceived = true + } + } + } + + ExclusiveGroup { + id: _mapTypeButtonsExclusiveGroup + } + + MapFitFunctions { + id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! + map: _flightMap + usePlannedHomePosition: false + planMasterController: _planMasterController + + property real leftToolWidth: toolStrip.x + toolStrip.width + } + + // Add wima Areas to the Map + MapItemView { + property bool _enableWima: wimaController.enableWimaController.value + + model: _enableWima ? wimaController.visualItems : 0 + + delegate: MapPolygon{ + path: object.path; + border.color: "black" + color: object.type === "WimaJoinedAreaData" ? "gray" + : object.type === "WimaServiceAreaData" ? "yellow" + : object.type === "WimaMeasurementAreaData" ? "green" + : "transparent" + opacity: 0.25 + z: 0 + } + } + + // Add mission items generated by wima planer to the map + // all Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.missionItems + path: wimaController.waypointPath + showItems: _wimaEnabled && _showAllWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-3 + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "gray" + } + // current Items + /*WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.currentMissionItems + path: wimaController.currentWaypointPath + showItems: _wimaEnabled && _showCurrentWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-1 + zOrderLines: QGroundControl.zOrderWaypointIndicators-2 + color: "green" // gray with alpha 0.7 + }*/ + + // Add trajectory points to the map + MapItemView { + model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0 + + delegate: MapPolyline { + line.width: 3 + line.color: "red" + z: QGroundControl.zOrderTrajectoryLines + path: [ + object.coordinate1, + object.coordinate2, + ] + } + } + + // Add the vehicles to the map + MapItemView { + model: QGroundControl.multiVehicleManager.vehicles + + delegate: VehicleMapItem { + vehicle: object + coordinate: object.coordinate + map: flightMap + size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight + z: QGroundControl.zOrderVehicles + } + } + + // Add ADSB vehicles to the map + MapItemView { + model: _activeVehicle ? _activeVehicle.adsbVehicles : [] + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + delegate: VehicleMapItem { + coordinate: object.coordinate + altitude: object.altitude + callsign: object.callsign + heading: object.heading + alert: object.alert + map: flightMap + z: QGroundControl.zOrderVehicles + } + } + + // Add the items associated with each vehicles flight plan to the map + Repeater { + model: QGroundControl.multiVehicleManager.vehicles + + PlanMapItems { + map: flightMap + largeMapView: _mainIsMap + masterController: masterController + isActiveVehicle: _vehicle.active + + property var _vehicle: object + + PlanMasterController { + id: masterController + Component.onCompleted: startStaticActiveVehicle(object) + } + } + } + + // Allow custom builds to add map items + CustomMapItems { + map: flightMap + largeMapView: _mainIsMap + } + + GeoFenceMapVisuals { + map: flightMap + myGeoFenceController: _geoFenceController + interactive: false + planView: false + homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate() + } + + // Rally points on map + MapItemView { + model: _rallyPointController.points + + delegate: MapQuickItem { + id: itemIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: object.coordinate + z: QGroundControl.zOrderMapItems + + sourceItem: MissionItemIndexLabel { + id: itemIndexLabel + label: qsTr("R", "rally point map item label") + } + } + } + + // Camera trigger points + MapItemView { + model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0 + + delegate: CameraTriggerIndicator { + coordinate: object.coordinate + z: QGroundControl.zOrderTopMost + } + } + + // GoTo Location visuals + MapQuickItem { + id: gotoLocationItem + visible: false + z: QGroundControl.zOrderMapItems + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Goto here", "Goto here waypoint") + } + + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + gotoLocationItem.coordinate = coord + gotoLocationItem.visible = true + } + + function hide() { + gotoLocationItem.visible = false + } + + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + + // Orbit editing visuals + QGCMapCircleVisuals { + id: orbitMapCircle + mapControl: parent + mapCircle: _mapCircle + visible: false + + property alias center: _mapCircle.center + property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle + + readonly property real defaultRadius: 30 + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + _mapCircle.radius.rawValue = defaultRadius + orbitMapCircle.center = coord + orbitMapCircle.visible = true + } + + function hide() { + orbitMapCircle.visible = false + } + + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + + function radius() { + return _mapCircle.radius.rawValue + } + + Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle + + QGCMapCircle { + id: _mapCircle + interactive: true + radius.rawValue: 30 + showRotation: true + clockwiseRotation: true + } + } + + // Orbit telemetry visuals + QGCMapCircleVisuals { + id: orbitTelemetryCircle + mapControl: parent + mapCircle: _activeVehicle ? _activeVehicle.orbitMapCircle : null + visible: _activeVehicle ? _activeVehicle.orbitActive : false + } + + MapQuickItem { + id: orbitCenterIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate() + visible: orbitTelemetryCircle.visible + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Orbit", "Orbit waypoint") + } + } + + // Handle guided mode clicks + MouseArea { + anchors.fill: parent + + Menu { + id: clickMenu + + property var coord + + MenuItem { + text: qsTr("Go to location") + visible: guidedActionsController.showGotoLocation + + onTriggered: { + gotoLocationItem.show(clickMenu.coord) + orbitMapCircle.hide() + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) + } + } + + MenuItem { + text: qsTr("Orbit at location") + visible: guidedActionsController.showOrbit + + onTriggered: { + orbitMapCircle.show(clickMenu.coord) + gotoLocationItem.hide() + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) + } + } + } + + onClicked: { + if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) { + return + } + orbitMapCircle.hide() + gotoLocationItem.hide() + var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */) + if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) { + clickMenu.coord = clickCoord + clickMenu.popup() + } else if (guidedActionsController.showGotoLocation) { + gotoLocationItem.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord) + } else if (guidedActionsController.showOrbit) { + orbitMapCircle.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord) + } + } + } + + MapScale { + id: mapScale + anchors.right: parent.right + anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33) + anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight + anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33) + mapControl: flightMap + visible: !ScreenTools.isTinyScreen + state: "bottomMode" + states: [ + State { + name: "topMode" + AnchorChanges { + target: mapScale + anchors.top: parent.top + anchors.bottom: undefined + } + }, + State { + name: "bottomMode" + AnchorChanges { + target: mapScale + anchors.top: undefined + anchors.bottom: parent.bottom + } + } + ] + } + + // Airspace overlap support + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : [] + delegate: MapCircle { + center: object.center + radius: object.radius + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : [] + delegate: MapPolygon { + path: object.polygon + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + +} diff --git a/src/FlightDisplay/FlightDisplayViewMap_REMOTE_16429.qml b/src/FlightDisplay/FlightDisplayViewMap_REMOTE_16429.qml new file mode 100644 index 0000000000000000000000000000000000000000..5c714a8f90a1f2280937200d23030f58e45e94cb --- /dev/null +++ b/src/FlightDisplay/FlightDisplayViewMap_REMOTE_16429.qml @@ -0,0 +1,572 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 +import QtQuick.Dialogs 1.2 + +import QGroundControl 1.0 +import QGroundControl.Airspace 1.0 +import QGroundControl.Controllers 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightDisplay 1.0 +import QGroundControl.FlightMap 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Vehicle 1.0 + +FlightMap { + id: flightMap + anchors.fill: parent + mapName: _mapName + allowGCSLocationCenter: !userPanned + allowVehicleLocationCenter: !_keepVehicleCentered + planView: false + + + property alias scaleState: mapScale.state + + // The following properties must be set by the consumer + property var planMasterController + property var wimaController + property var guidedActionsController + property var flightWidgets + property var rightPanelWidth + property var qgcView ///< QGCView control which contains this map + property var multiVehicleView ///< true: multi-vehicle view, false: single vehicle view + + property rect centerViewport: Qt.rect(0, 0, width, height) + + property var _planMasterController: planMasterController + property var _missionController: _planMasterController.missionController + property var _geoFenceController: _planMasterController.geoFenceController + property var _rallyPointController: _planMasterController.rallyPointController + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate() + property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2) + property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + + property bool _disableVehicleTracking: false + property bool _keepVehicleCentered: _mainIsMap ? false : true + + property bool _wimaEnabled: wimaController.enableWimaController.value + property bool _showAllWimaItems: wimaController.showAllMissionItems.value + property bool _showCurrentWimaItems: wimaController.showCurrentMissionItems.value + + function updateAirspace(reset) { + if(_airspaceEnabled) { + var coordinateNW = flightMap.toCoordinate(Qt.point(0,0), false /* clipToViewPort */) + var coordinateSE = flightMap.toCoordinate(Qt.point(width,height), false /* clipToViewPort */) + if(coordinateNW.isValid && coordinateSE.isValid) { + QGroundControl.airspaceManager.setROI(coordinateNW, coordinateSE, false /*planView*/, reset) + } + } + } + + // Track last known map position and zoom from Fly view in settings + + onZoomLevelChanged: { + QGroundControl.flightMapZoom = zoomLevel + updateAirspace(false) + } + onCenterChanged: { + QGroundControl.flightMapPosition = center + updateAirspace(false) + } + + // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires + onUserPannedChanged: { + if (userPanned) { + console.log("user panned") + userPanned = false + _disableVehicleTracking = true + panRecenterTimer.restart() + } + } + + on_AirspaceEnabledChanged: { + updateAirspace(true) + } + + function pointInRect(point, rect) { + return point.x > rect.x && + point.x < rect.x + rect.width && + point.y > rect.y && + point.y < rect.y + rect.height; + } + + property real _animatedLatitudeStart + property real _animatedLatitudeStop + property real _animatedLongitudeStart + property real _animatedLongitudeStop + property real animatedLatitude + property real animatedLongitude + + onAnimatedLatitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + onAnimatedLongitudeChanged: flightMap.center = QtPositioning.coordinate(animatedLatitude, animatedLongitude) + + NumberAnimation on animatedLatitude { id: animateLat; from: _animatedLatitudeStart; to: _animatedLatitudeStop; duration: 1000 } + NumberAnimation on animatedLongitude { id: animateLong; from: _animatedLongitudeStart; to: _animatedLongitudeStop; duration: 1000 } + + function animatedMapRecenter(fromCoord, toCoord) { + _animatedLatitudeStart = fromCoord.latitude + _animatedLongitudeStart = fromCoord.longitude + _animatedLatitudeStop = toCoord.latitude + _animatedLongitudeStop = toCoord.longitude + animateLat.start() + animateLong.start() + } + + function recenterNeeded() { + var vehiclePoint = flightMap.fromCoordinate(_activeVehicleCoordinate, false /* clipToViewport */) + var toolStripRightEdge = mapFromItem(toolStrip, toolStrip.x, 0).x + toolStrip.width + var instrumentsWidth = 0 + if (QGroundControl.corePlugin.options.instrumentWidget && QGroundControl.corePlugin.options.instrumentWidget.widgetPosition === CustomInstrumentWidget.POS_TOP_RIGHT) { + // Assume standard instruments + instrumentsWidth = flightDisplayViewWidgets.getPreferredInstrumentWidth() + } + var centerViewport = Qt.rect(toolStripRightEdge, 0, width - toolStripRightEdge - instrumentsWidth, height) + return !pointInRect(vehiclePoint, centerViewport) + } + + function updateMapToVehiclePosition() { + // We let FlightMap handle first vehicle position + if (firstVehiclePositionReceived && _activeVehicleCoordinate.isValid && !_disableVehicleTracking) { + if (_keepVehicleCentered) { + flightMap.center = _activeVehicleCoordinate + } else { + if (firstVehiclePositionReceived && recenterNeeded()) { + animatedMapRecenter(flightMap.center, _activeVehicleCoordinate) + } + } + } + } + + Timer { + id: panRecenterTimer + interval: 10000 + running: false + + onTriggered: { + _disableVehicleTracking = false + updateMapToVehiclePosition() + } + } + + Timer { + interval: 500 + running: true + repeat: true + onTriggered: updateMapToVehiclePosition() + } + + QGCPalette { id: qgcPal; colorGroupEnabled: true } + QGCMapPalette { id: mapPal; lightColors: isSatelliteMap } + + Connections { + target: _missionController + + onNewItemsFromVehicle: { + var visualItems = _missionController.visualItems + if (visualItems && visualItems.count !== 1) { + mapFitFunctions.fitMapViewportToMissionItems() + firstVehiclePositionReceived = true + } + } + } + + ExclusiveGroup { + id: _mapTypeButtonsExclusiveGroup + } + + MapFitFunctions { + id: mapFitFunctions // The name for this id cannot be changed without breaking references outside of this code. Beware! + map: _flightMap + usePlannedHomePosition: false + planMasterController: _planMasterController + + property real leftToolWidth: toolStrip.x + toolStrip.width + } + + // Add wima Areas to the Map + MapItemView { + property bool _enableWima: wimaController.enableWimaController.value + + model: _enableWima ? wimaController.visualItems : 0 + + delegate: MapPolygon{ + path: object.path; + border.color: "black" + color: object.type === "WimaJoinedAreaData" ? "gray" + : object.type === "WimaServiceAreaData" ? "yellow" + : object.type === "WimaMeasurementAreaData" ? "green" + : "transparent" + opacity: 0.25 + z: 0 + } + } + + // Add mission items generated by wima planer to the map + // all Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.missionItems + path: wimaController.waypointPath + showItems: _wimaEnabled && _showAllWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-2 + zOrderLines: QGroundControl.zOrderWaypointLines-2 + color: "gray" + } + // current Items + WimaPlanMapItems { + map: flightMap + largeMapView: _mainIsMap + missionItems: wimaController.currentMissionItems + path: wimaController.currentWaypointPath + showItems: _wimaEnabled && _showCurrentWimaItems + zOrderWP: QGroundControl.zOrderWaypointIndicators-1 + zOrderLines: QGroundControl.zOrderWaypointLines-1 + color: "green" + } + + // Add trajectory points to the map + MapItemView { + model: _mainIsMap ? _activeVehicle ? _activeVehicle.trajectoryPoints : 0 : 0 + + delegate: MapPolyline { + line.width: 3 + line.color: "red" + z: QGroundControl.zOrderTrajectoryLines + path: [ + object.coordinate1, + object.coordinate2, + ] + } + } + + // Add the vehicles to the map + MapItemView { + model: QGroundControl.multiVehicleManager.vehicles + + delegate: VehicleMapItem { + vehicle: object + coordinate: object.coordinate + map: flightMap + size: _mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight + z: QGroundControl.zOrderVehicles + } + } + + // Add ADSB vehicles to the map + MapItemView { + model: _activeVehicle ? _activeVehicle.adsbVehicles : [] + property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle + delegate: VehicleMapItem { + coordinate: object.coordinate + altitude: object.altitude + callsign: object.callsign + heading: object.heading + alert: object.alert + map: flightMap + z: QGroundControl.zOrderVehicles + } + } + + // Add the items associated with each vehicles flight plan to the map + Repeater { + model: QGroundControl.multiVehicleManager.vehicles + + PlanMapItems { + map: flightMap + largeMapView: _mainIsMap + masterController: masterController + isActiveVehicle: _vehicle.active + + property var _vehicle: object + + PlanMasterController { + id: masterController + Component.onCompleted: startStaticActiveVehicle(object) + } + } + } + + // Allow custom builds to add map items + CustomMapItems { + map: flightMap + largeMapView: _mainIsMap + } + + GeoFenceMapVisuals { + map: flightMap + myGeoFenceController: _geoFenceController + interactive: false + planView: false + homePosition: _activeVehicle && _activeVehicle.homePosition.isValid ? _activeVehicle.homePosition : QtPositioning.coordinate() + } + + // Rally points on map + MapItemView { + model: _rallyPointController.points + + delegate: MapQuickItem { + id: itemIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: object.coordinate + z: QGroundControl.zOrderMapItems + + sourceItem: MissionItemIndexLabel { + id: itemIndexLabel + label: qsTr("R", "rally point map item label") + } + } + } + + // Camera trigger points + MapItemView { + model: _activeVehicle ? _activeVehicle.cameraTriggerPoints : 0 + + delegate: CameraTriggerIndicator { + coordinate: object.coordinate + z: QGroundControl.zOrderTopMost + } + } + + // GoTo Location visuals + MapQuickItem { + id: gotoLocationItem + visible: false + z: QGroundControl.zOrderMapItems + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Goto here", "Goto here waypoint") + } + + property bool inGotoFlightMode: _activeVehicle ? _activeVehicle.flightMode === _activeVehicle.gotoFlightMode : false + property var activeVehicle: _activeVehicle + + onInGotoFlightModeChanged: { + if (!inGotoFlightMode && visible) { + // Hide goto indicator when vehicle falls out of guided mode + visible = false + } + } + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + gotoLocationItem.coordinate = coord + gotoLocationItem.visible = true + } + + function hide() { + gotoLocationItem.visible = false + } + + function actionConfirmed() { + // We leave the indicator visible. The handling for onInGuidedModeChanged will hide it. + } + + function actionCancelled() { + hide() + } + } + + // Orbit editing visuals + QGCMapCircleVisuals { + id: orbitMapCircle + mapControl: parent + mapCircle: _mapCircle + visible: false + + property alias center: _mapCircle.center + property alias clockwiseRotation: _mapCircle.clockwiseRotation + property var activeVehicle: _activeVehicle + + readonly property real defaultRadius: 30 + + onActiveVehicleChanged: { + if (!_activeVehicle) { + visible = false + } + } + + function show(coord) { + _mapCircle.radius.rawValue = defaultRadius + orbitMapCircle.center = coord + orbitMapCircle.visible = true + } + + function hide() { + orbitMapCircle.visible = false + } + + function actionConfirmed() { + // Live orbit status is handled by telemetry so we hide here and telemetry will show again. + hide() + } + + function actionCancelled() { + hide() + } + + function radius() { + return _mapCircle.radius.rawValue + } + + Component.onCompleted: guidedActionsController.orbitMapCircle = orbitMapCircle + + QGCMapCircle { + id: _mapCircle + interactive: true + radius.rawValue: 30 + showRotation: true + clockwiseRotation: true + } + } + + // Orbit telemetry visuals + QGCMapCircleVisuals { + id: orbitTelemetryCircle + mapControl: parent + mapCircle: _activeVehicle ? _activeVehicle.orbitMapCircle : null + visible: _activeVehicle ? _activeVehicle.orbitActive : false + } + + MapQuickItem { + id: orbitCenterIndicator + anchorPoint.x: sourceItem.anchorPointX + anchorPoint.y: sourceItem.anchorPointY + coordinate: _activeVehicle ? _activeVehicle.orbitMapCircle.center : QtPositioning.coordinate() + visible: orbitTelemetryCircle.visible + + sourceItem: MissionItemIndexLabel { + checked: true + index: -1 + label: qsTr("Orbit", "Orbit waypoint") + } + } + + // Handle guided mode clicks + MouseArea { + anchors.fill: parent + + Menu { + id: clickMenu + + property var coord + + MenuItem { + text: qsTr("Go to location") + visible: guidedActionsController.showGotoLocation + + onTriggered: { + gotoLocationItem.show(clickMenu.coord) + orbitMapCircle.hide() + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickMenu.coord, gotoLocationItem) + } + } + + MenuItem { + text: qsTr("Orbit at location") + visible: guidedActionsController.showOrbit + + onTriggered: { + orbitMapCircle.show(clickMenu.coord) + gotoLocationItem.hide() + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickMenu.coord, orbitMapCircle) + } + } + } + + onClicked: { + if (guidedActionsController.guidedUIVisible || (!guidedActionsController.showGotoLocation && !guidedActionsController.showOrbit)) { + return + } + orbitMapCircle.hide() + gotoLocationItem.hide() + var clickCoord = flightMap.toCoordinate(Qt.point(mouse.x, mouse.y), false /* clipToViewPort */) + if (guidedActionsController.showGotoLocation && guidedActionsController.showOrbit) { + clickMenu.coord = clickCoord + clickMenu.popup() + } else if (guidedActionsController.showGotoLocation) { + gotoLocationItem.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionGoto, clickCoord) + } else if (guidedActionsController.showOrbit) { + orbitMapCircle.show(clickCoord) + guidedActionsController.confirmAction(guidedActionsController.actionOrbit, clickCoord) + } + } + } + + MapScale { + id: mapScale + anchors.right: parent.right + anchors.margins: ScreenTools.defaultFontPixelHeight * (0.33) + anchors.topMargin: ScreenTools.defaultFontPixelHeight * (0.33) + state === "bottomMode" ? 0 : ScreenTools.toolbarHeight + anchors.bottomMargin: ScreenTools.defaultFontPixelHeight * (0.33) + mapControl: flightMap + visible: !ScreenTools.isTinyScreen + state: "bottomMode" + states: [ + State { + name: "topMode" + AnchorChanges { + target: mapScale + anchors.top: parent.top + anchors.bottom: undefined + } + }, + State { + name: "bottomMode" + AnchorChanges { + target: mapScale + anchors.top: undefined + anchors.bottom: parent.bottom + } + } + ] + } + + // Airspace overlap support + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.circles : [] + delegate: MapCircle { + center: object.center + radius: object.radius + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + + MapItemView { + model: _airspaceEnabled && QGroundControl.settingsManager.airMapSettings.enableAirspace && QGroundControl.airspaceManager.airspaceVisible ? QGroundControl.airspaceManager.airspaces.polygons : [] + delegate: MapPolygon { + path: object.polygon + color: object.color + border.color: object.lineColor + border.width: object.lineWidth + } + } + +} diff --git a/src/FlightDisplay/FlightDisplayWimaMenu.qml b/src/FlightDisplay/FlightDisplayWimaMenu.qml index 32d8aaa4be72a42c09f857698b4b4ce5c63cb95a..8303de75d1f9f3bd4c69f4012d4ef43390ccd243 100644 --- a/src/FlightDisplay/FlightDisplayWimaMenu.qml +++ b/src/FlightDisplay/FlightDisplayWimaMenu.qml @@ -310,6 +310,14 @@ Item { Layout.fillWidth: true } + QGCButton { + id: buttonRemoveTrajectoryHistory + text: qsTr("Clear Trajectory") + onClicked: wimaController.removeVehicleTrajectoryHistory() + Layout.columnSpan: 2 + Layout.fillWidth: true + } + // progess bar Rectangle { diff --git a/src/Vehicle/Vehicle.h b/src/Vehicle/Vehicle.h index cba6240ea911692c2e6e05377215bd9268b7e120..1fd95b22862115753bbcc31fe455df869fe9e6bb 100644 --- a/src/Vehicle/Vehicle.h +++ b/src/Vehicle/Vehicle.h @@ -1051,7 +1051,7 @@ public: QGCCameraManager* dynamicCameras () { return _cameras; } QString hobbsMeter (); - /// @true: When flying a mission the vehicle is always facing towards the next waypoint + /// @true: When flying a mission the vehicle is always facing towards the next setCurrentMissionSequence bool vehicleYawsToNextWaypointInMission(void) const; /// The vehicle is responsible for making the initial request for the Plan. diff --git a/src/Wima/WimaController.cc b/src/Wima/WimaController.cc index e52cde8b9e9c78e351bc316f8fbbc1390f0bef5b..0c76e2fb1a34cd42d901b5ff1957906da90887b4 100644 --- a/src/Wima/WimaController.cc +++ b/src/Wima/WimaController.cc @@ -65,7 +65,7 @@ WimaController::WimaController(QObject *parent) enableDisableLowBatteryHandling(enableLowBatteryHandling->rawValue()); } -QmlObjectVectorModel* WimaController::visualItems() +QmlObjectListModel* WimaController::visualItems() { return &_visualItems; } @@ -92,16 +92,26 @@ WimaDataContainer *WimaController::dataContainer() return _container; } -QmlObjectVectorModel *WimaController::missionItems() +QmlObjectListModel *WimaController::missionItems() { return &_missionItems; } +QmlObjectListModel *WimaController::currentMissionItems() +{ + return &_currentMissionItems; +} + QVariantList WimaController::waypointPath() { return _waypointPath; } +QVariantList WimaController::currentWaypointPath() +{ + return _currentWaypointPath; +} + Fact *WimaController::enableWimaController() { return &_enableWimaController; @@ -253,7 +263,7 @@ void WimaController::resetPhase() bool WimaController::uploadToVehicle() { if ( !_serviceArea.containsCoordinate(_masterController->managerVehicle()->coordinate()) - && _missionController->visualItems()->count() > 0) { + && _currentMissionItems.count() > 0) { setUploadOverrideRequired(true); return false; } @@ -264,9 +274,10 @@ bool WimaController::uploadToVehicle() bool WimaController::forceUploadToVehicle() { setUploadOverrideRequired(false); - if (_missionController->visualItems()->count() < 1) + if (_currentMissionItems.count() < 1) return false; + _missionController->removeAll(); // set homeposition of settingsItem QmlObjectListModel* visuals = _missionController->visualItems(); MissionSettingsItem* settingsItem = visuals->value(0); @@ -276,6 +287,27 @@ bool WimaController::forceUploadToVehicle() } settingsItem->setCoordinate(_takeoffLandPostion); + // copy mission items from _currentMissionItems to _missionController + for (int i = 0; i < _currentMissionItems.count(); i++){ + SimpleMissionItem *item = _currentMissionItems.value(i); + _missionController->insertSimpleMissionItem(*item, visuals->count()); + if (item->command() == MAV_CMD_DO_CHANGE_SPEED) { + } + } + + for (int i = 0; i < _missionController->visualItems()->count(); i++){ + SimpleMissionItem *item = _missionController->visualItems()->value(i); + if (item == nullptr) + continue; + if (item->command() == MAV_CMD_DO_CHANGE_SPEED) { + } + } + for (int i = 0; i < _missionController->visualItems()->count(); i++){ + SimpleMissionItem *item = _missionController->visualItems()->value(i); + if (item == nullptr) + continue; + } + _masterController->sendToVehicle(); return true; @@ -284,6 +316,7 @@ bool WimaController::forceUploadToVehicle() void WimaController::removeFromVehicle() { _masterController->removeAllFromVehicle(); + _missionController->removeAll(); } bool WimaController::checkSmartRTLPreCondition() @@ -326,9 +359,16 @@ bool WimaController::initSmartRTL() bool retValue = calcReturnPath(); if (!retValue) return false; + emit uploadAndExecuteConfirmRequired(); return true; } +void WimaController::removeVehicleTrajectoryHistory() +{ + Vehicle *managerVehicle = masterController()->managerVehicle(); + managerVehicle->trajectoryPoints()->clear(); +} + void WimaController::saveToCurrent() { @@ -376,12 +416,12 @@ bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoo return retVal; } -bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVector &coordinateList) +bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVector &coordinateList) { return extractCoordinateList(missionItems, coordinateList, 0, missionItems.count()-1); } -bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVector &coordinateList, int startIndex, int endIndex) +bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVector &coordinateList, int startIndex, int endIndex) { if ( startIndex >= 0 && startIndex < missionItems.count() @@ -409,12 +449,12 @@ bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, Q return true; } -bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVariantList &coordinateList) +bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList) { return extractCoordinateList(missionItems, coordinateList, 0 , missionItems.count()-1); } -bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex) +bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex) { QVector geoCoordintateList; @@ -450,26 +490,26 @@ bool WimaController::fetchContainerData() // reset visual items _visualItems.clear(); _missionItems.clearAndDeleteContents(); - _missionController->removeAll(); + _currentMissionItems.clearAndDeleteContents(); + _waypointPath.clear(); + _currentWaypointPath.clear(); - _localPlanDataValid = false; + emit visualItemsChanged(); + emit missionItemsChanged(); + emit currentMissionItemsChanged(); + emit currentWaypointPathChanged(); - // fetch data from container - QSharedPointer planData; - if (_container != nullptr) { - planData = _container->pull(); - } else { + _localPlanDataValid = false; + + if (_container == nullptr) { qWarning("WimaController::fetchContainerData(): No container assigned!"); return false; } - // extract mission items - QList> tempMissionItems = planData->missionItems(); - if (tempMissionItems.size() < 1) - return false; + WimaPlanData planData = _container->pull(); // extract list with WimaAreas - QList areaList = planData->areaList(); + QList areaList = planData.areaList(); int areaCounter = 0; int numAreas = 4; // extract only numAreas Areas, if there are more they are invalid and ignored @@ -510,21 +550,37 @@ bool WimaController::fetchContainerData() if (areaCounter >= numAreas) break; - } + } - if (areaCounter != numAreas) { - qWarning("WimaController::fetchContainerData(): areaCounter != numAreas"); + // extract mission items + QList tempMissionItems = planData.missionItems(); + if (tempMissionItems.size() < 1) return false; - } - // create SimpleMissionItems - for (auto item : tempMissionItems) - _missionItems.append(new SimpleMissionItem( - _masterController->managerVehicle(), - true /* flyView*/, *item, this)); + // create mission items + _missionController->removeAll(); + QmlObjectListModel* missionControllerVisualItems = _missionController->visualItems(); + // create SimpleMissionItem by using _missionController + for ( int i = 0; i < tempMissionItems.size(); i++) { + _missionController->insertSimpleMissionItem(tempMissionItems[i], missionControllerVisualItems->count()); + } + // copy mission items from _missionController to _missionItems + for ( int i = 1; i < missionControllerVisualItems->count(); i++) { + SimpleMissionItem *visualItem = qobject_cast((*missionControllerVisualItems)[i]); + if (visualItem == nullptr) { + qWarning("WimaController::fetchContainerData(): Nullptr at SimpleMissionItem!"); + return false; + } + SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this); + _missionItems.append(visualItemCopy); + } + if (areaCounter != numAreas) + return false; + + if (!setTakeoffLandPosition()) + return false; - setTakeoffLandPosition(); updateWaypointPath(); // set _nextPhaseStartWaypointIndex to 1 @@ -533,10 +589,8 @@ bool WimaController::fetchContainerData() _nextPhaseStartWaypointIndex.setRawValue(reverse? _missionItems.count() : int(1)); connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); - /* if(!calcNextPhase()) return false; - */ emit visualItemsChanged(); emit missionItemsChanged(); @@ -547,17 +601,13 @@ bool WimaController::fetchContainerData() bool WimaController::calcNextPhase() { - auto start = std::chrono::high_resolution_clock::now(); if (_missionItems.count() < 1) { _startWaypointIndex = 0; _endWaypointIndex = 0; return false; } - qWarning() << "size QObject: " << sizeof (QObject); - qWarning() << "size MissionItem: " << sizeof (MissionItem); // 912 - qWarning() << "size VisualMissionItem: " << sizeof (VisualMissionItem); //384 - qWarning() << "size SimpleMissionItem: " << sizeof (SimpleMissionItem); // 3272 + _currentMissionItems.clearAndDeleteContents(); bool reverse = _reverse.rawValue().toBool(); // Reverses the phase direction. Phases go from high to low waypoint numbers, if true. int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt()-1; @@ -744,15 +794,29 @@ bool WimaController::calcNextPhase() } _missionController->setLandCommand(*landItem); + // copy to _currentMissionItems + for ( int i = 1; i < missionControllerVisuals->count(); i++) { + SimpleMissionItem *visualItem = missionControllerVisuals->value(i); + if (visualItem == nullptr) { + qWarning("WimaController::calcNextPhase(): Nullptr at SimpleMissionItem!"); + _currentMissionItems.clear(); + return false; + } + + SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this); + _currentMissionItems.append(visualItemCopy); + } + _setPhaseDistance(_measurementPathLength + _arrivalPathLength + _returnPathLength); _setPhaseDuration(_measurementPathLength/_flightSpeed.rawValue().toDouble() + (_arrivalPathLength + _returnPathLength) / _arrivalReturnSpeed.rawValue().toDouble()); + _missionController->removeAll(); // remove items from _missionController, will be added on upload updateAltitude(); - qWarning() << "WimaController::calcNextPhase() exec time: " - << std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start).count() << " ms"; + updateCurrentPath(); + emit currentMissionItemsChanged(); + return true; } @@ -763,6 +827,13 @@ void WimaController::updateWaypointPath() emit waypointPathChanged(); } +void WimaController::updateCurrentPath() +{ + _currentWaypointPath.clear(); + extractCoordinateList(_currentMissionItems, _currentWaypointPath, 0, _currentMissionItems.count()-1); + + emit currentWaypointPathChanged(); +} void WimaController::updateNextWaypoint() { @@ -793,9 +864,8 @@ bool WimaController::setTakeoffLandPosition() void WimaController::updateflightSpeed() { int speedItemCounter = 0; - QmlObjectListModel *visualMissionItems = _missionController->visualItems(); - for (int i = 0; i < visualMissionItems->count(); i++) { - SimpleMissionItem *item = visualMissionItems->value(i); + for (int i = 0; i < _currentMissionItems.count(); i++) { + SimpleMissionItem *item = _currentMissionItems.value(i); if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) { speedItemCounter++; if (speedItemCounter == 2) { @@ -815,9 +885,8 @@ void WimaController::updateflightSpeed() void WimaController::updateArrivalReturnSpeed() { int speedItemCounter = 0; - QmlObjectListModel *visualMissionItems = _missionController->visualItems(); - for (int i = 0; i < visualMissionItems->count(); i++) { - SimpleMissionItem *item = visualMissionItems->value(i); + for (int i = 0; i < _currentMissionItems.count(); i++) { + SimpleMissionItem *item = _currentMissionItems.value(i); if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) { speedItemCounter++; if (speedItemCounter != 2) { @@ -837,9 +906,8 @@ void WimaController::updateArrivalReturnSpeed() void WimaController::updateAltitude() { - QmlObjectListModel *visualMissionItems = _missionController->visualItems(); - for (int i = 0; i < visualMissionItems->count(); i++) { - SimpleMissionItem *item = visualMissionItems->value(i); + for (int i = 0; i < _currentMissionItems.count(); i++) { + SimpleMissionItem *item = _currentMissionItems.value(i); if (item == nullptr) { qWarning("WimaController::updateAltitude(): nullptr"); return; @@ -867,20 +935,24 @@ void WimaController::checkBatteryLevel() _setVehicleHasLowBattery(true); if (!_lowBatteryHandlingTriggered) { QString errorString; - attemptCounter++; - if (attemptCounter > 3) { - _lowBatteryHandlingTriggered = true; - attemptCounter = 0; - } + attemptCounter++; if (_checkSmartRTLPreCondition(errorString) == true) { managerVehicle->pauseVehicle(); if (_calcReturnPath(errorString)) { + _lowBatteryHandlingTriggered = true; + attemptCounter = 0; emit returnBatteryLowConfirmRequired(); } else { - qgcApp()->showMessage(tr("Battery level is low. Smart RTL not possible.")); - qgcApp()->showMessage(errorString); + if (attemptCounter > 3) { + qgcApp()->showMessage(tr("Battery level is low. Smart RTL not possible.")); + qgcApp()->showMessage(errorString); + } } } + if (attemptCounter > 3) { // try 3 times, somtimes vehicle is outside joined area + _lowBatteryHandlingTriggered = true; + attemptCounter = 0; + } } } else { @@ -899,6 +971,8 @@ void WimaController::smartRTLCleanUp(bool flying) _executingSmartRTL = false; _loadCurrentMissionItemsFromBuffer(); _showAllMissionItems.setRawValue(true); + _missionController->removeAllFromVehicle(); + _missionController->removeAll(); disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp); } } @@ -1030,16 +1104,36 @@ bool WimaController::_calcReturnPath(QString &errorSring) } _missionController->setLandCommand(*landItem); + // copy to _currentMissionItems + //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count(); + for ( int i = 1; i < missionControllerVisuals->count(); i++) { + SimpleMissionItem *visualItem = missionControllerVisuals->value(i); + if (visualItem == nullptr) { + qWarning("WimaController: Nullptr at SimpleMissionItem!"); + _currentMissionItems.clear(); + return false; + } + + SimpleMissionItem *visualItemCopy = new SimpleMissionItem(*visualItem, true, this); + _currentMissionItems.append(visualItemCopy); + } + //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count(); + _setPhaseDistance(_phaseDistance + _arrivalPathLength + _returnPathLength); _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble() + (_arrivalPathLength + _returnPathLength) / _arrivalReturnSpeed.rawValue().toDouble()); + _missionController->removeAll(); // remove items from _missionController, will be added on upload updateAltitude(); + updateCurrentPath(); + emit currentMissionItemsChanged(); + + + //qWarning() << "_currentMissionItems.count()" << _currentMissionItems.count(); _showAllMissionItems.setRawValue(false); managerVehicle->trajectoryPoints()->clear(); - emit uploadAndExecuteConfirmRequired(); return true; } @@ -1065,34 +1159,21 @@ bool WimaController::_executeSmartRTL(QString &errorSring) void WimaController::_loadCurrentMissionItemsFromBuffer() { - _missionController->removeAll(); + _currentMissionItems.clear(); int numItems = _missionItemsBuffer.count(); - for (int i = 0; i < numItems; i++) { - SimpleMissionItem *item = _missionItemsBuffer.value(i); - if (item != nullptr) - _missionController->insertSimpleMissionItem(item->missionItem(), i+1); - else { - qWarning("WimaController::_loadCurrentMissionItemsFromBuffer(): internal error"); - return; - } - } - _missionItems.clearAndDeleteContents(); + for (int i = 0; i < numItems; i++) + _currentMissionItems.append(_missionItemsBuffer.removeAt(0)); + + updateCurrentPath(); } void WimaController::_saveCurrentMissionItemsToBuffer() { _missionItemsBuffer.clear(); - int numItems = _missionController->visualItems()->count(); - for (int i = 0; i < numItems; i++) { - SimpleMissionItem *item = _missionController->visualItems()->value(i); - if (item != nullptr) - _missionItems.append(new SimpleMissionItem(*item, true /* flyView */, this)); - else { - qWarning("WimaController::_loadCurrentMissionItemsFromBuffer(): internal error"); - return; - } - } + int numCurrentMissionItems = _currentMissionItems.count(); + for (int i = 0; i < numCurrentMissionItems; i++) + _missionItemsBuffer.append(_currentMissionItems.removeAt(0)); } diff --git a/src/Wima/WimaController.cc.orig b/src/Wima/WimaController.cc.orig new file mode 100644 index 0000000000000000000000000000000000000000..14af70a3b6bafd4a3142ce105b5e0f75034b4150 --- /dev/null +++ b/src/Wima/WimaController.cc.orig @@ -0,0 +1,1150 @@ +#include "WimaController.h" + +const char* WimaController::wimaFileExtension = "wima"; +const char* WimaController::areaItemsName = "AreaItems"; +const char* WimaController::missionItemsName = "MissionItems"; +const char* WimaController::settingsGroup = "WimaController"; +const char* WimaController::enableWimaControllerName = "EnableWimaController"; +const char* WimaController::overlapWaypointsName = "OverlapWaypoints"; +const char* WimaController::maxWaypointsPerPhaseName = "MaxWaypointsPerPhase"; +const char* WimaController::startWaypointIndexName = "StartWaypointIndex"; +const char* WimaController::showAllMissionItemsName = "ShowAllMissionItems"; +const char* WimaController::showCurrentMissionItemsName = "ShowCurrentMissionItems"; +const char* WimaController::flightSpeedName = "FlightSpeed"; +const char* WimaController::arrivalReturnSpeedName = "ArrivalReturnSpeed"; +const char* WimaController::altitudeName = "Altitude"; +const char* WimaController::reverseName = "Reverse"; + +WimaController::WimaController(QObject *parent) + : QObject (parent) + , _container (nullptr) + , _joinedArea (this) + , _measurementArea (this) + , _serviceArea (this) + , _corridor (this) + , _localPlanDataValid (false) + , _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/WimaController.SettingsGroup.json"), this)) + , _enableWimaController (settingsGroup, _metaDataMap[enableWimaControllerName]) + , _overlapWaypoints (settingsGroup, _metaDataMap[overlapWaypointsName]) + , _maxWaypointsPerPhase (settingsGroup, _metaDataMap[maxWaypointsPerPhaseName]) + , _nextPhaseStartWaypointIndex (settingsGroup, _metaDataMap[startWaypointIndexName]) + , _showAllMissionItems (settingsGroup, _metaDataMap[showAllMissionItemsName]) + , _showCurrentMissionItems (settingsGroup, _metaDataMap[showCurrentMissionItemsName]) + , _flightSpeed (settingsGroup, _metaDataMap[flightSpeedName]) + , _arrivalReturnSpeed (settingsGroup, _metaDataMap[arrivalReturnSpeedName]) + , _altitude (settingsGroup, _metaDataMap[altitudeName]) + , _reverse (settingsGroup, _metaDataMap[reverseName]) + , _endWaypointIndex (0) + , _startWaypointIndex (0) + , _uploadOverrideRequired (false) + , _measurementPathLength (-1) + , _arrivalPathLength (-1) + , _returnPathLength (-1) + , _phaseDistance (-1) + , _phaseDuration (-1) + , _vehicleHasLowBattery (false) + , _lowBatteryHandlingTriggered(false) + , _executingSmartRTL (false) + +{ + _showAllMissionItems.setRawValue(true); + _showCurrentMissionItems.setRawValue(true); + connect(&_overlapWaypoints, &Fact::rawValueChanged, this, &WimaController::updateNextWaypoint); + connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this, &WimaController::recalcCurrentPhase); + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + connect(&_flightSpeed, &Fact::rawValueChanged, this, &WimaController::updateflightSpeed); + connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this, &WimaController::updateArrivalReturnSpeed); + connect(&_altitude, &Fact::rawValueChanged, this, &WimaController::updateAltitude); + connect(&_reverse, &Fact::rawValueChanged, this, &WimaController::reverseChangedHandler); + + // setup low battery handling + connect(&_checkBatteryTimer, &QTimer::timeout, this, &WimaController::checkBatteryLevel); + _checkBatteryTimer.setInterval(500); + Fact *enableLowBatteryHandling = qgcApp()->toolbox()->settingsManager()->wimaSettings()->enableLowBatteryHandling(); + connect(enableLowBatteryHandling, &Fact::rawValueChanged, this, &WimaController::enableDisableLowBatteryHandling); + enableDisableLowBatteryHandling(enableLowBatteryHandling->rawValue()); +} + +QmlObjectVectorModel* WimaController::visualItems() +{ + return &_visualItems; +} + +QStringList WimaController::loadNameFilters() const +{ + QStringList filters; + + filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension) << + tr("All Files (*.*)"); + return filters; +} + +QStringList WimaController::saveNameFilters() const +{ + QStringList filters; + + filters << tr("Supported types (*.%1 *.%2)").arg(wimaFileExtension).arg(AppSettings::planFileExtension); + return filters; +} + +WimaDataContainer *WimaController::dataContainer() +{ + return _container; +} + +QmlObjectVectorModel *WimaController::missionItems() +{ + return &_missionItems; +} + +QVariantList WimaController::waypointPath() +{ + return _waypointPath; +} + +Fact *WimaController::enableWimaController() +{ + return &_enableWimaController; +} + +Fact *WimaController::overlapWaypoints() +{ + return &_overlapWaypoints; +} + +Fact *WimaController::maxWaypointsPerPhase() +{ + return &_maxWaypointsPerPhase; +} + +Fact *WimaController::showAllMissionItems() +{ + return &_showAllMissionItems; +} + +Fact *WimaController::showCurrentMissionItems() +{ + return &_showCurrentMissionItems; +} + +Fact *WimaController::flightSpeed() +{ + return &_flightSpeed; +} + +Fact *WimaController::arrivalReturnSpeed() +{ + return &_arrivalReturnSpeed; +} + +Fact *WimaController::altitude() +{ + return &_altitude; +} + +Fact *WimaController::reverse() +{ + return &_reverse; +} + +bool WimaController::uploadOverrideRequired() const +{ + return _uploadOverrideRequired; +} + +double WimaController::phaseDistance() const +{ + return _phaseDistance; +} + +double WimaController::phaseDuration() const +{ + return _phaseDuration; +} + +bool WimaController::vehicleHasLowBattery() const +{ + return _vehicleHasLowBattery; +} + +Fact *WimaController::startWaypointIndex() +{ + return &_nextPhaseStartWaypointIndex; +} + +void WimaController::setMasterController(PlanMasterController *masterC) +{ + _masterController = masterC; + emit masterControllerChanged(); +} + +void WimaController::setMissionController(MissionController *missionC) +{ + _missionController = missionC; + emit missionControllerChanged(); +} + +/*! + * \fn void WimaController::setDataContainer(WimaDataContainer *container) + * Sets the pointer to the \c WimaDataContainer, which is meant to exchange data between the \c WimaController and the \c WimaPlaner. + * + * \sa WimaPlaner, WimaDataContainer, WimaPlanData + */ +void WimaController::setDataContainer(WimaDataContainer *container) +{ + if (container != nullptr) { + if (_container != nullptr) { + disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData); + } + + _container = container; + connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData); + + emit dataContainerChanged(); + } +} + +void WimaController::setUploadOverrideRequired(bool overrideRequired) +{ + if (_uploadOverrideRequired != overrideRequired) { + _uploadOverrideRequired = overrideRequired; + + emit uploadOverrideRequiredChanged(); + } +} + +void WimaController::nextPhase() +{ + calcNextPhase(); +} + +void WimaController::previousPhase() +{ + bool reverseBool = _reverse.rawValue().toBool(); + if (!reverseBool){ + int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt(); + if (startIndex > 0) { + _nextPhaseStartWaypointIndex.setRawValue(1+std::max(_startWaypointIndex + - _maxWaypointsPerPhase.rawValue().toInt() + + _overlapWaypoints.rawValue().toInt(), 0)); + } + } + else { + int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt(); + if (startIndex <= _missionItems.count()) { + _nextPhaseStartWaypointIndex.setRawValue(1+std::min(_startWaypointIndex + + _maxWaypointsPerPhase.rawValue().toInt() + - _overlapWaypoints.rawValue().toInt(), _missionItems.count()-1)); + } + } +} + +void WimaController::resetPhase() +{ + bool reverseBool = _reverse.rawValue().toBool(); + if (!reverseBool) { + _nextPhaseStartWaypointIndex.setRawValue(int(1)); + } + else { + _nextPhaseStartWaypointIndex.setRawValue(_missionItems.count()); + } +} + +bool WimaController::uploadToVehicle() +{ + if ( !_serviceArea.containsCoordinate(_masterController->managerVehicle()->coordinate()) + && _missionController->visualItems()->count() > 0) { + setUploadOverrideRequired(true); + return false; + } + + return forceUploadToVehicle(); +} + +bool WimaController::forceUploadToVehicle() +{ + setUploadOverrideRequired(false); + if (_missionController->visualItems()->count() < 1) + return false; + + // set homeposition of settingsItem + QmlObjectListModel* visuals = _missionController->visualItems(); + MissionSettingsItem* settingsItem = visuals->value(0); + if (settingsItem == nullptr) { + qWarning("WimaController::updateCurrentMissionItems(): nullptr"); + return false; + } + settingsItem->setCoordinate(_takeoffLandPostion); + +<<<<<<< HEAD +======= + // copy mission items from _currentMissionItems to _missionController + for (int i = 0; i < _currentMissionItems.count(); i++){ + SimpleMissionItem *item = _currentMissionItems.value(i); + _missionController->insertSimpleMissionItem(*item, visuals->count()); + if (item->command() == MAV_CMD_DO_CHANGE_SPEED) { + } + } + + for (int i = 0; i < _missionController->visualItems()->count(); i++){ + SimpleMissionItem *item = _missionController->visualItems()->value(i); + if (item == nullptr) + continue; + if (item->command() == MAV_CMD_DO_CHANGE_SPEED) { + } + } + for (int i = 0; i < _missionController->visualItems()->count(); i++){ + SimpleMissionItem *item = _missionController->visualItems()->value(i); + if (item == nullptr) + continue; + } + +>>>>>>> temp + _masterController->sendToVehicle(); + + return true; +} + +void WimaController::removeFromVehicle() +{ + _masterController->removeAllFromVehicle(); +} + +bool WimaController::checkSmartRTLPreCondition() +{ + QString errorString; + bool retValue = _checkSmartRTLPreCondition(errorString); + if (retValue == false) { + qgcApp()->showMessage(errorString); + return false; + } + return true; +} + +bool WimaController::calcReturnPath() +{ + QString errorString; + bool retValue = _calcReturnPath(errorString); + if (retValue == false) { + qgcApp()->showMessage(errorString); + return false; + } + return true; +} + +bool WimaController::executeSmartRTL() +{ + QString errorString; + bool retValue = _executeSmartRTL(errorString); + if (!retValue) { + qgcApp()->showMessage(errorString); + } + + return retValue; +} + +bool WimaController::initSmartRTL() +{ + masterController()->managerVehicle()->pauseVehicle(); + QString errorString; + bool retValue = calcReturnPath(); + if (!retValue) + return false; + emit uploadAndExecuteConfirmRequired(); + return true; +} + +void WimaController::removeVehicleTrajectoryHistory() +{ + Vehicle *managerVehicle = masterController()->managerVehicle(); + managerVehicle->trajectoryPoints()->clear(); +} + +void WimaController::saveToCurrent() +{ + +} + +void WimaController::saveToFile(const QString& filename) +{ + QString file = filename; +} + +bool WimaController::loadFromCurrent() +{ + return true; +} + +bool WimaController::loadFromFile(const QString &filename) +{ + QString file = filename; + return true; +} + + + +QJsonDocument WimaController::saveToJson(FileType fileType) +{ + if(fileType) + { + + } + return QJsonDocument(); +} + +bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordinate &destination, QVector &path) +{ + using namespace GeoUtilities; + using namespace PolygonCalculus; + QVector path2D; + bool retVal = PolygonCalculus::shortestPath( + toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)), + /*start point*/ QPointF(0,0), + /*destination*/ toCartesian2D(destination, start), + /*shortest path*/ path2D); + path.append(toGeo(path2D, /*origin*/ start)); + + return retVal; +} + +bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVector &coordinateList) +{ + return extractCoordinateList(missionItems, coordinateList, 0, missionItems.count()-1); +} + +bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVector &coordinateList, int startIndex, int endIndex) +{ + if ( startIndex >= 0 + && startIndex < missionItems.count() + && endIndex >= 0 + && endIndex < missionItems.count()) { + if (startIndex > endIndex) { + if (!extractCoordinateList(missionItems, coordinateList, startIndex, missionItems.count()-1)) + return false; + if (!extractCoordinateList(missionItems, coordinateList, 0, endIndex)) + return false; + } else { + for (int i = startIndex; i <= endIndex; i++) { + SimpleMissionItem *mItem = missionItems.value(i); + + if (mItem == nullptr) { + coordinateList.clear(); + return false; + } + coordinateList.append(mItem->coordinate()); + } + } + } else + return false; + + return true; +} + +bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVariantList &coordinateList) +{ + return extractCoordinateList(missionItems, coordinateList, 0 , missionItems.count()-1); +} + +bool WimaController::extractCoordinateList(QmlObjectVectorModel &missionItems, QVariantList &coordinateList, int startIndex, int endIndex) +{ + QVector geoCoordintateList; + + bool retValue = extractCoordinateList(missionItems, geoCoordintateList, startIndex, endIndex); + + if (!retValue) + return false; + + for (int i = 0; i < geoCoordintateList.size(); i++) { + QGeoCoordinate vertex = geoCoordintateList[i]; + if ( (qFuzzyIsNull(vertex.latitude()) && qFuzzyIsNull(vertex.longitude())) + || !vertex.isValid()) + geoCoordintateList.removeAt(i); + } + + for (auto coordinate : geoCoordintateList) + coordinateList.append(QVariant::fromValue(coordinate)); + + return true; +} + +/*! + * \fn void WimaController::containerDataValidChanged(bool valid) + * Pulls plan data generated by \c WimaPlaner from the \c _container if the data is valid (\a valid equals true). + * Is connected to the dataValidChanged() signal of the \c WimaDataContainer. + * + * \sa WimaDataContainer, WimaPlaner, WimaPlanData + */ +bool WimaController::fetchContainerData() +{ + // fetch only if valid, return true on sucess + + // reset visual items + _visualItems.clear(); + _missionItems.clearAndDeleteContents(); + _missionController->removeAll(); + + _localPlanDataValid = false; + + // fetch data from container + QSharedPointer planData; + if (_container != nullptr) { + planData = _container->pull(); + } else { + qWarning("WimaController::fetchContainerData(): No container assigned!"); + return false; + } + + // extract mission items + QList> tempMissionItems = planData->missionItems(); + if (tempMissionItems.size() < 1) + return false; + + // extract list with WimaAreas + QList areaList = planData->areaList(); + + int areaCounter = 0; + int numAreas = 4; // extract only numAreas Areas, if there are more they are invalid and ignored + for (int i = 0; i < areaList.size(); i++) { + const WimaAreaData *areaData = areaList[i]; + + if (areaData->type() == WimaServiceAreaData::typeString) { // is it a service area? + _serviceArea = *qobject_cast(areaData); + areaCounter++; + _visualItems.append(&_serviceArea); + + continue; + } + + if (areaData->type() == WimaMeasurementAreaData::typeString) { // is it a measurement area? + _measurementArea = *qobject_cast(areaData); + areaCounter++; + _visualItems.append(&_measurementArea); + + continue; + } + + if (areaData->type() == WimaCorridorData::typeString) { // is it a corridor? + _corridor = *qobject_cast(areaData); + areaCounter++; + //_visualItems.append(&_corridor); // not needed + + continue; + } + + if (areaData->type() == WimaJoinedAreaData::typeString) { // is it a corridor? + _joinedArea = *qobject_cast(areaData); + areaCounter++; + _visualItems.append(&_joinedArea); + + continue; + } + + if (areaCounter >= numAreas) + break; + } + + if (areaCounter != numAreas) { + qWarning("WimaController::fetchContainerData(): areaCounter != numAreas"); + return false; + } + + // create SimpleMissionItems + for (auto item : tempMissionItems) + _missionItems.append(new SimpleMissionItem( + _masterController->managerVehicle(), + true /* flyView*/, *item, this)); + + + setTakeoffLandPosition(); + updateWaypointPath(); + + // set _nextPhaseStartWaypointIndex to 1 + disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + bool reverse = _reverse.rawValue().toBool(); + _nextPhaseStartWaypointIndex.setRawValue(reverse? _missionItems.count() : int(1)); + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + + /* + if(!calcNextPhase()) + return false; + */ + + emit visualItemsChanged(); + emit missionItemsChanged(); + + _localPlanDataValid = true; + return true; +} + +bool WimaController::calcNextPhase() +{ + auto start = std::chrono::high_resolution_clock::now(); + if (_missionItems.count() < 1) { + _startWaypointIndex = 0; + _endWaypointIndex = 0; + return false; + } + + qWarning() << "size QObject: " << sizeof (QObject); + qWarning() << "size MissionItem: " << sizeof (MissionItem); // 912 + qWarning() << "size VisualMissionItem: " << sizeof (VisualMissionItem); //384 + qWarning() << "size SimpleMissionItem: " << sizeof (SimpleMissionItem); // 3272 + + bool reverse = _reverse.rawValue().toBool(); // Reverses the phase direction. Phases go from high to low waypoint numbers, if true. + int startIndex = _nextPhaseStartWaypointIndex.rawValue().toInt()-1; + if (!reverse) { + if (startIndex > _missionItems.count()-1) + return false; + } + else { + if (startIndex < 0) + return false; + } + _startWaypointIndex = startIndex; + + int maxWaypointsPerPhase = _maxWaypointsPerPhase.rawValue().toInt(); + // determine end waypoint index + bool lastMissionPhaseReached = false; + if (!reverse) { + _endWaypointIndex = std::min(_startWaypointIndex + maxWaypointsPerPhase - 1, _missionItems.count()-1); + if (_endWaypointIndex == _missionItems.count() - 1) + lastMissionPhaseReached = true; + } + else { + _endWaypointIndex = std::max(_startWaypointIndex - maxWaypointsPerPhase + 1, 0); + if (_endWaypointIndex == 0) + lastMissionPhaseReached = true; + } + + + // extract waypoints + QVector CSWpList; // list with potential waypoints (from _missionItems), for _currentMissionItems + + if (!reverse) { + if (!extractCoordinateList(_missionItems, CSWpList, _startWaypointIndex, _endWaypointIndex)) { + qWarning("WimaController::calcNextPhase(): error on waypoint extraction."); + return false; + } + } else { + if (!extractCoordinateList(_missionItems, CSWpList, _endWaypointIndex, _startWaypointIndex)) { + qWarning("WimaController::calcNextPhase(): error on waypoint extraction."); + return false; + } + + // reverse path + QVector reversePath; + for (QGeoCoordinate c : CSWpList) + reversePath.prepend(c); + CSWpList.clear(); + CSWpList.append(reversePath); + } + + + // calculate phase length + _measurementPathLength = 0; + for (int i = 0; i < CSWpList.size()-1; ++i) + _measurementPathLength += CSWpList[i].distanceTo(CSWpList[i+1]); + + + // set start waypoint index for next phase + if (!lastMissionPhaseReached) { + disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + if (!reverse) { + int untruncated = std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0); + int truncated = std::min(untruncated , _missionItems.count()-1); + _nextPhaseStartWaypointIndex.setRawValue(truncated + 1); + } + else { + int untruncated = std::min(_endWaypointIndex - 1 + _overlapWaypoints.rawValue().toInt(), _missionItems.count()-1); + int truncated = std::max(untruncated , 0); + _nextPhaseStartWaypointIndex.setRawValue(truncated + 1); + } + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + } + + // calculate path from home to first waypoint + QVector arrivalPath; + if (!_takeoffLandPostion.isValid()){ + qWarning("WimaController::calcNextPhase(): _takeoffLandPostion not valid."); + return false; + } + if ( !calcShortestPath(_takeoffLandPostion, CSWpList.first(), arrivalPath) ) { + qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint."); + return false; + } + + // calculate arrival path length + _arrivalPathLength = 0; + for (int i = 0; i < arrivalPath.size()-1; ++i) + _arrivalPathLength += arrivalPath[i].distanceTo(arrivalPath[i+1]); + + arrivalPath.removeFirst(); + + // calculate path from last waypoint to home + QVector returnPath; + if ( !calcShortestPath(CSWpList.last(), _takeoffLandPostion, returnPath) ) { + qWarning("WimaController::calcNextPhase(): Not able to calc path from home to first waypoint."); + return false; + } + + // calculate arrival path length + _returnPathLength = 0; + for (int i = 0; i < returnPath.size()-1; ++i) + _returnPathLength += returnPath[i].distanceTo(returnPath[i+1]); + + returnPath.removeFirst(); + returnPath.removeLast(); + + + + // create Mission Items + _missionController->removeAll(); + QmlObjectListModel* missionControllerVisuals = _missionController->visualItems(); + + // set homeposition of settingsItem + MissionSettingsItem* settingsItem = missionControllerVisuals->value(0); + if (settingsItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + settingsItem->setCoordinate(_takeoffLandPostion); + + // set takeoff position for first mission item (bug) + missionController()->insertSimpleMissionItem(_takeoffLandPostion, 1); + SimpleMissionItem *takeoffItem = missionControllerVisuals->value(1); + if (takeoffItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + takeoffItem->setCoordinate(_takeoffLandPostion); + + // create change speed item, after take off + _missionController->insertSimpleMissionItem(_takeoffLandPostion, 2); + SimpleMissionItem *speedItem = missionControllerVisuals->value(2); + if (speedItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED);// set coordinate must be after setCommand (setCommand sets coordinate to zero) + speedItem->setCoordinate(_takeoffLandPostion); + speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble()); + + // insert arrival path + for (auto coordinate : arrivalPath) + _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count()); + + // create change speed item, after arrival path + int index = missionControllerVisuals->count(); + _missionController->insertSimpleMissionItem(CSWpList.first(), index); + speedItem = missionControllerVisuals->value(index); + if (speedItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); // set coordinate must be after setCommand (setCommand sets coordinate to zero) + speedItem->setCoordinate(CSWpList.first()); + speedItem->missionItem().setParam2(_flightSpeed.rawValue().toDouble()); + + // insert Circular Survey coordinates + for (auto coordinate : CSWpList) + _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count()); + + // create change speed item, after circular survey + index = missionControllerVisuals->count(); + _missionController->insertSimpleMissionItem(CSWpList.last(), index); + speedItem = missionControllerVisuals->value(index); + if (speedItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); // set coordinate must be after setCommand (setCommand sets coordinate to zero) + speedItem->setCoordinate(CSWpList.last()); + speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble()); + + // insert return path coordinates + for (auto coordinate : returnPath) + _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count()); + + // set land command for last mission item + index = missionControllerVisuals->count(); + _missionController->insertSimpleMissionItem(_takeoffLandPostion, index); + SimpleMissionItem *landItem = missionControllerVisuals->value(index); + if (landItem == nullptr) { + qWarning("WimaController::calcNextPhase(): nullptr"); + return false; + } + _missionController->setLandCommand(*landItem); + + _setPhaseDistance(_measurementPathLength + _arrivalPathLength + _returnPathLength); + _setPhaseDuration(_measurementPathLength/_flightSpeed.rawValue().toDouble() + + (_arrivalPathLength + _returnPathLength) + / _arrivalReturnSpeed.rawValue().toDouble()); + updateAltitude(); + + qWarning() << "WimaController::calcNextPhase() exec time: " + << std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - start).count() << " ms"; + return true; +} + +void WimaController::updateWaypointPath() +{ + _waypointPath.clear(); + extractCoordinateList(_missionItems, _waypointPath, 0, _missionItems.count()-1); + + emit waypointPathChanged(); +} + +void WimaController::updateNextWaypoint() +{ + if (_endWaypointIndex < _missionItems.count()-2) { + disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + _nextPhaseStartWaypointIndex.setRawValue(1 + std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0)); + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + } +} + +void WimaController::recalcCurrentPhase() +{ + disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + _nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1); + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + calcNextPhase(); +} + +bool WimaController::setTakeoffLandPosition() +{ + _takeoffLandPostion.setAltitude(0); + _takeoffLandPostion.setLongitude(_serviceArea.center().longitude()); + _takeoffLandPostion.setLatitude(_serviceArea.center().latitude()); + + return true; +} + +void WimaController::updateflightSpeed() +{ + int speedItemCounter = 0; + QmlObjectListModel *visualMissionItems = _missionController->visualItems(); + for (int i = 0; i < visualMissionItems->count(); i++) { + SimpleMissionItem *item = visualMissionItems->value(i); + if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) { + speedItemCounter++; + if (speedItemCounter == 2) { + item->missionItem().setParam2(_flightSpeed.rawValue().toDouble()); + } + } + } + + _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble() + + (_arrivalPathLength + _returnPathLength) + / _arrivalReturnSpeed.rawValue().toDouble()); + + if (speedItemCounter != 3) + qWarning("WimaController::updateflightSpeed(): internal error."); +} + +void WimaController::updateArrivalReturnSpeed() +{ + int speedItemCounter = 0; + QmlObjectListModel *visualMissionItems = _missionController->visualItems(); + for (int i = 0; i < visualMissionItems->count(); i++) { + SimpleMissionItem *item = visualMissionItems->value(i); + if (item != nullptr && item->command() == MAV_CMD_DO_CHANGE_SPEED) { + speedItemCounter++; + if (speedItemCounter != 2) { + item->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble()); + } + } + } + + _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble() + + (_arrivalPathLength + _returnPathLength) + / _arrivalReturnSpeed.rawValue().toDouble()); + + if (speedItemCounter != 3) + qWarning("WimaController::updateArrivalReturnSpeed(): internal error."); + +} + +void WimaController::updateAltitude() +{ + QmlObjectListModel *visualMissionItems = _missionController->visualItems(); + for (int i = 0; i < visualMissionItems->count(); i++) { + SimpleMissionItem *item = visualMissionItems->value(i); + if (item == nullptr) { + qWarning("WimaController::updateAltitude(): nullptr"); + return; + } + item->altitude()->setRawValue(_altitude.rawValue().toDouble()); + } +} + +void WimaController::checkBatteryLevel() +{ + Vehicle *managerVehicle = masterController()->managerVehicle(); + WimaSettings* wimaSettings = qgcApp()->toolbox()->settingsManager()->wimaSettings(); + int batteryThreshold = wimaSettings->lowBatteryThreshold()->rawValue().toInt(); + bool enabled = _enableWimaController.rawValue().toBool(); + + static long attemptCounter = 0; + + if (managerVehicle != nullptr && enabled == true) { + Fact *battery1percentRemaining = managerVehicle->battery1FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName); + Fact *battery2percentRemaining = managerVehicle->battery2FactGroup()->getFact(VehicleBatteryFactGroup::_percentRemainingFactName); + + + if (battery1percentRemaining->rawValue().toDouble() < batteryThreshold + && battery2percentRemaining->rawValue().toDouble() < batteryThreshold) { + _setVehicleHasLowBattery(true); + if (!_lowBatteryHandlingTriggered) { + QString errorString; + attemptCounter++; + if (_checkSmartRTLPreCondition(errorString) == true) { + managerVehicle->pauseVehicle(); + if (_calcReturnPath(errorString)) { + _lowBatteryHandlingTriggered = true; + attemptCounter = 0; + emit returnBatteryLowConfirmRequired(); + } else { + if (attemptCounter > 3) { + qgcApp()->showMessage(tr("Battery level is low. Smart RTL not possible.")); + qgcApp()->showMessage(errorString); + } + } + } + if (attemptCounter > 3) { // try 3 times, somtimes vehicle is outside joined area + _lowBatteryHandlingTriggered = true; + attemptCounter = 0; + } + } + } + else { + _setVehicleHasLowBattery(false); + _lowBatteryHandlingTriggered = false; + } + + } +} + +void WimaController::smartRTLCleanUp(bool flying) +{ + + if ( !flying) { // vehicle has landed + if (_executingSmartRTL) { + _executingSmartRTL = false; + _loadCurrentMissionItemsFromBuffer(); + _showAllMissionItems.setRawValue(true); + _missionController->removeAllFromVehicle(); + _missionController->removeAll(); + disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp); + } + } +} + +void WimaController::enableDisableLowBatteryHandling(QVariant enable) +{ + if (enable.toBool()) { + _checkBatteryTimer.start(); + } else { + _checkBatteryTimer.stop(); + } +} + +void WimaController::reverseChangedHandler() +{ + disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + _nextPhaseStartWaypointIndex.setRawValue(_endWaypointIndex+1); + connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase); + + calcNextPhase(); +} + +void WimaController::_setPhaseDistance(double distance) +{ + if (!qFuzzyCompare(distance, _phaseDistance)) { + _phaseDistance = distance; + + emit phaseDistanceChanged(); + } +} + +void WimaController::_setPhaseDuration(double duration) +{ + if (!qFuzzyCompare(duration, _phaseDuration)) { + _phaseDuration = duration; + + emit phaseDurationChanged(); + } +} + +bool WimaController::_checkSmartRTLPreCondition(QString &errorString) +{ + if (!_localPlanDataValid) { + errorString.append(tr("No WiMA data available. Please define at least a measurement and a service area.")); + return false; + } + Vehicle *managerVehicle = masterController()->managerVehicle(); + if (!managerVehicle->flying()) { + errorString.append(tr("Vehicle is not flying. Smart RTL not available.")); + return false; + } + + return true; +} + +bool WimaController::_calcReturnPath(QString &errorSring) +{ + // it is assumed that checkSmartRTLPreCondition() was called first and true was returned + + + Vehicle *managerVehicle = masterController()->managerVehicle(); + + QGeoCoordinate currentVehiclePosition = managerVehicle->coordinate(); + // check if vehicle inside _joinedArea, this statement is not inside checkSmartRTLPreCondition() because during checkSmartRTLPreCondition() vehicle is not paused yet + if (!_joinedArea.containsCoordinate(currentVehiclePosition)) { + errorSring.append(tr("Vehicle not inside joined area. Action not supported.")); + return false; + } + + // calculate return path + QVector returnPath; + calcShortestPath(currentVehiclePosition, _takeoffLandPostion, returnPath); + // successful? + if (returnPath.isEmpty()) { + errorSring.append(tr("Not able to calculate return path.")); + return false; + } + // qWarning() << "returnPath.size()" << returnPath.size(); + + _saveCurrentMissionItemsToBuffer(); + + // create Mission Items + removeFromVehicle(); + QmlObjectListModel* missionControllerVisuals = _missionController->visualItems(); + + // set homeposition of settingsItem + MissionSettingsItem* settingsItem = missionControllerVisuals->value(0); + if (settingsItem == nullptr) { + qWarning("WimaController: nullptr"); + return false; + } + settingsItem->setCoordinate(_takeoffLandPostion); + + // copy from returnPath to _missionController + QGeoCoordinate speedItemCoordinate = returnPath.first(); + for (auto coordinate : returnPath) { + _missionController->insertSimpleMissionItem(coordinate, missionControllerVisuals->count()); + } + //qWarning() << "missionControllerVisuals->count()" << missionControllerVisuals->count(); + + // create speed item + int speedItemIndex = 1; + _missionController->insertSimpleMissionItem(speedItemCoordinate, speedItemIndex); + SimpleMissionItem *speedItem = missionControllerVisuals->value(speedItemIndex); + if (speedItem == nullptr) { + qWarning("WimaController: nullptr"); + return false; + } + speedItem->setCommand(MAV_CMD_DO_CHANGE_SPEED); + speedItem->setCoordinate(speedItemCoordinate); + speedItem->missionItem().setParam2(_arrivalReturnSpeed.rawValue().toDouble()); + + // set second item command to ordinary waypoint (is takeoff) + SimpleMissionItem *secondItem = missionControllerVisuals->value(2); + if (secondItem == nullptr) { + qWarning("WimaController: nullptr"); + return false; + } + secondItem->setCoordinate(speedItemCoordinate); + secondItem->setCommand(MAV_CMD_NAV_WAYPOINT); + + + // set land command for last mission item + SimpleMissionItem *landItem = missionControllerVisuals->value(missionControllerVisuals->count()-1); + if (landItem == nullptr) { + qWarning("WimaController: nullptr"); + return false; + } + _missionController->setLandCommand(*landItem); + + _setPhaseDistance(_phaseDistance + _arrivalPathLength + _returnPathLength); + _setPhaseDuration(_phaseDistance/_flightSpeed.rawValue().toDouble() + + (_arrivalPathLength + _returnPathLength) + / _arrivalReturnSpeed.rawValue().toDouble()); + updateAltitude(); + + _showAllMissionItems.setRawValue(false); + managerVehicle->trajectoryPoints()->clear(); + + return true; +} + +void WimaController::_setVehicleHasLowBattery(bool batteryLow) +{ + if (_vehicleHasLowBattery != batteryLow) { + _vehicleHasLowBattery = batteryLow; + + emit vehicleHasLowBatteryChanged(); + } +} + +bool WimaController::_executeSmartRTL(QString &errorSring) +{ + Q_UNUSED(errorSring) + _executingSmartRTL = true; + connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp); + forceUploadToVehicle(); + masterController()->managerVehicle()->startMission(); + + return true; +} + +void WimaController::_loadCurrentMissionItemsFromBuffer() +{ + _missionController->removeAll(); + int numItems = _missionItemsBuffer.count(); +<<<<<<< HEAD + for (int i = 0; i < numItems; i++) { + SimpleMissionItem *item = _missionItemsBuffer.value(i); + if (item != nullptr) + _missionController->insertSimpleMissionItem(item->missionItem(), i+1); + else { + qWarning("WimaController::_loadCurrentMissionItemsFromBuffer(): internal error"); + return; + } + } + _missionItems.clearAndDeleteContents(); +======= + qWarning() << "WimaController::_loadCurrentMissionItemsFromBuffer: numItems" << numItems; + for (int i = 0; i < numItems; i++) + _currentMissionItems.append(_missionItemsBuffer.removeAt(0)); + + updateCurrentPath(); +>>>>>>> temp +} + + +void WimaController::_saveCurrentMissionItemsToBuffer() +{ + _missionItemsBuffer.clear(); +<<<<<<< HEAD + int numItems = _missionController->visualItems()->count(); + for (int i = 0; i < numItems; i++) { + SimpleMissionItem *item = _missionController->visualItems()->value(i); + if (item != nullptr) + _missionItems.append(new SimpleMissionItem(*item, true /* flyView */, this)); + else { + qWarning("WimaController::_loadCurrentMissionItemsFromBuffer(): internal error"); + return; + } + } +======= + int numItems = _currentMissionItems.count(); + qWarning() << "WimaController::_saveCurrentMissionItemsToBuffer: numItems" << numItems; + for (int i = 0; i < numItems; i++) + _missionItemsBuffer.append(_currentMissionItems.removeAt(0)); +>>>>>>> temp +} + + + diff --git a/src/Wima/WimaController.h b/src/Wima/WimaController.h index b39b96eff19195193e83ee346d6a0071e0451ec7..2d39c2e36d57b5a6d3928d7bc4a04a8f805a7313 100644 --- a/src/Wima/WimaController.h +++ b/src/Wima/WimaController.h @@ -108,6 +108,7 @@ public: Q_INVOKABLE bool calcReturnPath(); // wrapper for _calcReturnPath(QString &errorSring)# Q_INVOKABLE bool executeSmartRTL(); // wrapper for _executeSmartRTL(QString &errorSring) Q_INVOKABLE bool initSmartRTL(); + Q_INVOKABLE void removeVehicleTrajectoryHistory(); Q_INVOKABLE void saveToCurrent ();