|
|
@ -13,19 +13,21 @@ |
|
|
|
#include "JsonHelper.h" |
|
|
|
#include "JsonHelper.h" |
|
|
|
#include "SettingsManager.h" |
|
|
|
#include "SettingsManager.h" |
|
|
|
#include "AppSettings.h" |
|
|
|
#include "AppSettings.h" |
|
|
|
|
|
|
|
#include "QGCQGeoCoordinate.h" |
|
|
|
|
|
|
|
|
|
|
|
#include <QNetworkAccessManager> |
|
|
|
#include <QNetworkAccessManager> |
|
|
|
#include <QUrlQuery> |
|
|
|
#include <QUrlQuery> |
|
|
|
#include <QJsonDocument> |
|
|
|
#include <QJsonDocument> |
|
|
|
#include <QJsonArray> |
|
|
|
#include <QJsonArray> |
|
|
|
#include <QNetworkProxy> |
|
|
|
#include <QNetworkProxy> |
|
|
|
|
|
|
|
#include <QSet> |
|
|
|
|
|
|
|
|
|
|
|
QGC_LOGGING_CATEGORY(AirMapManagerLog, "AirMapManagerLog") |
|
|
|
QGC_LOGGING_CATEGORY(AirMapManagerLog, "AirMapManagerLog") |
|
|
|
|
|
|
|
|
|
|
|
AirMapManager::AirMapManager(QGCApplication* app, QGCToolbox* toolbox) |
|
|
|
AirMapManager::AirMapManager(QGCApplication* app, QGCToolbox* toolbox) |
|
|
|
: QGCTool(app, toolbox) |
|
|
|
: QGCTool(app, toolbox) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_updateTimer.setInterval(5000); |
|
|
|
_updateTimer.setInterval(2000); |
|
|
|
_updateTimer.setSingleShot(true); |
|
|
|
_updateTimer.setSingleShot(true); |
|
|
|
connect(&_updateTimer, &QTimer::timeout, this, &AirMapManager::_updateToROI); |
|
|
|
connect(&_updateTimer, &QTimer::timeout, this, &AirMapManager::_updateToROI); |
|
|
|
} |
|
|
|
} |
|
|
@ -46,10 +48,10 @@ void AirMapManager::_get(QUrl url) |
|
|
|
{ |
|
|
|
{ |
|
|
|
QNetworkRequest request(url); |
|
|
|
QNetworkRequest request(url); |
|
|
|
|
|
|
|
|
|
|
|
qDebug() << url.toString(QUrl::FullyEncoded); |
|
|
|
//qDebug() << url.toString(QUrl::FullyEncoded);
|
|
|
|
qDebug() << _toolbox->settingsManager()->appSettings()->airMapKey()->rawValueString(); |
|
|
|
//qDebug() << "Settings API key: " << _toolbox->settingsManager()->appSettings()->airMapKey()->rawValueString();
|
|
|
|
|
|
|
|
|
|
|
|
request.setRawHeader("X-API-Key", _toolbox->settingsManager()->appSettings()->airMapKey()->rawValueString().toUtf8()); |
|
|
|
request.setRawHeader("X-API-Key", _toolbox->settingsManager()->appSettings()->airMapKey()->rawValueString().toUtf8()); |
|
|
|
|
|
|
|
|
|
|
|
QNetworkProxy tProxy; |
|
|
|
QNetworkProxy tProxy; |
|
|
|
tProxy.setType(QNetworkProxy::DefaultProxy); |
|
|
|
tProxy.setType(QNetworkProxy::DefaultProxy); |
|
|
@ -113,61 +115,75 @@ void AirMapManager::_getError(QNetworkReply::NetworkError code) |
|
|
|
errorMsg = QString("Error during download. Error: (%1, %2)").arg(code).arg(reply->errorString()); |
|
|
|
errorMsg = QString("Error during download. Error: (%1, %2)").arg(code).arg(reply->errorString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_state == State::RetrieveItems) { |
|
|
|
|
|
|
|
if (--_numAwaitingItems == 0) { |
|
|
|
|
|
|
|
_state = State::Idle; |
|
|
|
|
|
|
|
// TODO: handle properly
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
// FIXME
|
|
|
|
qWarning() << errorMsg; |
|
|
|
qWarning() << errorMsg; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AirMapManager::_updateToROI(void) |
|
|
|
void AirMapManager::_updateToROI(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Build up the polygon for the query
|
|
|
|
if (_state != State::Idle) { |
|
|
|
|
|
|
|
qDebug() << "Error: state not idle (yet)"; |
|
|
|
QJsonObject polygonJson; |
|
|
|
// restart timer?
|
|
|
|
|
|
|
|
return; |
|
|
|
polygonJson["type"] = "Polygon"; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
QGeoCoordinate left = _roiCenter.atDistanceAndAzimuth(_roiRadius, -90); |
|
|
|
|
|
|
|
QGeoCoordinate right = _roiCenter.atDistanceAndAzimuth(_roiRadius, 90); |
|
|
|
|
|
|
|
QGeoCoordinate top = _roiCenter.atDistanceAndAzimuth(_roiRadius, 0); |
|
|
|
|
|
|
|
QGeoCoordinate bottom = _roiCenter.atDistanceAndAzimuth(_roiRadius, 180); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QGeoCoordinate topLeft(top.latitude(), left.longitude()); |
|
|
|
|
|
|
|
QGeoCoordinate topRight(top.latitude(), right.longitude()); |
|
|
|
|
|
|
|
QGeoCoordinate bottomLeft(bottom.latitude(), left.longitude()); |
|
|
|
|
|
|
|
QGeoCoordinate bottomRight(bottom.latitude(), left.longitude()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QJsonValue coordValue; |
|
|
|
|
|
|
|
QJsonArray rgVertex; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GeoJson polygons are right handed and include duplicate first and last vertex
|
|
|
|
|
|
|
|
JsonHelper::saveGeoJsonCoordinate(topLeft, false /* writeAltitude */, coordValue); |
|
|
|
|
|
|
|
rgVertex.append(coordValue); |
|
|
|
|
|
|
|
JsonHelper::saveGeoJsonCoordinate(bottomLeft, false /* writeAltitude */, coordValue); |
|
|
|
|
|
|
|
rgVertex.append(coordValue); |
|
|
|
|
|
|
|
JsonHelper::saveGeoJsonCoordinate(bottomRight, false /* writeAltitude */, coordValue); |
|
|
|
|
|
|
|
rgVertex.append(coordValue); |
|
|
|
|
|
|
|
JsonHelper::saveGeoJsonCoordinate(topRight, false /* writeAltitude */, coordValue); |
|
|
|
|
|
|
|
rgVertex.append(coordValue); |
|
|
|
|
|
|
|
JsonHelper::saveGeoJsonCoordinate(topLeft, false /* writeAltitude */, coordValue); |
|
|
|
|
|
|
|
rgVertex.append(coordValue); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QJsonArray rgPolygon; |
|
|
|
// Build up the polygon for the query
|
|
|
|
rgPolygon.append(rgVertex); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
polygonJson["coordinates"] = rgPolygon; |
|
|
|
// QJsonObject polygonJson;
|
|
|
|
QJsonDocument polygonJsonDoc(polygonJson); |
|
|
|
//
|
|
|
|
|
|
|
|
// polygonJson["type"] = "Polygon";
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// QGeoCoordinate left = _roiCenter.atDistanceAndAzimuth(_roiRadius, -90);
|
|
|
|
|
|
|
|
// QGeoCoordinate right = _roiCenter.atDistanceAndAzimuth(_roiRadius, 90);
|
|
|
|
|
|
|
|
// QGeoCoordinate top = _roiCenter.atDistanceAndAzimuth(_roiRadius, 0);
|
|
|
|
|
|
|
|
// QGeoCoordinate bottom = _roiCenter.atDistanceAndAzimuth(_roiRadius, 180);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// QGeoCoordinate topLeft(top.latitude(), left.longitude());
|
|
|
|
|
|
|
|
// QGeoCoordinate topRight(top.latitude(), right.longitude());
|
|
|
|
|
|
|
|
// QGeoCoordinate bottomLeft(bottom.latitude(), left.longitude());
|
|
|
|
|
|
|
|
// QGeoCoordinate bottomRight(bottom.latitude(), left.longitude());
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// QJsonValue coordValue;
|
|
|
|
|
|
|
|
// QJsonArray rgVertex;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// // GeoJson polygons are right handed and include duplicate first and last vertex
|
|
|
|
|
|
|
|
// JsonHelper::saveGeoJsonCoordinate(topLeft, false /* writeAltitude */, coordValue);
|
|
|
|
|
|
|
|
// rgVertex.append(coordValue);
|
|
|
|
|
|
|
|
// JsonHelper::saveGeoJsonCoordinate(bottomLeft, false /* writeAltitude */, coordValue);
|
|
|
|
|
|
|
|
// rgVertex.append(coordValue);
|
|
|
|
|
|
|
|
// JsonHelper::saveGeoJsonCoordinate(bottomRight, false /* writeAltitude */, coordValue);
|
|
|
|
|
|
|
|
// rgVertex.append(coordValue);
|
|
|
|
|
|
|
|
// JsonHelper::saveGeoJsonCoordinate(topRight, false /* writeAltitude */, coordValue);
|
|
|
|
|
|
|
|
// rgVertex.append(coordValue);
|
|
|
|
|
|
|
|
// JsonHelper::saveGeoJsonCoordinate(topLeft, false /* writeAltitude */, coordValue);
|
|
|
|
|
|
|
|
// rgVertex.append(coordValue);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// QJsonArray rgPolygon;
|
|
|
|
|
|
|
|
// rgPolygon.append(rgVertex);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// polygonJson["coordinates"] = rgPolygon;
|
|
|
|
|
|
|
|
// QJsonDocument polygonJsonDoc(polygonJson);
|
|
|
|
|
|
|
|
|
|
|
|
// Build up the http query
|
|
|
|
// Build up the http query
|
|
|
|
|
|
|
|
|
|
|
|
QUrlQuery airspaceQuery; |
|
|
|
QUrlQuery airspaceQuery; |
|
|
|
|
|
|
|
|
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("geometry"), QString::fromUtf8(polygonJsonDoc.toJson(QJsonDocument::Compact))); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("latitude"), QString::number(_roiCenter.latitude(), 'f', 10)); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("types"), QStringLiteral("airport,controlled_airspace,tfr,wildfire")); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("longitude"), QString::number(_roiCenter.longitude(), 'f', 10)); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("full"), QStringLiteral("true")); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("weather"), QStringLiteral("true")); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("geometry_format"), QStringLiteral("geojson")); |
|
|
|
airspaceQuery.addQueryItem(QStringLiteral("buffer"), QString::number(_roiRadius, 'f', 0)); |
|
|
|
|
|
|
|
|
|
|
|
QUrl airMapAirspaceUrl(QStringLiteral("https://api.airmap.com/airspace/v2/search")); |
|
|
|
QUrl airMapAirspaceUrl(QStringLiteral("https://api.airmap.com/status/alpha/point")); |
|
|
|
airMapAirspaceUrl.setQuery(airspaceQuery); |
|
|
|
airMapAirspaceUrl.setQuery(airspaceQuery); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_state = State::RetrieveList; |
|
|
|
_get(airMapAirspaceUrl); |
|
|
|
_get(airMapAirspaceUrl); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -178,22 +194,98 @@ void AirMapManager::_parseAirspaceJson(const QJsonDocument& airspaceDoc) |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_polygonList.clearAndDeleteContents(); |
|
|
|
|
|
|
|
_circleList.clearAndDeleteContents(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QJsonObject rootObject = airspaceDoc.object(); |
|
|
|
QJsonObject rootObject = airspaceDoc.object(); |
|
|
|
const QJsonArray& airspaceArray = rootObject["data"].toArray(); |
|
|
|
|
|
|
|
for (int i=0; i< airspaceArray.count(); i++) { |
|
|
|
switch(_state) { |
|
|
|
const QJsonObject& airspaceObject = airspaceArray[i].toObject(); |
|
|
|
case State::RetrieveList: |
|
|
|
QString airspaceType(airspaceObject["type"].toString()); |
|
|
|
{ |
|
|
|
qDebug() << airspaceType; |
|
|
|
QSet<QString> advisorySet; |
|
|
|
qDebug() << airspaceObject["name"].toString(); |
|
|
|
const QJsonArray& advisoriesArray = rootObject["data"].toObject()["advisories"].toArray(); |
|
|
|
QGeoCoordinate center(airspaceObject["latitude"].toDouble(), airspaceObject["longitude"].toDouble()); |
|
|
|
for (int i=0; i< advisoriesArray.count(); i++) { |
|
|
|
qDebug() << center; |
|
|
|
const QJsonObject& advisoryObject = advisoriesArray[i].toObject(); |
|
|
|
if (airspaceType == "airport") { |
|
|
|
QString advisoryId(advisoryObject["id"].toString()); |
|
|
|
_circleList.append(new CircularAirspaceRestriction(center, 8046.72)); |
|
|
|
qDebug() << "Adivsory id: " << advisoryId; |
|
|
|
|
|
|
|
advisorySet.insert(advisoryId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& advisoryId : advisorySet) { |
|
|
|
|
|
|
|
QUrl url(QStringLiteral("https://api.airmap.com/airspace/v2/")+advisoryId); |
|
|
|
|
|
|
|
_get(url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_numAwaitingItems = advisorySet.size(); |
|
|
|
|
|
|
|
_state = State::RetrieveItems; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case State::RetrieveItems: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
qDebug() << "got item"; |
|
|
|
|
|
|
|
const QJsonArray& airspaceArray = rootObject["data"].toArray(); |
|
|
|
|
|
|
|
for (int i=0; i< airspaceArray.count(); i++) { |
|
|
|
|
|
|
|
const QJsonObject& airspaceObject = airspaceArray[i].toObject(); |
|
|
|
|
|
|
|
QString airspaceType(airspaceObject["type"].toString()); |
|
|
|
|
|
|
|
QString airspaceId(airspaceObject["id"].toString()); |
|
|
|
|
|
|
|
QString airspaceName(airspaceObject["name"].toString()); |
|
|
|
|
|
|
|
const QJsonObject& airspaceGeometry(airspaceObject["geometry"].toObject()); |
|
|
|
|
|
|
|
QString geometryType(airspaceGeometry["type"].toString()); |
|
|
|
|
|
|
|
qDebug() << "Airspace ID:" << airspaceId << "name:" << airspaceName << "type:" << airspaceType << "geometry:" << geometryType; |
|
|
|
|
|
|
|
if (geometryType == "Polygon") { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const QJsonArray& airspaceCoordinates(airspaceGeometry["coordinates"].toArray()[0].toArray()); |
|
|
|
|
|
|
|
QString errorString; |
|
|
|
|
|
|
|
QmlObjectListModel list; |
|
|
|
|
|
|
|
if (JsonHelper::loadPolygon(airspaceCoordinates, list, this, errorString)) { |
|
|
|
|
|
|
|
QVariantList polygon; |
|
|
|
|
|
|
|
for (int i = 0; i < list.count(); ++i) { |
|
|
|
|
|
|
|
polygon.append(QVariant::fromValue(((QGCQGeoCoordinate*)list[i])->coordinate())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
list.clearAndDeleteContents(); |
|
|
|
|
|
|
|
_nextPolygonList.append(new PolygonAirspaceRestriction(polygon)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//FIXME
|
|
|
|
|
|
|
|
qDebug() << errorString; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// TODO: are there any circles?
|
|
|
|
|
|
|
|
qDebug() << "Unknown geometry type:" << geometryType; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (--_numAwaitingItems == 0) { |
|
|
|
|
|
|
|
_polygonList.clearAndDeleteContents(); |
|
|
|
|
|
|
|
_circleList.clearAndDeleteContents(); |
|
|
|
|
|
|
|
for (const auto& circle : _nextcircleList) { |
|
|
|
|
|
|
|
_circleList.append(circle); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_nextcircleList.clear(); |
|
|
|
|
|
|
|
for (const auto& polygon : _nextPolygonList) { |
|
|
|
|
|
|
|
_polygonList.append(polygon); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_nextPolygonList.clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_state = State::Idle; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
qDebug() << "Error: wrong state"; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://api.airmap.com/airspace/v2/search API
|
|
|
|
|
|
|
|
// const QJsonArray& airspaceArray = rootObject["data"].toArray();
|
|
|
|
|
|
|
|
// for (int i=0; i< airspaceArray.count(); i++) {
|
|
|
|
|
|
|
|
// const QJsonObject& airspaceObject = airspaceArray[i].toObject();
|
|
|
|
|
|
|
|
// QString airspaceType(airspaceObject["type"].toString());
|
|
|
|
|
|
|
|
// qDebug() << airspaceType;
|
|
|
|
|
|
|
|
// qDebug() << airspaceObject["name"].toString();
|
|
|
|
|
|
|
|
// QGeoCoordinate center(airspaceObject["latitude"].toDouble(), airspaceObject["longitude"].toDouble());
|
|
|
|
|
|
|
|
// qDebug() << center;
|
|
|
|
|
|
|
|
// if (airspaceType == "airport") {
|
|
|
|
|
|
|
|
// _circleList.append(new CircularAirspaceRestriction(center, 5000));
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
AirspaceRestriction::AirspaceRestriction(QObject* parent) |
|
|
|
AirspaceRestriction::AirspaceRestriction(QObject* parent) |
|
|
|