mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-24 17:08:36 -05:00
327 lines
14 KiB
C++
327 lines
14 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
// Copyright (C) 2024 Jon Beniston, M7RCE <jon@beniston.com> //
|
||
|
// //
|
||
|
// This program 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 as version 3 of the License, or //
|
||
|
// (at your option) any later version. //
|
||
|
// //
|
||
|
// This program 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 V3 for more details. //
|
||
|
// //
|
||
|
// You should have received a copy of the GNU General Public License //
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "nasaglobalimagery.h"
|
||
|
|
||
|
#include <QDebug>
|
||
|
#include <QUrl>
|
||
|
#include <QUrlQuery>
|
||
|
#include <QNetworkReply>
|
||
|
#include <QXmlStreamReader>
|
||
|
#include <QNetworkDiskCache>
|
||
|
#include <QJsonDocument>
|
||
|
#include <QJsonObject>
|
||
|
|
||
|
NASAGlobalImagery::NASAGlobalImagery()
|
||
|
{
|
||
|
m_networkManager = new QNetworkAccessManager();
|
||
|
QObject::connect(m_networkManager, &QNetworkAccessManager::finished, this, &NASAGlobalImagery::handleReply);
|
||
|
|
||
|
QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
||
|
QDir writeableDir(locations[0]);
|
||
|
if (!writeableDir.mkpath(QStringLiteral("cache") + QDir::separator() + QStringLiteral("nasaglobalimagery"))) {
|
||
|
qDebug() << "Failed to create cache/nasaglobalimagery";
|
||
|
}
|
||
|
|
||
|
m_cache = new QNetworkDiskCache();
|
||
|
m_cache->setCacheDirectory(locations[0] + QDir::separator() + QStringLiteral("cache") + QDir::separator() + QStringLiteral("nasaglobalimagery"));
|
||
|
m_cache->setMaximumCacheSize(100000000);
|
||
|
m_networkManager->setCache(m_cache);
|
||
|
}
|
||
|
|
||
|
NASAGlobalImagery::~NASAGlobalImagery()
|
||
|
{
|
||
|
QObject::disconnect(m_networkManager, &QNetworkAccessManager::finished, this, &NASAGlobalImagery::handleReply);
|
||
|
delete m_networkManager;
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::getData()
|
||
|
{
|
||
|
QUrl url(QString("https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/1.0.0/WMTSCapabilities.xml"));
|
||
|
m_networkManager->get(QNetworkRequest(url));
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::getMetaData()
|
||
|
{
|
||
|
QUrl url(QString("https://worldview.earthdata.nasa.gov/config/wv.json"));
|
||
|
m_networkManager->get(QNetworkRequest(url));
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::handleReply(QNetworkReply* reply)
|
||
|
{
|
||
|
if (reply)
|
||
|
{
|
||
|
if (!reply->error())
|
||
|
{
|
||
|
QString url = reply->url().toEncoded().constData();
|
||
|
QByteArray bytes = reply->readAll();
|
||
|
|
||
|
if (url.endsWith(".xml")) {
|
||
|
handleXML(bytes);
|
||
|
} else if (url.endsWith(".svg")) {
|
||
|
handleSVG(url, bytes);
|
||
|
} else if (url.endsWith(".json")) {
|
||
|
handleJSON(bytes);
|
||
|
} else if (url.endsWith(".html")) {
|
||
|
handleHTML(url, bytes);
|
||
|
} else {
|
||
|
qDebug() << "NASAGlobalImagery::handleReply: unexpected URL: " << url;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
qDebug() << "NASAGlobalImagery::handleReply: error: " << reply->error();
|
||
|
}
|
||
|
reply->deleteLater();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
qDebug() << "NASAGlobalImagery::handleReply: reply is null";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::handleXML(const QByteArray& bytes)
|
||
|
{
|
||
|
QXmlStreamReader xmlReader(bytes);
|
||
|
QList<DataSet> dataSets;
|
||
|
|
||
|
while (!xmlReader.atEnd() && !xmlReader.hasError())
|
||
|
{
|
||
|
while (xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("Capabilities"))
|
||
|
{
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("Contents"))
|
||
|
{
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("Layer"))
|
||
|
{
|
||
|
QString identifier;
|
||
|
QString colorMap;
|
||
|
QList<Legend> legends;
|
||
|
QString tileMatrixSet;
|
||
|
QStringList urls;
|
||
|
QString format;
|
||
|
QString defaultDateTime;
|
||
|
QStringList dates;
|
||
|
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("Identifier"))
|
||
|
{
|
||
|
identifier = xmlReader.readElementText();
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("TileMatrixSetLink"))
|
||
|
{
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("TileMatrixSet"))
|
||
|
{
|
||
|
tileMatrixSet = xmlReader.readElementText();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("Style"))
|
||
|
{
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("LegendURL"))
|
||
|
{
|
||
|
Legend legend;
|
||
|
|
||
|
legend.m_url = xmlReader.attributes().value("xlink:href").toString();
|
||
|
legend.m_width = (int)xmlReader.attributes().value("width").toFloat();
|
||
|
legend.m_height = (int)xmlReader.attributes().value("height").toFloat();
|
||
|
//qDebug() << legend.m_url << legend.m_width << legend.m_height;
|
||
|
legends.append(legend);
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("Metadata"))
|
||
|
{
|
||
|
colorMap = xmlReader.attributes().value("xlink:href").toString();
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("Format"))
|
||
|
{
|
||
|
format = xmlReader.readElementText();
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("ResourceURL"))
|
||
|
{
|
||
|
QString url = xmlReader.attributes().value("template").toString();
|
||
|
if (!url.isEmpty()) {
|
||
|
urls.append(url);
|
||
|
}
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("Dimension"))
|
||
|
{
|
||
|
while(xmlReader.readNextStartElement())
|
||
|
{
|
||
|
if (xmlReader.name() == QLatin1String("Default"))
|
||
|
{
|
||
|
defaultDateTime = xmlReader.readElementText();
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("Value"))
|
||
|
{
|
||
|
dates.append(xmlReader.readElementText());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Some layers are <Format>application/vnd.mapbox-vector-tile</Format>
|
||
|
if (!identifier.isEmpty() && !tileMatrixSet.isEmpty() && ((format == "image/png") || (format == "image/jpeg")))
|
||
|
{
|
||
|
DataSet dataSet;
|
||
|
dataSet.m_identifier = identifier;
|
||
|
dataSet.m_legends = legends;
|
||
|
dataSet.m_tileMatrixSet = tileMatrixSet;
|
||
|
dataSet.m_format = format;
|
||
|
dataSet.m_defaultDateTime = defaultDateTime;
|
||
|
dataSet.m_dates = dates;
|
||
|
dataSets.append(dataSet);
|
||
|
|
||
|
//qDebug() << "Adding layer" << identifier << colorMap << legends << tileMatrixSet;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (xmlReader.name() == QLatin1String("ServiceMetadataURL"))
|
||
|
{
|
||
|
// Empty?
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmlReader.skipCurrentElement();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Ignore "Premature end of document." here even if ok
|
||
|
if (!xmlReader.atEnd() && xmlReader.hasError())
|
||
|
{
|
||
|
qDebug() << "NASAGlobalImagery::handleReply: Error parsing XML: " << xmlReader.errorString();
|
||
|
}
|
||
|
|
||
|
emit dataUpdated(dataSets);
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::downloadLegend(const Legend& legend)
|
||
|
{
|
||
|
QUrl url(legend.m_url);
|
||
|
m_networkManager->get(QNetworkRequest(url));
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::downloadHTML(const QString& urlString)
|
||
|
{
|
||
|
QUrl url(urlString);
|
||
|
m_networkManager->get(QNetworkRequest(url));
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::handleSVG(const QString& url, const QByteArray& bytes)
|
||
|
{
|
||
|
emit legendAvailable(url, bytes);
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::handleJSON(const QByteArray& bytes)
|
||
|
{
|
||
|
MetaData metaData;
|
||
|
|
||
|
QJsonDocument document = QJsonDocument::fromJson(bytes);
|
||
|
if (document.isObject())
|
||
|
{
|
||
|
QJsonObject obj = document.object();
|
||
|
if (obj.contains(QStringLiteral("layers")))
|
||
|
{
|
||
|
for (const auto& oRef : obj.value(QStringLiteral("layers")).toObject())
|
||
|
{
|
||
|
Layer layer;
|
||
|
QJsonObject o = oRef.toObject();
|
||
|
|
||
|
if (o.contains(QStringLiteral("id"))) {
|
||
|
layer.m_identifier = o.value(QStringLiteral("id")).toString();
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("title"))) {
|
||
|
layer.m_title = o.value(QStringLiteral("title")).toString();
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("subtitle"))) {
|
||
|
layer.m_subtitle = o.value(QStringLiteral("subtitle")).toString();
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("description"))) {
|
||
|
layer.m_descriptionURL = "https://worldview.earthdata.nasa.gov/config/metadata/layers/" + o.value(QStringLiteral("description")).toString() + ".html";
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("startDate"))) {
|
||
|
layer.m_startDate = QDateTime::fromString(o.value(QStringLiteral("startDate")).toString(), Qt::ISODate);
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("endDate"))) {
|
||
|
layer.m_endDate = QDateTime::fromString(o.value(QStringLiteral("endDate")).toString(), Qt::ISODate);
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("ongoing"))) {
|
||
|
layer.m_ongoing = o.value(QStringLiteral("ongoing")).toBool();
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("layerPeriod"))) {
|
||
|
layer.m_layerPeriod = o.value(QStringLiteral("layerPeriod")).toString();
|
||
|
}
|
||
|
if (o.contains(QStringLiteral("layergroup"))) {
|
||
|
layer.m_layerGroup = o.value(QStringLiteral("layergroup")).toString();
|
||
|
}
|
||
|
if (!layer.m_identifier.isEmpty()) {
|
||
|
metaData.m_layers.insert(layer.m_identifier, layer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
emit metaDataUpdated(metaData);
|
||
|
}
|
||
|
|
||
|
void NASAGlobalImagery::handleHTML(const QString& url, const QByteArray& bytes)
|
||
|
{
|
||
|
emit htmlAvailable(url, bytes);
|
||
|
}
|