diff --git a/wxdata/include/scwx/awips/impact_based_warnings.hpp b/wxdata/include/scwx/awips/impact_based_warnings.hpp new file mode 100644 index 00000000..ff64bb99 --- /dev/null +++ b/wxdata/include/scwx/awips/impact_based_warnings.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace scwx +{ +namespace awips +{ + +enum class ThreatCategory +{ + Base, + Significant, + Considerable, + Destructive, + Catastrophic, + Unknown +}; + +ThreatCategory GetThreatCategory(const std::string& name); +const std::string& GetThreatCategoryName(ThreatCategory threatCategory); + +} // namespace awips +} // namespace scwx diff --git a/wxdata/include/scwx/awips/text_product_message.hpp b/wxdata/include/scwx/awips/text_product_message.hpp index 80ba4a16..a83f7b82 100644 --- a/wxdata/include/scwx/awips/text_product_message.hpp +++ b/wxdata/include/scwx/awips/text_product_message.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -56,15 +57,16 @@ struct SegmentHeader struct Segment { - std::optional header_; - std::vector productContent_; - std::optional codedLocation_; - std::optional codedMotion_; + std::optional header_ {}; + std::vector productContent_ {}; + std::optional codedLocation_ {}; + std::optional codedMotion_ {}; - Segment() : - header_ {}, productContent_ {}, codedLocation_ {}, codedMotion_ {} - { - } + bool observed_ {false}; + ThreatCategory threatCategory_ {ThreatCategory::Base}; + bool tornadoPossible_ {false}; + + Segment() = default; Segment(const Segment&) = delete; Segment& operator=(const Segment&) = delete; diff --git a/wxdata/source/scwx/awips/impact_based_warnings.cpp b/wxdata/source/scwx/awips/impact_based_warnings.cpp new file mode 100644 index 00000000..75f04d1e --- /dev/null +++ b/wxdata/source/scwx/awips/impact_based_warnings.cpp @@ -0,0 +1,31 @@ +#include +#include + +#include + +#include + +namespace scwx +{ +namespace awips +{ + +static const std::string logPrefix_ = "scwx::awips::impact_based_warnings"; + +static const std::unordered_map + threatCategoryName_ {{ThreatCategory::Base, "Base"}, + {ThreatCategory::Significant, "Significant"}, + {ThreatCategory::Considerable, "Considerable"}, + {ThreatCategory::Destructive, "Destructive"}, + {ThreatCategory::Catastrophic, "Catastrophic"}, + {ThreatCategory::Unknown, "?"}}; + +SCWX_GET_ENUM(ThreatCategory, GetThreatCategory, threatCategoryName_) + +const std::string& GetThreatCategoryName(ThreatCategory threatCategory) +{ + return threatCategoryName_.at(threatCategory); +} + +} // 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 ffbd41dc..cccd9e07 100644 --- a/wxdata/source/scwx/awips/text_product_message.cpp +++ b/wxdata/source/scwx/awips/text_product_message.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -304,6 +305,14 @@ void ParseCodedInformation(std::shared_ptr segment, { typedef std::vector::const_iterator StringIterator; + static constexpr std::size_t kThreatCategoryTagCount = 4; + static const std::array + kThreatCategoryTags {"FLASH FLOOD DAMAGE THREAT...", + "SNOW SQUALL IMPACT...", + "THUNDERSTORM DAMAGE THREAT...", + "TORNADO DAMAGE THREAT..."}; + std::array::const_iterator threatTagIt; + std::vector& productContent = segment->productContent_; StringIterator codedLocationBegin = productContent.cend(); @@ -325,8 +334,8 @@ void ParseCodedInformation(std::shared_ptr segment, codedLocationEnd = it; } - if (codedMotionBegin == productContent.cend() && - it->starts_with("TIME...MOT...LOC")) + else if (codedMotionBegin == productContent.cend() && + it->starts_with("TIME...MOT...LOC")) { codedMotionBegin = it; } @@ -338,6 +347,37 @@ void ParseCodedInformation(std::shared_ptr segment, { codedMotionEnd = it; } + + else if (!segment->observed_ && + it->find("...OBSERVED") != std::string::npos) + { + segment->observed_ = true; + } + + else if (!segment->tornadoPossible_ && *it == "TORNADO...POSSIBLE") + { + segment->tornadoPossible_ = true; + } + + else if (segment->threatCategory_ == ThreatCategory::Base && + (threatTagIt = std::find_if(kThreatCategoryTags.cbegin(), + kThreatCategoryTags.cend(), + [&it](const std::string& tag) { + return it->starts_with(tag); + })) != kThreatCategoryTags.cend() && + it->length() > threatTagIt->length()) + { + const std::string threatCategoryName = + it->substr(threatTagIt->length()); + + ThreatCategory threatCategory = GetThreatCategory(threatCategoryName); + if (threatCategory == ThreatCategory::Unknown) + { + threatCategory = ThreatCategory::Base; + } + + segment->threatCategory_ = threatCategory; + } } if (codedLocationBegin != productContent.cend()) diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 0ce08cbb..47ada181 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -14,6 +14,7 @@ endif() set(HDR_AWIPS include/scwx/awips/coded_location.hpp include/scwx/awips/coded_time_motion_location.hpp + include/scwx/awips/impact_based_warnings.hpp include/scwx/awips/message.hpp include/scwx/awips/phenomenon.hpp include/scwx/awips/pvtec.hpp @@ -24,6 +25,7 @@ set(HDR_AWIPS include/scwx/awips/coded_location.hpp include/scwx/awips/wmo_header.hpp) set(SRC_AWIPS source/scwx/awips/coded_location.cpp source/scwx/awips/coded_time_motion_location.cpp + source/scwx/awips/impact_based_warnings.cpp source/scwx/awips/message.cpp source/scwx/awips/phenomenon.cpp source/scwx/awips/pvtec.cpp