From 56cda08b0dedda052629605fbbbe7724c207e159 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 27 Jan 2022 12:59:43 -0600 Subject: [PATCH] Parse coded information from text product content --- wxdata/include/scwx/awips/coded_location.hpp | 6 +- .../scwx/awips/coded_time_motion_location.hpp | 6 +- wxdata/source/scwx/awips/coded_location.cpp | 13 +++ .../scwx/awips/coded_time_motion_location.cpp | 15 ++++ .../scwx/awips/text_product_message.cpp | 84 +++++++++++++++++-- 5 files changed, 115 insertions(+), 9 deletions(-) diff --git a/wxdata/include/scwx/awips/coded_location.hpp b/wxdata/include/scwx/awips/coded_location.hpp index 45cfade2..0ac03d95 100644 --- a/wxdata/include/scwx/awips/coded_location.hpp +++ b/wxdata/include/scwx/awips/coded_location.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -32,7 +33,10 @@ public: std::vector coordinates() const; - bool Parse(const StringRange& lines, const std::string& wfo = ""); + bool Parse(const StringRange& lines, const std::string& wfo = {}); + + static std::optional Create(const StringRange& lines, + const std::string& wfo = {}); private: std::unique_ptr p; diff --git a/wxdata/include/scwx/awips/coded_time_motion_location.hpp b/wxdata/include/scwx/awips/coded_time_motion_location.hpp index 41e4bfb5..6b7b9a19 100644 --- a/wxdata/include/scwx/awips/coded_time_motion_location.hpp +++ b/wxdata/include/scwx/awips/coded_time_motion_location.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -36,7 +37,10 @@ public: uint8_t speed() const; std::vector coordinates() const; - bool Parse(const StringRange& lines, const std::string& wfo = ""); + bool Parse(const StringRange& lines, const std::string& wfo = {}); + + static std::optional + Create(const StringRange& lines, const std::string& wfo = {}); private: std::unique_ptr p; diff --git a/wxdata/source/scwx/awips/coded_location.cpp b/wxdata/source/scwx/awips/coded_location.cpp index c2b8fb00..f6ff067a 100644 --- a/wxdata/source/scwx/awips/coded_location.cpp +++ b/wxdata/source/scwx/awips/coded_location.cpp @@ -205,5 +205,18 @@ bool CodedLocation::Parse(const StringRange& lines, const std::string& wfo) return dataValid; } +std::optional CodedLocation::Create(const StringRange& lines, + const std::string& wfo) +{ + std::optional location = std::make_optional(); + + if (!location->Parse(lines, wfo)) + { + location.reset(); + } + + return location; +} + } // namespace awips } // namespace scwx diff --git a/wxdata/source/scwx/awips/coded_time_motion_location.cpp b/wxdata/source/scwx/awips/coded_time_motion_location.cpp index da402858..e3f94bea 100644 --- a/wxdata/source/scwx/awips/coded_time_motion_location.cpp +++ b/wxdata/source/scwx/awips/coded_time_motion_location.cpp @@ -234,5 +234,20 @@ bool CodedTimeMotionLocation::Parse(const StringRange& lines, return dataValid; } +std::optional +CodedTimeMotionLocation::Create(const StringRange& lines, + const std::string& wfo) +{ + std::optional motion = + std::make_optional(); + + if (!motion->Parse(lines, wfo)) + { + motion.reset(); + } + + return motion; +} + } // namespace awips } // namespace scwx diff --git a/wxdata/source/scwx/awips/text_product_message.cpp b/wxdata/source/scwx/awips/text_product_message.cpp index a8a7f768..c6250041 100644 --- a/wxdata/source/scwx/awips/text_product_message.cpp +++ b/wxdata/source/scwx/awips/text_product_message.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -59,10 +61,15 @@ struct SegmentHeader struct Segment { - std::optional header_; - std::vector productContent_; + std::optional header_; + std::vector productContent_; + std::optional codedLocation_; + std::optional codedMotion_; - Segment() : header_ {}, productContent_ {} {} + Segment() : + header_ {}, productContent_ {}, codedLocation_ {}, codedMotion_ {} + { + } Segment(const Segment&) = delete; Segment& operator=(const Segment&) = delete; @@ -71,9 +78,11 @@ struct Segment Segment& operator=(Segment&&) noexcept = default; }; +static void ParseCodedInformation(std::shared_ptr segment, + const std::string& wfo); static std::vector ParseProductContent(std::istream& is); -void SkipBlankLines(std::istream& is); -bool TryParseEndOfProduct(std::istream& is); +static void SkipBlankLines(std::istream& is); +static bool TryParseEndOfProduct(std::istream& is); static std::vector TryParseMndHeader(std::istream& is); static std::vector TryParseOverviewBlock(std::istream& is); static std::optional TryParseSegmentHeader(std::istream& is); @@ -156,6 +165,8 @@ bool TextProductMessage::Parse(std::istream& is) segment->productContent_ = ParseProductContent(is); SkipBlankLines(is); + ParseCodedInformation(segment, p->wmoHeader_->icao()); + if (segment->header_.has_value() || !segment->productContent_.empty()) { p->segments_.push_back(std::move(segment)); @@ -165,6 +176,58 @@ bool TextProductMessage::Parse(std::istream& is) return dataValid; } +void ParseCodedInformation(std::shared_ptr segment, + const std::string& wfo) +{ + typedef std::vector::const_iterator StringIterator; + + std::vector& productContent = segment->productContent_; + + StringIterator codedLocationBegin = productContent.cend(); + StringIterator codedLocationEnd = productContent.cend(); + StringIterator codedMotionBegin = productContent.cend(); + StringIterator codedMotionEnd = productContent.cend(); + + for (auto it = productContent.cbegin(); it != productContent.cend(); ++it) + { + if (codedLocationBegin == productContent.cend() && + it->starts_with("LAT...LON")) + { + codedLocationBegin = it; + } + else if (codedLocationBegin != productContent.cend() && + codedLocationEnd == productContent.cend() && + !it->starts_with(" ") /* Continuation line */) + { + codedLocationEnd = it; + } + + if (codedMotionBegin == productContent.cend() && + it->starts_with("TIME...MOT...LOC")) + { + codedMotionBegin = it; + } + else if (codedMotionBegin != productContent.cend() && + codedMotionEnd == productContent.cend() && + !it->starts_with(" ") /* Continuation line */) + { + codedMotionEnd = it; + } + } + + if (codedLocationBegin != productContent.cend()) + { + segment->codedLocation_ = + CodedLocation::Create({codedLocationBegin, codedLocationEnd}, wfo); + } + + if (codedMotionBegin != productContent.cend()) + { + segment->codedMotion_ = CodedTimeMotionLocation::Create( + {codedMotionBegin, codedMotionEnd}, wfo); + } +} + std::vector ParseProductContent(std::istream& is) { std::vector productContent; @@ -367,8 +430,10 @@ std::optional TryParseVtecString(std::istream& is) if (std::regex_search(line, rePVtecString)) { - vtec = Vtec(); - vtec->pVtec_.Parse(line); + bool vtecValid; + + vtec = Vtec(); + vtecValid = vtec->pVtec_.Parse(line); isBegin = is.tellg(); @@ -384,6 +449,11 @@ std::optional TryParseVtecString(std::istream& is) // the line is.seekg(isBegin, std::ios_base::beg); } + + if (!vtecValid) + { + vtec.reset(); + } } else {