Starting to parse alphanumeric data from storm tracking information

This commit is contained in:
Dan Paulat 2024-02-20 23:27:08 -06:00
parent 2cd76d7da4
commit 0415223571
4 changed files with 156 additions and 1 deletions

View file

@ -2,6 +2,12 @@
#include <scwx/wsr88d/rpg/graphic_product_message.hpp>
#include <optional>
#include <units/angle.h>
#include <units/length.h>
#include <units/velocity.h>
namespace scwx
{
namespace wsr88d
@ -12,6 +18,27 @@ namespace rpg
class StormTrackingInformationMessage : public GraphicProductMessage
{
public:
struct StiRecord
{
struct Position
{
std::optional<units::angle::degrees<float>> azimuth_ {};
std::optional<units::length::nautical_miles<float>> range_ {};
};
Position currentPosition_ {};
std::optional<units::angle::degrees<float>> direction_;
std::optional<units::velocity::knots<float>> speed_;
std::array<Position, 4> forecastPosition_ {};
std::optional<units::length::nautical_miles<float>> forecastError_ {};
std::optional<units::length::nautical_miles<float>> meanError_ {};
std::optional<std::int16_t> maxDbz_ {};
std::optional<units::length::feet<float>> maxDbzHeight_ {};
};
explicit StormTrackingInformationMessage();
~StormTrackingInformationMessage();

View file

@ -31,6 +31,8 @@ public:
size_t data_size() const override;
const std::vector<std::vector<std::string>>& page_list() const;
bool Parse(std::istream& is);
bool Parse(std::istream& is, bool skipHeader);

View file

@ -1,5 +1,9 @@
#include <scwx/wsr88d/rpg/storm_tracking_information_message.hpp>
#include <scwx/util/logger.hpp>
#include <scwx/util/strings.hpp>
#include <scwx/util/time.hpp>
#include <unordered_map>
namespace scwx
{
@ -17,6 +21,21 @@ class StormTrackingInformationMessage::Impl
public:
explicit Impl() {}
~Impl() = default;
void ParseGraphicBlock(
const std::shared_ptr<const GraphicAlphanumericBlock>& block);
void ParseTabularBlock(
const std::shared_ptr<const TabularAlphanumericBlock>& block);
void ParseStormPositionForecastPage(const std::vector<std::string>& page);
void ParseStormCellTrackingDataPage(const std::vector<std::string>& page);
// STORM POSITION/FORECAST
std::optional<std::uint16_t> radarId_ {};
std::optional<std::chrono::sys_time<std::chrono::seconds>> dateTime_ {};
std::optional<std::uint16_t> numStormCells_ {};
std::unordered_map<std::string, StiRecord> stiRecords_ {};
};
StormTrackingInformationMessage::StormTrackingInformationMessage() :
@ -34,9 +53,110 @@ bool StormTrackingInformationMessage::Parse(std::istream& is)
{
bool dataValid = GraphicProductMessage::Parse(is);
std::shared_ptr<GraphicAlphanumericBlock> graphicBlock = nullptr;
std::shared_ptr<TabularAlphanumericBlock> 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<const GraphicAlphanumericBlock>& block)
{
// TODO
(void) (block);
}
void StormTrackingInformationMessage::Impl::ParseTabularBlock(
const std::shared_ptr<const TabularAlphanumericBlock>& 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<std::string>& 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<std::uint16_t>(line.substr(14, 3));
}
if (dateTime_ == std::nullopt)
{
static const std::string kDateTimeFormat_ {"%m:%d:%y/%H:%M:%S"};
dateTime_ = util::TryParseDateTime<std::chrono::seconds>(
kDateTimeFormat_, line.substr(29, 17));
}
if (numStormCells_ == std::nullopt)
{
numStormCells_ =
util::TryParseUnsignedLong<std::uint16_t>(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<std::string>& page)
{
// TODO
(void) (page);
}
std::shared_ptr<StormTrackingInformationMessage>
StormTrackingInformationMessage::Create(Level3MessageHeader&& header,
std::istream& is)

View file

@ -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<std::vector<std::string>>&
TabularAlphanumericBlock::page_list() const
{
return p->pageList_;
}
bool TabularAlphanumericBlock::Parse(std::istream& is)
{
return Parse(is, false);