From e8a0cf5fa9a88bd73fe514136f877881db37e3a2 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 5 Aug 2024 00:04:18 -0500 Subject: [PATCH] Removing old alert layer --- scwx-qt/scwx-qt.cmake | 2 - .../source/scwx/qt/map/alert_layer_old.cpp | 498 ------------------ .../source/scwx/qt/map/alert_layer_old.hpp | 34 -- 3 files changed, 534 deletions(-) delete mode 100644 scwx-qt/source/scwx/qt/map/alert_layer_old.cpp delete mode 100644 scwx-qt/source/scwx/qt/map/alert_layer_old.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index d399f4e0..b6e2c44e 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -120,7 +120,6 @@ set(SRC_MANAGER source/scwx/qt/manager/alert_manager.cpp source/scwx/qt/manager/timeline_manager.cpp source/scwx/qt/manager/update_manager.cpp) set(HDR_MAP source/scwx/qt/map/alert_layer.hpp - source/scwx/qt/map/alert_layer_old.hpp source/scwx/qt/map/color_table_layer.hpp source/scwx/qt/map/draw_layer.hpp source/scwx/qt/map/generic_layer.hpp @@ -136,7 +135,6 @@ set(HDR_MAP source/scwx/qt/map/alert_layer.hpp source/scwx/qt/map/radar_range_layer.hpp source/scwx/qt/map/radar_site_layer.hpp) set(SRC_MAP source/scwx/qt/map/alert_layer.cpp - source/scwx/qt/map/alert_layer_old.cpp source/scwx/qt/map/color_table_layer.cpp source/scwx/qt/map/draw_layer.cpp source/scwx/qt/map/generic_layer.cpp diff --git a/scwx-qt/source/scwx/qt/map/alert_layer_old.cpp b/scwx-qt/source/scwx/qt/map/alert_layer_old.cpp deleted file mode 100644 index ff01d4c5..00000000 --- a/scwx-qt/source/scwx/qt/map/alert_layer_old.cpp +++ /dev/null @@ -1,498 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace scwx -{ -namespace qt -{ -namespace map -{ - -static const std::string logPrefix_ = "scwx::qt::map::alert_layer_old"; -static const auto logger_ = scwx::util::Logger::Create(logPrefix_); - -static std::vector -AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer); -static QMapLibre::Feature -CreateFeature(const awips::CodedLocation& codedLocation); -static QMapLibre::Coordinate -GetMapboxCoordinate(const common::Coordinate& coordinate); -static QMapLibre::Coordinates - GetMapboxCoordinates(const awips::CodedLocation& codedLocation); -static QString GetSourceId(awips::Phenomenon phenomenon, bool alertActive); -static QString GetSuffix(awips::Phenomenon phenomenon, bool alertActive); - -static const QVariantMap kEmptyFeatureCollection_ { - {"type", "geojson"}, - {"data", QVariant::fromValue(std::list {})}}; -static const std::vector kAlertPhenomena_ { - awips::Phenomenon::Marine, - awips::Phenomenon::FlashFlood, - awips::Phenomenon::SevereThunderstorm, - awips::Phenomenon::SnowSquall, - awips::Phenomenon::Tornado}; - -template -struct AlertTypeOldHash; - -template<> -struct AlertTypeOldHash> -{ - size_t operator()(const std::pair& x) const; -}; - -class AlertLayerOldHandler : public QObject -{ - Q_OBJECT -public: - explicit AlertLayerOldHandler() : - textEventManager_ {manager::TextEventManager::Instance()}, - alertUpdateTimer_ {scwx::util::io_context()}, - alertSourceMap_ {}, - featureMap_ {} - { - for (auto& phenomenon : kAlertPhenomena_) - { - for (bool alertActive : {false, true}) - { - alertSourceMap_.emplace(std::make_pair(phenomenon, alertActive), - kEmptyFeatureCollection_); - } - } - - connect(textEventManager_.get(), - &manager::TextEventManager::AlertUpdated, - this, - &AlertLayerOldHandler::HandleAlert); - } - ~AlertLayerOldHandler() - { - std::unique_lock lock(alertMutex_); - alertUpdateTimer_.cancel(); - } - - static std::shared_ptr Instance(); - - std::list* FeatureList(awips::Phenomenon phenomenon, - bool alertActive); - - void HandleAlert(const types::TextEventKey& key, size_t messageIndex); - void UpdateAlerts(); - - std::shared_ptr textEventManager_; - - boost::asio::steady_timer alertUpdateTimer_; - std::unordered_map, - QVariantMap, - AlertTypeOldHash>> - alertSourceMap_; - std::unordered_multimap::iterator, - std::chrono::system_clock::time_point>, - types::TextEventHash> - featureMap_; - std::shared_mutex alertMutex_; - -signals: - void AlertsUpdated(awips::Phenomenon phenomenon, bool alertActive); -}; - -class AlertLayerOldImpl : public QObject -{ - Q_OBJECT -public: - explicit AlertLayerOldImpl(std::shared_ptr context) : - context_ {context}, - alertLayerOldHandler_ {AlertLayerOldHandler::Instance()} - { - connect(alertLayerOldHandler_.get(), - &AlertLayerOldHandler::AlertsUpdated, - this, - &AlertLayerOldImpl::UpdateSource); - } - ~AlertLayerOldImpl() {}; - - void UpdateSource(awips::Phenomenon phenomenon, bool alertActive); - - std::shared_ptr context_; - std::shared_ptr alertLayerOldHandler_; -}; - -AlertLayerOld::AlertLayerOld(std::shared_ptr context) : - p(std::make_unique(context)) -{ -} - -AlertLayerOld::~AlertLayerOld() = default; - -std::vector AlertLayerOld::AddLayers(awips::Phenomenon phenomenon, - const std::string& before) -{ - logger_->debug("AddLayers(): {}", awips::GetPhenomenonCode(phenomenon)); - - std::vector layers {}; - - auto map = p->context_->map().lock(); - if (map == nullptr) - { - return layers; - } - - const QString beforeLayer {QString::fromStdString(before)}; - - // Add/update GeoJSON sources and create layers - for (bool alertActive : {false, true}) - { - p->UpdateSource(phenomenon, alertActive); - auto newLayers = AddAlertLayer(map, phenomenon, alertActive, beforeLayer); - layers.insert(layers.end(), newLayers.cbegin(), newLayers.cend()); - } - - return layers; -} - -std::list* -AlertLayerOldHandler::FeatureList(awips::Phenomenon phenomenon, - bool alertActive) -{ - std::list* featureList = nullptr; - - auto key = std::make_pair(phenomenon, alertActive); - auto it = alertSourceMap_.find(key); - if (it != alertSourceMap_.cend()) - { - featureList = reinterpret_cast*>( - it->second["data"].data()); - } - - return featureList; -} - -void AlertLayerOldHandler::HandleAlert(const types::TextEventKey& key, - size_t messageIndex) -{ - // Skip alert if there are more messages to be processed - if (messageIndex + 1 < textEventManager_->message_count(key)) - { - return; - } - - auto message = textEventManager_->message_list(key).at(messageIndex); - std::unordered_set, - AlertTypeOldHash>> - alertsUpdated {}; - - // Take a unique lock before modifying feature lists - std::unique_lock lock(alertMutex_); - - // Remove existing features for key - auto existingFeatures = featureMap_.equal_range(key); - for (auto it = existingFeatures.first; it != existingFeatures.second; ++it) - { - auto& [phenomenon, alertActive, featureIt, eventEnd] = it->second; - auto featureList = FeatureList(phenomenon, alertActive); - if (featureList != nullptr) - { - // Remove existing feature for key - featureList->erase(featureIt); - - // Mark alert type as updated - alertsUpdated.emplace(phenomenon, alertActive); - } - } - featureMap_.erase(existingFeatures.first, existingFeatures.second); - - for (auto segment : message->segments()) - { - if (!segment->codedLocation_.has_value()) - { - continue; - } - - auto& vtec = segment->header_->vtecString_.front(); - auto action = vtec.pVtec_.action(); - awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); - auto eventEnd = vtec.pVtec_.event_end(); - bool alertActive = (action != awips::PVtec::Action::Canceled); - - // If the event has ended, skip it - if (eventEnd < std::chrono::system_clock::now()) - { - continue; - } - - auto featureList = FeatureList(phenomenon, alertActive); - if (featureList != nullptr) - { - // Add alert location to polygon list - auto featureIt = featureList->emplace( - featureList->cend(), - CreateFeature(segment->codedLocation_.value())); - - // Store iterator for created feature in feature map - featureMap_.emplace(std::piecewise_construct, - std::forward_as_tuple(key), - std::forward_as_tuple( - phenomenon, alertActive, featureIt, eventEnd)); - - // Mark alert type as updated - alertsUpdated.emplace(phenomenon, alertActive); - } - } - - // Release the lock after completing feature list updates - lock.unlock(); - - for (auto& alert : alertsUpdated) - { - // Emit signal for each updated alert type - Q_EMIT AlertsUpdated(alert.first, alert.second); - } -} - -void AlertLayerOldHandler::UpdateAlerts() -{ - logger_->trace("UpdateAlerts"); - - // Take a unique lock before modifying feature lists - std::unique_lock lock(alertMutex_); - - std::unordered_set, - AlertTypeOldHash>> - alertsUpdated {}; - - // Evaluate each rendered feature for expiration - for (auto it = featureMap_.begin(); it != featureMap_.end();) - { - auto& [phenomenon, alertActive, featureIt, eventEnd] = it->second; - - // If the event has ended, remove it from the feature list - if (eventEnd < std::chrono::system_clock::now()) - { - logger_->debug("Alert expired: {}", it->first.ToString()); - - auto featureList = FeatureList(phenomenon, alertActive); - if (featureList != nullptr) - { - // Remove existing feature for key - featureList->erase(featureIt); - - // Mark alert type as updated - alertsUpdated.emplace(phenomenon, alertActive); - } - - // Erase current item and increment iterator - it = featureMap_.erase(it); - } - else - { - // Current item is not expired, continue - ++it; - } - } - - for (auto& alert : alertsUpdated) - { - // Emit signal for each updated alert type - Q_EMIT AlertsUpdated(alert.first, alert.second); - } - - using namespace std::chrono; - alertUpdateTimer_.expires_after(15s); - alertUpdateTimer_.async_wait( - [this](const boost::system::error_code& e) - { - if (e == boost::asio::error::operation_aborted) - { - logger_->debug("Alert update timer cancelled"); - } - else if (e != boost::system::errc::success) - { - logger_->warn("Alert update timer error: {}", e.message()); - } - else - { - try - { - UpdateAlerts(); - } - catch (const std::exception& ex) - { - logger_->error(ex.what()); - } - } - }); -} - -void AlertLayerOldImpl::UpdateSource(awips::Phenomenon phenomenon, - bool alertActive) -{ - auto map = context_->map().lock(); - if (map == nullptr) - { - return; - } - - // Take a shared lock before using feature lists - std::shared_lock lock(alertLayerOldHandler_->alertMutex_); - - // Update source, relies on alert source being defined - map->updateSource(GetSourceId(phenomenon, alertActive), - alertLayerOldHandler_->alertSourceMap_.at( - std::make_pair(phenomenon, alertActive))); -} - -std::shared_ptr AlertLayerOldHandler::Instance() -{ - static std::weak_ptr alertLayerOldHandlerReference {}; - static std::mutex instanceMutex {}; - - std::unique_lock lock(instanceMutex); - - std::shared_ptr alertLayerOldHandler = - alertLayerOldHandlerReference.lock(); - - if (alertLayerOldHandler == nullptr) - { - alertLayerOldHandler = std::make_shared(); - alertLayerOldHandlerReference = alertLayerOldHandler; - - alertLayerOldHandler->UpdateAlerts(); - } - - return alertLayerOldHandler; -} - -static std::vector -AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer) -{ - settings::PaletteSettings& paletteSettings = - settings::PaletteSettings::Instance(); - - QString layerPrefix = QString::fromStdString( - types::GetLayerName(types::LayerType::Alert, phenomenon)); - - QString sourceId = GetSourceId(phenomenon, alertActive); - QString idSuffix = GetSuffix(phenomenon, alertActive); - auto outlineColor = util::color::ToRgba8PixelT( - paletteSettings.alert_color(phenomenon, alertActive).GetValue()); - - QString bgLayerId = QString("%1::bg-%2").arg(layerPrefix).arg(idSuffix); - QString fgLayerId = QString("%1::fg-%2").arg(layerPrefix).arg(idSuffix); - - if (map->layerExists(bgLayerId)) - { - map->removeLayer(bgLayerId); - } - if (map->layerExists(fgLayerId)) - { - map->removeLayer(fgLayerId); - } - - const float opacity = outlineColor[3] / 255.0f; - - map->addLayer( - bgLayerId, {{"type", "line"}, {"source", sourceId}}, beforeLayer); - map->setLayoutProperty(bgLayerId, "line-join", "round"); - map->setLayoutProperty(bgLayerId, "line-cap", "round"); - map->setPaintProperty(bgLayerId, "line-color", "rgba(0, 0, 0, 255)"); - map->setPaintProperty(bgLayerId, "line-opacity", QString("%1").arg(opacity)); - map->setPaintProperty(bgLayerId, "line-width", "5"); - - map->addLayer( - fgLayerId, {{"type", "line"}, {"source", sourceId}}, beforeLayer); - map->setLayoutProperty(fgLayerId, "line-join", "round"); - map->setLayoutProperty(fgLayerId, "line-cap", "round"); - map->setPaintProperty(fgLayerId, - "line-color", - QString("rgba(%1, %2, %3, %4)") - .arg(outlineColor[0]) - .arg(outlineColor[1]) - .arg(outlineColor[2]) - .arg(outlineColor[3])); - map->setPaintProperty(fgLayerId, "line-opacity", QString("%1").arg(opacity)); - map->setPaintProperty(fgLayerId, "line-width", "3"); - - return {bgLayerId.toStdString(), fgLayerId.toStdString()}; -} - -static QMapLibre::Feature -CreateFeature(const awips::CodedLocation& codedLocation) -{ - auto mapboxCoordinates = GetMapboxCoordinates(codedLocation); - - return QMapLibre::Feature { - QMapLibre::Feature::PolygonType, - std::initializer_list { - std::initializer_list {{mapboxCoordinates}}}}; -} - -static QMapLibre::Coordinate -GetMapboxCoordinate(const common::Coordinate& coordinate) -{ - return {coordinate.latitude_, coordinate.longitude_}; -} - -static QMapLibre::Coordinates -GetMapboxCoordinates(const awips::CodedLocation& codedLocation) -{ - auto scwxCoordinates = codedLocation.coordinates(); - QMapLibre::Coordinates mapboxCoordinates(scwxCoordinates.size() + 1u); - - std::transform(scwxCoordinates.cbegin(), - scwxCoordinates.cend(), - mapboxCoordinates.begin(), - [](auto& coordinate) -> QMapLibre::Coordinate - { return GetMapboxCoordinate(coordinate); }); - - mapboxCoordinates.back() = GetMapboxCoordinate(scwxCoordinates.front()); - - return mapboxCoordinates; -} - -static QString GetSourceId(awips::Phenomenon phenomenon, bool alertActive) -{ - return QString("alertPolygon-%1").arg(GetSuffix(phenomenon, alertActive)); -} - -static QString GetSuffix(awips::Phenomenon phenomenon, bool alertActive) -{ - return QString("-%1.%2") - .arg(QString::fromStdString(awips::GetPhenomenonCode(phenomenon))) - .arg(alertActive); -} - -size_t AlertTypeOldHash>::operator()( - const std::pair& x) const -{ - size_t seed = 0; - boost::hash_combine(seed, x.first); - boost::hash_combine(seed, x.second); - return seed; -} - -} // namespace map -} // namespace qt -} // namespace scwx - -#include "alert_layer_old.moc" diff --git a/scwx-qt/source/scwx/qt/map/alert_layer_old.hpp b/scwx-qt/source/scwx/qt/map/alert_layer_old.hpp deleted file mode 100644 index dd06a4ed..00000000 --- a/scwx-qt/source/scwx/qt/map/alert_layer_old.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -namespace scwx -{ -namespace qt -{ -namespace map -{ - -class AlertLayerOldImpl; - -class AlertLayerOld -{ -public: - explicit AlertLayerOld(std::shared_ptr context); - ~AlertLayerOld(); - - std::vector AddLayers(awips::Phenomenon phenomenon, - const std::string& before = {}); - -private: - std::unique_ptr p; -}; - -} // namespace map -} // namespace qt -} // namespace scwx