From b2d648e960265da6dca4d62ae2d17fbf54fee5a3 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 8 Jul 2024 22:55:54 -0500 Subject: [PATCH] Add alert layer lines --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 193 ++++++++++++++++++++- 1 file changed, 186 insertions(+), 7 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index e281c055..528539bd 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -1,5 +1,8 @@ #include +#include #include +#include +#include #include #include @@ -20,6 +23,8 @@ namespace map static const std::string logPrefix_ = "scwx::qt::map::alert_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); +static const boost::gil::rgba32f_pixel_t kBlack_ {0.0f, 0.0f, 0.0f, 1.0f}; + template struct AlertTypeHash; @@ -29,7 +34,7 @@ struct AlertTypeHash> size_t operator()(const std::pair& x) const; }; -class AlertLayerHandler : QObject +class AlertLayerHandler : public QObject { Q_OBJECT public: @@ -92,26 +97,83 @@ public: std::mutex alertMutex_ {}; signals: + void AlertAdded(const std::shared_ptr& segmentRecord, + awips::Phenomenon phenomenon); + void AlertUpdated(const std::shared_ptr& segmentRecord); void AlertsUpdated(awips::Phenomenon phenomenon, bool alertActive); }; class AlertLayer::Impl { public: - explicit Impl([[maybe_unused]] std::shared_ptr context, - awips::Phenomenon phenomenon) : - phenomenon_ {phenomenon} + explicit Impl(std::shared_ptr context, + awips::Phenomenon phenomenon) : + phenomenon_ {phenomenon}, + borders_ {{false, std::make_shared(context)}, + {true, std::make_shared(context)}}, + lines_ {{false, std::make_shared(context)}, + {true, std::make_shared(context)}} { - } - ~Impl() {}; + auto& paletteSettings = settings::PaletteSettings::Instance(); - awips::Phenomenon phenomenon_; + for (auto alertActive : {false, true}) + { + lineColor_.emplace( + alertActive, + util::color::ToRgba8PixelT( + paletteSettings.alert_color(phenomenon_, alertActive) + .GetValue())); + } + + ConnectSignals(); + } + ~Impl() { receiver_ = nullptr; }; + + void AddAlert( + const std::shared_ptr& segmentRecord); + void UpdateAlert( + const std::shared_ptr& segmentRecord); + void ConnectSignals(); + + static void AddLine(std::shared_ptr& lines, + std::shared_ptr& di, + const common::Coordinate& p1, + const common::Coordinate& p2, + boost::gil::rgba32f_pixel_t color, + float width, + std::chrono::system_clock::time_point startTime, + std::chrono::system_clock::time_point endTime); + static void + AddLines(std::shared_ptr& lines, + const std::vector& coordinates, + boost::gil::rgba32_pixel_t color, + float width, + std::chrono::system_clock::time_point startTime, + std::chrono::system_clock::time_point endTime, + std::vector>& drawItems); + + const awips::Phenomenon phenomenon_; + + std::unique_ptr receiver_ {std::make_unique()}; + + std::unordered_map> borders_; + std::unordered_map> lines_; + + std::unordered_map lineColor_; }; AlertLayer::AlertLayer(std::shared_ptr context, awips::Phenomenon phenomenon) : DrawLayer(context), p(std::make_unique(context, phenomenon)) { + for (auto alertActive : {false, true}) + { + auto& borders = p->borders_.at(alertActive); + auto& lines = p->lines_.at(alertActive); + + AddDrawItem(borders); + AddDrawItem(lines); + } } AlertLayer::~AlertLayer() = default; @@ -121,6 +183,18 @@ void AlertLayer::Initialize() logger_->debug("Initialize: {}", awips::GetPhenomenonText(p->phenomenon_)); DrawLayer::Initialize(); + + for (auto alertActive : {false, true}) + { + auto& borders = p->borders_.at(alertActive); + auto& lines = p->lines_.at(alertActive); + + borders->StartLines(); + borders->FinishLines(); + + lines->StartLines(); + lines->FinishLines(); + } } void AlertLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) @@ -183,6 +257,8 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, if (segmentRecord->segmentEnd_ > segmentBegin) { segmentRecord->segmentEnd_ = segmentBegin; + + Q_EMIT AlertUpdated(segmentRecord); } } @@ -210,6 +286,8 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, segmentsForKey.push_back(segmentRecord); segmentsForType.push_back(segmentRecord); + Q_EMIT AlertAdded(segmentRecord, phenomenon); + alertsUpdated.emplace(phenomenon, alertActive); } @@ -223,6 +301,107 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, } } +void AlertLayer::Impl::ConnectSignals() +{ + QObject::connect( + &AlertLayerHandler::Instance(), + &AlertLayerHandler::AlertAdded, + receiver_.get(), + [this]( + const std::shared_ptr& segmentRecord, + awips::Phenomenon phenomenon) + { + if (phenomenon == phenomenon_) + { + AddAlert(segmentRecord); + } + }); +} + +void AlertLayer::Impl::AddAlert( + const std::shared_ptr& segmentRecord) +{ + auto& segment = segmentRecord->segment_; + + auto& vtec = segment->header_->vtecString_.front(); + auto action = vtec.pVtec_.action(); + bool alertActive = (action != awips::PVtec::Action::Canceled); + auto& startTime = segmentRecord->segmentBegin_; + auto& endTime = segmentRecord->segmentEnd_; + + auto& lineColor = lineColor_.at(alertActive); + auto& lines = lines_.at(alertActive); + + const auto& coordinates = segment->codedLocation_->coordinates(); + + std::vector> drawItems {}; + + AddLines(lines, coordinates, kBlack_, 5.0f, startTime, endTime, drawItems); + AddLines(lines, coordinates, lineColor, 3.0f, startTime, endTime, drawItems); + + lines->FinishLines(); +} + +void AlertLayer::Impl::UpdateAlert( + [[maybe_unused]] const std::shared_ptr& + segmentRecord) +{ + // TODO +} + +void AlertLayer::Impl::AddLines( + std::shared_ptr& lines, + const std::vector& coordinates, + boost::gil::rgba32_pixel_t color, + float width, + std::chrono::system_clock::time_point startTime, + std::chrono::system_clock::time_point endTime, + std::vector>& drawItems) +{ + for (std::size_t i = 0, j = 1; i < coordinates.size(); ++i, ++j) + { + if (j >= coordinates.size()) + { + j = 0; + + // Ignore repeated coordinates at the end + if (coordinates[i] == coordinates[j]) + { + break; + } + } + + auto di = lines->AddLine(); + AddLine(lines, + di, + coordinates[i], + coordinates[j], + color, + width, + startTime, + endTime); + + drawItems.push_back(di); + } +} + +void AlertLayer::Impl::AddLine(std::shared_ptr& lines, + std::shared_ptr& di, + const common::Coordinate& p1, + const common::Coordinate& p2, + boost::gil::rgba32f_pixel_t color, + float width, + std::chrono::system_clock::time_point startTime, + std::chrono::system_clock::time_point endTime) +{ + lines->SetLineLocation( + di, p1.latitude_, p1.longitude_, p2.latitude_, p2.longitude_); + lines->SetLineModulate(di, color); + lines->SetLineWidth(di, width); + lines->SetLineStartTime(di, startTime); + lines->SetLineEndTime(di, endTime); +} + AlertLayerHandler& AlertLayerHandler::Instance() { static AlertLayerHandler alertLayerHandler_ {};