diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro
index cf615e4cef0944e6a582564fcee6ff0646b24e04..564325873ba3a930500b2cfcfa7564e265d35200 100644
--- a/qgroundcontrol.pro
+++ b/qgroundcontrol.pro
@@ -264,6 +264,7 @@ INCLUDEPATH += \
src/ui/px4_configuration \
src/ui/main \
src/ui/toolbar \
+ src/ui/flightdisplay \
src/VehicleSetup \
src/AutoPilotPlugins \
src/QmlControls
@@ -490,7 +491,8 @@ HEADERS += \
src/uas/UASMessageHandler.h \
src/ui/toolbar/MainToolBar.h \
src/QmlControls/ScreenTools.h \
- src/QGCLoggingCategory.h
+ src/QGCLoggingCategory.h \
+ src/ui/flightdisplay/QGCFlightDisplay.h
SOURCES += \
src/main.cc \
@@ -631,7 +633,8 @@ SOURCES += \
src/uas/UASMessageHandler.cc \
src/ui/toolbar/MainToolBar.cc \
src/QmlControls/ScreenTools.cc \
- src/QGCLoggingCategory.cc
+ src/QGCLoggingCategory.cc \
+ src/ui/flightdisplay/QGCFlightDisplay.cc
#
# Unit Test specific configuration goes here
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 629936dd5b382dcb184950242994c16cc6ebb46d..93fecfe5b8b17a8e0ecb7b2448f583d18ac815f1 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -305,6 +305,21 @@
src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_05cell.svg
src/AutoPilotPlugins/PX4/Images/PowerComponentBattery_06cell.svg
src/ui/toolbar/MainToolBar.qml
+ src/ui/flightdisplay/FlightDisplay.qml
+ src/ui/flightdisplay/components/qmldir
+ src/ui/flightdisplay/components/QGCAltitudeWidget.qml
+ src/ui/flightdisplay/components/QGCAttitudeWidget.qml
+ src/ui/flightdisplay/components/QGCCompass.qml
+ src/ui/flightdisplay/components/QGCCurrentAltitude.qml
+ src/ui/flightdisplay/components/QGCCurrentSpeed.qml
+ src/ui/flightdisplay/components/QGCMapBackground.qml
+ src/ui/flightdisplay/components/QGCPitchWidget.qml
+ src/ui/flightdisplay/components/QGCSpeedWidget.qml
+ src/ui/flightdisplay/components/compass.svg
+ src/ui/flightdisplay/components/compassNeedle.svg
+ src/ui/flightdisplay/components/crossHair.svg
+ src/ui/flightdisplay/components/rollDial.svg
+ src/ui/flightdisplay/components/rollPointer.svg
src/AutoPilotPlugins/PX4/ParameterFactMetaData.xml
diff --git a/src/qgcunittest/MockUAS.h b/src/qgcunittest/MockUAS.h
index 5f396e7de78403baa984ee132b8c3d611d159ad5..0db0c3e14b1c825a0c7fa12ccd0fb4806061084a 100644
--- a/src/qgcunittest/MockUAS.h
+++ b/src/qgcunittest/MockUAS.h
@@ -49,6 +49,7 @@ public:
// Implemented UASInterface overrides
virtual int getSystemType(void) { return _systemType; }
virtual int getUASID(void) const { return _systemId; }
+ virtual bool isAirplane() { return false; }
virtual QGCUASParamManagerInterface* getParamManager() { return &_paramManager; };
// sendMessage is only supported if a mavlink plugin is installed.
diff --git a/src/uas/UAS.cc b/src/uas/UAS.cc
index 5237d50da10a9bdb210e32c27098962233ae634b..c16b6770950f4a9a76309d8372809274582d2d96 100644
--- a/src/uas/UAS.cc
+++ b/src/uas/UAS.cc
@@ -2673,6 +2673,21 @@ int UAS::getSystemType()
return this->type;
}
+/** @brief Is it an airplane (or like one)?,..)*/
+bool UAS::isAirplane()
+{
+ switch(this->type) {
+ case MAV_TYPE_GENERIC:
+ case MAV_TYPE_FIXED_WING:
+ case MAV_TYPE_AIRSHIP:
+ case MAV_TYPE_FLAPPING_WING:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
/**
* Halt the uas.
*/
diff --git a/src/uas/UAS.h b/src/uas/UAS.h
index 53f2ba1c36e9f0563fc9b887bf420aa10ec2d1c0..fadb9b2867537ebef5e7c81672f873d437d80e7b 100644
--- a/src/uas/UAS.h
+++ b/src/uas/UAS.h
@@ -508,7 +508,8 @@ public:
}
- int getSystemType();
+ int getSystemType();
+ bool isAirplane();
/**
* @brief Returns true for systems that can reverse. If the system has no control over position, it returns false as
diff --git a/src/uas/UASInterface.h b/src/uas/UASInterface.h
index 276d28b5edfc36ad84ad2ae46d9b6ad03ee0367f..a30f6685c5cdd69e867c014d8c27f565bcf4afb4 100644
--- a/src/uas/UASInterface.h
+++ b/src/uas/UASInterface.h
@@ -213,6 +213,8 @@ public:
/** @brief Get the type of the system (airplane, quadrotor, helicopter,..)*/
virtual int getSystemType() = 0;
+ /** @brief Is it an airplane (or like one)?,..)*/
+ virtual bool isAirplane() = 0;
/** @brief Indicates whether this system is capable of controlling a reverse velocity.
* Used for, among other things, altering joystick input to either -1:1 or 0:1 range.
*/
diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc
index ee96c7b92ed95bc7515b25827da1e5d00f45d9b9..eab3cb41799414b69839705c5b438619a4472e78 100644
--- a/src/ui/MainWindow.cc
+++ b/src/ui/MainWindow.cc
@@ -60,6 +60,7 @@ This file is part of the QGROUNDCONTROL project
#include "QGCTabbedInfoView.h"
#include "UASRawStatusView.h"
#include "PrimaryFlightDisplay.h"
+#include "QGCFlightDisplay.h"
#include "SetupView.h"
#include "SerialSettingsDialog.h"
#include "terminalconsole.h"
@@ -447,7 +448,8 @@ void MainWindow::_buildPlannerView(void)
void MainWindow::_buildPilotView(void)
{
if (!_pilotView) {
- _pilotView = new PrimaryFlightDisplay(this);
+ //_pilotView = new PrimaryFlightDisplay(this);
+ _pilotView = new QGCFlightDisplay(this);
_pilotView->setVisible(false);
}
}
@@ -560,7 +562,8 @@ void MainWindow::_createInnerDockWidget(const QString& widgetName)
widget = hddisplay;
} else if (widgetName == _pfdDockWidgetName) {
- widget = new PrimaryFlightDisplay(this);
+ widget = new QGCFlightDisplay(this);
+ //widget = new PrimaryFlightDisplay(this);
} else if (widgetName == _hudDockWidgetName) {
widget = new HUD(320,240,this);
} else if (widgetName == _uasInfoViewDockWidgetName) {
diff --git a/src/ui/flightdisplay/FlightDisplay.qml b/src/ui/flightdisplay/FlightDisplay.qml
new file mode 100644
index 0000000000000000000000000000000000000000..c4463c9e148fa700cde4e8706f23192f210e3b40
--- /dev/null
+++ b/src/ui/flightdisplay/FlightDisplay.qml
@@ -0,0 +1,364 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Main Tool Bar
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Controls.Styles 1.2
+
+import QGroundControl.HUDControls 1.0
+
+Rectangle {
+ id: root
+ color: Qt.rgba(0,0,0,0);
+
+ property real roll: isNaN(flightDisplay.roll) ? 0 : flightDisplay.roll
+ property real pitch: isNaN(flightDisplay.pitch) ? 0 : flightDisplay.pitch
+
+ Component.onCompleted:
+ {
+ mapBackground.visible = flightDisplay.loadSetting("enableMapBackground", false);
+ mapBackground.alwaysNorth = flightDisplay.loadSetting("mapAlwaysNorth", false);
+ attitudeWidget.visible = flightDisplay.loadSetting("enableattitudeWidget", true);
+ attitudeWidget.displayBackground = flightDisplay.loadSetting("displayRollPitchBackground", true);
+ pitchWidget.visible = flightDisplay.loadSetting("enablepitchWidget", true);
+ altitudeWidget.visible = flightDisplay.loadSetting("enablealtitudeWidget", true);
+ speedWidget.visible = flightDisplay.loadSetting("enablespeedWidget", true);
+ compassIndicator.visible = flightDisplay.loadSetting("enableCompassIndicator", true);
+ currentSpeed.showAirSpeed = flightDisplay.loadSetting("showAirSpeed", true);
+ currentSpeed.showGroundSpeed = flightDisplay.loadSetting("showGroundSpeed", true);
+ currentAltitude.showClimbRate = flightDisplay.loadSetting("showCurrentClimbRate", true);
+ currentAltitude.showAltitude = flightDisplay.loadSetting("showCurrentAltitude", true);
+ mapTypeMenu.update();
+ }
+
+ Rectangle {
+ id: windowBackground
+ anchors.fill: parent
+ anchors.centerIn: parent
+ visible: !attitudeWidget.visible && !mapBackground.visible
+ color: Qt.hsla(0.25, 0.5, 0.45)
+ z: 0
+ }
+
+ Menu {
+ id: mapTypeMenu
+ function setCurrentMap(map) {
+ for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) {
+ if (map === mapBackground.mapItem.supportedMapTypes[i].name) {
+ mapBackground.mapItem.activeMapType = mapBackground.mapItem.supportedMapTypes[i]
+ return;
+ }
+ }
+ }
+ function addMap(map) {
+ var mItem = mapTypeMenu.addItem(map);
+ var menuSlot = function() {setCurrentMap(map);};
+ mItem.triggered.connect(menuSlot);
+ }
+ function update() {
+ clear()
+ for (var i = 0; i < mapBackground.mapItem.supportedMapTypes.length; i++) {
+ addMap(mapBackground.mapItem.supportedMapTypes[i].name);
+ }
+ if (mapBackground.mapItem.supportedMapTypes.length > 0)
+ setCurrentMap(mapBackground.mapItem.activeMapType.name);
+ }
+ }
+
+ Menu {
+ id: contextMenu
+
+ MenuItem {
+ text: "Roll/Pitch Indicators"
+ checkable: true
+ checked: attitudeWidget.visible
+ onTriggered:
+ {
+ attitudeWidget.visible = !attitudeWidget.visible;
+ flightDisplay.saveSetting("enableattitudeWidget", attitudeWidget.visible);
+ }
+ }
+
+ MenuItem {
+ text: "Display Roll/Pitch Background"
+ checkable: true
+ checked: attitudeWidget.displayBackground
+ onTriggered:
+ {
+ attitudeWidget.displayBackground = !attitudeWidget.displayBackground;
+ flightDisplay.saveSetting("displayRollPitchBackground", attitudeWidget.displayBackground);
+ }
+ }
+
+ MenuItem {
+ text: "Pitch Indicator"
+ checkable: true
+ checked: pitchWidget.visible
+ onTriggered:
+ {
+ pitchWidget.visible = !pitchWidget.visible;
+ flightDisplay.saveSetting("enablepitchWidget", pitchWidget.visible);
+ }
+ }
+
+ MenuItem {
+ text: "Altitude Indicator"
+ checkable: true
+ checked: altitudeWidget.visible
+ onTriggered:
+ {
+ altitudeWidget.visible = !altitudeWidget.visible;
+ flightDisplay.saveSetting("enablealtitudeWidget", altitudeWidget.visible);
+ }
+ }
+
+ MenuItem {
+ text: "Current Altitude"
+ checkable: true
+ checked: currentAltitude.showAltitude
+ onTriggered:
+ {
+ currentAltitude.showAltitude = !currentAltitude.showAltitude;
+ flightDisplay.saveSetting("showCurrentAltitude", currentAltitude.showAltitude);
+ }
+ }
+
+ MenuItem {
+ text: "Current Climb Rate"
+ checkable: true
+ checked: currentAltitude.showClimbRate
+ onTriggered:
+ {
+ currentAltitude.showClimbRate = !currentAltitude.showClimbRate;
+ flightDisplay.saveSetting("showCurrentClimbRate", currentAltitude.showClimbRate);
+ }
+ }
+
+ MenuItem {
+ text: "Speed Indicator"
+ checkable: true
+ checked: speedWidget.visible
+ onTriggered:
+ {
+ speedWidget.visible = !speedWidget.visible;
+ flightDisplay.saveSetting("enablespeedWidget", speedWidget.visible);
+ }
+ }
+
+ MenuItem {
+ text: "Current Air Speed"
+ checkable: true
+ checked: currentSpeed.showAirSpeed
+ onTriggered:
+ {
+ currentSpeed.showAirSpeed = !currentSpeed.showAirSpeed;
+ flightDisplay.saveSetting("showAirSpeed", currentSpeed.showAirSpeed);
+ }
+ }
+
+ MenuItem {
+ text: "Current Ground Speed"
+ checkable: true
+ checked: currentSpeed.showGroundSpeed
+ onTriggered:
+ {
+ currentSpeed.showGroundSpeed = !currentSpeed.showGroundSpeed;
+ flightDisplay.saveSetting("showGroundSpeed", currentSpeed.showGroundSpeed);
+ }
+ }
+
+ MenuItem {
+ text: "Compass"
+ checkable: true
+ checked: compassIndicator.visible
+ onTriggered:
+ {
+ compassIndicator.visible = !compassIndicator.visible;
+ flightDisplay.saveSetting("enableCompassIndicator", compassIndicator.visible);
+ }
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: "Map Background"
+ checkable: true
+ checked: mapBackground.visible
+ onTriggered:
+ {
+ mapBackground.visible = !mapBackground.visible;
+ flightDisplay.saveSetting("enableMapBackground", mapBackground.visible);
+ }
+ }
+
+ MenuItem {
+ text: "Map Follows Heading"
+ checkable: true
+ checked: !mapBackground.alwaysNorth
+ onTriggered:
+ {
+ mapBackground.alwaysNorth = !mapBackground.alwaysNorth;
+ flightDisplay.saveSetting("mapAlwaysNorth", mapBackground.alwaysNorth);
+ }
+ }
+
+ MenuItem {
+ text: "Map Type..."
+ checkable: false
+ onTriggered:
+ {
+ mapTypeMenu.popup();
+ }
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: "Restore Defaults"
+ onTriggered:
+ {
+ attitudeWidget.visible = true;
+ flightDisplay.saveSetting("enableattitudeWidget", attitudeWidget.visible);
+ attitudeWidget.displayBackground = true;
+ flightDisplay.saveSetting("displayRollPitchBackground", attitudeWidget.displayBackground);
+ pitchWidget.visible = true;
+ flightDisplay.saveSetting("enablepitchWidget", pitchWidget.visible);
+ altitudeWidget.visible = true;
+ flightDisplay.saveSetting("enablealtitudeWidget", altitudeWidget.visible);
+ currentAltitude.showAltitude = true;
+ flightDisplay.saveSetting("showCurrentAltitude", currentAltitude.showAltitude);
+ currentAltitude.showClimbRate = true;
+ flightDisplay.saveSetting("showCurrentClimbRate", currentAltitude.showClimbRate);
+ speedWidget.visible = true;
+ flightDisplay.saveSetting("enablespeedWidget", speedWidget.visible);
+ currentSpeed.showAirSpeed = true;
+ flightDisplay.saveSetting("showAirSpeed", currentSpeed.showAirSpeed);
+ currentSpeed.showGroundSpeed = true;
+ flightDisplay.saveSetting("showGroundSpeed", currentSpeed.showGroundSpeed);
+ compassIndicator.visible = true;
+ flightDisplay.saveSetting("enableCompassIndicator", compassIndicator.visible);
+ mapBackground.visible = false;
+ flightDisplay.saveSetting("enableMapBackground", mapBackground.visible);
+ mapBackground.alwaysNorth = false;
+ flightDisplay.saveSetting("mapAlwaysNorth", mapBackground.alwaysNorth);
+ }
+ }
+
+ }
+
+ QGCMapBackground {
+ id: mapBackground
+ anchors.centerIn: parent
+ visible: false
+ heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading
+ latitude: flightDisplay.latitude
+ longitude: flightDisplay.longitude
+ z: 5
+ }
+
+ QGCAttitudeWidget {
+ id: attitudeWidget
+ anchors.centerIn: parent
+ rollAngle: roll
+ pitchAngle: pitch
+ backgroundOpacity: mapBackground.visible ? 0.25 : 1.0
+ z: 10
+ }
+
+ QGCPitchWidget {
+ id: pitchWidget
+ anchors.verticalCenter: parent.verticalCenter
+ opacity: 0.5
+ pitchAngle: pitch
+ rollAngle: roll
+ z: 20
+ }
+
+ QGCAltitudeWidget {
+ id: altitudeWidget
+ anchors.right: parent.right
+ width: 40
+ altitude: flightDisplay.altitudeWGS84
+ z: 30
+ }
+
+ QGCSpeedWidget {
+ id: speedWidget
+ anchors.left: parent.left
+ width: 40
+ speed: flightDisplay.groundSpeed
+ z: 40
+ }
+
+ QGCCurrentSpeed {
+ id: currentSpeed
+ anchors.left: parent.left
+ width: 80
+ airspeed: flightDisplay.airSpeed
+ groundspeed: flightDisplay.groundSpeed
+ showAirSpeed: true
+ showGroundSpeed: true
+ visible: currentSpeed.showGroundSpeed || currentSpeed.showAirSpeed
+ z: 50
+ }
+
+ QGCCurrentAltitude {
+ id: currentAltitude
+ anchors.right: parent.right
+ width: 80
+ altitude: flightDisplay.altitudeWGS84
+ vertZ: flightDisplay.climbRate
+ showAltitude: true
+ showClimbRate: true
+ visible: (currentAltitude.showAltitude || currentAltitude.showClimbRate)
+ z: 60
+ }
+
+ QGCCompass {
+ id: compassIndicator
+ y: root.height * 0.65
+ anchors.horizontalCenter: parent.horizontalCenter
+ heading: isNaN(flightDisplay.heading) ? 0 : flightDisplay.heading
+ z: 70
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ if (mouse.button == Qt.RightButton)
+ {
+ contextMenu.popup()
+ }
+ }
+ z: 100
+ }
+
+}
+
diff --git a/src/ui/flightdisplay/QGCFlightDisplay.cc b/src/ui/flightdisplay/QGCFlightDisplay.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f926ff5de149e8486e8dfa5c062bc41ed97304a7
--- /dev/null
+++ b/src/ui/flightdisplay/QGCFlightDisplay.cc
@@ -0,0 +1,310 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Main Flight Display
+ * @author Gus Grubba
+ */
+
+#include
+#include
+#include
+
+#include "QGCFlightDisplay.h"
+#include "UASManager.h"
+
+#define UPDATE_TIMER 50
+
+const char* kMainFlightDisplayGroup = "MainFlightDisplay";
+
+QGCFlightDisplay::QGCFlightDisplay(QWidget *parent)
+ : QGCQmlWidgetHolder(parent)
+ , _mav(NULL)
+ , _roll(0.0)
+ , _pitch(0.0)
+ , _heading(0.0)
+ , _altitudeAMSL(0.0)
+ , _altitudeWGS84(0.0)
+ , _altitudeRelative(0.0)
+ , _groundSpeed(0.0)
+ , _airSpeed(0.0)
+ , _climbRate(0.0)
+ , _navigationAltitudeError(0.0)
+ , _navigationSpeedError(0.0)
+ , _navigationCrosstrackError(0.0)
+ , _navigationTargetBearing(0.0)
+ , _latitude(37.803784)
+ , _longitude(-122.462276)
+ , _refreshTimer(new QTimer(this))
+ , _valuesChanged(false)
+ , _valuesLastPainted(0)
+{
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ setObjectName("MainFlightDisplay");
+ // Get rid of layout default margins
+ QLayout* pl = layout();
+ if(pl) {
+ pl->setContentsMargins(0,0,0,0);
+ }
+ setMinimumWidth(270);
+ setMinimumHeight(300);
+ setContextPropertyObject("flightDisplay", this);
+ setSource(QUrl::fromUserInput("qrc:/qml/FlightDisplay.qml"));
+ setVisible(true);
+ // Connect with UAS signal
+ _setActiveUAS(UASManager::instance()->getActiveUAS());
+ connect(UASManager::instance(), SIGNAL(UASDeleted(UASInterface*)), this, SLOT(_forgetUAS(UASInterface*)));
+ connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(_setActiveUAS(UASInterface*)));
+ // Refresh timer
+ _refreshTimer->setInterval(UPDATE_TIMER);
+ connect(_refreshTimer, SIGNAL(timeout()), this, SLOT(_checkUpdate()));
+}
+
+QGCFlightDisplay::~QGCFlightDisplay()
+{
+ _refreshTimer->stop();
+}
+
+void QGCFlightDisplay::saveSetting(const QString& name, bool value)
+{
+ QSettings settings;
+ QString key(kMainFlightDisplayGroup);
+ key += "/" + name;
+ settings.setValue(key, value);
+}
+
+bool QGCFlightDisplay::loadSetting(const QString& name, bool defaultValue)
+{
+ QSettings settings;
+ QString key(kMainFlightDisplayGroup);
+ key += "/" + name;
+ return settings.value(key, defaultValue).toBool();
+}
+
+void QGCFlightDisplay::_forgetUAS(UASInterface* uas)
+{
+ if (_mav != NULL && _mav == uas) {
+ // Disconnect any previously connected active MAV
+ disconnect(_mav, SIGNAL(attitudeChanged (UASInterface*, double,double,double,quint64)), this, SLOT(_updateAttitude(UASInterface*, double, double, double, quint64)));
+ disconnect(_mav, SIGNAL(attitudeChanged (UASInterface*, int,double,double,double,quint64)), this, SLOT(_updateAttitude(UASInterface*,int,double, double, double, quint64)));
+ disconnect(_mav, SIGNAL(speedChanged (UASInterface*, double, double, quint64)), this, SLOT(_updateSpeed(UASInterface*, double, double, quint64)));
+ disconnect(_mav, SIGNAL(altitudeChanged (UASInterface*, double, double, double, double, quint64)), this, SLOT(_updateAltitude(UASInterface*, double, double, double, double, quint64)));
+ disconnect(_mav, SIGNAL(navigationControllerErrorsChanged(UASInterface*, double, double, double)), this, SLOT(_updateNavigationControllerErrors(UASInterface*, double, double, double)));
+ disconnect(_mav, &UASInterface::NavigationControllerDataChanged, this, &QGCFlightDisplay::_updateNavigationControllerData);
+ }
+ _mav = NULL;
+}
+
+void QGCFlightDisplay::_setActiveUAS(UASInterface* uas)
+{
+ if (uas == _mav)
+ return;
+ // Disconnect the previous one (if any)
+ if(_mav) {
+ _forgetUAS(_mav);
+ }
+ if (uas) {
+ // Now connect the new UAS
+ // Setup communication
+ connect(uas, SIGNAL(attitudeChanged (UASInterface*,double,double,double,quint64)), this, SLOT(_updateAttitude(UASInterface*, double, double, double, quint64)));
+ connect(uas, SIGNAL(attitudeChanged (UASInterface*,int,double,double,double,quint64)), this, SLOT(_updateAttitude(UASInterface*,int,double, double, double, quint64)));
+ connect(uas, SIGNAL(speedChanged (UASInterface*, double, double, quint64)), this, SLOT(_updateSpeed(UASInterface*, double, double, quint64)));
+ connect(uas, SIGNAL(altitudeChanged (UASInterface*, double, double, double, double, quint64)), this, SLOT(_updateAltitude(UASInterface*, double, double, double, double, quint64)));
+ connect(uas, SIGNAL(navigationControllerErrorsChanged (UASInterface*, double, double, double)), this, SLOT(_updateNavigationControllerErrors(UASInterface*, double, double, double)));
+ connect(uas, &UASInterface::NavigationControllerDataChanged, this, &QGCFlightDisplay::_updateNavigationControllerData);
+ // Set new UAS
+ _mav = uas;
+ }
+}
+
+void QGCFlightDisplay::_updateAttitude(UASInterface*, double roll, double pitch, double yaw, quint64)
+{
+ if (isinf(roll)) {
+ _roll = std::numeric_limits::quiet_NaN();
+ } else {
+ bool update = false;
+ float rolldeg = roll * (180.0 / M_PI);
+ if (fabsf(roll - rolldeg) > 2.5f) {
+ update = true;
+ }
+ _roll = rolldeg;
+ if (update)
+ {
+ if(_refreshTimer->isActive()) emit rollChanged();
+ _valuesChanged = true;
+ }
+ }
+ if (isinf(pitch)) {
+ _pitch = std::numeric_limits::quiet_NaN();
+ } else {
+ bool update = false;
+ float pitchdeg = pitch * (180.0 / M_PI);
+ if (fabsf(pitch - pitchdeg) > 2.5f) {
+ update = true;
+ }
+ _pitch = pitchdeg;
+ if (update)
+ {
+ if(_refreshTimer->isActive()) emit pitchChanged();
+ _valuesChanged = true;
+ }
+ }
+ if (isinf(yaw)) {
+ _heading = std::numeric_limits::quiet_NaN();
+ } else {
+ bool update = false;
+ yaw = yaw * (180.0 / M_PI);
+ if (yaw < 0) yaw += 360;
+ if (fabsf(_heading - yaw) > 10.0f) {
+ update = true;
+ }
+ _heading = yaw;
+ if (update)
+ {
+ if(_refreshTimer->isActive()) emit headingChanged();
+ _valuesChanged = true;
+ }
+ }
+}
+
+void QGCFlightDisplay::_updateAttitude(UASInterface* uas, int, double roll, double pitch, double yaw, quint64 timestamp)
+{
+ _updateAttitude(uas, roll, pitch, yaw, timestamp);
+}
+
+void QGCFlightDisplay::_updateSpeed(UASInterface*, double groundSpeed, double airSpeed, quint64)
+{
+ double oldgroundSpeed = _groundSpeed;
+ double oldairSpeed = _airSpeed;
+ _groundSpeed = groundSpeed;
+ _airSpeed = airSpeed;
+ if (fabsf(oldgroundSpeed - groundSpeed) > 0.5f) {
+ if(_refreshTimer->isActive()) emit groundSpeedChanged();
+ _valuesChanged = true;
+ }
+ if (fabsf(oldairSpeed - airSpeed) > 1.0f) {
+ if(_refreshTimer->isActive()) emit airSpeedChanged();
+ _valuesChanged = true;
+ }
+}
+
+void QGCFlightDisplay::_updateAltitude(UASInterface*, double altitudeAMSL, double altitudeWGS84, double altitudeRelative, double climbRate, quint64) {
+ double oldclimbRate = _climbRate;
+ double oldaltitudeRelative = _altitudeRelative;
+ double oldaltitudeWGS84 = _altitudeWGS84;
+ double oldaltitudeAMSL = _altitudeAMSL;
+ _climbRate = climbRate;
+ _altitudeRelative = altitudeRelative;
+ _altitudeWGS84 = altitudeWGS84;
+ _altitudeAMSL = altitudeAMSL;
+ if(_climbRate > -0.01 && _climbRate < 0.01) {
+ _climbRate = 0.0;
+ }
+ if (fabsf(oldaltitudeAMSL - altitudeAMSL) > 0.5f) {
+ if(_refreshTimer->isActive()) emit altitudeAMSLChanged();
+ _valuesChanged = true;
+ }
+ if (fabsf(oldaltitudeWGS84 - altitudeWGS84) > 0.5f) {
+ if(_refreshTimer->isActive()) emit altitudeWGS84Changed();
+ _valuesChanged = true;
+ }
+ if (fabsf(oldaltitudeRelative - altitudeRelative) > 0.5f) {
+ if(_refreshTimer->isActive()) emit altitudeRelativeChanged();
+ _valuesChanged = true;
+ }
+ if (fabsf(oldclimbRate - climbRate) > 0.5f) {
+ if(_refreshTimer->isActive()) emit climbRateChanged();
+ _valuesChanged = true;
+ }
+}
+
+void QGCFlightDisplay::_updateNavigationControllerErrors(UASInterface*, double altitudeError, double speedError, double xtrackError) {
+ _navigationAltitudeError = altitudeError;
+ _navigationSpeedError = speedError;
+ _navigationCrosstrackError = xtrackError;
+}
+
+void QGCFlightDisplay::_updateNavigationControllerData(UASInterface *uas, float, float, float, float targetBearing, float) {
+ if (_mav == uas) {
+ _navigationTargetBearing = targetBearing;
+ }
+}
+
+/*
+ * Internal
+ */
+
+bool QGCFlightDisplay::_isAirplane() {
+ if (_mav)
+ return _mav->isAirplane();
+ return false;
+}
+
+// TODO: Implement. Should return true when navigating.
+// That would be (PX4) in AUTO and RTL modes.
+// This could forward to a virtual on UAS bool isNavigatingAutonomusly() or whatever.
+bool QGCFlightDisplay::_shouldDisplayNavigationData() {
+ return true;
+}
+
+void QGCFlightDisplay::showEvent(QShowEvent* event)
+{
+ // React only to internal (pre-display) events
+ QWidget::showEvent(event);
+ _refreshTimer->start(UPDATE_TIMER);
+}
+
+void QGCFlightDisplay::hideEvent(QHideEvent* event)
+{
+ // React only to internal (pre-display) events
+ _refreshTimer->stop();
+ QWidget::hideEvent(event);
+}
+
+void QGCFlightDisplay::_checkUpdate()
+{
+ if (_mav && (_valuesChanged || (QGC::groundTimeMilliseconds() - _valuesLastPainted) > 260)) {
+ _valuesChanged = false;
+ _valuesLastPainted = QGC::groundTimeMilliseconds();
+ emit rollChanged();
+ emit pitchChanged();
+ emit headingChanged();
+ emit altitudeAMSLChanged();
+ emit altitudeWGS84Changed();
+ emit altitudeRelativeChanged();
+ emit climbRateChanged();
+ emit groundSpeedChanged();
+ emit airSpeedChanged();
+ emit repaintRequestedChanged();
+ emit latitudeChanged();
+ emit longitudeChanged();
+ }
+ if(_mav) {
+ _latitude = _mav->getLatitude();
+ _longitude = _mav->getLongitude();
+ if(_latitude) emit latitudeChanged();
+ if(_longitude) emit longitudeChanged();
+ }
+}
+
diff --git a/src/ui/flightdisplay/QGCFlightDisplay.h b/src/ui/flightdisplay/QGCFlightDisplay.h
new file mode 100644
index 0000000000000000000000000000000000000000..be50cdb0dfaf5698dff5ed0cd496569caa5bae11
--- /dev/null
+++ b/src/ui/flightdisplay/QGCFlightDisplay.h
@@ -0,0 +1,140 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Main Flight Display
+ * @author Gus Grubba
+ */
+
+#ifndef QGCFLIGHTDISPLAY_H
+#define QGCFLIGHTDISPLAY_H
+
+#include "QGCQmlWidgetHolder.h"
+
+class UASInterface;
+
+class QGCFlightDisplay : public QGCQmlWidgetHolder
+{
+ Q_OBJECT
+public:
+ QGCFlightDisplay(QWidget* parent = NULL);
+ ~QGCFlightDisplay();
+
+ Q_PROPERTY(float roll READ roll NOTIFY rollChanged)
+ Q_PROPERTY(float pitch READ pitch NOTIFY pitchChanged)
+ Q_PROPERTY(float heading READ heading NOTIFY headingChanged)
+ Q_PROPERTY(float groundSpeed READ groundSpeed NOTIFY groundSpeedChanged)
+ Q_PROPERTY(float airSpeed READ airSpeed NOTIFY airSpeedChanged)
+ Q_PROPERTY(float climbRate READ climbRate NOTIFY climbRateChanged)
+ Q_PROPERTY(float altitudeRelative READ altitudeRelative NOTIFY altitudeRelativeChanged)
+ Q_PROPERTY(float altitudeWGS84 READ altitudeWGS84 NOTIFY altitudeWGS84Changed)
+ Q_PROPERTY(float altitudeAMSL READ altitudeAMSL NOTIFY altitudeAMSLChanged)
+ Q_PROPERTY(bool repaintRequested READ repaintRequested NOTIFY repaintRequestedChanged)
+ Q_PROPERTY(float latitude READ latitude NOTIFY latitudeChanged)
+ Q_PROPERTY(float longitude READ longitude NOTIFY longitudeChanged)
+
+ Q_INVOKABLE void saveSetting (const QString &key, bool value);
+ Q_INVOKABLE bool loadSetting (const QString &key, bool defaultValue);
+
+ float roll () { return _roll; }
+ float pitch () { return _pitch; }
+ float heading () { return _heading; }
+ float groundSpeed () { return _groundSpeed; }
+ float airSpeed () { return _airSpeed; }
+ float climbRate () { return _climbRate; }
+ float altitudeRelative () { return _altitudeRelative; }
+ float altitudeWGS84 () { return _altitudeWGS84; }
+ float altitudeAMSL () { return _altitudeAMSL; }
+ float latitude () { return _latitude; }
+ float longitude () { return _longitude; }
+ bool repaintRequested () { return true; }
+
+ /** @brief Start updating widget */
+ void showEvent(QShowEvent* event);
+ /** @brief Stop updating widget */
+ void hideEvent(QHideEvent* event);
+
+signals:
+ void rollChanged ();
+ void pitchChanged ();
+ void headingChanged ();
+ void groundSpeedChanged ();
+ void airSpeedChanged ();
+ void climbRateChanged ();
+ void altitudeRelativeChanged();
+ void altitudeWGS84Changed ();
+ void altitudeAMSLChanged ();
+ void repaintRequestedChanged();
+ void latitudeChanged ();
+ void longitudeChanged ();
+
+private slots:
+ /** @brief Attitude from main autopilot / system state */
+ void _updateAttitude (UASInterface* uas, double roll, double pitch, double yaw, quint64 timestamp);
+ /** @brief Attitude from one specific component / redundant autopilot */
+ void _updateAttitude (UASInterface* uas, int component, double roll, double pitch, double yaw, quint64 timestamp);
+ /** @brief Speed */
+ void _updateSpeed (UASInterface* uas, double _groundSpeed, double _airSpeed, quint64 timestamp);
+ /** @brief Altitude */
+ void _updateAltitude (UASInterface* uas, double _altitudeAMSL, double _altitudeWGS84, double _altitudeRelative, double _climbRate, quint64 timestamp);
+ void _updateNavigationControllerErrors (UASInterface* uas, double altitudeError, double speedError, double xtrackError);
+ void _updateNavigationControllerData (UASInterface *uas, float navRoll, float navPitch, float navBearing, float targetBearing, float targetDistance);
+ void _forgetUAS (UASInterface* uas);
+ void _setActiveUAS (UASInterface* uas);
+ void _checkUpdate ();
+
+private:
+ bool _isAirplane ();
+ bool _shouldDisplayNavigationData ();
+
+private:
+ UASInterface* _mav;
+
+ float _roll;
+ float _pitch;
+ float _heading;
+
+ float _altitudeAMSL;
+ float _altitudeWGS84;
+ float _altitudeRelative;
+
+ float _groundSpeed;
+ float _airSpeed;
+ float _climbRate;
+
+ float _navigationAltitudeError;
+ float _navigationSpeedError;
+ float _navigationCrosstrackError;
+ float _navigationTargetBearing;
+
+ float _latitude;
+ float _longitude;
+
+ QTimer* _refreshTimer;
+ bool _valuesChanged;
+ quint64 _valuesLastPainted;
+};
+
+
+#endif // QGCFLIGHTDISPLAY_H
diff --git a/src/ui/flightdisplay/components/QGCAltitudeWidget.qml b/src/ui/flightdisplay/components/QGCAltitudeWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..e1ac294fe1babe89771000e8e63cc3a82795ce3f
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCAltitudeWidget.qml
@@ -0,0 +1,104 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Altitude Indicator
+ * @author Gus Grubba
+ */
+
+// TODO: This is temporary until I find a better way to display a large range of numbers
+
+import QtQuick 2.4
+
+Rectangle {
+ id: root
+ property real altitude: 50
+ property real _reticleSpacing: 29
+ property real _reticleHeight: 1
+ property real _reticleSlot: _reticleSpacing + _reticleHeight
+ property var _speedArray: []
+ property int _currentCenter: 0
+ property int _currentStart: -100
+
+ function updateArray() {
+ var tmpArray = [];
+ _currentCenter = Math.floor(altitude / 5) * 5;
+ _currentStart = _currentCenter + 100;
+ for(var i = 0; i < 40; i++) {
+ tmpArray[i] = _currentStart - (i * 5);
+ }
+ _speedArray = tmpArray;
+ }
+
+ Component.onCompleted:
+ {
+ updateArray() ;
+ }
+
+ onAltitudeChanged: {
+ if(Math.abs(_currentCenter - altitude) > 50) {
+ updateArray() ;
+ }
+ }
+
+ anchors.verticalCenter: parent.verticalCenter
+
+ height: parent.height * 0.75 > 280 ? 280 : parent.height * 0.75
+ clip: true
+ smooth: true
+ border.color: Qt.rgba(1,1,1,0.25)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: Qt.rgba(0,0,0,0.35) }
+ GradientStop { position: 0.5; color: Qt.rgba(0,0,0,0.15) }
+ GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.35) }
+ }
+ Column{
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: _reticleSpacing
+ Repeater {
+ model: _speedArray
+ Rectangle {
+ width: root.width
+ height: _reticleHeight
+ color: Qt.rgba(1,1,1,0.1)
+ Text {
+ property real _alt: modelData
+ visible: (_alt % 10 === 0)
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ antialiasing: true
+ font.weight: _alt < 0 ? Font.Light : Font.DemiBold
+ text: _alt < 0 ? -_alt : _alt
+ color: _alt < 0 ? "#ef2526" : "white"
+ style: Text.Outline
+ styleColor: Qt.rgba(0,0,0,0.25)
+ }
+ }
+ }
+ transform: Translate {
+ y: ((altitude - _currentCenter) * _reticleSlot / 5) - (_reticleSlot / 2)
+ }
+ }
+}
diff --git a/src/ui/flightdisplay/components/QGCAttitudeWidget.qml b/src/ui/flightdisplay/components/QGCAttitudeWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..d30d89b62234d3f007816cbaf7fa16e1bf093642
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCAttitudeWidget.qml
@@ -0,0 +1,125 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Main Flight Display
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.4
+
+Item {
+ id: root
+ property real rollAngle : 0
+ property real pitchAngle: 0
+ property real backgroundOpacity: 1
+ property bool displayBackground: true
+
+ anchors.fill: parent
+
+ Item {
+ id: background
+ width: parent.width * 4
+ height: parent.height * 4
+ anchors.centerIn: parent
+
+ Rectangle {
+ anchors.fill: parent
+ color: Qt.rgba(0,0,0,0)
+ visible: displayBackground
+
+ Rectangle {
+ id: sky
+ visible: displayBackground
+ anchors.fill: parent
+ smooth: true
+ antialiasing: true
+ gradient: Gradient {
+ GradientStop { position: 0.25; color: Qt.hsla(0.6, 1.0, 0.25, backgroundOpacity) }
+ GradientStop { position: 0.5; color: Qt.hsla(0.6, 0.5, 0.75, backgroundOpacity) }
+ }
+ }
+
+ Rectangle {
+ id: ground
+ visible: displayBackground
+ height: sky.height / 2
+ anchors {
+ left: sky.left;
+ right: sky.right;
+ bottom: sky.bottom
+ }
+ smooth: true
+ antialiasing: true
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: Qt.hsla(0.25, 0.5, 0.45, backgroundOpacity) }
+ GradientStop { position: 0.25; color: Qt.hsla(0.25, 0.75, 0.25, backgroundOpacity) }
+ }
+ }
+
+ transform: [
+ Translate {
+ y: (root.visible && root.displayBackground) ? pitchAngle * 4 : 0
+ },
+ Rotation {
+ origin.x: background.width / 2
+ origin.y: background.height / 2
+ angle: (root.visible && root.displayBackground) ? -rollAngle : 0
+ }]
+ }
+
+ }
+
+ Image {
+ id: rollDial
+ anchors { bottom: root.verticalCenter; horizontalCenter: parent.horizontalCenter}
+ source: "/qml/rollDial.svg"
+ mipmap: true
+ width: 250
+ fillMode: Image.PreserveAspectFit
+ transform: Rotation {
+ origin.x: rollDial.width / 2
+ origin.y: rollDial.height
+ angle: -rollAngle
+ }
+ }
+
+ Image {
+ id: pointer
+ anchors { bottom: root.verticalCenter; horizontalCenter: parent.horizontalCenter}
+ source: "/qml/rollPointer.svg"
+ smooth: true
+ width: rollDial.width
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ anchors.centerIn: parent
+ source: "/qml/crossHair.svg"
+ mipmap: true
+ width: rollDial.width
+ fillMode: Image.PreserveAspectFit
+ }
+
+}
diff --git a/src/ui/flightdisplay/components/QGCCompass.qml b/src/ui/flightdisplay/components/QGCCompass.qml
new file mode 100644
index 0000000000000000000000000000000000000000..1cb162b690e656bd1f9ee0b27eb1eac4a578828a
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCCompass.qml
@@ -0,0 +1,74 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Compass
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.4
+
+Item {
+ id: root
+ width: parent.width * 0.25 > 150 ? parent.width * 0.25 : 150
+ height: width
+ property real heading : 0
+ Image {
+ id: compass
+ anchors.centerIn: parent
+ source: "/qml/compass.svg"
+ mipmap: true
+ width: root.width
+ fillMode: Image.PreserveAspectFit
+ transform: Rotation {
+ origin.x: compass.width / 2
+ origin.y: compass.height / 2
+ angle: -heading
+ }
+ }
+ Image {
+ id: pointer
+ anchors.bottom: compass.top
+ anchors.horizontalCenter: root.horizontalCenter
+ source: "/qml/compassNeedle.svg"
+ smooth: true
+ width: compass.width * 0.1
+ fillMode: Image.PreserveAspectFit
+ }
+ Rectangle {
+ anchors.centerIn: compass
+ width: 40
+ height: 25
+ border.color: Qt.rgba(1,1,1,0.25)
+ color: Qt.rgba(1,1,1,0.1)
+ Text {
+ text: heading.toFixed(0)
+ font.weight: Font.DemiBold
+ color: "white"
+ anchors.centerIn: parent
+ }
+ }
+}
+
+
diff --git a/src/ui/flightdisplay/components/QGCCurrentAltitude.qml b/src/ui/flightdisplay/components/QGCCurrentAltitude.qml
new file mode 100644
index 0000000000000000000000000000000000000000..206cbeb93432d6bd270fe4ef1c84bf00f60f5381
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCCurrentAltitude.qml
@@ -0,0 +1,62 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Current Altitude Indicator
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.1
+
+Rectangle {
+ id: root
+ property real altitude: 0
+ property real vertZ: 0
+ property bool showAltitude: true
+ property bool showClimbRate: true
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ height: (showAltitude && showClimbRate) ? 50 : 25
+ color: "black"
+ border.color: Qt.rgba(1,1,1,0.25)
+ opacity: 1.0
+ Column{
+ anchors.centerIn: parent
+ spacing: 4
+ Text {
+ text: 'h: ' + altitude.toFixed(1)
+ font.weight: Font.DemiBold
+ color: "white"
+ anchors.right: parent.right
+ visible: showAltitude
+ }
+ Text {
+ text: 'vZ: ' + vertZ.toFixed(1)
+ color: "white"
+ font.weight: showAltitude ? Font.Normal : Font.DemiBold
+ anchors.right: parent.right
+ visible: showClimbRate
+ }
+ }
+}
diff --git a/src/ui/flightdisplay/components/QGCCurrentSpeed.qml b/src/ui/flightdisplay/components/QGCCurrentSpeed.qml
new file mode 100644
index 0000000000000000000000000000000000000000..cc42cf5059fe3b7cfdf5da7444bd455d2a39bf66
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCCurrentSpeed.qml
@@ -0,0 +1,62 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Current Speed Indicator
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.1
+
+Rectangle {
+ id: root
+ property real airspeed: 0
+ property real groundspeed: 0
+ property bool showAirSpeed: true
+ property bool showGroundSpeed: true
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ height: (showAirSpeed && showGroundSpeed) ? 50 : 25
+ color: "black"
+ border.color: Qt.rgba(1,1,1,0.25)
+ opacity: 1.0
+ Column{
+ anchors.centerIn: parent
+ spacing: 4
+ Text {
+ text: 'GS: ' + groundspeed.toFixed(1)
+ font.weight: Font.DemiBold
+ color: "white"
+ anchors.right: parent.right
+ visible: showGroundSpeed
+ }
+ Text {
+ text: 'AS: ' + airspeed.toFixed(1)
+ color: "white"
+ anchors.right: parent.right
+ font.weight: showAirSpeed ? Font.Normal : Font.DemiBold
+ visible: showAirSpeed
+ }
+ }
+}
diff --git a/src/ui/flightdisplay/components/QGCMapBackground.qml b/src/ui/flightdisplay/components/QGCMapBackground.qml
new file mode 100644
index 0000000000000000000000000000000000000000..9e880a5e8a6575f3d2d0481b594e4d3bf2714376
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCMapBackground.qml
@@ -0,0 +1,90 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Map Background
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.4
+import QtPositioning 5.3
+import QtLocation 5.3
+
+Rectangle {
+ id: root
+ property real latitude: 37.803784
+ property real longitude : -122.462276
+ property real zoomLevel: 12
+ property real heading: 0
+ property bool alwaysNorth: true
+ property alias mapItem: map
+
+ anchors.fill: parent
+ color: Qt.rgba(0,0,0,0)
+ clip: true
+
+ function adjustSize() {
+ if(root.visible) {
+ if(alwaysNorth) {
+ map.width = root.width;
+ map.height = root.height;
+ } else {
+ var diag = Math.ceil(Math.sqrt((root.width * root.width) + (root.height * root.height)));
+ map.width = diag;
+ map.height = diag;
+ }
+ } else {
+ map.width = 1;
+ map.height = 1;
+ }
+ }
+
+ Plugin {
+ id: mapPlugin
+ name: "osm"
+ }
+
+ Map {
+ id: map
+ plugin: mapPlugin
+ width: 1
+ height: 1
+ zoomLevel: zoomLevel
+ anchors.centerIn: parent
+ center: map.visible ? QtPositioning.coordinate(latitude, longitude) : QtPositioning.coordinate(0,0)
+ transform: Rotation {
+ origin.x: map.width / 2
+ origin.y: map.height / 2
+ angle: map.visible ? (alwaysNorth ? 0 : -heading) : 0
+ }
+ gesture.flickDeceleration: 3000
+ gesture.enabled: true
+ }
+
+ onVisibleChanged: adjustSize();
+ onWidthChanged: adjustSize();
+ onHeightChanged: adjustSize();
+ onAlwaysNorthChanged: adjustSize();
+
+}
diff --git a/src/ui/flightdisplay/components/QGCPitchWidget.qml b/src/ui/flightdisplay/components/QGCPitchWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..f66582e6f97e1961575359a6bd0b3dbd55694713
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCPitchWidget.qml
@@ -0,0 +1,94 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Pitch Indicator
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.1
+
+Rectangle {
+ property real pitchAngle: 0
+ property real rollAngle: 0
+ property real _reticleHeight: 1
+ property real _reticleSpacing: 20
+ property real _reticleSlot: _reticleSpacing + _reticleHeight
+ height: 130
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ clip: true
+ color: Qt.rgba(0,0,0,0)
+ Item {
+ height: parent.height
+ width: parent.width
+ Column{
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: _reticleSpacing
+ Repeater {
+ model: 36
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: ((modelData * 5 - 90) % 10) === 0 ? 50 : 30
+ height: _reticleHeight
+ color: "white"
+ antialiasing: true
+ smooth: true
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.horizontalCenterOffset: -40
+ anchors.verticalCenter: parent.verticalCenter
+ smooth: true
+ font.weight: Font.DemiBold
+ text: -(modelData * 5 - 90)
+ color: "white"
+ visible: ((modelData * 5 - 90) % 10) === 0
+ }
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.horizontalCenterOffset: 40
+ anchors.verticalCenter: parent.verticalCenter
+ smooth: true
+ font.weight: Font.DemiBold
+ text: -(modelData * 5 - 90)
+ color: "white"
+ visible: ((modelData * 5 - 90) % 10) === 0
+ }
+ }
+ }
+ }
+ transform: [ Translate {
+ y: (pitchAngle * _reticleSlot / 5) - (_reticleSlot / 2)
+ }]
+ }
+ transform: [
+ Rotation {
+ origin.x: width / 2
+ origin.y: height / 2
+ angle: -rollAngle
+ }
+ ]
+}
diff --git a/src/ui/flightdisplay/components/QGCSpeedWidget.qml b/src/ui/flightdisplay/components/QGCSpeedWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..2b326a998d8daa5d81c827cff821311614a6ae8c
--- /dev/null
+++ b/src/ui/flightdisplay/components/QGCSpeedWidget.qml
@@ -0,0 +1,78 @@
+/*=====================================================================
+
+QGroundControl Open Source Ground Control Station
+
+(c) 2009, 2015 QGROUNDCONTROL PROJECT
+
+This file is part of the QGROUNDCONTROL project
+
+ QGROUNDCONTROL is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ QGROUNDCONTROL is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QGROUNDCONTROL. If not, see .
+
+======================================================================*/
+
+/**
+ * @file
+ * @brief QGC Speed Indicator
+ * @author Gus Grubba
+ */
+
+import QtQuick 2.4
+
+Rectangle {
+ id: root
+ property real speed: 0
+ property real _reticleSpacing: 14
+ property real _reticleHeight: 1
+ property real _reticleSlot: _reticleSpacing + _reticleHeight
+
+ anchors.verticalCenter: parent.verticalCenter
+
+ height: parent.height * 0.75 > 280 ? 280 : parent.height * 0.75
+ clip: true
+ smooth: true
+ border.color: Qt.rgba(1,1,1,0.25)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: Qt.rgba(0,0,0,0.35) }
+ GradientStop { position: 0.5; color: Qt.rgba(0,0,0,0.15) }
+ GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.35) }
+ }
+ Column{
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: _reticleSpacing
+ Repeater {
+ model: 40
+ Rectangle {
+ width: root.width
+ height: _reticleHeight
+ color: Qt.rgba(1,1,1,0.1)
+ Text {
+ property real _speed: -(index - 20)
+ visible: (_speed % 5 === 0)
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ antialiasing: true
+ font.weight: _speed < 0 ? Font.Light : Font.DemiBold
+ text: _speed < 0 ? -_speed : _speed
+ color: _speed < 0 ? "#ef2526" : "white"
+ style: Text.Outline
+ styleColor: Qt.rgba(0,0,0,0.25)
+ }
+ }
+ }
+ transform: Translate {
+ y: (speed * _reticleSlot) - (_reticleSlot / 2)
+ }
+ }
+}
diff --git a/src/ui/flightdisplay/components/compass.svg b/src/ui/flightdisplay/components/compass.svg
new file mode 100644
index 0000000000000000000000000000000000000000..8ea39a907e64ba153d9ca0829db16c3762c79160
--- /dev/null
+++ b/src/ui/flightdisplay/components/compass.svg
@@ -0,0 +1,12761 @@
+
+
+
+
+
+
+
+
+
+
+]>
+
diff --git a/src/ui/flightdisplay/components/compassNeedle.svg b/src/ui/flightdisplay/components/compassNeedle.svg
new file mode 100644
index 0000000000000000000000000000000000000000..be343594a00a4bdfe83501d4fbb9f851938b6aba
--- /dev/null
+++ b/src/ui/flightdisplay/components/compassNeedle.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/src/ui/flightdisplay/components/crossHair.svg b/src/ui/flightdisplay/components/crossHair.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3ec51bb680206f2cfaa589fd283516e3bf7d5ead
--- /dev/null
+++ b/src/ui/flightdisplay/components/crossHair.svg
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/ui/flightdisplay/components/qmldir b/src/ui/flightdisplay/components/qmldir
new file mode 100644
index 0000000000000000000000000000000000000000..cda9932d45b6f7072fa1316f0ca45978c063803a
--- /dev/null
+++ b/src/ui/flightdisplay/components/qmldir
@@ -0,0 +1,10 @@
+Module QGroundControl.HUDControls
+
+QGCAltitudeWidget 1.0 QGCAltitudeWidget.qml
+QGCAttitudeWidget 1.0 QGCAttitudeWidget.qml
+QGCCompass 1.0 QGCCompass.qml
+QGCCurrentAltitude 1.0 QGCCurrentAltitude.qml
+QGCCurrentSpeed 1.0 QGCCurrentSpeed.qml
+QGCMapBackground 1.0 QGCMapBackground.qml
+QGCPitchWidget 1.0 QGCPitchWidget.qml
+QGCSpeedWidget 1.0 QGCSpeedWidget.qml
diff --git a/src/ui/flightdisplay/components/rollDial.svg b/src/ui/flightdisplay/components/rollDial.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3be775dbc1a7f01754b94f2470b82e9ee9ec4305
--- /dev/null
+++ b/src/ui/flightdisplay/components/rollDial.svg
@@ -0,0 +1,38 @@
+
+
+
diff --git a/src/ui/flightdisplay/components/rollPointer.svg b/src/ui/flightdisplay/components/rollPointer.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7b151db0fea3b8ef3af91aa317d23396b3838ab0
--- /dev/null
+++ b/src/ui/flightdisplay/components/rollPointer.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/src/ui/flightdisplay/components/src/compass.ai b/src/ui/flightdisplay/components/src/compass.ai
new file mode 100644
index 0000000000000000000000000000000000000000..2a8071ff177f7cd29b0e4092cd02a3b67f9c1272
--- /dev/null
+++ b/src/ui/flightdisplay/components/src/compass.ai
@@ -0,0 +1,6614 @@
+%PDF-1.5
%
+1 0 obj
<>/OCGs[5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 165 0 R 166 0 R 167 0 R 168 0 R 169 0 R 218 0 R 219 0 R 220 0 R 221 0 R 222 0 R 272 0 R 273 0 R 274 0 R 275 0 R 276 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<>stream
+
+
+
+
+ application/pdf
+
+
+ compass
+
+
+ 2015-03-31T00:15:11-04:00
+ 2015-03-31T00:15:11-04:00
+ 2015-03-29T22:36:53-04:00
+ Adobe Illustrator CC 2014 (Macintosh)
+
+
+
+ 256
+ 256
+ JPEG
+ /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYqtkkjjXlIwRR1ZiAPxxVL5/MOkw1HreoR2jBb8en44qgZfOFsP7q3d/9Yhf1csNKhn84
XJ+xbovzJP6qY0qO0jX5r0yJKqLIu6hQaFfpJ6Yq7V9fmsjGkSo0jbsGBoF+gjriqBTzhcj7dujf
IkfrrjSomLzhbH+9t3T/AFSG/XxxpUdB5h0mag9b0ye0gK/j0/HAqYRyRyLyjYOp6MpBH4YquxV2
KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kpff69p9nVWf1JR/uuPc/SegxVILzzV
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
+
+
+
+ uuid:8b1c99e6-0e8a-9f44-a599-4d42e0d91f89
+ xmp.did:0c136065-95c5-4a0d-b26a-3e59fc225b99
+ uuid:5D20892493BFDB11914A8590D31508C8
+ proof:pdf
+
+ xmp.iid:9793267d-1e93-4f39-92a6-570fdb45ddbe
+ xmp.did:9793267d-1e93-4f39-92a6-570fdb45ddbe
+ uuid:5D20892493BFDB11914A8590D31508C8
+ proof:pdf
+
+
+
+
+ saved
+ xmp.iid:058bc2a7-ba50-4e17-96bb-2976aefb1ff5
+ 2015-03-29T19:39:17-04:00
+ Adobe Illustrator CC 2014 (Macintosh)
+ /
+
+
+ saved
+ xmp.iid:0c136065-95c5-4a0d-b26a-3e59fc225b99
+ 2015-03-29T22:36:51-04:00
+ Adobe Illustrator CC 2014 (Macintosh)
+ /
+
+
+
+ Print
+ Document
+ False
+ True
+ 1
+
+ 4.000000
+ 4.000000
+ Inches
+
+
+
+ Black
+
+
+
+
+
+ Default Swatch Group
+ 0
+
+
+
+ White
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+
+
+ Black
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 100.000000
+
+
+ CMYK Red
+ CMYK
+ PROCESS
+ 0.000000
+ 100.000000
+ 100.000000
+ 0.000000
+
+
+ CMYK Yellow
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 100.000000
+ 0.000000
+
+
+ CMYK Green
+ CMYK
+ PROCESS
+ 100.000000
+ 0.000000
+ 100.000000
+ 0.000000
+
+
+ CMYK Cyan
+ CMYK
+ PROCESS
+ 100.000000
+ 0.000000
+ 0.000000
+ 0.000000
+
+
+ CMYK Blue
+ CMYK
+ PROCESS
+ 100.000000
+ 100.000000
+ 0.000000
+ 0.000000
+
+
+ CMYK Magenta
+ CMYK
+ PROCESS
+ 0.000000
+ 100.000000
+ 0.000000
+ 0.000000
+
+
+ C=15 M=100 Y=90 K=10
+ CMYK
+ PROCESS
+ 15.000000
+ 100.000000
+ 90.000000
+ 10.000000
+
+
+ C=0 M=90 Y=85 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 90.000000
+ 85.000000
+ 0.000000
+
+
+ C=0 M=80 Y=95 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 80.000000
+ 95.000000
+ 0.000000
+
+
+ C=0 M=50 Y=100 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 50.000000
+ 100.000000
+ 0.000000
+
+
+ C=0 M=35 Y=85 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 35.000000
+ 85.000000
+ 0.000000
+
+
+ C=5 M=0 Y=90 K=0
+ CMYK
+ PROCESS
+ 5.000000
+ 0.000000
+ 90.000000
+ 0.000000
+
+
+ C=20 M=0 Y=100 K=0
+ CMYK
+ PROCESS
+ 20.000000
+ 0.000000
+ 100.000000
+ 0.000000
+
+
+ C=50 M=0 Y=100 K=0
+ CMYK
+ PROCESS
+ 50.000000
+ 0.000000
+ 100.000000
+ 0.000000
+
+
+ C=75 M=0 Y=100 K=0
+ CMYK
+ PROCESS
+ 75.000000
+ 0.000000
+ 100.000000
+ 0.000000
+
+
+ C=85 M=10 Y=100 K=10
+ CMYK
+ PROCESS
+ 85.000000
+ 10.000000
+ 100.000000
+ 10.000000
+
+
+ C=90 M=30 Y=95 K=30
+ CMYK
+ PROCESS
+ 90.000000
+ 30.000000
+ 95.000000
+ 30.000000
+
+
+ C=75 M=0 Y=75 K=0
+ CMYK
+ PROCESS
+ 75.000000
+ 0.000000
+ 75.000000
+ 0.000000
+
+
+ C=80 M=10 Y=45 K=0
+ CMYK
+ PROCESS
+ 80.000000
+ 10.000000
+ 45.000000
+ 0.000000
+
+
+ C=70 M=15 Y=0 K=0
+ CMYK
+ PROCESS
+ 70.000000
+ 15.000000
+ 0.000000
+ 0.000000
+
+
+ C=85 M=50 Y=0 K=0
+ CMYK
+ PROCESS
+ 85.000000
+ 50.000000
+ 0.000000
+ 0.000000
+
+
+ C=100 M=95 Y=5 K=0
+ CMYK
+ PROCESS
+ 100.000000
+ 95.000000
+ 5.000000
+ 0.000000
+
+
+ C=100 M=100 Y=25 K=25
+ CMYK
+ PROCESS
+ 100.000000
+ 100.000000
+ 25.000000
+ 25.000000
+
+
+ C=75 M=100 Y=0 K=0
+ CMYK
+ PROCESS
+ 75.000000
+ 100.000000
+ 0.000000
+ 0.000000
+
+
+ C=50 M=100 Y=0 K=0
+ CMYK
+ PROCESS
+ 50.000000
+ 100.000000
+ 0.000000
+ 0.000000
+
+
+ C=35 M=100 Y=35 K=10
+ CMYK
+ PROCESS
+ 35.000000
+ 100.000000
+ 35.000000
+ 10.000000
+
+
+ C=10 M=100 Y=50 K=0
+ CMYK
+ PROCESS
+ 10.000000
+ 100.000000
+ 50.000000
+ 0.000000
+
+
+ C=0 M=95 Y=20 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 95.000000
+ 20.000000
+ 0.000000
+
+
+ C=25 M=25 Y=40 K=0
+ CMYK
+ PROCESS
+ 25.000000
+ 25.000000
+ 40.000000
+ 0.000000
+
+
+ C=40 M=45 Y=50 K=5
+ CMYK
+ PROCESS
+ 40.000000
+ 45.000000
+ 50.000000
+ 5.000000
+
+
+ C=50 M=50 Y=60 K=25
+ CMYK
+ PROCESS
+ 50.000000
+ 50.000000
+ 60.000000
+ 25.000000
+
+
+ C=55 M=60 Y=65 K=40
+ CMYK
+ PROCESS
+ 55.000000
+ 60.000000
+ 65.000000
+ 40.000000
+
+
+ C=25 M=40 Y=65 K=0
+ CMYK
+ PROCESS
+ 25.000000
+ 40.000000
+ 65.000000
+ 0.000000
+
+
+ C=30 M=50 Y=75 K=10
+ CMYK
+ PROCESS
+ 30.000000
+ 50.000000
+ 75.000000
+ 10.000000
+
+
+ C=35 M=60 Y=80 K=25
+ CMYK
+ PROCESS
+ 35.000000
+ 60.000000
+ 80.000000
+ 25.000000
+
+
+ C=40 M=65 Y=90 K=35
+ CMYK
+ PROCESS
+ 40.000000
+ 65.000000
+ 90.000000
+ 35.000000
+
+
+ C=40 M=70 Y=100 K=50
+ CMYK
+ PROCESS
+ 40.000000
+ 70.000000
+ 100.000000
+ 50.000000
+
+
+ C=50 M=70 Y=80 K=70
+ CMYK
+ PROCESS
+ 50.000000
+ 70.000000
+ 80.000000
+ 70.000000
+
+
+
+
+
+ Grays
+ 1
+
+
+
+ C=0 M=0 Y=0 K=100
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 100.000000
+
+
+ C=0 M=0 Y=0 K=90
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 89.999400
+
+
+ C=0 M=0 Y=0 K=80
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 79.998800
+
+
+ C=0 M=0 Y=0 K=70
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 69.999700
+
+
+ C=0 M=0 Y=0 K=60
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 59.999100
+
+
+ C=0 M=0 Y=0 K=50
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 50.000000
+
+
+ C=0 M=0 Y=0 K=40
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 39.999400
+
+
+ C=0 M=0 Y=0 K=30
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 29.998800
+
+
+ C=0 M=0 Y=0 K=20
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 19.999700
+
+
+ C=0 M=0 Y=0 K=10
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 9.999100
+
+
+ C=0 M=0 Y=0 K=5
+ CMYK
+ PROCESS
+ 0.000000
+ 0.000000
+ 0.000000
+ 4.998800
+
+
+
+
+
+ Brights
+ 1
+
+
+
+ C=0 M=100 Y=100 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 100.000000
+ 100.000000
+ 0.000000
+
+
+ C=0 M=75 Y=100 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 75.000000
+ 100.000000
+ 0.000000
+
+
+ C=0 M=10 Y=95 K=0
+ CMYK
+ PROCESS
+ 0.000000
+ 10.000000
+ 95.000000
+ 0.000000
+
+
+ C=85 M=10 Y=100 K=0
+ CMYK
+ PROCESS
+ 85.000000
+ 10.000000
+ 100.000000
+ 0.000000
+
+
+ C=100 M=90 Y=0 K=0
+ CMYK
+ PROCESS
+ 100.000000
+ 90.000000
+ 0.000000
+ 0.000000
+
+
+ C=60 M=90 Y=0 K=0
+ CMYK
+ PROCESS
+ 60.000000
+ 90.000000
+ 0.003100
+ 0.003100
+
+
+
+
+
+
+ Adobe PDF library 11.00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
endstream
endobj
3 0 obj
<>
endobj
11 0 obj
<>/Resources<>/ExtGState<>/Properties<>/XObject<>>>/Thumb 287 0 R/TrimBox[0.0 0.0 288.0 288.0]/Type/Page>>
endobj
278 0 obj
<>stream
+H|WIGگȆ0?``ɐ#2Ki&;*^>çp~JAǰ
߿_ӗӏa_;Ձq^BZ_O~ tt= -įwQ-szc6g4cĺFlQc0Jqr0Θг@;,2bOP54=Δ/|惡8 E/VfjZ#.9-VLZZz߭J}ܭckl]*l~y!?