diff --git a/wxdata/include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp new file mode 100644 index 00000000..be55c815 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class HdaHailSymbolPacketImpl; + +class HdaHailSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit HdaHailSymbolPacket(); + ~HdaHailSymbolPacket(); + + HdaHailSymbolPacket(const HdaHailSymbolPacket&) = delete; + HdaHailSymbolPacket& operator=(const HdaHailSymbolPacket&) = delete; + + HdaHailSymbolPacket(HdaHailSymbolPacket&&) noexcept; + HdaHailSymbolPacket& operator=(HdaHailSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + int16_t probability_of_hail(size_t i) const; + int16_t probability_of_severe_hail(size_t i) const; + uint16_t max_hail_size(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/mesocyclone_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/mesocyclone_symbol_packet.hpp new file mode 100644 index 00000000..9640f80f --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/mesocyclone_symbol_packet.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class MesocycloneSymbolPacketImpl; + +class MesocycloneSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit MesocycloneSymbolPacket(); + ~MesocycloneSymbolPacket(); + + MesocycloneSymbolPacket(const MesocycloneSymbolPacket&) = delete; + MesocycloneSymbolPacket& operator=(const MesocycloneSymbolPacket&) = delete; + + MesocycloneSymbolPacket(MesocycloneSymbolPacket&&) noexcept; + MesocycloneSymbolPacket& operator=(MesocycloneSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + int16_t radius_of_mesocyclone(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/point_feature_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/point_feature_symbol_packet.hpp new file mode 100644 index 00000000..7d879180 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/point_feature_symbol_packet.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class PointFeatureSymbolPacketImpl; + +class PointFeatureSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit PointFeatureSymbolPacket(); + ~PointFeatureSymbolPacket(); + + PointFeatureSymbolPacket(const PointFeatureSymbolPacket&) = delete; + PointFeatureSymbolPacket& + operator=(const PointFeatureSymbolPacket&) = delete; + + PointFeatureSymbolPacket(PointFeatureSymbolPacket&&) noexcept; + PointFeatureSymbolPacket& operator=(PointFeatureSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + uint16_t point_feature_type(size_t i) const; + uint16_t point_feature_attribute(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + size_t MinBlockLength() const override; + size_t MaxBlockLength() const override; + + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/point_graphic_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/point_graphic_symbol_packet.hpp new file mode 100644 index 00000000..f278a203 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/point_graphic_symbol_packet.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class PointGraphicSymbolPacketImpl; + +class PointGraphicSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit PointGraphicSymbolPacket(); + ~PointGraphicSymbolPacket(); + + PointGraphicSymbolPacket(const PointGraphicSymbolPacket&) = delete; + PointGraphicSymbolPacket& + operator=(const PointGraphicSymbolPacket&) = delete; + + PointGraphicSymbolPacket(PointGraphicSymbolPacket&&) noexcept; + PointGraphicSymbolPacket& operator=(PointGraphicSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/scit_forecast_data_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/scit_forecast_data_packet.hpp new file mode 100644 index 00000000..56061d7a --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/scit_forecast_data_packet.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class ScitForecastDataPacketImpl; + +class ScitForecastDataPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit ScitForecastDataPacket(); + ~ScitForecastDataPacket(); + + ScitForecastDataPacket(const ScitForecastDataPacket&) = delete; + ScitForecastDataPacket& operator=(const ScitForecastDataPacket&) = delete; + + ScitForecastDataPacket(ScitForecastDataPacket&&) noexcept; + ScitForecastDataPacket& operator=(ScitForecastDataPacket&&) noexcept; + + const std::vector& data() const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/special_graphic_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/special_graphic_symbol_packet.hpp new file mode 100644 index 00000000..e730d20c --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/special_graphic_symbol_packet.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class SpecialGraphicSymbolPacketImpl; + +class SpecialGraphicSymbolPacket : public Packet +{ +public: + explicit SpecialGraphicSymbolPacket(); + ~SpecialGraphicSymbolPacket(); + + SpecialGraphicSymbolPacket(const SpecialGraphicSymbolPacket&) = delete; + SpecialGraphicSymbolPacket& + operator=(const SpecialGraphicSymbolPacket&) = delete; + + SpecialGraphicSymbolPacket(SpecialGraphicSymbolPacket&&) noexcept; + SpecialGraphicSymbolPacket& operator=(SpecialGraphicSymbolPacket&&) noexcept; + + uint16_t packet_code() const; + uint16_t length_of_block() const; + + size_t data_size() const override; + + bool Parse(std::istream& is) override; + + virtual size_t RecordCount() const = 0; + +protected: + virtual size_t MinBlockLength() const; + virtual size_t MaxBlockLength() const; + + virtual bool ParseData(std::istream& is) = 0; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/sti_circle_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/sti_circle_symbol_packet.hpp new file mode 100644 index 00000000..e0c8d77a --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/sti_circle_symbol_packet.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class StiCircleSymbolPacketImpl; + +class StiCircleSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit StiCircleSymbolPacket(); + ~StiCircleSymbolPacket(); + + StiCircleSymbolPacket(const StiCircleSymbolPacket&) = delete; + StiCircleSymbolPacket& operator=(const StiCircleSymbolPacket&) = delete; + + StiCircleSymbolPacket(StiCircleSymbolPacket&&) noexcept; + StiCircleSymbolPacket& operator=(StiCircleSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + uint16_t radius_of_circle(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/storm_id_symbol_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/storm_id_symbol_packet.hpp new file mode 100644 index 00000000..20974205 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/storm_id_symbol_packet.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class StormIdSymbolPacketImpl; + +class StormIdSymbolPacket : public SpecialGraphicSymbolPacket +{ +public: + explicit StormIdSymbolPacket(); + ~StormIdSymbolPacket(); + + StormIdSymbolPacket(const StormIdSymbolPacket&) = delete; + StormIdSymbolPacket& operator=(const StormIdSymbolPacket&) = delete; + + StormIdSymbolPacket(StormIdSymbolPacket&&) noexcept; + StormIdSymbolPacket& operator=(StormIdSymbolPacket&&) noexcept; + + int16_t i_position(size_t i) const; + int16_t j_position(size_t i) const; + const std::array& character(size_t i) const; + + size_t RecordCount() const override; + + static std::shared_ptr Create(std::istream& is); + +protected: + bool ParseData(std::istream& is) override; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp new file mode 100644 index 00000000..07ccd0b0 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp @@ -0,0 +1,140 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::hda_hail_symbol_packet] "; + +struct HdaHailSymbol +{ + int16_t iPosition_; + int16_t jPosition_; + int16_t probabilityOfHail_; + int16_t probabilityOfSevereHail_; + uint16_t maxHailSize_; + + HdaHailSymbol() : + iPosition_ {0}, + jPosition_ {0}, + probabilityOfHail_ {0}, + probabilityOfSevereHail_ {0}, + maxHailSize_ {0} + { + } +}; + +class HdaHailSymbolPacketImpl +{ +public: + explicit HdaHailSymbolPacketImpl() : symbol_ {}, recordCount_ {0} {} + ~HdaHailSymbolPacketImpl() = default; + + std::vector symbol_; + size_t recordCount_; +}; + +HdaHailSymbolPacket::HdaHailSymbolPacket() : + p(std::make_unique()) +{ +} +HdaHailSymbolPacket::~HdaHailSymbolPacket() = default; + +HdaHailSymbolPacket::HdaHailSymbolPacket(HdaHailSymbolPacket&&) noexcept = + default; +HdaHailSymbolPacket& +HdaHailSymbolPacket::operator=(HdaHailSymbolPacket&&) noexcept = default; + +int16_t HdaHailSymbolPacket::i_position(size_t i) const +{ + return p->symbol_[i].iPosition_; +} + +int16_t HdaHailSymbolPacket::j_position(size_t i) const +{ + return p->symbol_[i].jPosition_; +} + +int16_t HdaHailSymbolPacket::probability_of_hail(size_t i) const +{ + return p->symbol_[i].probabilityOfHail_; +} + +int16_t HdaHailSymbolPacket::probability_of_severe_hail(size_t i) const +{ + return p->symbol_[i].probabilityOfSevereHail_; +} + +uint16_t HdaHailSymbolPacket::max_hail_size(size_t i) const +{ + return p->symbol_[i].maxHailSize_; +} + +size_t HdaHailSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool HdaHailSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (packet_code() != 19) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 10; + p->symbol_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + HdaHailSymbol& s = p->symbol_[i]; + + is.read(reinterpret_cast(&s.iPosition_), 2); + is.read(reinterpret_cast(&s.jPosition_), 2); + is.read(reinterpret_cast(&s.probabilityOfHail_), 2); + is.read(reinterpret_cast(&s.probabilityOfSevereHail_), 2); + is.read(reinterpret_cast(&s.maxHailSize_), 2); + + s.iPosition_ = ntohs(s.iPosition_); + s.jPosition_ = ntohs(s.jPosition_); + s.probabilityOfHail_ = ntohs(s.probabilityOfHail_); + s.probabilityOfSevereHail_ = ntohs(s.probabilityOfSevereHail_); + s.maxHailSize_ = ntohs(s.maxHailSize_); + } + } + + return blockValid; +} + +std::shared_ptr +HdaHailSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/mesocyclone_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/mesocyclone_symbol_packet.cpp new file mode 100644 index 00000000..c6a97f3e --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/mesocyclone_symbol_packet.cpp @@ -0,0 +1,123 @@ +#include + +#include +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::mesocyclone_symbol_packet] "; + +static const std::set packetCodes_ = {3, 11}; + +struct MesocycloneSymbol +{ + int16_t iPosition_; + int16_t jPosition_; + int16_t radiusOfMesocyclone_; + + MesocycloneSymbol() : + iPosition_ {0}, jPosition_ {0}, radiusOfMesocyclone_ {0} + { + } +}; + +class MesocycloneSymbolPacketImpl +{ +public: + explicit MesocycloneSymbolPacketImpl() : symbol_ {}, recordCount_ {0} {} + ~MesocycloneSymbolPacketImpl() = default; + + std::vector symbol_; + size_t recordCount_; +}; + +MesocycloneSymbolPacket::MesocycloneSymbolPacket() : + p(std::make_unique()) +{ +} +MesocycloneSymbolPacket::~MesocycloneSymbolPacket() = default; + +MesocycloneSymbolPacket::MesocycloneSymbolPacket( + MesocycloneSymbolPacket&&) noexcept = default; +MesocycloneSymbolPacket& MesocycloneSymbolPacket::operator=( + MesocycloneSymbolPacket&&) noexcept = default; + +int16_t MesocycloneSymbolPacket::i_position(size_t i) const +{ + return p->symbol_[i].iPosition_; +} + +int16_t MesocycloneSymbolPacket::j_position(size_t i) const +{ + return p->symbol_[i].jPosition_; +} + +int16_t MesocycloneSymbolPacket::radius_of_mesocyclone(size_t i) const +{ + return p->symbol_[i].radiusOfMesocyclone_; +} + +size_t MesocycloneSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool MesocycloneSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (!packetCodes_.contains(packet_code())) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 6; + p->symbol_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + MesocycloneSymbol& s = p->symbol_[i]; + + is.read(reinterpret_cast(&s.iPosition_), 2); + is.read(reinterpret_cast(&s.jPosition_), 2); + is.read(reinterpret_cast(&s.radiusOfMesocyclone_), 2); + + s.iPosition_ = ntohs(s.iPosition_); + s.jPosition_ = ntohs(s.jPosition_); + s.radiusOfMesocyclone_ = ntohs(s.radiusOfMesocyclone_); + } + } + + return blockValid; +} + +std::shared_ptr +MesocycloneSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp index da90f8b1..400abc86 100644 --- a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp @@ -2,12 +2,19 @@ #include #include +#include #include #include +#include +#include +#include #include #include #include +#include #include +#include +#include #include #include #include @@ -33,6 +40,7 @@ typedef std::function(std::istream&)> static const std::unordered_map create_ { {1, TextAndSpecialSymbolPacket::Create}, {2, TextAndSpecialSymbolPacket::Create}, + {3, MesocycloneSymbolPacket::Create}, {4, WindBarbDataPacket::Create}, {5, VectorArrowDataPacket::Create}, {6, LinkedVectorPacket::Create}, @@ -40,9 +48,20 @@ static const std::unordered_map create_ { {8, TextAndSpecialSymbolPacket::Create}, {9, LinkedVectorPacket::Create}, {10, UnlinkedVectorPacket::Create}, + {11, MesocycloneSymbolPacket::Create}, + {12, PointGraphicSymbolPacket::Create}, + {13, PointGraphicSymbolPacket::Create}, + {14, PointGraphicSymbolPacket::Create}, + {15, StormIdSymbolPacket::Create}, {16, DigitalRadialDataArrayPacket::Create}, {17, DigitalPrecipitationDataArrayPacket::Create}, {18, PrecipitationRateDataArrayPacket::Create}, + {19, HdaHailSymbolPacket::Create}, + {20, PointFeatureSymbolPacket::Create}, + {23, ScitForecastDataPacket::Create}, + {24, ScitForecastDataPacket::Create}, + {25, StiCircleSymbolPacket::Create}, + {26, PointGraphicSymbolPacket::Create}, {0x0802, SetColorLevelPacket::Create}, {0x0E03, LinkedContourVectorPacket::Create}, {0x3501, UnlinkedContourVectorPacket::Create}, diff --git a/wxdata/source/scwx/wsr88d/rpg/point_feature_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/point_feature_symbol_packet.cpp new file mode 100644 index 00000000..14e4907a --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/point_feature_symbol_packet.cpp @@ -0,0 +1,143 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::point_feature_symbol_packet] "; + +struct PointFeature +{ + int16_t iPosition_; + int16_t jPosition_; + uint16_t pointFeatureType_; + uint16_t pointFeatureAttribute_; + + PointFeature() : + iPosition_ {0}, + jPosition_ {0}, + pointFeatureType_ {0}, + pointFeatureAttribute_ {0} + { + } +}; + +class PointFeatureSymbolPacketImpl +{ +public: + explicit PointFeatureSymbolPacketImpl() : pointFeature_ {}, recordCount_ {0} + { + } + ~PointFeatureSymbolPacketImpl() = default; + + std::vector pointFeature_; + size_t recordCount_; +}; + +PointFeatureSymbolPacket::PointFeatureSymbolPacket() : + p(std::make_unique()) +{ +} +PointFeatureSymbolPacket::~PointFeatureSymbolPacket() = default; + +PointFeatureSymbolPacket::PointFeatureSymbolPacket( + PointFeatureSymbolPacket&&) noexcept = default; +PointFeatureSymbolPacket& PointFeatureSymbolPacket::operator=( + PointFeatureSymbolPacket&&) noexcept = default; + +size_t PointFeatureSymbolPacket::MinBlockLength() const +{ + return 8; +} + +size_t PointFeatureSymbolPacket::MaxBlockLength() const +{ + return 32760; +} + +int16_t PointFeatureSymbolPacket::i_position(size_t i) const +{ + return p->pointFeature_[i].iPosition_; +} + +int16_t PointFeatureSymbolPacket::j_position(size_t i) const +{ + return p->pointFeature_[i].jPosition_; +} + +uint16_t PointFeatureSymbolPacket::point_feature_type(size_t i) const +{ + return p->pointFeature_[i].pointFeatureType_; +} + +uint16_t PointFeatureSymbolPacket::point_feature_attribute(size_t i) const +{ + return p->pointFeature_[i].pointFeatureAttribute_; +} + +size_t PointFeatureSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool PointFeatureSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (packet_code() != 20) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 8; + p->pointFeature_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + PointFeature& f = p->pointFeature_[i]; + + is.read(reinterpret_cast(&f.iPosition_), 2); + is.read(reinterpret_cast(&f.jPosition_), 2); + is.read(reinterpret_cast(&f.pointFeatureType_), 2); + is.read(reinterpret_cast(&f.pointFeatureAttribute_), 2); + + f.iPosition_ = ntohs(f.iPosition_); + f.jPosition_ = ntohs(f.jPosition_); + f.pointFeatureType_ = ntohs(f.pointFeatureType_); + f.pointFeatureAttribute_ = ntohs(f.pointFeatureAttribute_); + } + } + + return blockValid; +} + +std::shared_ptr +PointFeatureSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/point_graphic_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/point_graphic_symbol_packet.cpp new file mode 100644 index 00000000..1266d5a0 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/point_graphic_symbol_packet.cpp @@ -0,0 +1,114 @@ +#include + +#include +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::point_graphic_symbol_packet] "; + +static const std::set packetCodes_ = {12, 13, 14, 26}; + +struct PointGraphic +{ + int16_t iPosition_; + int16_t jPosition_; + + PointGraphic() : iPosition_ {0}, jPosition_ {0} {} +}; + +class PointGraphicSymbolPacketImpl +{ +public: + explicit PointGraphicSymbolPacketImpl() : pointGraphic_ {}, recordCount_ {0} + { + } + ~PointGraphicSymbolPacketImpl() = default; + + std::vector pointGraphic_; + size_t recordCount_; +}; + +PointGraphicSymbolPacket::PointGraphicSymbolPacket() : + p(std::make_unique()) +{ +} +PointGraphicSymbolPacket::~PointGraphicSymbolPacket() = default; + +PointGraphicSymbolPacket::PointGraphicSymbolPacket( + PointGraphicSymbolPacket&&) noexcept = default; +PointGraphicSymbolPacket& PointGraphicSymbolPacket::operator=( + PointGraphicSymbolPacket&&) noexcept = default; + +int16_t PointGraphicSymbolPacket::i_position(size_t i) const +{ + return p->pointGraphic_[i].iPosition_; +} + +int16_t PointGraphicSymbolPacket::j_position(size_t i) const +{ + return p->pointGraphic_[i].jPosition_; +} + +size_t PointGraphicSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool PointGraphicSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (!packetCodes_.contains(packet_code())) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 4; + p->pointGraphic_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + PointGraphic& f = p->pointGraphic_[i]; + + is.read(reinterpret_cast(&f.iPosition_), 2); + is.read(reinterpret_cast(&f.jPosition_), 2); + + f.iPosition_ = ntohs(f.iPosition_); + f.jPosition_ = ntohs(f.jPosition_); + } + } + + return blockValid; +} + +std::shared_ptr +PointGraphicSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/scit_forecast_data_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/scit_forecast_data_packet.cpp new file mode 100644 index 00000000..a0599920 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/scit_forecast_data_packet.cpp @@ -0,0 +1,89 @@ +#include + +#include +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::scit_forecast_data_packet] "; + +static const std::set packetCodes_ = {23, 24}; + +class ScitForecastDataPacketImpl +{ +public: + explicit ScitForecastDataPacketImpl() : data_ {}, recordCount_ {0} {} + ~ScitForecastDataPacketImpl() = default; + + std::vector data_; + size_t recordCount_; +}; + +ScitForecastDataPacket::ScitForecastDataPacket() : + p(std::make_unique()) +{ +} +ScitForecastDataPacket::~ScitForecastDataPacket() = default; + +ScitForecastDataPacket::ScitForecastDataPacket( + ScitForecastDataPacket&&) noexcept = default; +ScitForecastDataPacket& +ScitForecastDataPacket::operator=(ScitForecastDataPacket&&) noexcept = default; + +const std::vector& ScitForecastDataPacket::data() const +{ + return p->data_; +} + +size_t ScitForecastDataPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool ScitForecastDataPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (!packetCodes_.contains(packet_code())) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block(); + p->data_.resize(p->recordCount_); + is.read(reinterpret_cast(p->data_.data()), p->recordCount_); + } + + return blockValid; +} + +std::shared_ptr +ScitForecastDataPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/special_graphic_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/special_graphic_symbol_packet.cpp new file mode 100644 index 00000000..cca2bc9b --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/special_graphic_symbol_packet.cpp @@ -0,0 +1,125 @@ +#include + +#include +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::special_graphic_symbol_packet] "; + +static const std::set packetCodes_ = { + 3, 11, 12, 13, 14, 15, 19, 20, 23, 24, 25, 26}; + +class SpecialGraphicSymbolPacketImpl +{ +public: + explicit SpecialGraphicSymbolPacketImpl() : + packetCode_ {0}, lengthOfBlock_ {0} + { + } + ~SpecialGraphicSymbolPacketImpl() = default; + + uint16_t packetCode_; + uint16_t lengthOfBlock_; +}; + +SpecialGraphicSymbolPacket::SpecialGraphicSymbolPacket() : + p(std::make_unique()) +{ +} +SpecialGraphicSymbolPacket::~SpecialGraphicSymbolPacket() = default; + +SpecialGraphicSymbolPacket::SpecialGraphicSymbolPacket( + SpecialGraphicSymbolPacket&&) noexcept = default; +SpecialGraphicSymbolPacket& SpecialGraphicSymbolPacket::operator=( + SpecialGraphicSymbolPacket&&) noexcept = default; + +uint16_t SpecialGraphicSymbolPacket::packet_code() const +{ + return p->packetCode_; +} + +uint16_t SpecialGraphicSymbolPacket::length_of_block() const +{ + return p->lengthOfBlock_; +} + +size_t SpecialGraphicSymbolPacket::data_size() const +{ + return p->lengthOfBlock_ + 4u; +} + +bool SpecialGraphicSymbolPacket::Parse(std::istream& is) +{ + bool blockValid = true; + + std::streampos isBegin = is.tellg(); + + is.read(reinterpret_cast(&p->packetCode_), 2); + is.read(reinterpret_cast(&p->lengthOfBlock_), 2); + + p->packetCode_ = ntohs(p->packetCode_); + p->lengthOfBlock_ = ntohs(p->lengthOfBlock_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + const size_t minBlockLength = MinBlockLength(); + const size_t maxBlockLength = MaxBlockLength(); + + if (!packetCodes_.contains(p->packetCode_)) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << p->packetCode_; + blockValid = false; + } + else if (p->lengthOfBlock_ < minBlockLength || + p->lengthOfBlock_ > maxBlockLength) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid length of block: " << p->packetCode_; + blockValid = false; + } + } + + if (blockValid) + { + blockValid = ParseData(is); + } + + std::streampos isEnd = is.tellg(); + + if (!ValidateMessage(is, isEnd - isBegin)) + { + blockValid = false; + } + + return blockValid; +} + +size_t SpecialGraphicSymbolPacket::MinBlockLength() const +{ + return 1; +} + +size_t SpecialGraphicSymbolPacket::MaxBlockLength() const +{ + return 32767; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/sti_circle_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/sti_circle_symbol_packet.cpp new file mode 100644 index 00000000..38145701 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/sti_circle_symbol_packet.cpp @@ -0,0 +1,117 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::sti_circle_symbol_packet] "; + +struct StiCircleSymbol +{ + int16_t iPosition_; + int16_t jPosition_; + uint16_t radiusOfCircle_; + + StiCircleSymbol() : iPosition_ {0}, jPosition_ {0}, radiusOfCircle_ {0} {} +}; + +class StiCircleSymbolPacketImpl +{ +public: + explicit StiCircleSymbolPacketImpl() : symbol_ {}, recordCount_ {0} {} + ~StiCircleSymbolPacketImpl() = default; + + std::vector symbol_; + size_t recordCount_; +}; + +StiCircleSymbolPacket::StiCircleSymbolPacket() : + p(std::make_unique()) +{ +} +StiCircleSymbolPacket::~StiCircleSymbolPacket() = default; + +StiCircleSymbolPacket::StiCircleSymbolPacket(StiCircleSymbolPacket&&) noexcept = + default; +StiCircleSymbolPacket& +StiCircleSymbolPacket::operator=(StiCircleSymbolPacket&&) noexcept = default; + +int16_t StiCircleSymbolPacket::i_position(size_t i) const +{ + return p->symbol_[i].iPosition_; +} + +int16_t StiCircleSymbolPacket::j_position(size_t i) const +{ + return p->symbol_[i].jPosition_; +} + +uint16_t StiCircleSymbolPacket::radius_of_circle(size_t i) const +{ + return p->symbol_[i].radiusOfCircle_; +} + +size_t StiCircleSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool StiCircleSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (packet_code() != 25) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 6; + p->symbol_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + StiCircleSymbol& s = p->symbol_[i]; + + is.read(reinterpret_cast(&s.iPosition_), 2); + is.read(reinterpret_cast(&s.jPosition_), 2); + is.read(reinterpret_cast(&s.radiusOfCircle_), 2); + + s.iPosition_ = ntohs(s.iPosition_); + s.jPosition_ = ntohs(s.jPosition_); + s.radiusOfCircle_ = ntohs(s.radiusOfCircle_); + } + } + + return blockValid; +} + +std::shared_ptr +StiCircleSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/storm_id_symbol_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/storm_id_symbol_packet.cpp new file mode 100644 index 00000000..6a6ed9f3 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/storm_id_symbol_packet.cpp @@ -0,0 +1,116 @@ +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::storm_id_symbol_packet] "; + +struct StormIdSymbol +{ + int16_t iPosition_; + int16_t jPosition_; + std::array character_; + + StormIdSymbol() : iPosition_ {0}, jPosition_ {0}, character_ {0} {} +}; + +class StormIdSymbolPacketImpl +{ +public: + explicit StormIdSymbolPacketImpl() : symbol_ {}, recordCount_ {0} {} + ~StormIdSymbolPacketImpl() = default; + + std::vector symbol_; + size_t recordCount_; +}; + +StormIdSymbolPacket::StormIdSymbolPacket() : + p(std::make_unique()) +{ +} +StormIdSymbolPacket::~StormIdSymbolPacket() = default; + +StormIdSymbolPacket::StormIdSymbolPacket(StormIdSymbolPacket&&) noexcept = + default; +StormIdSymbolPacket& +StormIdSymbolPacket::operator=(StormIdSymbolPacket&&) noexcept = default; + +int16_t StormIdSymbolPacket::i_position(size_t i) const +{ + return p->symbol_[i].iPosition_; +} + +int16_t StormIdSymbolPacket::j_position(size_t i) const +{ + return p->symbol_[i].jPosition_; +} + +const std::array& StormIdSymbolPacket::character(size_t i) const +{ + return p->symbol_[i].character_; +} + +size_t StormIdSymbolPacket::RecordCount() const +{ + return p->recordCount_; +} + +bool StormIdSymbolPacket::ParseData(std::istream& is) +{ + bool blockValid = true; + + if (packet_code() != 15) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid packet code: " << packet_code(); + blockValid = false; + } + + if (blockValid) + { + p->recordCount_ = length_of_block() / 6; + p->symbol_.resize(p->recordCount_); + + for (size_t i = 0; i < p->recordCount_; i++) + { + StormIdSymbol& s = p->symbol_[i]; + + is.read(reinterpret_cast(&s.iPosition_), 2); + is.read(reinterpret_cast(&s.jPosition_), 2); + is.read(reinterpret_cast(s.character_.data()), 2); + + s.iPosition_ = ntohs(s.iPosition_); + s.jPosition_ = ntohs(s.jPosition_); + } + } + + return blockValid; +} + +std::shared_ptr +StormIdSymbolPacket::Create(std::istream& is) +{ + std::shared_ptr packet = + std::make_shared(); + + if (!packet->Parse(is)) + { + packet.reset(); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index f588c2b3..35608977 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -48,17 +48,25 @@ set(SRC_WSR88D_RDA source/scwx/wsr88d/rda/clutter_filter_map.cpp source/scwx/wsr88d/rda/volume_coverage_pattern_data.cpp) set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp + include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp include/scwx/wsr88d/rpg/level3_message_header.hpp include/scwx/wsr88d/rpg/linked_contour_vector_packet.hpp include/scwx/wsr88d/rpg/linked_vector_packet.hpp + include/scwx/wsr88d/rpg/mesocyclone_symbol_packet.hpp include/scwx/wsr88d/rpg/packet.hpp include/scwx/wsr88d/rpg/packet_factory.hpp + include/scwx/wsr88d/rpg/point_feature_symbol_packet.hpp + include/scwx/wsr88d/rpg/point_graphic_symbol_packet.hpp include/scwx/wsr88d/rpg/precipitation_rate_data_array_packet.hpp include/scwx/wsr88d/rpg/product_description_block.hpp include/scwx/wsr88d/rpg/product_symbology_block.hpp include/scwx/wsr88d/rpg/radial_data_packet.hpp include/scwx/wsr88d/rpg/raster_data_packet.hpp + include/scwx/wsr88d/rpg/scit_forecast_data_packet.hpp include/scwx/wsr88d/rpg/set_color_level_packet.hpp + include/scwx/wsr88d/rpg/special_graphic_symbol_packet.hpp + include/scwx/wsr88d/rpg/sti_circle_symbol_packet.hpp + include/scwx/wsr88d/rpg/storm_id_symbol_packet.hpp include/scwx/wsr88d/rpg/text_and_special_symbol_packet.hpp include/scwx/wsr88d/rpg/unlinked_contour_vector_packet.hpp include/scwx/wsr88d/rpg/unlinked_vector_packet.hpp @@ -67,17 +75,25 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/digital_precipitation_data_array_pack include/scwx/wsr88d/rpg/wmo_header.hpp) set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.cpp source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp + source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp source/scwx/wsr88d/rpg/level3_message_header.cpp source/scwx/wsr88d/rpg/linked_contour_vector_packet.cpp source/scwx/wsr88d/rpg/linked_vector_packet.cpp + source/scwx/wsr88d/rpg/mesocyclone_symbol_packet.cpp source/scwx/wsr88d/rpg/packet.cpp source/scwx/wsr88d/rpg/packet_factory.cpp + source/scwx/wsr88d/rpg/point_feature_symbol_packet.cpp + source/scwx/wsr88d/rpg/point_graphic_symbol_packet.cpp source/scwx/wsr88d/rpg/precipitation_rate_data_array_packet.cpp source/scwx/wsr88d/rpg/product_description_block.cpp source/scwx/wsr88d/rpg/product_symbology_block.cpp source/scwx/wsr88d/rpg/radial_data_packet.cpp source/scwx/wsr88d/rpg/raster_data_packet.cpp + source/scwx/wsr88d/rpg/scit_forecast_data_packet.cpp source/scwx/wsr88d/rpg/set_color_level_packet.cpp + source/scwx/wsr88d/rpg/special_graphic_symbol_packet.cpp + source/scwx/wsr88d/rpg/sti_circle_symbol_packet.cpp + source/scwx/wsr88d/rpg/storm_id_symbol_packet.cpp source/scwx/wsr88d/rpg/text_and_special_symbol_packet.cpp source/scwx/wsr88d/rpg/unlinked_contour_vector_packet.cpp source/scwx/wsr88d/rpg/unlinked_vector_packet.cpp