diff --git a/src/blackcore/weathermanager.cpp b/src/blackcore/weathermanager.cpp new file mode 100644 index 000000000..e914d323d --- /dev/null +++ b/src/blackcore/weathermanager.cpp @@ -0,0 +1,119 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "weathermanager.h" +#include "blackcore/weatherdata.h" +#include "blackmisc/logmessage.h" +#include "blackmisc/weather/weatherdataplugininfolist.h" + +using namespace BlackMisc; +using namespace BlackMisc::Geo; +using namespace BlackMisc::Weather; +using namespace BlackMisc::PhysicalQuantities; + +namespace BlackCore +{ + + CWeatherManager::CWeatherManager(QObject *parent) : QObject(parent) + { + m_pluginManagerWeatherData.collectPlugins(); + loadWeatherDataPlugins(); + } + + void CWeatherManager::setWeatherToClear(bool value) + { + m_isWeatherClear = value; + // todo: send weather grid to drivers from here + } + + void CWeatherManager::requestWeatherGrid(const CWeatherGrid &weatherGrid, + const BlackMisc::CSlot &callback) + { + if (m_isWeatherClear) + { + callback(CWeatherGrid::getClearWeatherGrid()); + return; + } + + WeatherRequest weatherRequest { weatherGrid, callback }; + m_pendingRequests.append(weatherRequest); + + // Serialize the requests, since plugins can handle only one at a time + if (m_pendingRequests.size() == 1) { fetchNextWeatherData(); } + } + + bool CWeatherManager::loadWeatherDataPlugins() + { + const CWeatherDataPluginInfoList weatherDataPluginInfos = m_pluginManagerWeatherData.getAvailableWeatherDataPlugins(); + if (weatherDataPluginInfos.isEmpty()) + { + CLogMessage(this).warning("No weather data plugin found!"); + return false; + } + + for (const auto &pluginInfo : weatherDataPluginInfos) + { + IWeatherDataFactory *factory = m_pluginManagerWeatherData.getPluginById(pluginInfo.getIdentifier()); + if (!factory) + { + CLogMessage(this).error("Failed to create IWeatherDataFactory for %1") << pluginInfo.getIdentifier(); + return false; + } + + IWeatherData *weatherData = factory->create(this); + if (!weatherData) + { + CLogMessage(this).error("Failed to create IWeatherData instance for %1") << pluginInfo.getIdentifier(); + return false; + } + + connect(weatherData, &IWeatherData::fetchingFinished, this, &CWeatherManager::handleNextRequest); + m_weatherDataPlugins.append(weatherData); + delete factory; + } + return true; + } + + void CWeatherManager::fetchNextWeatherData() + { + const WeatherRequest weatherRequest = m_pendingRequests.first(); + PhysicalQuantities::CLength maxDistance(100.0, CLengthUnit::km()); + + for (IWeatherData *plugin : m_weatherDataPlugins) + { + plugin->fetchWeatherData(weatherRequest.weatherGrid, maxDistance); + } + } + + void CWeatherManager::handleNextRequest() + { + Q_ASSERT(!m_pendingRequests.isEmpty()); + + IWeatherData *weatherDataPlugin = qobject_cast(sender()); + Q_ASSERT(weatherDataPlugin); + auto fetchedWeatherGrid = weatherDataPlugin->getWeatherData(); + + const WeatherRequest weatherRequest = m_pendingRequests.first(); + CWeatherGrid requestedWeatherGrid = weatherRequest.weatherGrid; + + // Interpolation. So far it just picks the closest point without interpolation. + for (CGridPoint &gridPoint : requestedWeatherGrid) + { + const auto nearestGridPoint = fetchedWeatherGrid.findClosest(1, gridPoint.getPosition()).frontOrDefault(); + gridPoint.copyWeatherDataFrom(nearestGridPoint); + } + + weatherRequest.callback(requestedWeatherGrid); + m_pendingRequests.pop_front(); + + // In case there are pending requests, start over again + if (m_pendingRequests.size() > 0) { fetchNextWeatherData(); } + } + +} diff --git a/src/blackcore/weathermanager.h b/src/blackcore/weathermanager.h new file mode 100644 index 000000000..8851f9ec5 --- /dev/null +++ b/src/blackcore/weathermanager.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKCORE_WEATHERMANAGER_H +#define BLACKCORE_WEATHERMANAGER_H + +#include "blackcore/blackcoreexport.h" +#include "blackcore/pluginmanagerweatherdata.h" +#include "blackmisc/geo/coordinategeodetic.h" +#include "blackmisc/weather/weathergrid.h" +#include "blackmisc/weather/weathergridprovider.h" +#include "blackmisc/slot.h" +#include +#include + +namespace BlackCore +{ + class IWeatherData; + + /*! + * CWeatherManager + */ + class BLACKCORE_EXPORT CWeatherManager : + public QObject, + public BlackMisc::Weather::IWeatherGridProvider + { + Q_OBJECT + Q_INTERFACES(BlackMisc::Weather::IWeatherGridProvider) + + public: + //! Default constructor + CWeatherManager(QObject *parent = nullptr); + + //! Override weather to clear + void setWeatherToClear(bool value); + + //! Is weather overwritten to clear? + bool isWeatherClear() const { return m_isWeatherClear; } + + //! Request weather by grid + virtual void requestWeatherGrid(const BlackMisc::Weather::CWeatherGrid &weatherGrid, + const BlackMisc::CSlot &callback) override; + + private: + struct WeatherRequest + { + BlackMisc::Weather::CWeatherGrid weatherGrid; + BlackMisc::CSlot callback; + }; + + bool loadWeatherDataPlugins(); + + void fetchNextWeatherData(); + void handleNextRequest(); + + CPluginManagerWeatherData m_pluginManagerWeatherData { this }; + QVector m_weatherDataPlugins; + QVector m_pendingRequests; + BlackMisc::Weather::CWeatherGrid m_weatherGrid; + bool m_isWeatherClear = false; + }; + +} // ns + +#endif // guard diff --git a/src/blackmisc/weather/gridpoint.cpp b/src/blackmisc/weather/gridpoint.cpp index 0146a23e2..d675b678a 100644 --- a/src/blackmisc/weather/gridpoint.cpp +++ b/src/blackmisc/weather/gridpoint.cpp @@ -13,6 +13,7 @@ using namespace BlackMisc::Aviation; using namespace BlackMisc::Geo; +using namespace BlackMisc::PhysicalQuantities; namespace BlackMisc { @@ -28,6 +29,14 @@ namespace BlackMisc m_windLayers(windLayers) { } + void CGridPoint::copyWeatherDataFrom(const CGridPoint &other) + { + setCloudLayers(other.getCloudLayers()); + setTemperatureLayers(other.getTemperatureLayers()); + setVisibilityLayers(other.getVisibilityLayers()); + setWindLayers(other.getWindLayers()); + } + CVariant CGridPoint::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } diff --git a/src/blackmisc/weather/gridpoint.h b/src/blackmisc/weather/gridpoint.h index e388b70e7..6d07dc7fa 100644 --- a/src/blackmisc/weather/gridpoint.h +++ b/src/blackmisc/weather/gridpoint.h @@ -80,6 +80,9 @@ namespace BlackMisc //! Get wind layers CWindLayerList getWindLayers() const { return m_windLayers; } + //! Copies all weather data from other without modifying identifier and position. + void copyWeatherDataFrom(const CGridPoint &other); + //! \copydoc BlackMisc::Mixin::Index::propertyByIndex CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;