diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 267da846..10b80f1d 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -650,7 +650,7 @@ void MainWindowImpl::ConfigureMapLayout() { if (maps_.at(mapIndex) == nullptr) { - maps_[mapIndex] = new map::MapWidget(settings_); + maps_[mapIndex] = new map::MapWidget(mapIndex, settings_); } hs->addWidget(maps_[mapIndex]); diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 1df8f2ff..2502567d 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,9 @@ class MapWidgetImpl : public QObject public: explicit MapWidgetImpl(MapWidget* widget, + std::size_t id, const QMapLibreGL::Settings& settings) : + id_ {id}, uuid_ {boost::uuids::random_generator()()}, context_ {std::make_shared()}, widget_ {widget}, @@ -120,9 +123,15 @@ public: threadPool_.join(); } + void AddLayer(types::LayerType type, + types::LayerDescription description, + const std::string& before = {}); void AddLayer(const std::string& id, std::shared_ptr layer, const std::string& before = {}); + void AddLayers(); + void AddPlacefileLayer(const std::string& placefileName, + const std::string& before = "colorTable"); void ConnectSignals(); void ImGuiCheckFonts(); void InitializeNewRadarProductView(const std::string& colorPalette); @@ -133,9 +142,12 @@ public: void RemovePlacefileLayer(const std::string& placefileName); void RunMousePicking(); void SetRadarSite(const std::string& radarSite); + void UpdateLoadedStyle(); void UpdatePlacefileLayers(); bool UpdateStoredMapParameters(); + std::string FindMapSymbologyLayer(); + common::Level2Product GetLevel2ProductOrDefault(const std::string& productName) const; @@ -143,6 +155,7 @@ public: boost::asio::thread_pool threadPool_ {1u}; + std::size_t id_; boost::uuids::uuid uuid_; std::shared_ptr context_; @@ -153,6 +166,9 @@ public: std::shared_ptr map_; std::list layerList_; + QStringList styleLayers_; + types::LayerVector customLayers_; + ImGuiContext* imGuiContext_; std::string imGuiContextName_; bool imGuiRendererInitialized_; @@ -198,8 +214,8 @@ public slots: void Update(); }; -MapWidget::MapWidget(const QMapLibreGL::Settings& settings) : - p(std::make_unique(this, settings)) +MapWidget::MapWidget(std::size_t id, const QMapLibreGL::Settings& settings) : + p(std::make_unique(this, id, settings)) { if (settings::GeneralSettings::Instance().anti_aliasing_enabled().GetValue()) { @@ -590,7 +606,7 @@ void MapWidget::SelectRadarSite(std::shared_ptr radarSite, false); } - AddLayers(); + p->AddLayers(); // TODO: Disable refresh from old site @@ -738,66 +754,154 @@ void MapWidget::changeStyle() Q_EMIT MapStyleChanged(p->currentStyle_->name_); } -void MapWidget::AddLayers() +std::string MapWidgetImpl::FindMapSymbologyLayer() { - logger_->debug("AddLayers()"); + std::string before = "ferry"; + + for (const QString& qlayer : styleLayers_) + { + const std::string layer = qlayer.toStdString(); + + // Draw below layers defined in map style + auto it = std::find_if( + currentStyle_->drawBelow_.cbegin(), + currentStyle_->drawBelow_.cend(), + [&layer](const std::string& styleLayer) -> bool + { + std::regex re {styleLayer, std::regex_constants::icase}; + return std::regex_match(layer, re); + }); + + if (it != currentStyle_->drawBelow_.cend()) + { + before = layer; + break; + } + } + + return before; +} + +void MapWidgetImpl::AddLayers() +{ + logger_->debug("Add Layers"); // Clear custom layers - for (const std::string& id : p->layerList_) + for (const std::string& id : layerList_) { - p->map_->removeLayer(id.c_str()); + map_->removeLayer(id.c_str()); } - p->layerList_.clear(); - p->placefileLayers_.clear(); + layerList_.clear(); + placefileLayers_.clear(); - auto radarProductView = p->context_->radar_product_view(); + // Update custom layer list from model + customLayers_ = model::LayerModel::Instance()->GetLayers(); - if (radarProductView != nullptr) + // Start by drawing layers before any style-defined layers + std::string before = styleLayers_.front().toStdString(); + + // Loop through each custom layer in reverse order + for (auto it = customLayers_.crbegin(); it != customLayers_.crend(); ++it) { - p->radarProductLayer_ = std::make_shared(p->context_); - p->colorTableLayer_ = std::make_shared(p->context_); - - std::shared_ptr radarSite = - p->radarProductManager_->radar_site(); - - const auto& mapStyle = *p->currentStyle_; - - std::string before = "ferry"; - - for (const QString& qlayer : p->map_->layerIds()) + if (it->type_ == types::LayerType::Map) { - const std::string layer = qlayer.toStdString(); - - // Draw below layers defined in map style - auto it = std::find_if( - mapStyle.drawBelow_.cbegin(), - mapStyle.drawBelow_.cend(), - [&layer](const std::string& styleLayer) -> bool - { - std::regex re {styleLayer, std::regex_constants::icase}; - return std::regex_match(layer, re); - }); - - if (it != mapStyle.drawBelow_.cend()) + // Style-defined map layers + switch (std::get(it->description_)) { - before = layer; + // Subsequent layers are drawn underneath the map symbology layer + case types::MapLayer::MapUnderlay: + before = FindMapSymbologyLayer(); + break; + + // Subsequent layers are drawn after all style-defined layers + case types::MapLayer::MapSymbology: + before = ""; + break; + + default: break; } } - - p->AddLayer("radar", p->radarProductLayer_, before); - RadarRangeLayer::Add(p->map_, - radarProductView->range(), - {radarSite->latitude(), radarSite->longitude()}); - p->AddLayer("colorTable", p->colorTableLayer_); + else if (it->displayed_[id_]) + { + // If the layer is displayed for the current map, add it + AddLayer(it->type_, it->description_, before); + } } +} - p->alertLayer_->AddLayers("colorTable"); +void MapWidgetImpl::AddLayer(types::LayerType type, + types::LayerDescription description, + const std::string& before) +{ + std::string layerName = types::GetLayerName(type, description); - p->UpdatePlacefileLayers(); + auto radarProductView = context_->radar_product_view(); - p->overlayLayer_ = std::make_shared(p->context_); - p->AddLayer("overlay", p->overlayLayer_); + if (type == types::LayerType::Radar) + { + // If there is a radar product view, create the radar product layer + if (radarProductView != nullptr) + { + radarProductLayer_ = std::make_shared(context_); + AddLayer(layerName, radarProductLayer_, before); + } + } + else if (type == types::LayerType::Alert) + { + // Add the alert layer for the phenomenon + alertLayer_->AddLayers(std::get(description), before); + } + else if (type == types::LayerType::Placefile) + { + // Add the placefile layer + AddPlacefileLayer(std::get(description), before); + } + else if (type == types::LayerType::Information) + { + switch (std::get(description)) + { + // Create the map overlay layer + case types::InformationLayer::MapOverlay: + overlayLayer_ = std::make_shared(context_); + AddLayer(layerName, overlayLayer_, before); + break; + + // If there is a radar product view, create the color table layer + case types::InformationLayer::ColorTable: + if (radarProductView != nullptr) + { + colorTableLayer_ = std::make_shared(context_); + AddLayer(layerName, colorTableLayer_, before); + } + break; + + default: + break; + } + } + else if (type == types::LayerType::Data) + { + switch (std::get(description)) + { + // If there is a radar product view, create the radar range layer + case types::DataLayer::RadarRange: + if (radarProductView != nullptr) + { + std::shared_ptr radarSite = + radarProductManager_->radar_site(); + RadarRangeLayer::Add( + map_, + radarProductView->range(), + {radarSite->latitude(), radarSite->longitude()}, + QString::fromStdString(before)); + } + break; + + default: + break; + } + } } void MapWidgetImpl::RemovePlacefileLayer(const std::string& placefileName) @@ -841,21 +945,26 @@ void MapWidgetImpl::UpdatePlacefileLayers() // If the layer doesn't exist, create it if (it == placefileLayers_.end()) { - std::shared_ptr placefileLayer = - std::make_shared(context_, placefileName); - placefileLayers_.push_back(placefileLayer); - AddLayer( - GetPlacefileLayerName(placefileName), placefileLayer, "colorTable"); - - // When the layer updates, trigger a map widget update - connect(placefileLayer.get(), - &PlacefileLayer::DataReloaded, - widget_, - [this]() { widget_->update(); }); + AddPlacefileLayer(placefileName); } } } +void MapWidgetImpl::AddPlacefileLayer(const std::string& placefileName, + const std::string& before) +{ + std::shared_ptr placefileLayer = + std::make_shared(context_, placefileName); + placefileLayers_.push_back(placefileLayer); + AddLayer(GetPlacefileLayerName(placefileName), placefileLayer, before); + + // When the layer updates, trigger a map widget update + connect(placefileLayer.get(), + &PlacefileLayer::DataReloaded, + widget_, + [this]() { widget_->update(); }); +} + std::string MapWidgetImpl::GetPlacefileLayerName(const std::string& placefileName) { @@ -1147,7 +1256,8 @@ void MapWidget::mapChanged(QMapLibreGL::Map::MapChange mapChange) switch (mapChange) { case QMapLibreGL::Map::MapChangeDidFinishLoadingStyle: - AddLayers(); + p->UpdateLoadedStyle(); + p->AddLayers(); break; default: @@ -1155,6 +1265,11 @@ void MapWidget::mapChanged(QMapLibreGL::Map::MapChange mapChange) } } +void MapWidgetImpl::UpdateLoadedStyle() +{ + styleLayers_ = map_->layerIds(); +} + void MapWidgetImpl::RadarProductManagerConnect() { if (radarProductManager_ != nullptr) @@ -1265,7 +1380,7 @@ void MapWidgetImpl::InitializeNewRadarProductView( if (map_ != nullptr) { - widget_->AddLayers(); + AddLayers(); } } diff --git a/scwx-qt/source/scwx/qt/map/map_widget.hpp b/scwx-qt/source/scwx/qt/map/map_widget.hpp index d18bec6e..aadf1a8e 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.hpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.hpp @@ -32,7 +32,7 @@ class MapWidget : public QOpenGLWidget Q_OBJECT public: - explicit MapWidget(const QMapLibreGL::Settings&); + explicit MapWidget(std::size_t id, const QMapLibreGL::Settings&); ~MapWidget(); common::Level3ProductCategoryMap GetAvailableLevel3Categories(); @@ -130,8 +130,6 @@ private: void initializeGL() override final; void paintGL() override final; - void AddLayers(); - std::unique_ptr p; friend class MapWidgetImpl;