mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-30 20:40:20 -04: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);
 | |
| }
 |