diff --git a/src/blackmisc/blackmisc.pro b/src/blackmisc/blackmisc.pro index 54c4a34e7..2e586797c 100644 --- a/src/blackmisc/blackmisc.pro +++ b/src/blackmisc/blackmisc.pro @@ -37,7 +37,8 @@ HEADERS += *.h \ $$PWD/audio/*.h \ $$PWD/simulation/*.h \ $$PWD/simulation/fscommon/*.h \ - $$PWD/simulation/fsx/*.h + $$PWD/simulation/fsx/*.h \ + $$PWD/weather/*.h SOURCES += *.cpp \ $$PWD/pq/*.cpp \ @@ -49,7 +50,8 @@ SOURCES += *.cpp \ $$PWD/audio/*.cpp \ $$PWD/simulation/*.cpp \ $$PWD/simulation/fscommon/*.cpp \ - $$PWD/simulation/fsx/*.cpp + $$PWD/simulation/fsx/*.cpp \ + $$PWD/weather/*.cpp DESTDIR = $$BuildRoot/lib DLLDESTDIR = $$BuildRoot/bin diff --git a/src/blackmisc/blackmiscfreefunctions.cpp b/src/blackmisc/blackmiscfreefunctions.cpp index 05b6c1350..2d66f01e2 100644 --- a/src/blackmisc/blackmiscfreefunctions.cpp +++ b/src/blackmisc/blackmiscfreefunctions.cpp @@ -100,6 +100,7 @@ void BlackMisc::registerMetadata() Audio::registerMetadata(); Hardware::registerMetadata(); Event::registerMetadata(); + Weather::registerMetadata(); // needed by XBus proxy class qRegisterMetaType>(); diff --git a/src/blackmisc/blackmiscfreefunctions.h b/src/blackmisc/blackmiscfreefunctions.h index 70eb18a16..536a5de49 100644 --- a/src/blackmisc/blackmiscfreefunctions.h +++ b/src/blackmisc/blackmiscfreefunctions.h @@ -108,6 +108,12 @@ namespace BlackMisc BLACKMISC_EXPORT void registerMetadata(); } + namespace Weather + { + //! Register metadata for Simulation + BLACKMISC_EXPORT void registerMetadata(); + } + //! Register all relevant metadata in BlackMisc BLACKMISC_EXPORT void registerMetadata(); diff --git a/src/blackmisc/propertyindex.h b/src/blackmisc/propertyindex.h index bbd32e2bc..943aab358 100644 --- a/src/blackmisc/propertyindex.h +++ b/src/blackmisc/propertyindex.h @@ -65,6 +65,10 @@ namespace BlackMisc GlobalIndexCAircraftIcaoCode = 2600, GlobalIndexCAirlineIcaoCode = 2700, GlobalIndexCAirportIcaoCode = 2800, + GlobalIndexCMetar = 2900, + GlobalIndexCCloudLayer = 2910, + GlobalIndexCPresentWeather = 2920, + GlobalIndexCWindLayer = 2930, GlobalIndexICoordinateGeodetic = 3000, GlobalIndexCCoordinateGeodetic = 3100, GlobalIndexCClient = 4000, diff --git a/src/blackmisc/weather/blackmiscfreefunctions_wxmeta.cpp b/src/blackmisc/weather/blackmiscfreefunctions_wxmeta.cpp new file mode 100644 index 000000000..8048a441c --- /dev/null +++ b/src/blackmisc/weather/blackmiscfreefunctions_wxmeta.cpp @@ -0,0 +1,28 @@ +/* Copyright (C) 2015 + * 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 "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/weather/weather.h" + +/* + * Metadata for aviation + * + * In a separate file to workaround a limitation of MinGW: + * http://stackoverflow.com/q/16596876/1639256 + */ +void BlackMisc::Weather::registerMetadata() +{ + CMetar::registerMetadata(); + CMetarSet::registerMetadata(); + CPresentWeather::registerMetadata(); + CPresentWeatherList::registerMetadata(); + CCloudLayer::registerMetadata(); + CCloudLayerList::registerMetadata(); + CWindLayer::registerMetadata(); +} diff --git a/src/blackmisc/weather/cloudlayer.cpp b/src/blackmisc/weather/cloudlayer.cpp new file mode 100644 index 000000000..71d211950 --- /dev/null +++ b/src/blackmisc/weather/cloudlayer.cpp @@ -0,0 +1,77 @@ +/* Copyright (C) 2015 + * 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 "blackmisc/weather/cloudlayer.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/variant.h" + +#include +#include + +using namespace BlackMisc::Aviation; + +namespace BlackMisc +{ + namespace Weather + { + + CCloudLayer::CCloudLayer(CAltitude ceiling, Coverage coverage) : + m_ceiling(ceiling), m_coverage(coverage) + { } + + CVariant CCloudLayer::propertyByIndex(const BlackMisc::CPropertyIndex &index) const + { + if (index.isMyself()) { return CVariant::from(*this); } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexCeiling: + return CVariant::fromValue(m_ceiling); + case IndexCoverage: + return CVariant::fromValue(m_coverage); + default: + return CValueObject::propertyByIndex(index); + } + } + + void CCloudLayer::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) + { + if (index.isMyself()) { (*this) = variant.to(); return; } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexCeiling: + setCeiling(variant.value()); + break; + case IndexCoverage: + setCoverage(variant.value()); + break; + default: + CValueObject::setPropertyByIndex(variant, index); + break; + } + } + + QString CCloudLayer::convertToQString(bool /** i18n **/) const + { + static const QHash hash = + { + { None, "" }, + { Few, "few" }, + { Scattered, "scattered" }, + { Broken, "broken" }, + { Overcast, "overcast" } + }; + + return QString("%1 in %2").arg(hash.value(m_coverage)).arg(m_ceiling.toQString()); + } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/cloudlayer.h b/src/blackmisc/weather/cloudlayer.h new file mode 100644 index 000000000..2be589909 --- /dev/null +++ b/src/blackmisc/weather/cloudlayer.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_CLOUDLAYER_H +#define BLACKMISC_WEATHER_CLOUDLAYER_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/valueobject.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/aviation/altitude.h" + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object for a cloud layer + */ + class BLACKMISC_EXPORT CCloudLayer : public CValueObject + { + public: + //! Cloud coverage + enum Coverage + { + None, + Few, + Scattered, + Broken, + Overcast + }; + + //! Properties by index + enum ColumnIndex + { + IndexCloudLayer = BlackMisc::CPropertyIndex::GlobalIndexCCloudLayer, + IndexCeiling, + IndexCoverage + }; + + //! Default constructor. + CCloudLayer() = default; + + //! Constructor + CCloudLayer(BlackMisc::Aviation::CAltitude ceiling, Coverage coverage); + + //! Set ceiling + void setCeiling(BlackMisc::Aviation::CAltitude ceiling) { m_ceiling = ceiling; } + + //! Get ceiling + BlackMisc::Aviation::CAltitude getCeiling() const { return m_ceiling; } + + //! Set coverage + void setCoverage(Coverage coverage) { m_coverage = coverage; } + + //! Get coverage + Coverage getCoverage() const { return m_coverage; } + + //! \copydoc CValueObject::propertyByIndex + CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + + //! \copydoc CValueObject::setPropertyByIndex + void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index); + + //! \copydoc CValueObject::convertToQString + QString convertToQString(bool i18n = false) const; + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CCloudLayer) + BlackMisc::Aviation::CAltitude m_ceiling; + Coverage m_coverage; + }; + } // namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CCloudLayer) +Q_DECLARE_METATYPE(BlackMisc::Weather::CCloudLayer::Coverage) +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Weather::CCloudLayer, ( + attr(o.m_ceiling), + attr(o.m_coverage) +)) + +#endif // guard diff --git a/src/blackmisc/weather/cloudlayerlist.cpp b/src/blackmisc/weather/cloudlayerlist.cpp new file mode 100644 index 000000000..e8f9dff83 --- /dev/null +++ b/src/blackmisc/weather/cloudlayerlist.cpp @@ -0,0 +1,33 @@ +/* Copyright (C) 2015 + * 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 "cloudlayerlist.h" + +using namespace BlackMisc::Aviation; + +namespace BlackMisc +{ + namespace Weather + { + CCloudLayerList::CCloudLayerList(const CSequence &other) : + CSequence(other) + { } + + bool CCloudLayerList::containsCeiling(const CAltitude &ceiling) const + { + return contains(&CCloudLayer::getCeiling, ceiling); + } + + CCloudLayer CCloudLayerList::findByCeiling(const CAltitude &ceiling) const + { + return findFirstByOrDefault(&CCloudLayer::getCeiling, ceiling); + } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/cloudlayerlist.h b/src/blackmisc/weather/cloudlayerlist.h new file mode 100644 index 000000000..344eab286 --- /dev/null +++ b/src/blackmisc/weather/cloudlayerlist.h @@ -0,0 +1,52 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_CLOUDLAYERLIST_H +#define BLACKMISC_WEATHER_CLOUDLAYERLIST_H + +#include "cloudlayer.h" +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/sequence.h" + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object encapsulating a set of cloud layers + */ + class BLACKMISC_EXPORT CCloudLayerList : + public CSequence, + public BlackMisc::Mixin::MetaType + { + public: + BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CCloudLayerList) + + //! Default constructor. + CCloudLayerList() = default; + + //! Construct from a base class object. + CCloudLayerList(const CSequence &other); + + //! Contains cloud layer with ceiling? + bool containsCeiling(const BlackMisc::Aviation::CAltitude &ceiling) const; + + //! Find cloud layer by ceiling + CCloudLayer findByCeiling(const BlackMisc::Aviation::CAltitude &ceiling) const; + }; + + } //namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CCloudLayerList) +Q_DECLARE_METATYPE(BlackMisc::CSequence) + +#endif //guard diff --git a/src/blackmisc/weather/metar.cpp b/src/blackmisc/weather/metar.cpp new file mode 100644 index 000000000..06a030238 --- /dev/null +++ b/src/blackmisc/weather/metar.cpp @@ -0,0 +1,207 @@ +/* Copyright (C) 2015 + * 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 "metar.h" +#include "blackmiscfreefunctions.h" + +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Aviation; + +namespace BlackMisc +{ + namespace Weather + { + + CMetar::CMetar() + { + setCavok(); + } + + void CMetar::setMessage(const QString &message) + { + m_metarMessage = message; + } + + QString CMetar::getMessage() const + { + return m_metarMessage; + } + + void CMetar::setReportType(ReportType type) + { + m_reportType = type; + } + + CMetar::ReportType CMetar::getReportType() const + { + return m_reportType; + } + + void CMetar::setAirportIcaoCode(const CAirportIcaoCode &icao) + { + m_airport = icao; + } + + CAirportIcaoCode CMetar::getAirportIcaoCode() const + { + return m_airport; + } + + void CMetar::setDayTime(int reportDay, const PhysicalQuantities::CTime &reportTime) + { + m_reportDay = reportDay; m_reportTime = reportTime; + } + + int CMetar::getDay() const + { + return m_reportDay; + } + + PhysicalQuantities::CTime CMetar::getTime() const + { + return m_reportTime; + } + + void CMetar::setAutomated(bool isAutomated) + { + m_isAutomated = isAutomated; + } + + void CMetar::setCavok() + { + m_visibility = CLength(10000, CLengthUnit::km()); + m_presentWeathers.clear(); + m_cloudLayers.clear(); + } + + bool CMetar::isCavok() const + { + return false; + } + + void CMetar::setWindLayer(const CWindLayer &windLayer) + { + m_windLayer = windLayer; + } + + CWindLayer CMetar::getWindLayer() const + { + return m_windLayer; + } + + void CMetar::setVisibility(const PhysicalQuantities::CLength &visibility) + { + m_visibility = visibility; + } + + PhysicalQuantities::CLength CMetar::getVisibility() const + { + return m_visibility; + } + + void CMetar::addPresentWeather(const CPresentWeather &presentWeather) + { + m_presentWeathers.push_back(presentWeather); + } + + CPresentWeatherList CMetar::getPresentWeather() const + { + return m_presentWeathers; + } + + void CMetar::addCloudLayer(const CCloudLayer &cloudLayer) + { + m_cloudLayers.push_back(cloudLayer); + } + + CCloudLayerList CMetar::getCloudLayers() const + { + return m_cloudLayers; + } + + void CMetar::setTemperature(const PhysicalQuantities::CTemperature &temperature) + { + m_temperature = temperature; + } + + PhysicalQuantities::CTemperature CMetar::getTemperature() const + { + return m_temperature; + } + + void CMetar::setDewPoint(const PhysicalQuantities::CTemperature &dewPoint) + { + m_dewPoint = dewPoint; + } + + PhysicalQuantities::CTemperature CMetar::getDewPoint() const + { + return m_dewPoint; + } + + void CMetar::setAltimeter(const PhysicalQuantities::CPressure &altimeter) + { + m_altimeter = altimeter; + } + + PhysicalQuantities::CPressure CMetar::getAltimeter() const + { + return m_altimeter; + } + + QString CMetar::getMetarText() const + { + QString metarDescription; + metarDescription += QString("Station: %1 \n").arg(m_airport.getIcaoCode()); + metarDescription += QString("Date/Time: %1 %2 UTC\n").arg(m_reportDay).arg(m_reportTime.formattedHrsMin()); + metarDescription += m_windLayer.toQString(); + metarDescription += "\n"; + metarDescription += QString("Visibility: %1\n").arg(m_visibility.toQString()); + metarDescription += QString("Weather: "); + QString presentWeathers; + for (const auto &presentWeather : m_presentWeathers) + { + if (!presentWeathers.isEmpty()) presentWeathers += ","; + presentWeathers += " "; + presentWeathers += presentWeather.toQString(); + } + metarDescription += presentWeathers.simplified(); + metarDescription += QString("\n"); + metarDescription += QString("Clouds:"); + QString clouds; + for (const auto &layer : m_cloudLayers) + { + if (!clouds.isEmpty()) clouds += ","; + clouds += " "; + clouds += layer.toQString(); + } + metarDescription += clouds; + metarDescription += QString("\n"); + metarDescription += QString("Temperature: %1\n").arg(m_temperature.toQString()); + metarDescription += QString("Dewpoint: %1\n").arg(m_dewPoint.toQString()); + metarDescription += QString("Altimeter: %1\n").arg(m_altimeter.toQString()); + return metarDescription; + } + + QString CMetar::convertToQString(bool i18n) const + { + Q_UNUSED(i18n); + QString s(m_airport.getIcaoCode()); + return s; + } + + CMetar CMetar::CAVOK() + { + CMetar metar; + metar.setCavok(); + return metar; + } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/metar.h b/src/blackmisc/weather/metar.h new file mode 100644 index 000000000..4aad3e70d --- /dev/null +++ b/src/blackmisc/weather/metar.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_AVIATION_METAR_H +#define BLACKMISC_AVIATION_METAR_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/valueobject.h" +#include "blackmisc/aviation/airporticaocode.h" +#include "blackmisc/weather/cloudlayerlist.h" +#include "blackmisc/weather/presentweatherlist.h" +#include "blackmisc/weather/windlayer.h" +#include "blackmisc/pq/time.h" +#include "blackmisc/pq/length.h" +#include "blackmisc/pq/temperature.h" +#include "blackmisc/pq/pressure.h" + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object encapsulating information about METAR + * FIXME: runway visibilities + * FIXME: runway wind shear + * FIXME: remarks + */ + class BLACKMISC_EXPORT CMetar : public CValueObject + { + public: + //! Report type + enum ReportType + { + METAR, + SPECI + }; + + //! Default constructor + CMetar(); + + //! Set METAR message + void setMessage(const QString &message); + + //! Get METAR message + QString getMessage() const; + + //! Set report type + void setReportType(ReportType type); + + //! Get report type + ReportType getReportType() const; + + //! Set airport icao code + void setAirportIcaoCode(const BlackMisc::Aviation::CAirportIcaoCode &icao); + + //! Get airport icao code + BlackMisc::Aviation::CAirportIcaoCode getAirportIcaoCode() const; + + //! Set day and time + void setDayTime(int reportDay, const PhysicalQuantities::CTime &reportTime); + + //! Get report day + int getDay() const; + + //! Get report time + PhysicalQuantities::CTime getTime() const; + + //! Set the station to automated + void setAutomated(bool isAutomated); + + //! Is the station automated? + bool isAutomated() const { return m_isAutomated; } + + //! Set the weather to CAVOK + void setCavok(); + + //! Is CAVOK? + bool isCavok() const; + + //! Set wind information + void setWindLayer(const CWindLayer &windLayer); + + //! Get wind layer + CWindLayer getWindLayer() const; + + //! Set visibility information + void setVisibility(const PhysicalQuantities::CLength &visibility); + + //! Get visibility + PhysicalQuantities::CLength getVisibility() const; + + //! Add information about present weather + void addPresentWeather(const CPresentWeather &presentWeather); + + //! Get present weather list + CPresentWeatherList getPresentWeather() const; + + //! Add cloud layer + void addCloudLayer(const CCloudLayer &cloudLayer); + + //! Get all cloud layers + CCloudLayerList getCloudLayers() const; + + //! Remove all cloud layers + void removeAllClouds() { m_cloudLayers.clear(); } + + //! Set temperature + void setTemperature(const PhysicalQuantities::CTemperature &temperature); + + //! Get temperature + PhysicalQuantities::CTemperature getTemperature() const; + + //! Set dew point + void setDewPoint(const PhysicalQuantities::CTemperature &dewPoint); + + //! Get dew point + PhysicalQuantities::CTemperature getDewPoint() const; + + //! Set altimeter + void setAltimeter(const PhysicalQuantities::CPressure &altimeter); + + //! Get altimeter + PhysicalQuantities::CPressure getAltimeter() const; + + //! Returns the metar in a descriptive text + QString getMetarText() const; + + //! \copydoc CValueObject::convertToQString + QString convertToQString(bool i18n = false) const; + + //! Return CAVOK metar + static CMetar CAVOK(); + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CMetar) + QString m_metarMessage; + ReportType m_reportType = METAR; + BlackMisc::Aviation::CAirportIcaoCode m_airport; + int m_reportDay = 0; + PhysicalQuantities::CTime m_reportTime; + bool m_isAutomated = false; + CWindLayer m_windLayer; + PhysicalQuantities::CLength m_visibility; + CPresentWeatherList m_presentWeathers; + CCloudLayerList m_cloudLayers; + PhysicalQuantities::CTemperature m_temperature; + PhysicalQuantities::CTemperature m_dewPoint; + PhysicalQuantities::CPressure m_altimeter; + }; + } // namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CMetar) +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Weather::CMetar, ( + attr(o.m_metarMessage), + attr(o.m_reportType), + attr(o.m_airport), + attr(o.m_reportDay), + attr(o.m_reportTime), + attr(o.m_isAutomated), + attr(o.m_windLayer), + attr(o.m_visibility), + attr(o.m_presentWeathers), + attr(o.m_cloudLayers), + attr(o.m_temperature), + attr(o.m_dewPoint), + attr(o.m_altimeter) +)) + +#endif // guard diff --git a/src/blackmisc/weather/metarset.cpp b/src/blackmisc/weather/metarset.cpp new file mode 100644 index 000000000..d4cffeae9 --- /dev/null +++ b/src/blackmisc/weather/metarset.cpp @@ -0,0 +1,21 @@ +/* Copyright (C) 2015 + * 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 "metarset.h" + +namespace BlackMisc +{ + namespace Weather + { + CMetarSet::CMetarSet(const CCollection &other) : + CCollection(other) + { } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/metarset.h b/src/blackmisc/weather/metarset.h new file mode 100644 index 000000000..24dd3726b --- /dev/null +++ b/src/blackmisc/weather/metarset.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_METARSET_H +#define BLACKMISC_WEATHER_METARSET_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/weather/metar.h" +#include "blackmisc/collection.h" +#include "blackmisc/sequence.h" + +namespace BlackMisc +{ + namespace Weather + { + //! Collection of Metars + class BLACKMISC_EXPORT CMetarSet : + public CCollection, + public BlackMisc::Mixin::MetaType + { + public: + BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CMetarSet) + + //! Default constructor. + CMetarSet() = default; + + //! Construct from a base class object. + CMetarSet(const CCollection &other); + }; + + } //namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CMetarSet) +Q_DECLARE_METATYPE(BlackMisc::CCollection) +Q_DECLARE_METATYPE(BlackMisc::CSequence) + +#endif //guard diff --git a/src/blackmisc/weather/presentweather.cpp b/src/blackmisc/weather/presentweather.cpp new file mode 100644 index 000000000..ce40ba302 --- /dev/null +++ b/src/blackmisc/weather/presentweather.cpp @@ -0,0 +1,131 @@ +/* Copyright (C) 2015 + * 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 "blackmisc/weather/presentweather.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/variant.h" + +namespace BlackMisc +{ + namespace Weather + { + + CPresentWeather::CPresentWeather(Intensity intensity, Descriptor descriptor, int weatherPhenomena) : + m_intensity(intensity), m_descriptor(descriptor), m_weatherPhenomena(weatherPhenomena) + { } + + CVariant CPresentWeather::propertyByIndex(const BlackMisc::CPropertyIndex &index) const + { + if (index.isMyself()) { return CVariant::from(*this); } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexIntensity: + return CVariant::fromValue(static_cast(m_intensity)); + case IndexDescriptor: + return CVariant::fromValue(static_cast(m_descriptor)); + case IndexWeatherPhenomena: + return CVariant::fromValue(m_weatherPhenomena); + default: + return CValueObject::propertyByIndex(index); + } + } + + void CPresentWeather::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) + { + if (index.isMyself()) { (*this) = variant.to(); return; } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexIntensity: + setIntensity(static_cast(variant.toInt())); + break; + case IndexDescriptor: + setDescriptor(static_cast(variant.toInt())); + break; + case IndexWeatherPhenomena: + setWeatherPhenomena(variant.toInt()); + break; + default: + CValueObject::setPropertyByIndex(variant, index); + break; + } + } + + QString CPresentWeather::convertToQString(bool /** i18n **/) const + { + static const QHash intensityHash = + { + { Moderate, "moderate" }, + { Light, "light" }, + { Heavy, "heavy" }, + { InVincinity, "in vincinity" }, + }; + + static const QHash descriptorHash = + { + { None, "" }, + { Shallow, "shallow" }, + { Patches, "patches" }, + { Partial, "partial" }, + { Drifting, "drifting" }, + { Blowing, "blowing" }, + { Showers, "showers" }, + { Thunderstorm, "thunderstorm" }, + { Freezing, "freezing" }, + }; + + static const QHash weatherPhenomenaHash = + { + { Drizzle, "drizzle" }, + { Rain, "rain" }, + { Snow, "snow" }, + { SnowGrains, "snow srains" }, + { IceCrystals, "ice crystals" }, + { IcePellets, "ice pellets" }, + { Hail, "hail" }, + { SnowPellets, "snow pellets" }, + { Unknown, "unknown" }, + { Mist, "mist" }, + { Fog, "fog" }, + { Smoke, "smoke" }, + { VolcanicAsh, "volcanic ash" }, + { Dust, "dust" }, + { Sand, "sand" }, + { Haze, "haze" }, + { DustSandWhirls, "dustSand whirls" }, + { Squalls, "squalls" }, + { TornadoOrWaterspout, "tornado or waterspout" }, + { FunnelCloud, "funnel cloud" }, + { Sandstorm, "sandstorm" }, + { Duststorm, "duststorm" } + }; + + QString weatherPhenomenaAsString; + for (const auto &wp : weatherPhenomenaHash.keys()) + { + if (m_weatherPhenomena & wp) + { + if (!weatherPhenomenaAsString.isEmpty()) weatherPhenomenaAsString += " and "; + weatherPhenomenaAsString += weatherPhenomenaHash.value(wp); + } + } + + QString str; + str += intensityHash.value(m_intensity); + str += " "; + str += descriptorHash.value(m_descriptor); + str += " "; + str += weatherPhenomenaAsString; + return str; + } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/presentweather.h b/src/blackmisc/weather/presentweather.h new file mode 100644 index 000000000..1733b7616 --- /dev/null +++ b/src/blackmisc/weather/presentweather.h @@ -0,0 +1,141 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_PRESENTWEATHER_H +#define BLACKMISC_WEATHER_PRESENTWEATHER_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/valueobject.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object for a cloud layer + */ + class BLACKMISC_EXPORT CPresentWeather : public CValueObject + { + public: + //! Intensity + enum Intensity + { + Light, + Moderate, + Heavy, + InVincinity + }; + + //! Descriptor + enum Descriptor + { + None, + Shallow, + Patches, + Partial, + Drifting, + Blowing, + Showers, + Thunderstorm, + Freezing, + }; + + //! Weather Phenomenon + enum WeatherPhenomenon + { + NoPhenomena = 0, + Drizzle = 1 << 0, + Rain = 1 << 1, + Snow = 1 << 2, + SnowGrains = 1 << 3, + IceCrystals = 1 << 4, + IcePellets = 1 << 5, + Hail = 1 << 6, + SnowPellets = 1 << 7, + Unknown = 1 << 8, + Mist = 1 << 9, + Fog = 1 << 10, + Smoke = 1 << 11, + VolcanicAsh = 1 << 12, + Dust = 1 << 13, + Sand = 1 << 14, + Haze = 1 << 15, + DustSandWhirls = 1 << 16, + Squalls = 1 << 17, + TornadoOrWaterspout = 1 << 18, + FunnelCloud = 1 << 19, + Sandstorm = 1 << 20, + Duststorm = 1 << 21, + }; + + //! Properties by index + enum ColumnIndex + { + IndexPresentWeather = BlackMisc::CPropertyIndex::GlobalIndexCPresentWeather, + IndexIntensity, + IndexDescriptor, + IndexWeatherPhenomena + }; + + //! Default constructor. + CPresentWeather() = default; + + //! Constructor + CPresentWeather(Intensity intensity, Descriptor descriptor, int weatherPhenomena); + + //! Set intensity + void setIntensity(Intensity intensity) { m_intensity = intensity; } + + //! Get intensity + Intensity getIntensity() const { return m_intensity; } + + //! Set descriptor + void setDescriptor(Descriptor descriptor) { m_descriptor = descriptor; } + + //! Get descriptor + Descriptor getDescriptor() const { return m_descriptor; } + + //! Set weather phenomena + void setWeatherPhenomena(int phenomena) { m_weatherPhenomena = phenomena; } + + //! Get weather phenomenas + int getWeatherPhenomena() const { return m_weatherPhenomena; } + + //! \copydoc CValueObject::propertyByIndex + CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + + //! \copydoc CValueObject::setPropertyByIndex + void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index); + + //! \copydoc CValueObject::convertToQString + QString convertToQString(bool i18n = false) const; + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CPresentWeather) + Intensity m_intensity = Moderate; + Descriptor m_descriptor = None; + int m_weatherPhenomena; + }; + + } // namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CPresentWeather) +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Weather::CPresentWeather, ( + attr(o.m_intensity), + attr(o.m_descriptor), + attr(o.m_weatherPhenomena) + )) + +#endif // guard diff --git a/src/blackmisc/weather/presentweatherlist.cpp b/src/blackmisc/weather/presentweatherlist.cpp new file mode 100644 index 000000000..e293e0645 --- /dev/null +++ b/src/blackmisc/weather/presentweatherlist.cpp @@ -0,0 +1,21 @@ +/* Copyright (C) 2015 + * 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 "presentweatherlist.h" + +namespace BlackMisc +{ + namespace Weather + { + CPresentWeatherList::CPresentWeatherList(const CSequence &other) : + CSequence(other) + { } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/presentweatherlist.h b/src/blackmisc/weather/presentweatherlist.h new file mode 100644 index 000000000..63eb13bea --- /dev/null +++ b/src/blackmisc/weather/presentweatherlist.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_PRESENTWEATHERLIST_H +#define BLACKMISC_WEATHER_PRESENTWEATHERLIST_H + +#include "presentweather.h" +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/sequence.h" + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object encapsulating a list of present weathers + */ + class BLACKMISC_EXPORT CPresentWeatherList : + public CSequence, + public BlackMisc::Mixin::MetaType + { + public: + BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CPresentWeatherList) + + //! Default constructor. + CPresentWeatherList() = default; + + //! Construct from a base class object. + CPresentWeatherList(const CSequence &other); + }; + + } //namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CPresentWeatherList) +Q_DECLARE_METATYPE(BlackMisc::CSequence) + +#endif //guard diff --git a/src/blackmisc/weather/weather.h b/src/blackmisc/weather/weather.h new file mode 100644 index 000000000..1fcf1beff --- /dev/null +++ b/src/blackmisc/weather/weather.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_wEATHER_wEATHER_H +#define BLACKMISC_wEATHER_wEATHER_H + +/*! + * \namespace BlackMisc::Weather + * \brief Weather and Metar classes + */ + +#include "blackmisc/weather/metar.h" +#include "blackmisc/weather/metarset.h" +#include "blackmisc/weather/presentweather.h" +#include "blackmisc/weather/presentweatherlist.h" +#include "blackmisc/weather/cloudlayer.h" +#include "blackmisc/weather/cloudlayerlist.h" +#include "blackmisc/weather/windlayer.h" + +#endif // guard diff --git a/src/blackmisc/weather/windlayer.cpp b/src/blackmisc/weather/windlayer.cpp new file mode 100644 index 000000000..c112ca572 --- /dev/null +++ b/src/blackmisc/weather/windlayer.cpp @@ -0,0 +1,92 @@ +/* Copyright (C) 2015 + * 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 "blackmisc/weather/windlayer.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/variant.h" + +using namespace BlackMisc::PhysicalQuantities; +using namespace BlackMisc::Aviation; + +namespace BlackMisc +{ + namespace Weather + { + + CWindLayer::CWindLayer(const CAltitude &altitude, const CAngle &direction, const CSpeed &speed, const CSpeed &gustSpeed) : + m_altitude(altitude), m_directionMain(direction), m_speed(speed), m_gustSpeed(gustSpeed) + { } + + CVariant CWindLayer::propertyByIndex(const BlackMisc::CPropertyIndex &index) const + { + if (index.isMyself()) { return CVariant::from(*this); } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexAltitude: + return CVariant::fromValue(m_altitude); + case IndexDirection: + return CVariant::fromValue(m_directionMain); + case IndexDirectionVariable: + return CVariant::fromValue(m_directionVariable); + case IndexSpeed: + return CVariant::fromValue(m_speed); + case IndexGustSpeed: + return CVariant::fromValue(m_gustSpeed); + default: + return CValueObject::propertyByIndex(index); + } + } + + void CWindLayer::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) + { + if (index.isMyself()) { (*this) = variant.to(); return; } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexAltitude: + setAltitude(variant.value()); + break; + case IndexDirection: + setDirection(variant.value()); + break; + case IndexDirectionVariable: + setDirectionVariable(variant.toBool()); + break; + case IndexSpeed: + setSpeed(variant.value()); + break; + case IndexGustSpeed: + setGustSpeed(variant.value()); + break; + default: + CValueObject::setPropertyByIndex(variant, index); + break; + } + } + + QString CWindLayer::convertToQString(bool /** i18n **/) const + { + QString windAsString = QString("Wind: "); + if (m_directionVariable) windAsString += "variable "; + else windAsString += QString("%1 ").arg(m_directionMain.toQString()); + + if (m_directionFrom != CAngle() && m_directionTo != CAngle()) + { + windAsString += QString("variable between %1 and %2 ").arg(m_directionFrom.toQString()).arg(m_directionTo.toQString()); + } + + windAsString += QString("at %2").arg(m_speed.toQString()); + if (m_gustSpeed.value() > 0.5) windAsString += QString(" and gusts at %1").arg(m_gustSpeed.toQString()); + return windAsString; + } + + } // namespace +} // namespace diff --git a/src/blackmisc/weather/windlayer.h b/src/blackmisc/weather/windlayer.h new file mode 100644 index 000000000..039992fe5 --- /dev/null +++ b/src/blackmisc/weather/windlayer.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2015 + * 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 BLACKMISC_WEATHER_WINDLAYER_H +#define BLACKMISC_WEATHER_WINDLAYER_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/valueobject.h" +#include "blackmisc/propertyindex.h" +#include "blackmisc/blackmiscfreefunctions.h" +#include "blackmisc/pq/angle.h" +#include "blackmisc/pq/speed.h" +#include "blackmisc/aviation/altitude.h" +#include + +namespace BlackMisc +{ + namespace Weather + { + /*! + * Value object for a wind layer + */ + class BLACKMISC_EXPORT CWindLayer : public CValueObject + { + public: + //! Properties by index + enum ColumnIndex + { + IndexAltitude = BlackMisc::CPropertyIndex::GlobalIndexCWindLayer, + IndexDirection, + IndexDirectionVariable, + IndexSpeed, + IndexGustSpeed + }; + + //! Default constructor. + CWindLayer() = default; + + //! Constructor + CWindLayer(const BlackMisc::Aviation::CAltitude &altitude, const PhysicalQuantities::CAngle &direction, + const PhysicalQuantities::CSpeed &speed, const PhysicalQuantities::CSpeed &gustSpeed); + + //! Set altitude + void setAltitude(const BlackMisc::Aviation::CAltitude &altitude) { m_altitude = altitude; } + + //! Get altitude + BlackMisc::Aviation::CAltitude getAltitude() const { return m_altitude; } + + //! Set direction + void setDirection(const PhysicalQuantities::CAngle &main) { m_directionMain = main; } + + //! Set direction + //! Main direction will not be modified + void setDirection(const PhysicalQuantities::CAngle &from, const PhysicalQuantities::CAngle &to) + { + m_directionFrom = from; + m_directionTo = to; + } + + //! Set direction + void setDirection(const PhysicalQuantities::CAngle &main, const PhysicalQuantities::CAngle &from, const PhysicalQuantities::CAngle &to) + { + m_directionMain = main; + m_directionFrom = from; + m_directionTo = to; + } + + //! Get direction + PhysicalQuantities::CAngle getDirection() const { return m_directionMain; } + + //! Get direction from + PhysicalQuantities::CAngle getDirectionFrom() const { return m_directionFrom; } + + //! Get direction to + PhysicalQuantities::CAngle getDirectionTo() const { return m_directionTo; } + + //! Set direction to variable + void setDirectionVariable(bool variable = true) { m_directionVariable = variable; } + + //! Is direction variable? + bool isDirectionVariable() const { return m_directionVariable; } + + //! Set speed + void setSpeed(const PhysicalQuantities::CSpeed &speed) { m_speed = speed; } + + //! Get descriptor + PhysicalQuantities::CSpeed getSpeed() const { return m_speed; } + + //! Set gust speed + void setGustSpeed(const PhysicalQuantities::CSpeed &gustSpeed) { m_gustSpeed = gustSpeed; } + + //! Get weather phenomenas + PhysicalQuantities::CSpeed getGustSpeed() const { return m_gustSpeed; } + + //! \copydoc CValueObject::propertyByIndex + CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + + //! \copydoc CValueObject::setPropertyByIndex + void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index); + + //! \copydoc CValueObject::convertToQString + QString convertToQString(bool i18n = false) const; + + private: + BLACK_ENABLE_TUPLE_CONVERSION(CWindLayer) + BlackMisc::Aviation::CAltitude m_altitude; + PhysicalQuantities::CAngle m_directionMain; + PhysicalQuantities::CAngle m_directionFrom; + PhysicalQuantities::CAngle m_directionTo; + bool m_directionVariable = false; + PhysicalQuantities::CSpeed m_speed; + PhysicalQuantities::CSpeed m_gustSpeed; + + }; + + } // namespace +} // namespace + +Q_DECLARE_METATYPE(BlackMisc::Weather::CWindLayer) +BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Weather::CWindLayer, ( + attr(o.m_altitude), + attr(o.m_directionMain), + attr(o.m_directionFrom), + attr(o.m_directionTo), + attr(o.m_directionVariable), + attr(o.m_speed), + attr(o.m_gustSpeed) + )) + +#endif // guard