Commit 97d3383c authored by Gus Grubba's avatar Gus Grubba

Add alert to air traffic

Handled "airspace visible" state (not done)
Adjusted restriction map items color and opacity
Added/Updated icons for airspace traffic
Adjust colors for text over maps
parent 62b4fe2d
......@@ -172,6 +172,7 @@
<file alias="APM/BrandImageSub">src/FirmwarePlugin/APM/APMBrandImageSub.png</file>
<file alias="PX4/BrandImage">src/FirmwarePlugin/PX4/PX4BrandImage.png</file>
<file alias="subVehicleArrowOpaque.png">src/FlightMap/Images/sub.png</file>
<file alias="AlertAircraft.svg">src/FlightMap/Images/AlertAircraft.svg</file>
<file alias="AwarenessAircraft.svg">src/FlightMap/Images/AwarenessAircraft.svg</file>
</qresource>
<qresource prefix="/res">
......
......@@ -47,7 +47,7 @@ adv_sort(QObject* a, QObject* b)
AirMapAdvisory* aa = qobject_cast<AirMapAdvisory*>(a);
AirMapAdvisory* bb = qobject_cast<AirMapAdvisory*>(b);
if(!aa || !bb) return false;
return aa->color() > bb->color();
return (int)aa->color() > (int)bb->color();
}
//-----------------------------------------------------------------------------
......
......@@ -72,9 +72,7 @@ AirMapRestrictionManager::setROI(const QGeoCoordinate& center, double radiusMete
qWarning() << "unsupported geometry type: "<<(int)geometry.type();
break;
}
}
} else {
QString description = QString::fromStdString(result.error().description() ? result.error().description().get() : "");
emit error("Failed to retrieve Geofences",
......
......@@ -48,8 +48,8 @@ AirMapTrafficMonitor::_update(Traffic::Update::Type type, const std::vector<Traf
for (const auto& traffic : update) {
QString traffic_id = QString::fromStdString(traffic.id);
QString vehicle_id = QString::fromStdString(traffic.aircraft_id);
emit trafficUpdate(traffic_id, vehicle_id, QGeoCoordinate(traffic.latitude, traffic.longitude, traffic.altitude),
traffic.heading);
emit trafficUpdate(type == Traffic::Update::Type::alert, traffic_id, vehicle_id,
QGeoCoordinate(traffic.latitude, traffic.longitude, traffic.altitude), traffic.heading);
}
}
......
......@@ -40,7 +40,7 @@ public:
signals:
void error (const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);
void trafficUpdate (QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
void trafficUpdate (bool alert, QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
private:
void _update (airmap::Traffic::Update::Type type, const std::vector<airmap::Traffic::Update>& update);
......
......@@ -17,9 +17,8 @@ import QGroundControl.Airmap 1.0
Item {
id: _root
width: parent.width
height: colapsed ? colapsedRect.height : expandedRect.height
height: _colapsed ? colapsedRect.height : expandedRect.height
property bool colapsed: true
property bool showColapse: true
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
......@@ -27,6 +26,7 @@ Item {
property bool _validRules: _activeVehicle ? _activeVehicle.airspaceController.rulesets.valid : false
property bool _validAdvisories: _activeVehicle ? _activeVehicle.airspaceController.advisories.valid : false
property color _textColor: qgcPal.text
property bool _colapsed: _activeVehicle ? !_activeVehicle.airspaceController.airspaceVisible : true
readonly property real _radius: ScreenTools.defaultFontPixelWidth * 0.5
readonly property color _colorOrange: "#d75e0d"
......@@ -67,10 +67,10 @@ Item {
Rectangle {
id: colapsedRect
width: parent.width
height: colapsed ? colapsedRow.height + ScreenTools.defaultFontPixelHeight : 0
height: _colapsed ? colapsedRow.height + ScreenTools.defaultFontPixelHeight : 0
color: _validAdvisories ? getAispaceColor(_activeVehicle.airspaceController.advisories.airspaceColor) : _colorGray
radius: _radius
visible: colapsed
visible: _colapsed
Row {
id: colapsedRow
spacing: ScreenTools.defaultFontPixelWidth
......@@ -113,7 +113,10 @@ Item {
}
MouseArea {
anchors.fill: parent
onClicked: colapsed = false
enabled: _activeVehicle
onClicked: {
_activeVehicle.airspaceController.airspaceVisible = true
}
}
}
//---------------------------------------------------------------
......@@ -121,10 +124,10 @@ Item {
Rectangle {
id: expandedRect
width: parent.width
height: !colapsed ? expandedCol.height + ScreenTools.defaultFontPixelHeight : 0
height: !_colapsed ? expandedCol.height + ScreenTools.defaultFontPixelHeight : 0
color: _validAdvisories ? getAispaceColor(_activeVehicle.airspaceController.advisories.airspaceColor) : _colorGray
radius: _radius
visible: !colapsed
visible: !_colapsed
MouseArea {
anchors.fill: parent
onWheel: { wheel.accepted = true; }
......@@ -191,8 +194,8 @@ Item {
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
enabled: showColapse
onClicked: colapsed = true
enabled: showColapse && _activeVehicle
onClicked: _activeVehicle.airspaceController.airspaceVisible = false
}
}
AirspaceWeather {
......
## To be deleted when development is complete
* AirMapRestrictionManager seems to be incomplete (if not redundant). Shouldn't we use the array of AirSpace items returned by AirMapAdvisoryManager instead? In addition to the AirSpace object, it gives you a color to use in order of importance.
* Traffic monitor timeout is now set to 2 minutes following instructions from Thomas Voß.
* Add a "Wrong Way" icon to the airspace widget when not connected
......@@ -19,6 +19,7 @@
AirspaceController::AirspaceController(QObject* parent)
: QObject(parent)
, _manager(qgcApp()->toolbox()->airspaceManager())
, _airspaceVisible(false)
{
}
......
......@@ -25,22 +25,30 @@ public:
AirspaceController(QObject* parent = NULL);
~AirspaceController() = default;
Q_PROPERTY(QmlObjectListModel* polygons READ polygons CONSTANT) ///< List of AirspacePolygonRestriction objects
Q_PROPERTY(QmlObjectListModel* circles READ circles CONSTANT) ///< List of AirspaceCircularRestriction objects
Q_PROPERTY(QString providerName READ providerName CONSTANT)
Q_PROPERTY(AirspaceWeatherInfoProvider* weatherInfo READ weatherInfo CONSTANT)
Q_PROPERTY(AirspaceAdvisoryProvider* advisories READ advisories CONSTANT)
Q_PROPERTY(AirspaceRulesetsProvider* rulesets READ rulesets CONSTANT)
Q_INVOKABLE void setROI (QGeoCoordinate center, double radius);
QmlObjectListModel* polygons ();
QmlObjectListModel* circles ();
QString providerName();
AirspaceWeatherInfoProvider* weatherInfo ();
AirspaceAdvisoryProvider* advisories ();
AirspaceRulesetsProvider* rulesets ();
Q_PROPERTY(QmlObjectListModel* polygons READ polygons CONSTANT) ///< List of AirspacePolygonRestriction objects
Q_PROPERTY(QmlObjectListModel* circles READ circles CONSTANT) ///< List of AirspaceCircularRestriction objects
Q_PROPERTY(QString providerName READ providerName CONSTANT)
Q_PROPERTY(AirspaceWeatherInfoProvider* weatherInfo READ weatherInfo CONSTANT)
Q_PROPERTY(AirspaceAdvisoryProvider* advisories READ advisories CONSTANT)
Q_PROPERTY(AirspaceRulesetsProvider* rulesets READ rulesets CONSTANT)
Q_PROPERTY(bool airspaceVisible READ airspaceVisible WRITE setairspaceVisible NOTIFY airspaceVisibleChanged)
Q_INVOKABLE void setROI (QGeoCoordinate center, double radius);
QmlObjectListModel* polygons ();
QmlObjectListModel* circles ();
QString providerName ();
AirspaceWeatherInfoProvider* weatherInfo ();
AirspaceAdvisoryProvider* advisories ();
AirspaceRulesetsProvider* rulesets ();
bool airspaceVisible () { return _airspaceVisible; }
void setairspaceVisible (bool set) { _airspaceVisible = set; emit airspaceVisibleChanged(); }
signals:
void airspaceVisibleChanged ();
private:
AirspaceManager* _manager;
bool _airspaceVisible;
};
......@@ -53,7 +53,7 @@ public slots:
virtual void endFlight () = 0;
signals:
void trafficUpdate (QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
void trafficUpdate (bool alert, QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
void flightPermitStatusChanged ();
protected slots:
......
......@@ -51,6 +51,7 @@ FlightMap {
property var _activeVehicleCoordinate: _activeVehicle ? _activeVehicle.coordinate : QtPositioning.coordinate()
property var _gotoHereCoordinate: QtPositioning.coordinate()
property real _toolButtonTopMargin: parent.height - ScreenTools.availableHeight + (ScreenTools.defaultFontPixelHeight / 2)
property bool _airspaceManagement: QGroundControl.airmapSupported && _activeVehicle
property bool _disableVehicleTracking: false
property bool _keepVehicleCentered: _mainIsMap ? false : true
......@@ -198,15 +199,14 @@ FlightMap {
// Add ADSB vehicles to the map
MapItemView {
model: _activeVehicle ? _activeVehicle.adsbVehicles : 0
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
}
......@@ -331,22 +331,20 @@ FlightMap {
// Airspace overlap support
MapItemView {
model: QGroundControl.airmapSupported && _activeVehicle ? _activeVehicle.airspaceController.circles : []
model: _airspaceManagement && _activeVehicle.airspaceController.airspaceVisible ? _activeVehicle.airspaceController.circles : []
delegate: MapCircle {
center: object.center
radius: object.radius
border.color: "white"
color: "yellow"
opacity: 0.25
border.color: Qt.rgba(1,1,1,0.85)
color: Qt.rgba(0.94,0.87,0,0.25)
}
}
MapItemView {
model: QGroundControl.airmapSupported && _activeVehicle ? _activeVehicle.airspaceController.polygons : []
model: _airspaceManagement && _activeVehicle.airspaceController.airspaceVisible ? _activeVehicle.airspaceController.polygons : []
delegate: MapPolygon {
border.color: "white"
color: "yellow"
opacity: 0.25
border.color: Qt.rgba(1,1,1,0.85)
color: Qt.rgba(0.94,0.87,0,0.25)
path: object.polygon
}
}
......
......@@ -79,6 +79,15 @@ Item {
onValueChanged: _setInstrumentWidget()
}
Connections {
target: _activeVehicle ? _activeVehicle.airspaceController : null
onAirspaceVisibleChanged: {
if(_activeVehicle) {
widgetRoot.showValues = !_activeVehicle.airspaceController.airspaceVisible
}
}
}
Component.onCompleted: {
_setInstrumentWidget()
}
......@@ -133,9 +142,6 @@ Item {
width: getPreferredInstrumentWidth()
visible: _enableAirMap
anchors.margins: ScreenTools.defaultFontPixelHeight * 0.5
onColapsedChanged: {
widgetRoot.showValues = colapsed
}
}
//-------------------------------------------------------
//-- Instrument Panel
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="72px" height="72px" viewBox="0 0 72 72" style="enable-background:new 0 0 72 72;" xml:space="preserve">
<style type="text/css">
.st0{fill:#404040;}
.st1{fill:#FFCD35;}
</style>
<circle class="st0" cx="36" cy="36" r="36"/>
<circle class="st1" cx="36" cy="36" r="30.6"/>
<g>
<g id="flights">
<path d="M34.066,9.531c-1.349,0.775-2.116,2.277-2.116,3.833l0,11.91c0,1.634-0.842,3.152-2.227,4.018L12.838,39.845
c-1.548,0.967-2.488,2.664-2.488,4.489V46.8l18.25-5.703c1.661-0.519,3.35,0.722,3.35,2.463V54.9l-4.364,3.273
c-0.652,0.489-1.036,1.257-1.036,2.073V63L36,60.3l9.45,2.7v-2.754c0-0.816-0.384-1.584-1.036-2.073L40.05,54.9V43.56
c0-1.741,1.688-2.982,3.35-2.463L61.65,46.8v-2.466c0-1.825-0.94-3.522-2.488-4.489L42.277,29.292
c-1.385-0.866-2.227-2.384-2.227-4.018V13.05C40.05,10.255,36.886,7.912,34.066,9.531z"/>
</g>
</g>
</svg>
......@@ -25,6 +25,7 @@ MapQuickItem {
property string callsign: "" ///< Vehicle callsign
property double heading: vehicle ? vehicle.heading.value : Number.NaN ///< Vehicle heading, NAN for none
property real size: _adsbVehicle ? _adsbSize : _uavSize /// Size for icon
property bool alert: false /// Collision alert
anchorPoint.x: vehicleItem.width / 2
anchorPoint.y: vehicleItem.height / 2
......@@ -32,7 +33,7 @@ MapQuickItem {
property bool _adsbVehicle: vehicle ? false : true
property real _uavSize: ScreenTools.defaultFontPixelHeight * 5
property real _adsbSize: ScreenTools.defaultFontPixelHeight * 1.5
property real _adsbSize: ScreenTools.defaultFontPixelHeight * 2.5
property var _map: map
property bool _multiVehicle: QGroundControl.multiVehicleManager.vehicles.count > 1
......@@ -50,8 +51,8 @@ MapQuickItem {
visible: false
}
DropShadow {
anchors.fill: arrowIconShadow
visible: vehicleIcon.visible
anchors.fill: vehicleShadow
visible: vehicleIcon.visible && _adsbVehicle
horizontalOffset: 4
verticalOffset: 4
radius: 32.0
......@@ -61,7 +62,7 @@ MapQuickItem {
}
Image {
id: vehicleIcon
source: _adsbVehicle ? "/qmlimages/AwarenessAircraft.svg" : vehicle.vehicleImageOpaque
source: _adsbVehicle ? (alert ? "/qmlimages/AlertAircraft.svg" : "/qmlimages/AwarenessAircraft.svg") : vehicle.vehicleImageOpaque
mipmap: true
width: size
sourceSize.width: size
......@@ -81,7 +82,6 @@ MapQuickItem {
text: vehicleLabelText
font.pointSize: ScreenTools.smallFontPointSize
visible: _adsbVehicle ? !isNaN(altitude) : _multiVehicle
property string vehicleLabelText: visible ?
(_adsbVehicle ?
QGroundControl.metersToAppSettingsDistanceUnits(altitude).toFixed(0) + " " + QGroundControl.appSettingsDistanceUnitsString :
......@@ -97,7 +97,6 @@ MapQuickItem {
text: vehicleLabelText
font.pointSize: ScreenTools.smallFontPointSize
visible: _adsbVehicle ? !isNaN(altitude) : _multiVehicle
property string vehicleLabelText: visible && _adsbVehicle ? callsign : ""
}
}
......
......@@ -99,7 +99,7 @@ QGCView {
if(QGroundControl.airmapSupported) {
if(_enableAirMap) {
planControlColapsed = true
airspaceControl.colapsed = false
_activeVehicle.airspaceController.airspaceVisible = true
} else {
planControlColapsed = false
}
......@@ -164,9 +164,15 @@ QGCView {
}
}
Connections {
target: _activeVehicle ? _activeVehicle.airspaceController : undefined
onColapsedChanged: {
planControlColapsed = _activeVehicle.airspaceController.airspaceVisible
}
}
Component {
id: noItemForKML
QGCViewMessage {
message: qsTr("You need at least one item to create a KML.")
}
......@@ -530,11 +536,6 @@ QGCView {
width: parent.width
visible: _enableAirMap
showColapse: false
onColapsedChanged: {
if(!airspaceControl.colasped) {
planControlColapsed = true
}
}
}
//-------------------------------------------------------
// Mission Controls (Colapsed)
......
......@@ -15,7 +15,7 @@
QColor QGCMapPalette::_thumbJoystick[QGCMapPalette::_cColorGroups] = { QColor(255,255,255,127), QColor(0,0,0,127) };
QColor QGCMapPalette::_text [QGCMapPalette::_cColorGroups] = { QColor(255,255,255), QColor(0,0,0) };
QColor QGCMapPalette::_textOutline [QGCMapPalette::_cColorGroups] = { QColor(0,0,0), QColor(255,255,255) };
QColor QGCMapPalette::_textOutline [QGCMapPalette::_cColorGroups] = { QColor(0,0,0,192), QColor(255,255,255,192) };
QGCMapPalette::QGCMapPalette(QObject* parent) :
QObject(parent)
......
......@@ -18,29 +18,33 @@ ADSBVehicle::ADSBVehicle(mavlink_adsb_vehicle_t& adsbVehicle, QObject* parent)
, _callsign (adsbVehicle.callsign)
, _altitude (NAN)
, _heading (NAN)
, _alert (false)
{
if (!(adsbVehicle.flags | ADSB_FLAGS_VALID_COORDS)) {
qWarning() << "At least coords must be valid";
return;
}
update(adsbVehicle);
}
ADSBVehicle::ADSBVehicle(const QGeoCoordinate& location, float heading, QObject* parent)
: QObject(parent), _icaoAddress(0)
ADSBVehicle::ADSBVehicle(const QGeoCoordinate& location, float heading, bool alert, QObject* parent)
: QObject(parent)
, _icaoAddress(0)
, _alert(alert)
{
update(location, heading);
update(alert, location, heading);
}
void ADSBVehicle::update(const QGeoCoordinate& location, float heading)
void ADSBVehicle::update(bool alert, const QGeoCoordinate& location, float heading)
{
_coordinate = location;
_altitude = location.altitude();
_heading = heading;
emit coordinateChanged(_coordinate);
emit altitudeChanged(_altitude);
emit headingChanged(_heading);
_altitude = location.altitude();
_heading = heading;
_alert = alert;
emit coordinateChanged();
emit altitudeChanged();
emit headingChanged();
emit alertChanged();
_lastUpdateTimer.restart();
}
......@@ -59,13 +63,13 @@ void ADSBVehicle::update(mavlink_adsb_vehicle_t& adsbVehicle)
if (currCallsign != _callsign) {
_callsign = currCallsign;
emit callsignChanged(_callsign);
emit callsignChanged();
}
QGeoCoordinate newCoordinate(adsbVehicle.lat / 1e7, adsbVehicle.lon / 1e7);
if (newCoordinate != _coordinate) {
_coordinate = newCoordinate;
emit coordinateChanged(_coordinate);
emit coordinateChanged();
}
double newAltitude = NAN;
......@@ -74,7 +78,7 @@ void ADSBVehicle::update(mavlink_adsb_vehicle_t& adsbVehicle)
}
if (!(qIsNaN(newAltitude) && qIsNaN(_altitude)) && !qFuzzyCompare(newAltitude, _altitude)) {
_altitude = newAltitude;
emit altitudeChanged(_altitude);
emit altitudeChanged();
}
double newHeading = NAN;
......@@ -83,7 +87,7 @@ void ADSBVehicle::update(mavlink_adsb_vehicle_t& adsbVehicle)
}
if (!(qIsNaN(newHeading) && qIsNaN(_heading)) && !qFuzzyCompare(newHeading, _heading)) {
_heading = newHeading;
emit headingChanged(_heading);
emit headingChanged();
}
_lastUpdateTimer.restart();
}
......
......@@ -22,43 +22,50 @@ class ADSBVehicle : public QObject
public:
ADSBVehicle(mavlink_adsb_vehicle_t& adsbVehicle, QObject* parent = NULL);
ADSBVehicle(const QGeoCoordinate& location, float heading, QObject* parent = NULL);
ADSBVehicle(const QGeoCoordinate& location, float heading, bool alert = false, QObject* parent = NULL);
Q_PROPERTY(int icaoAddress READ icaoAddress CONSTANT)
Q_PROPERTY(QString callsign READ callsign NOTIFY callsignChanged)
Q_PROPERTY(QGeoCoordinate coordinate READ coordinate NOTIFY coordinateChanged)
Q_PROPERTY(double altitude READ altitude NOTIFY altitudeChanged) // NaN for not available
Q_PROPERTY(double heading READ heading NOTIFY headingChanged) // NaN for not available
Q_PROPERTY(bool alert READ alert NOTIFY alertChanged) // Collision path
int icaoAddress (void) const { return _icaoAddress; }
QString callsign (void) const { return _callsign; }
QGeoCoordinate coordinate (void) const { return _coordinate; }
double altitude (void) const { return _altitude; }
double heading (void) const { return _heading; }
bool alert (void) const { return _alert; }
/// Update the vehicle with new information
void update(mavlink_adsb_vehicle_t& adsbVehicle);
void update(const QGeoCoordinate& location, float heading);
void update(bool alert, const QGeoCoordinate& location, float heading);
/// check if the vehicle is expired and should be removed
bool expired();
signals:
void coordinateChanged(QGeoCoordinate coordinate);
void callsignChanged(QString callsign);
void altitudeChanged(double altitude);
void headingChanged(double heading);
void coordinateChanged ();
void callsignChanged ();
void altitudeChanged ();
void headingChanged ();
void alertChanged ();
private:
/* According with Thomas Voß, we should be using 2 minutes for the time being
static constexpr qint64 expirationTimeoutMs = 5000; ///< timeout with no update in ms after which the vehicle is removed.
///< AirMap sends updates for each vehicle every second.
*/
static constexpr qint64 expirationTimeoutMs = 120000;
uint32_t _icaoAddress;
QString _callsign;
QGeoCoordinate _coordinate;
double _altitude;
double _heading;
bool _alert;
QElapsedTimer _lastUpdateTimer;
};
......@@ -3009,15 +3009,15 @@ void Vehicle::_updateHighLatencyLink(void)
}
}
void Vehicle::_trafficUpdate(QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading)
void Vehicle::_trafficUpdate(bool alert, QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading)
{
Q_UNUSED(vehicle_id);
// qDebug() << "traffic update:" << traffic_id << vehicle_id << heading << location;
// TODO: filter based on minimum altitude?
if (_trafficVehicleMap.contains(traffic_id)) {
_trafficVehicleMap[traffic_id]->update(location, heading);
_trafficVehicleMap[traffic_id]->update(alert, location, heading);
} else {
ADSBVehicle* vehicle = new ADSBVehicle(location, heading, this);
ADSBVehicle* vehicle = new ADSBVehicle(location, heading, alert, this);
_trafficVehicleMap[traffic_id] = vehicle;
_adsbVehicles.append(vehicle);
}
......
......@@ -910,8 +910,8 @@ private slots:
void _updateHobbsMeter(void);
void _vehicleParamLoaded(bool ready);
void _trafficUpdate(QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
void _adsbTimerTimeout();
void _trafficUpdate (bool alert, QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);
void _adsbTimerTimeout ();
private:
bool _containsLink(LinkInterface* link);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment