mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 16:00:08 +00:00
Rename existing AlertLayer to AlertLayerOld, prepare AlertLayer skeleton
This commit is contained in:
parent
2e1b537c87
commit
044e6d6885
6 changed files with 587 additions and 462 deletions
|
|
@ -120,6 +120,7 @@ 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
|
||||
|
|
@ -135,6 +136,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -1,17 +1,5 @@
|
|||
#include <scwx/qt/map/alert_layer.hpp>
|
||||
#include <scwx/qt/manager/text_event_manager.hpp>
|
||||
#include <scwx/qt/settings/palette_settings.hpp>
|
||||
#include <scwx/qt/types/layer_types.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
#include <scwx/util/threads.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -23,473 +11,66 @@ namespace map
|
|||
static const std::string logPrefix_ = "scwx::qt::map::alert_layer";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
static std::vector<std::string>
|
||||
AddAlertLayer(std::shared_ptr<QMapLibre::Map> 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<QMapLibre::Feature> {})}};
|
||||
static const std::vector<awips::Phenomenon> kAlertPhenomena_ {
|
||||
awips::Phenomenon::Marine,
|
||||
awips::Phenomenon::FlashFlood,
|
||||
awips::Phenomenon::SevereThunderstorm,
|
||||
awips::Phenomenon::SnowSquall,
|
||||
awips::Phenomenon::Tornado};
|
||||
|
||||
template<class Key>
|
||||
struct AlertTypeHash;
|
||||
|
||||
template<>
|
||||
struct AlertTypeHash<std::pair<awips::Phenomenon, bool>>
|
||||
class AlertLayer::Impl
|
||||
{
|
||||
size_t operator()(const std::pair<awips::Phenomenon, bool>& x) const;
|
||||
};
|
||||
|
||||
class AlertLayerHandler : public QObject
|
||||
{
|
||||
Q_OBJECT public :
|
||||
explicit AlertLayerHandler() :
|
||||
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,
|
||||
&AlertLayerHandler::HandleAlert);
|
||||
}
|
||||
~AlertLayerHandler()
|
||||
{
|
||||
std::unique_lock lock(alertMutex_);
|
||||
alertUpdateTimer_.cancel();
|
||||
}
|
||||
|
||||
static std::shared_ptr<AlertLayerHandler> Instance();
|
||||
|
||||
std::list<QMapLibre::Feature>* FeatureList(awips::Phenomenon phenomenon,
|
||||
bool alertActive);
|
||||
|
||||
void HandleAlert(const types::TextEventKey& key, size_t messageIndex);
|
||||
void UpdateAlerts();
|
||||
|
||||
std::shared_ptr<manager::TextEventManager> textEventManager_;
|
||||
|
||||
boost::asio::steady_timer alertUpdateTimer_;
|
||||
std::unordered_map<std::pair<awips::Phenomenon, bool>,
|
||||
QVariantMap,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
alertSourceMap_;
|
||||
std::unordered_multimap<types::TextEventKey,
|
||||
std::tuple<awips::Phenomenon,
|
||||
bool,
|
||||
std::list<QMapLibre::Feature>::iterator,
|
||||
std::chrono::system_clock::time_point>,
|
||||
types::TextEventHash<types::TextEventKey>>
|
||||
featureMap_;
|
||||
std::shared_mutex alertMutex_;
|
||||
|
||||
signals:
|
||||
void AlertsUpdated(awips::Phenomenon phenomenon, bool alertActive);
|
||||
};
|
||||
|
||||
class AlertLayerImpl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AlertLayerImpl(std::shared_ptr<MapContext> context) :
|
||||
context_ {context}, alertLayerHandler_ {AlertLayerHandler::Instance()}
|
||||
explicit Impl([[maybe_unused]] std::shared_ptr<MapContext> context,
|
||||
awips::Phenomenon phenomenon) :
|
||||
phenomenon_ {phenomenon}
|
||||
{
|
||||
connect(alertLayerHandler_.get(),
|
||||
&AlertLayerHandler::AlertsUpdated,
|
||||
this,
|
||||
&AlertLayerImpl::UpdateSource);
|
||||
}
|
||||
~AlertLayerImpl() {};
|
||||
~Impl() {};
|
||||
|
||||
void UpdateSource(awips::Phenomenon phenomenon, bool alertActive);
|
||||
|
||||
std::shared_ptr<MapContext> context_;
|
||||
std::shared_ptr<AlertLayerHandler> alertLayerHandler_;
|
||||
awips::Phenomenon phenomenon_;
|
||||
};
|
||||
|
||||
AlertLayer::AlertLayer(std::shared_ptr<MapContext> context) :
|
||||
p(std::make_unique<AlertLayerImpl>(context))
|
||||
AlertLayer::AlertLayer(std::shared_ptr<MapContext> context,
|
||||
awips::Phenomenon phenomenon) :
|
||||
DrawLayer(context), p(std::make_unique<Impl>(context, phenomenon))
|
||||
{
|
||||
}
|
||||
|
||||
AlertLayer::~AlertLayer() = default;
|
||||
|
||||
std::vector<std::string> AlertLayer::AddLayers(awips::Phenomenon phenomenon,
|
||||
const std::string& before)
|
||||
void AlertLayer::Initialize()
|
||||
{
|
||||
logger_->debug("AddLayers(): {}", awips::GetPhenomenonCode(phenomenon));
|
||||
logger_->debug("Initialize: {}", awips::GetPhenomenonText(p->phenomenon_));
|
||||
|
||||
std::vector<std::string> 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;
|
||||
DrawLayer::Initialize();
|
||||
}
|
||||
|
||||
std::list<QMapLibre::Feature>*
|
||||
AlertLayerHandler::FeatureList(awips::Phenomenon phenomenon, bool alertActive)
|
||||
void AlertLayer::Render(const QMapLibre::CustomLayerRenderParameters& params)
|
||||
{
|
||||
std::list<QMapLibre::Feature>* featureList = nullptr;
|
||||
gl::OpenGLFunctions& gl = context()->gl();
|
||||
|
||||
auto key = std::make_pair(phenomenon, alertActive);
|
||||
auto it = alertSourceMap_.find(key);
|
||||
if (it != alertSourceMap_.cend())
|
||||
{
|
||||
featureList = reinterpret_cast<std::list<QMapLibre::Feature>*>(
|
||||
it->second["data"].data());
|
||||
}
|
||||
DrawLayer::Render(params);
|
||||
|
||||
return featureList;
|
||||
SCWX_GL_CHECK_ERROR();
|
||||
}
|
||||
|
||||
void AlertLayerHandler::HandleAlert(const types::TextEventKey& key,
|
||||
size_t messageIndex)
|
||||
void AlertLayer::Deinitialize()
|
||||
{
|
||||
// Skip alert if there are more messages to be processed
|
||||
if (messageIndex + 1 < textEventManager_->message_count(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
logger_->debug("Deinitialize: {}", awips::GetPhenomenonText(p->phenomenon_));
|
||||
|
||||
auto message = textEventManager_->message_list(key).at(messageIndex);
|
||||
std::unordered_set<std::pair<awips::Phenomenon, bool>,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
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);
|
||||
}
|
||||
DrawLayer::Deinitialize();
|
||||
}
|
||||
|
||||
void AlertLayerHandler::UpdateAlerts()
|
||||
bool AlertLayer::RunMousePicking(
|
||||
const QMapLibre::CustomLayerRenderParameters& params,
|
||||
const QPointF& mouseLocalPos,
|
||||
const QPointF& mouseGlobalPos,
|
||||
const glm::vec2& mouseCoords,
|
||||
const common::Coordinate& mouseGeoCoords,
|
||||
std::shared_ptr<types::EventHandler>& eventHandler)
|
||||
{
|
||||
logger_->trace("UpdateAlerts");
|
||||
|
||||
// Take a unique lock before modifying feature lists
|
||||
std::unique_lock lock(alertMutex_);
|
||||
|
||||
std::unordered_set<std::pair<awips::Phenomenon, bool>,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
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 AlertLayerImpl::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(alertLayerHandler_->alertMutex_);
|
||||
|
||||
// Update source, relies on alert source being defined
|
||||
map->updateSource(GetSourceId(phenomenon, alertActive),
|
||||
alertLayerHandler_->alertSourceMap_.at(
|
||||
std::make_pair(phenomenon, alertActive)));
|
||||
}
|
||||
|
||||
std::shared_ptr<AlertLayerHandler> AlertLayerHandler::Instance()
|
||||
{
|
||||
static std::weak_ptr<AlertLayerHandler> alertLayerHandlerReference {};
|
||||
static std::mutex instanceMutex {};
|
||||
|
||||
std::unique_lock lock(instanceMutex);
|
||||
|
||||
std::shared_ptr<AlertLayerHandler> alertLayerHandler =
|
||||
alertLayerHandlerReference.lock();
|
||||
|
||||
if (alertLayerHandler == nullptr)
|
||||
{
|
||||
alertLayerHandler = std::make_shared<AlertLayerHandler>();
|
||||
alertLayerHandlerReference = alertLayerHandler;
|
||||
|
||||
alertLayerHandler->UpdateAlerts();
|
||||
}
|
||||
|
||||
return alertLayerHandler;
|
||||
}
|
||||
|
||||
static std::vector<std::string>
|
||||
AddAlertLayer(std::shared_ptr<QMapLibre::Map> 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<QMapLibre::CoordinatesCollection> {
|
||||
std::initializer_list<QMapLibre::Coordinates> {{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 AlertTypeHash<std::pair<awips::Phenomenon, bool>>::operator()(
|
||||
const std::pair<awips::Phenomenon, bool>& x) const
|
||||
{
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, x.first);
|
||||
boost::hash_combine(seed, x.second);
|
||||
return seed;
|
||||
return DrawLayer::RunMousePicking(params,
|
||||
mouseLocalPos,
|
||||
mouseGlobalPos,
|
||||
mouseCoords,
|
||||
mouseGeoCoords,
|
||||
eventHandler);
|
||||
}
|
||||
|
||||
} // namespace map
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
||||
#include "alert_layer.moc"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
#include <scwx/qt/map/map_context.hpp>
|
||||
#include <scwx/qt/map/draw_layer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -14,19 +14,30 @@ namespace qt
|
|||
namespace map
|
||||
{
|
||||
|
||||
class AlertLayerImpl;
|
||||
|
||||
class AlertLayer
|
||||
class AlertLayer : public DrawLayer
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(AlertLayer)
|
||||
|
||||
public:
|
||||
explicit AlertLayer(std::shared_ptr<MapContext> context);
|
||||
explicit AlertLayer(std::shared_ptr<MapContext> context,
|
||||
scwx::awips::Phenomenon phenomenon);
|
||||
~AlertLayer();
|
||||
|
||||
std::vector<std::string> AddLayers(awips::Phenomenon phenomenon,
|
||||
const std::string& before = {});
|
||||
void Initialize() override final;
|
||||
void Render(const QMapLibre::CustomLayerRenderParameters&) override final;
|
||||
void Deinitialize() override final;
|
||||
|
||||
bool RunMousePicking(
|
||||
const QMapLibre::CustomLayerRenderParameters& params,
|
||||
const QPointF& mouseLocalPos,
|
||||
const QPointF& mouseGlobalPos,
|
||||
const glm::vec2& mouseCoords,
|
||||
const common::Coordinate& mouseGeoCoords,
|
||||
std::shared_ptr<types::EventHandler>& eventHandler) override final;
|
||||
|
||||
private:
|
||||
std::unique_ptr<AlertLayerImpl> p;
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace map
|
||||
|
|
|
|||
497
scwx-qt/source/scwx/qt/map/alert_layer_old.cpp
Normal file
497
scwx-qt/source/scwx/qt/map/alert_layer_old.cpp
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
#include <scwx/qt/map/alert_layer_old.hpp>
|
||||
#include <scwx/qt/manager/text_event_manager.hpp>
|
||||
#include <scwx/qt/settings/palette_settings.hpp>
|
||||
#include <scwx/qt/types/layer_types.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
#include <scwx/util/threads.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <shared_mutex>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
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<std::string>
|
||||
AddAlertLayer(std::shared_ptr<QMapLibre::Map> 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<QMapLibre::Feature> {})}};
|
||||
static const std::vector<awips::Phenomenon> kAlertPhenomena_ {
|
||||
awips::Phenomenon::Marine,
|
||||
awips::Phenomenon::FlashFlood,
|
||||
awips::Phenomenon::SevereThunderstorm,
|
||||
awips::Phenomenon::SnowSquall,
|
||||
awips::Phenomenon::Tornado};
|
||||
|
||||
template<class Key>
|
||||
struct AlertTypeHash;
|
||||
|
||||
template<>
|
||||
struct AlertTypeHash<std::pair<awips::Phenomenon, bool>>
|
||||
{
|
||||
size_t operator()(const std::pair<awips::Phenomenon, bool>& 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<AlertLayerOldHandler> Instance();
|
||||
|
||||
std::list<QMapLibre::Feature>* FeatureList(awips::Phenomenon phenomenon,
|
||||
bool alertActive);
|
||||
|
||||
void HandleAlert(const types::TextEventKey& key, size_t messageIndex);
|
||||
void UpdateAlerts();
|
||||
|
||||
std::shared_ptr<manager::TextEventManager> textEventManager_;
|
||||
|
||||
boost::asio::steady_timer alertUpdateTimer_;
|
||||
std::unordered_map<std::pair<awips::Phenomenon, bool>,
|
||||
QVariantMap,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
alertSourceMap_;
|
||||
std::unordered_multimap<types::TextEventKey,
|
||||
std::tuple<awips::Phenomenon,
|
||||
bool,
|
||||
std::list<QMapLibre::Feature>::iterator,
|
||||
std::chrono::system_clock::time_point>,
|
||||
types::TextEventHash<types::TextEventKey>>
|
||||
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<MapContext> 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<MapContext> context_;
|
||||
std::shared_ptr<AlertLayerOldHandler> alertLayerOldHandler_;
|
||||
};
|
||||
|
||||
AlertLayerOld::AlertLayerOld(std::shared_ptr<MapContext> context) :
|
||||
p(std::make_unique<AlertLayerOldImpl>(context))
|
||||
{
|
||||
}
|
||||
|
||||
AlertLayerOld::~AlertLayerOld() = default;
|
||||
|
||||
std::vector<std::string> AlertLayerOld::AddLayers(awips::Phenomenon phenomenon,
|
||||
const std::string& before)
|
||||
{
|
||||
logger_->debug("AddLayers(): {}", awips::GetPhenomenonCode(phenomenon));
|
||||
|
||||
std::vector<std::string> 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<QMapLibre::Feature>*
|
||||
AlertLayerOldHandler::FeatureList(awips::Phenomenon phenomenon,
|
||||
bool alertActive)
|
||||
{
|
||||
std::list<QMapLibre::Feature>* featureList = nullptr;
|
||||
|
||||
auto key = std::make_pair(phenomenon, alertActive);
|
||||
auto it = alertSourceMap_.find(key);
|
||||
if (it != alertSourceMap_.cend())
|
||||
{
|
||||
featureList = reinterpret_cast<std::list<QMapLibre::Feature>*>(
|
||||
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<std::pair<awips::Phenomenon, bool>,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
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<std::pair<awips::Phenomenon, bool>,
|
||||
AlertTypeHash<std::pair<awips::Phenomenon, bool>>>
|
||||
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> AlertLayerOldHandler::Instance()
|
||||
{
|
||||
static std::weak_ptr<AlertLayerOldHandler> alertLayerOldHandlerReference {};
|
||||
static std::mutex instanceMutex {};
|
||||
|
||||
std::unique_lock lock(instanceMutex);
|
||||
|
||||
std::shared_ptr<AlertLayerOldHandler> alertLayerOldHandler =
|
||||
alertLayerOldHandlerReference.lock();
|
||||
|
||||
if (alertLayerOldHandler == nullptr)
|
||||
{
|
||||
alertLayerOldHandler = std::make_shared<AlertLayerOldHandler>();
|
||||
alertLayerOldHandlerReference = alertLayerOldHandler;
|
||||
|
||||
alertLayerOldHandler->UpdateAlerts();
|
||||
}
|
||||
|
||||
return alertLayerOldHandler;
|
||||
}
|
||||
|
||||
static std::vector<std::string>
|
||||
AddAlertLayer(std::shared_ptr<QMapLibre::Map> 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<QMapLibre::CoordinatesCollection> {
|
||||
std::initializer_list<QMapLibre::Coordinates> {{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 AlertTypeHash<std::pair<awips::Phenomenon, bool>>::operator()(
|
||||
const std::pair<awips::Phenomenon, bool>& 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"
|
||||
34
scwx-qt/source/scwx/qt/map/alert_layer_old.hpp
Normal file
34
scwx-qt/source/scwx/qt/map/alert_layer_old.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
#include <scwx/qt/map/map_context.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace map
|
||||
{
|
||||
|
||||
class AlertLayerOldImpl;
|
||||
|
||||
class AlertLayerOld
|
||||
{
|
||||
public:
|
||||
explicit AlertLayerOld(std::shared_ptr<MapContext> context);
|
||||
~AlertLayerOld();
|
||||
|
||||
std::vector<std::string> AddLayers(awips::Phenomenon phenomenon,
|
||||
const std::string& before = {});
|
||||
|
||||
private:
|
||||
std::unique_ptr<AlertLayerOldImpl> p;
|
||||
};
|
||||
|
||||
} // namespace map
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
#include <scwx/qt/manager/hotkey_manager.hpp>
|
||||
#include <scwx/qt/manager/placefile_manager.hpp>
|
||||
#include <scwx/qt/manager/radar_product_manager.hpp>
|
||||
#include <scwx/qt/map/alert_layer.hpp>
|
||||
#include <scwx/qt/map/alert_layer_old.hpp>
|
||||
#include <scwx/qt/map/color_table_layer.hpp>
|
||||
#include <scwx/qt/map/layer_wrapper.hpp>
|
||||
#include <scwx/qt/map/map_provider.hpp>
|
||||
|
|
@ -79,7 +79,7 @@ public:
|
|||
imGuiRendererInitialized_ {false},
|
||||
radarProductManager_ {nullptr},
|
||||
radarProductLayer_ {nullptr},
|
||||
alertLayer_ {std::make_shared<AlertLayer>(context_)},
|
||||
alertLayer_ {std::make_shared<AlertLayerOld>(context_)},
|
||||
overlayLayer_ {nullptr},
|
||||
placefileLayer_ {nullptr},
|
||||
colorTableLayer_ {nullptr},
|
||||
|
|
@ -218,7 +218,7 @@ public:
|
|||
std::shared_ptr<manager::RadarProductManager> radarProductManager_;
|
||||
|
||||
std::shared_ptr<RadarProductLayer> radarProductLayer_;
|
||||
std::shared_ptr<AlertLayer> alertLayer_;
|
||||
std::shared_ptr<AlertLayerOld> alertLayer_;
|
||||
std::shared_ptr<OverlayLayer> overlayLayer_;
|
||||
std::shared_ptr<OverlayProductLayer> overlayProductLayer_ {nullptr};
|
||||
std::shared_ptr<PlacefileLayer> placefileLayer_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue