diff --git a/wxdata/include/scwx/wsr88d/rpg/storm_tracking_information_message.hpp b/wxdata/include/scwx/wsr88d/rpg/storm_tracking_information_message.hpp index fb2a00c2..7d238464 100644 --- a/wxdata/include/scwx/wsr88d/rpg/storm_tracking_information_message.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/storm_tracking_information_message.hpp @@ -2,6 +2,12 @@ #include +#include + +#include +#include +#include + namespace scwx { namespace wsr88d @@ -12,6 +18,27 @@ namespace rpg class StormTrackingInformationMessage : public GraphicProductMessage { public: + struct StiRecord + { + struct Position + { + std::optional> azimuth_ {}; + std::optional> range_ {}; + }; + + Position currentPosition_ {}; + std::optional> direction_; + std::optional> speed_; + + std::array forecastPosition_ {}; + + std::optional> forecastError_ {}; + std::optional> meanError_ {}; + + std::optional maxDbz_ {}; + std::optional> maxDbzHeight_ {}; + }; + explicit StormTrackingInformationMessage(); ~StormTrackingInformationMessage(); diff --git a/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp b/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp index e6ac58a8..0d41fe62 100644 --- a/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp @@ -31,6 +31,8 @@ public: size_t data_size() const override; + const std::vector>& page_list() const; + bool Parse(std::istream& is); bool Parse(std::istream& is, bool skipHeader); diff --git a/wxdata/source/scwx/wsr88d/rpg/storm_tracking_information_message.cpp b/wxdata/source/scwx/wsr88d/rpg/storm_tracking_information_message.cpp index 6201efd6..cc68a676 100644 --- a/wxdata/source/scwx/wsr88d/rpg/storm_tracking_information_message.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/storm_tracking_information_message.cpp @@ -1,5 +1,9 @@ #include #include +#include +#include + +#include namespace scwx { @@ -17,6 +21,21 @@ class StormTrackingInformationMessage::Impl public: explicit Impl() {} ~Impl() = default; + + void ParseGraphicBlock( + const std::shared_ptr& block); + void ParseTabularBlock( + const std::shared_ptr& block); + + void ParseStormPositionForecastPage(const std::vector& page); + void ParseStormCellTrackingDataPage(const std::vector& page); + + // STORM POSITION/FORECAST + std::optional radarId_ {}; + std::optional> dateTime_ {}; + std::optional numStormCells_ {}; + + std::unordered_map stiRecords_ {}; }; StormTrackingInformationMessage::StormTrackingInformationMessage() : @@ -34,9 +53,110 @@ bool StormTrackingInformationMessage::Parse(std::istream& is) { bool dataValid = GraphicProductMessage::Parse(is); + std::shared_ptr graphicBlock = nullptr; + std::shared_ptr tabularBlock = nullptr; + + if (dataValid) + { + graphicBlock = graphic_block(); + tabularBlock = tabular_block(); + } + + if (graphicBlock != nullptr) + { + p->ParseGraphicBlock(graphicBlock); + } + + if (tabularBlock != nullptr) + { + p->ParseTabularBlock(tabularBlock); + } + return dataValid; } +void StormTrackingInformationMessage::Impl::ParseGraphicBlock( + const std::shared_ptr& block) +{ + // TODO + (void) (block); +} + +void StormTrackingInformationMessage::Impl::ParseTabularBlock( + const std::shared_ptr& block) +{ + static const std::string kStormPositionForecast_ = "STORM POSITION/FORECAST"; + static const std::string kStormCellTrackingData_ = + "STORM CELL TRACKING/FORECAST ADAPTATION DATA"; + + for (auto& page : block->page_list()) + { + if (page.empty()) + { + logger_->warn("Unexpected empty page"); + continue; + } + + if (page[0].find(kStormPositionForecast_) != std::string::npos) + { + ParseStormPositionForecastPage(page); + } + else if (page[0].find(kStormCellTrackingData_) != std::string::npos) + { + ParseStormCellTrackingDataPage(page); + } + } +} + +void StormTrackingInformationMessage::Impl::ParseStormPositionForecastPage( + const std::vector& page) +{ + for (std::size_t i = 1; i < page.size(); ++i) + { + const std::string& line = page[i]; + + // clang-format off + // " RADAR ID 308 DATE/TIME 12:11:21/02:15:38 NUMBER OF STORM CELLS 34" + // clang-format on + if (i == 1 && line.size() >= 74) + { + if (radarId_ == std::nullopt) + { + radarId_ = + util::TryParseUnsignedLong(line.substr(14, 3)); + } + if (dateTime_ == std::nullopt) + { + static const std::string kDateTimeFormat_ {"%m:%d:%y/%H:%M:%S"}; + + dateTime_ = util::TryParseDateTime( + kDateTimeFormat_, line.substr(29, 17)); + } + if (numStormCells_ == std::nullopt) + { + numStormCells_ = + util::TryParseUnsignedLong(line.substr(71, 3)); + } + } + // clang-format off + // " V6 183/147 234/ 63 178/137 172/129 166/122 159/117 0.7/ 0.7" + // clang-format on + else if (i >= 7 && line.size() >= 80) + { + // TODO: STI Record + std::string stormId = line.substr(2, 2); + (void) (stormId); + } + } +} + +void StormTrackingInformationMessage::Impl::ParseStormCellTrackingDataPage( + const std::vector& page) +{ + // TODO + (void) (page); +} + std::shared_ptr StormTrackingInformationMessage::Create(Level3MessageHeader&& header, std::istream& is) diff --git a/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp b/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp index 0fa1185a..e6c29519 100644 --- a/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp @@ -54,7 +54,7 @@ TabularAlphanumericBlock::TabularAlphanumericBlock() : TabularAlphanumericBlock::~TabularAlphanumericBlock() = default; TabularAlphanumericBlock::TabularAlphanumericBlock( - TabularAlphanumericBlock&&) noexcept = default; + TabularAlphanumericBlock&&) noexcept = default; TabularAlphanumericBlock& TabularAlphanumericBlock::operator=( TabularAlphanumericBlock&&) noexcept = default; @@ -68,6 +68,12 @@ size_t TabularAlphanumericBlock::data_size() const return p->lengthOfBlock_; } +const std::vector>& +TabularAlphanumericBlock::page_list() const +{ + return p->pageList_; +} + bool TabularAlphanumericBlock::Parse(std::istream& is) { return Parse(is, false);