Skip to content

Commit

Permalink
Merge pull request #240 from dpaulat/feature/enhanced-alerts
Browse files Browse the repository at this point in the history
Show severity in Alert Dock
  • Loading branch information
dpaulat authored Jul 1, 2024
2 parents 60aed45 + c80b26b commit 86bd48a
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 19 deletions.
99 changes: 99 additions & 0 deletions scwx-qt/source/scwx/qt/model/alert_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class AlertModelImpl
explicit AlertModelImpl();
~AlertModelImpl() = default;

bool GetObserved(const types::TextEventKey& key);
awips::ThreatCategory GetThreatCategory(const types::TextEventKey& key);
bool GetTornadoPossible(const types::TextEventKey& key);

static std::string GetCounties(const types::TextEventKey& key);
static std::string GetState(const types::TextEventKey& key);
static std::chrono::system_clock::time_point
Expand All @@ -49,6 +53,18 @@ class AlertModelImpl

const GeographicLib::Geodesic& geodesic_;

std::unordered_map<types::TextEventKey,
bool,
types::TextEventHash<types::TextEventKey>>
observedMap_;
std::unordered_map<types::TextEventKey,
awips::ThreatCategory,
types::TextEventHash<types::TextEventKey>>
threatCategoryMap_;
std::unordered_map<types::TextEventKey,
bool,
types::TextEventHash<types::TextEventKey>>
tornadoPossibleMap_;
std::unordered_map<types::TextEventKey,
common::Coordinate,
types::TextEventHash<types::TextEventKey>>
Expand Down Expand Up @@ -125,6 +141,29 @@ QVariant AlertModel::data(const QModelIndex& index, int role) const
return QString::fromStdString(
awips::GetSignificanceText(textEventKey.significance_));

case static_cast<int>(Column::Tornado):
if (textEventKey.phenomenon_ == awips::Phenomenon::Tornado &&
p->GetObserved(textEventKey))
{
return tr("Observed");
}
if (p->GetTornadoPossible(textEventKey))
{
return tr("Possible");
}
break;

case static_cast<int>(Column::ThreatCategory):
if (role == Qt::DisplayRole)
{
return QString::fromStdString(awips::GetThreatCategoryName(
p->GetThreatCategory(textEventKey)));
}
else
{
return static_cast<int>(p->GetThreatCategory(textEventKey));
}

case static_cast<int>(Column::State):
return QString::fromStdString(AlertModelImpl::GetState(textEventKey));

Expand Down Expand Up @@ -204,6 +243,12 @@ AlertModel::headerData(int section, Qt::Orientation orientation, int role) const
case static_cast<int>(Column::Significance):
return tr("Significance");

case static_cast<int>(Column::ThreatCategory):
return tr("Category");

case static_cast<int>(Column::Tornado):
return tr("Tornado");

case static_cast<int>(Column::State):
return tr("State");

Expand Down Expand Up @@ -240,6 +285,14 @@ AlertModel::headerData(int section, Qt::Orientation orientation, int role) const
contentsSize = fontMetrics.size(0, QString(10, 'W'));
break;

case static_cast<int>(Column::ThreatCategory):
contentsSize = fontMetrics.size(0, QString(6, 'W'));
break;

case static_cast<int>(Column::Tornado):
contentsSize = fontMetrics.size(0, QString(5, 'W'));
break;

case static_cast<int>(Column::State):
contentsSize = fontMetrics.size(0, "WW, WW");
break;
Expand Down Expand Up @@ -285,6 +338,12 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey,
std::shared_ptr<const awips::Segment> alertSegment =
alertMessages[messageIndex]->segments().back();

p->observedMap_.insert_or_assign(alertKey, alertSegment->observed_);
p->threatCategoryMap_.insert_or_assign(alertKey,
alertSegment->threatCategory_);
p->tornadoPossibleMap_.insert_or_assign(alertKey,
alertSegment->tornadoPossible_);

if (alertSegment->codedLocation_.has_value())
{
// Update centroid and distance
Expand Down Expand Up @@ -365,6 +424,46 @@ AlertModelImpl::AlertModelImpl() :
{
}

bool AlertModelImpl::GetObserved(const types::TextEventKey& key)
{
bool observed = false;

auto it = observedMap_.find(key);
if (it != observedMap_.cend())
{
observed = it->second;
}

return observed;
}

awips::ThreatCategory
AlertModelImpl::GetThreatCategory(const types::TextEventKey& key)
{
awips::ThreatCategory threatCategory = awips::ThreatCategory::Base;

auto it = threatCategoryMap_.find(key);
if (it != threatCategoryMap_.cend())
{
threatCategory = it->second;
}

return threatCategory;
}

bool AlertModelImpl::GetTornadoPossible(const types::TextEventKey& key)
{
bool tornadoPossible = false;

auto it = tornadoPossibleMap_.find(key);
if (it != tornadoPossibleMap_.cend())
{
tornadoPossible = it->second;
}

return tornadoPossible;
}

std::string AlertModelImpl::GetCounties(const types::TextEventKey& key)
{
auto messageList = manager::TextEventManager::Instance()->message_list(key);
Expand Down
20 changes: 11 additions & 9 deletions scwx-qt/source/scwx/qt/model/alert_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ class AlertModel : public QAbstractTableModel
public:
enum class Column : int
{
Etn = 0,
OfficeId = 1,
Phenomenon = 2,
Significance = 3,
State = 4,
Counties = 5,
StartTime = 6,
EndTime = 7,
Distance = 8
Etn = 0,
OfficeId = 1,
Phenomenon = 2,
Significance = 3,
ThreatCategory = 4,
Tornado = 5,
State = 6,
Counties = 7,
StartTime = 8,
EndTime = 9,
Distance = 10
};

explicit AlertModel(QObject* parent = nullptr);
Expand Down
24 changes: 24 additions & 0 deletions wxdata/include/scwx/awips/impact_based_warnings.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <string>

namespace scwx
{
namespace awips
{

enum class ThreatCategory : int
{
Base = 0,
Significant = 1,
Considerable = 2,
Destructive = 3,
Catastrophic = 4,
Unknown
};

ThreatCategory GetThreatCategory(const std::string& name);
const std::string& GetThreatCategoryName(ThreatCategory threatCategory);

} // namespace awips
} // namespace scwx
18 changes: 10 additions & 8 deletions wxdata/include/scwx/awips/text_product_message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#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/pvtec.hpp>
#include <scwx/awips/ugc.hpp>
Expand Down Expand Up @@ -56,15 +57,16 @@ struct SegmentHeader

struct Segment
{
std::optional<SegmentHeader> header_;
std::vector<std::string> productContent_;
std::optional<CodedLocation> codedLocation_;
std::optional<CodedTimeMotionLocation> codedMotion_;
std::optional<SegmentHeader> header_ {};
std::vector<std::string> productContent_ {};
std::optional<CodedLocation> codedLocation_ {};
std::optional<CodedTimeMotionLocation> 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;
Expand Down
31 changes: 31 additions & 0 deletions wxdata/source/scwx/awips/impact_based_warnings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <scwx/awips/impact_based_warnings.hpp>
#include <scwx/util/enum.hpp>

#include <unordered_map>

#include <boost/algorithm/string.hpp>

namespace scwx
{
namespace awips
{

static const std::string logPrefix_ = "scwx::awips::impact_based_warnings";

static const std::unordered_map<ThreatCategory, std::string>
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
44 changes: 42 additions & 2 deletions wxdata/source/scwx/awips/text_product_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <scwx/util/logger.hpp>
#include <scwx/util/streams.hpp>

#include <algorithm>
#include <istream>
#include <string>

Expand Down Expand Up @@ -304,6 +305,14 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
{
typedef std::vector<std::string>::const_iterator StringIterator;

static constexpr std::size_t kThreatCategoryTagCount = 4;
static const std::array<std::string, kThreatCategoryTagCount>
kThreatCategoryTags {"FLASH FLOOD DAMAGE THREAT...",
"SNOW SQUALL IMPACT...",
"THUNDERSTORM DAMAGE THREAT...",
"TORNADO DAMAGE THREAT..."};
std::array<std::string, kThreatCategoryTagCount>::const_iterator threatTagIt;

std::vector<std::string>& productContent = segment->productContent_;

StringIterator codedLocationBegin = productContent.cend();
Expand All @@ -325,8 +334,8 @@ void ParseCodedInformation(std::shared_ptr<Segment> 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;
}
Expand All @@ -338,6 +347,37 @@ void ParseCodedInformation(std::shared_ptr<Segment> 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())
Expand Down
2 changes: 2 additions & 0 deletions wxdata/wxdata.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 86bd48a

Please sign in to comment.