From 951710dcfe12b441005cb1d0273ffd502b7ed71b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 5 Nov 2021 22:58:53 -0500 Subject: [PATCH] Allow selection of different level 2 products --- scwx-qt/source/scwx/qt/main/main_window.cpp | 51 +++++++++++++++- scwx-qt/source/scwx/qt/main/main_window.hpp | 5 +- scwx-qt/source/scwx/qt/map/map_widget.cpp | 60 +++++++++++++++---- scwx-qt/source/scwx/qt/map/map_widget.hpp | 4 ++ .../scwx/qt/view/level2_product_view.cpp | 57 ++++++++++++------ .../scwx/qt/view/level2_product_view.hpp | 13 +--- .../qt/view/radar_product_view_factory.cpp | 35 +++++++---- .../qt/view/radar_product_view_factory.hpp | 7 ++- .../scwx/wsr88d/rda/digital_radar_data.cpp | 2 +- 9 files changed, 174 insertions(+), 60 deletions(-) diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index b2e04284..ddb2cdb7 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -18,8 +18,22 @@ namespace main static const std::string logPrefix_ = "[scwx::qt::main::main_window] "; +class MainWindowImpl +{ +public: + explicit MainWindowImpl(MainWindow* mainWindow) : mainWindow_(mainWindow) {} + ~MainWindowImpl() = default; + + void SelectRadarProduct(common::Level2Product product); + + MainWindow* mainWindow_; + map::MapWidget* map_; +}; + MainWindow::MainWindow(QWidget* parent) : - QMainWindow(parent), ui(new Ui::MainWindow) + QMainWindow(parent), + p(std::make_unique(this)), + ui(new Ui::MainWindow) { ui->setupUi(this); @@ -27,9 +41,11 @@ MainWindow::MainWindow(QWidget* parent) : settings.setCacheDatabasePath("/tmp/mbgl-cache.db"); settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024); - ui->centralwidget->layout()->addWidget(new map::MapWidget(settings)); + p->map_ = new map::MapWidget(settings); - // Add Level2 Products + ui->centralwidget->layout()->addWidget(p->map_); + + // Add Level 2 Products QLayout* level2Layout = new ui::FlowLayout(); ui->level2Products->setLayout(level2Layout); @@ -41,6 +57,10 @@ MainWindow::MainWindow(QWidget* parent) : toolButton->setStatusTip( tr(common::GetLevel2Description(product).c_str())); level2Layout->addWidget(toolButton); + + connect(toolButton, &QToolButton::clicked, this, [=]() { + p->SelectRadarProduct(product); + }); } } @@ -76,6 +96,31 @@ void MainWindow::showEvent(QShowEvent* event) resizeDocks({ui->radarToolboxDock}, {150}, Qt::Horizontal); } +void MainWindowImpl::SelectRadarProduct(common::Level2Product product) +{ + const std::string& productName = common::GetLevel2Name(product); + + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Selecting Level 2 radar product: " << productName; + + for (QToolButton* toolButton : + mainWindow_->ui->level2Products->findChildren()) + { + if (toolButton->text().toStdString() == productName) + { + toolButton->setCheckable(true); + toolButton->setChecked(true); + } + else + { + toolButton->setChecked(false); + toolButton->setCheckable(false); + } + } + + map_->SelectRadarProduct(product); +} + } // namespace main } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/main/main_window.hpp b/scwx-qt/source/scwx/qt/main/main_window.hpp index 8073b51e..7510ca9a 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.hpp +++ b/scwx-qt/source/scwx/qt/main/main_window.hpp @@ -20,6 +20,8 @@ class MainWindow : public QMainWindow { Q_OBJECT + friend class MainWindowImpl; + public: MainWindow(QWidget* parent = nullptr); ~MainWindow(); @@ -27,7 +29,8 @@ public: void showEvent(QShowEvent* event) override; private: - Ui::MainWindow* ui; + std::unique_ptr p; + Ui::MainWindow* ui; }; } // namespace main diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 51549933..4f8f3109 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -44,6 +44,9 @@ public: settings_(settings), map_(), radarProductManager_ {std::make_shared()}, + radarProductLayer_ {nullptr}, + radarProductView_ {nullptr}, + overlayLayer_ {nullptr}, lastPos_(), frameDraws_(0) { @@ -57,6 +60,11 @@ public: std::shared_ptr radarProductManager_; + std::shared_ptr colorTable_; + std::shared_ptr radarProductView_; + std::shared_ptr radarProductLayer_; + std::shared_ptr overlayLayer_; + QPointF lastPos_; uint64_t frameDraws_; @@ -73,6 +81,8 @@ MapWidget::MapWidget(const QMapboxGLSettings& settings) : { p->radarProductManager_->LoadLevel2Data(ar2vFile.toUtf8().constData()); } + + SelectRadarProduct(common::Level2Product::Reflectivity); } MapWidget::~MapWidget() @@ -82,6 +92,27 @@ MapWidget::~MapWidget() makeCurrent(); } +void MapWidget::SelectRadarProduct(common::Level2Product product) +{ + p->radarProductView_ = + view::RadarProductViewFactory::Create(product, p->radarProductManager_); + + p->radarProductView_->Initialize(); + + QString colorTableFile = qgetenv("COLOR_TABLE"); + if (!colorTableFile.isEmpty()) + { + std::shared_ptr colorTable = + common::ColorTable::Load(colorTableFile.toUtf8().constData()); + p->radarProductView_->LoadColorTable(colorTable); + } + + if (p->map_ != nullptr) + { + AddLayers(); + } +} + qreal MapWidget::pixelRatio() { return devicePixelRatioF(); @@ -105,24 +136,29 @@ void MapWidget::changeStyle() void MapWidget::AddLayers() { - std::shared_ptr radarProductView = - view::RadarProductViewFactory::Create("L2REF", p->radarProductManager_); - - radarProductView->Initialize(); - - QString colorTableFile = qgetenv("COLOR_TABLE"); - if (!colorTableFile.isEmpty()) + // TODO: Improve this + if (p->map_->layerExists("rangeCircleLayer")) { - std::shared_ptr colorTable = - common::ColorTable::Load(colorTableFile.toUtf8().constData()); - radarProductView->LoadColorTable(colorTable); + p->map_->removeLayer("rangeCircleLayer"); + } + if (p->map_->sourceExists("rangeCircleSource")) + { + p->map_->removeSource("rangeCircleSource"); + } + if (p->map_->layerExists("radar")) + { + p->map_->removeLayer("radar"); + } + if (p->map_->layerExists("overlay")) + { + p->map_->removeLayer("overlay"); } // QMapboxGL::addCustomLayer will take ownership of the QScopedPointer QScopedPointer pHost( - new RadarProductLayer(radarProductView, p->gl_)); + new RadarProductLayer(p->radarProductView_, p->gl_)); QScopedPointer pOverlayHost( - new OverlayLayer(radarProductView, p->gl_)); + new OverlayLayer(p->radarProductView_, p->gl_)); QString before = "ferry"; diff --git a/scwx-qt/source/scwx/qt/map/map_widget.hpp b/scwx-qt/source/scwx/qt/map/map_widget.hpp index af176e6f..8bcff99c 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.hpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -29,6 +31,8 @@ public: explicit MapWidget(const QMapboxGLSettings&); ~MapWidget(); + void SelectRadarProduct(common::Level2Product product); + private: void changeStyle(); qreal pixelRatio(); diff --git a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp index aa6d6b4f..6047f943 100644 --- a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp +++ b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp @@ -17,14 +17,22 @@ static const std::string logPrefix_ = "[scwx::qt::view::level2_product_view] "; static constexpr uint32_t VERTICES_PER_BIN = 6; static constexpr uint32_t VALUES_PER_VERTEX = 2; -static const std::unordered_map - blockTypes_ {{PRODUCT_L2_REF, wsr88d::rda::DataBlockType::MomentRef}, - {PRODUCT_L2_VEL, wsr88d::rda::DataBlockType::MomentVel}, - {PRODUCT_L2_SW, wsr88d::rda::DataBlockType::MomentSw}, - {PRODUCT_L2_ZDR, wsr88d::rda::DataBlockType::MomentZdr}, - {PRODUCT_L2_PHI, wsr88d::rda::DataBlockType::MomentPhi}, - {PRODUCT_L2_RHO, wsr88d::rda::DataBlockType::MomentRho}, - {PRODUCT_L2_CFP, wsr88d::rda::DataBlockType::MomentCfp}}; +static const std::unordered_map + blockTypes_ { + {common::Level2Product::Reflectivity, + wsr88d::rda::DataBlockType::MomentRef}, + {common::Level2Product::Velocity, wsr88d::rda::DataBlockType::MomentVel}, + {common::Level2Product::SpectrumWidth, + wsr88d::rda::DataBlockType::MomentSw}, + {common::Level2Product::DifferentialReflectivity, + wsr88d::rda::DataBlockType::MomentZdr}, + {common::Level2Product::DifferentialPhase, + wsr88d::rda::DataBlockType::MomentPhi}, + {common::Level2Product::CorrelationCoefficient, + wsr88d::rda::DataBlockType::MomentRho}, + {common::Level2Product::ClutterFilterPowerRemoved, + wsr88d::rda::DataBlockType::MomentCfp}}; static std::chrono::system_clock::time_point TimePoint(uint16_t modifiedJulianDate, uint32_t milliseconds); @@ -33,11 +41,14 @@ class Level2ProductViewImpl { public: explicit Level2ProductViewImpl( - const std::string& productName, + common::Level2Product product, std::shared_ptr radarProductManager) : - radarProductManager_ {radarProductManager}, sweepTime_ {}, colorTable_ {} + product_ {product}, + radarProductManager_ {radarProductManager}, + sweepTime_ {}, + colorTable_ {} { - auto it = blockTypes_.find(productName); + auto it = blockTypes_.find(product); if (it != blockTypes_.end()) { @@ -45,13 +56,14 @@ public: } else { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Unknown product: \"" << productName << "\""; + BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Unknown product: \"" + << common::GetLevel2Name(product) << "\""; dataBlockType_ = wsr88d::rda::DataBlockType::Unknown; } } ~Level2ProductViewImpl() = default; + common::Level2Product product_; wsr88d::rda::DataBlockType dataBlockType_; std::shared_ptr radarProductManager_; @@ -65,9 +77,9 @@ public: }; Level2ProductView::Level2ProductView( - const std::string& productName, + common::Level2Product product, std::shared_ptr radarProductManager) : - p(std::make_unique(productName, radarProductManager)) + p(std::make_unique(product, radarProductManager)) { connect(radarProductManager.get(), &manager::RadarProductManager::Level2DataLoaded, @@ -169,14 +181,21 @@ void Level2ProductView::ComputeSweep() // TODO: Pick this based on view settings auto radarData = level2Data->radar_data()[0]; + auto momentData0 = radarData[0]->moment_data_block(p->dataBlockType_); + + if (momentData0 == nullptr) + { + BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "No moment data for " + << common::GetLevel2Name(p->product_); + return; + } + p->sweepTime_ = TimePoint(radarData[0]->modified_julian_date(), radarData[0]->collection_time()); // Calculate vertices timer.start(); - auto momentData0 = radarData[0]->moment_data_block(p->dataBlockType_); - // Setup vertex vector std::vector& vertices = p->vertices_; const size_t radials = radarData.size(); @@ -382,10 +401,10 @@ void Level2ProductView::ComputeSweep() } std::shared_ptr Level2ProductView::Create( - const std::string& productName, + common::Level2Product product, std::shared_ptr radarProductManager) { - return std::make_shared(productName, radarProductManager); + return std::make_shared(product, radarProductManager); } static std::chrono::system_clock::time_point diff --git a/scwx-qt/source/scwx/qt/view/level2_product_view.hpp b/scwx-qt/source/scwx/qt/view/level2_product_view.hpp index d9d5e6ac..2ba94ef4 100644 --- a/scwx-qt/source/scwx/qt/view/level2_product_view.hpp +++ b/scwx-qt/source/scwx/qt/view/level2_product_view.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -15,14 +16,6 @@ namespace qt namespace view { -const std::string PRODUCT_L2_REF = "L2REF"; -const std::string PRODUCT_L2_VEL = "L2VEL"; -const std::string PRODUCT_L2_SW = "L2SW"; -const std::string PRODUCT_L2_ZDR = "L2ZDR"; -const std::string PRODUCT_L2_PHI = "L2PHI"; -const std::string PRODUCT_L2_RHO = "L2RHO"; -const std::string PRODUCT_L2_CFP = "L2CFP"; - class Level2ProductViewImpl; class Level2ProductView : public RadarProductView @@ -31,7 +24,7 @@ class Level2ProductView : public RadarProductView public: explicit Level2ProductView( - const std::string& productName, + common::Level2Product product, std::shared_ptr radarProductManager); ~Level2ProductView(); @@ -44,7 +37,7 @@ public: std::tuple GetMomentData() const; static std::shared_ptr - Create(const std::string& productName, + Create(common::Level2Product product, std::shared_ptr radarProductManager); protected slots: diff --git a/scwx-qt/source/scwx/qt/view/radar_product_view_factory.cpp b/scwx-qt/source/scwx/qt/view/radar_product_view_factory.cpp index ac9826ac..437e0a0a 100644 --- a/scwx-qt/source/scwx/qt/view/radar_product_view_factory.cpp +++ b/scwx-qt/source/scwx/qt/view/radar_product_view_factory.cpp @@ -18,34 +18,43 @@ typedef std::function( std::shared_ptr radarProductManager)> CreateRadarProductFunction; -static const std::unordered_map - create_ {{PRODUCT_L2_REF, Level2ProductView::Create}, - {PRODUCT_L2_VEL, Level2ProductView::Create}, - {PRODUCT_L2_SW, Level2ProductView::Create}, - {PRODUCT_L2_ZDR, Level2ProductView::Create}, - {PRODUCT_L2_PHI, Level2ProductView::Create}, - {PRODUCT_L2_RHO, Level2ProductView::Create}, - {PRODUCT_L2_CFP, Level2ProductView::Create}}; - std::shared_ptr RadarProductViewFactory::Create( + const std::string& productGroup, const std::string& productName, std::shared_ptr radarProductManager) { std::shared_ptr view = nullptr; - if (create_.find(productName) == create_.end()) + if (productGroup == "L2") { - BOOST_LOG_TRIVIAL(warning) - << logPrefix_ << "Unknown radar product: " << productName; + common::Level2Product product = common::GetLevel2Product(productName); + + if (product == common::Level2Product::Unknown) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Unknown Level 2 radar product: " << productName; + } + else + { + view = Create(product, radarProductManager); + } } else { - view = create_.at(productName)(productName, radarProductManager); + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Unknown radar product group: " << productGroup; } return view; } +std::shared_ptr RadarProductViewFactory::Create( + common::Level2Product product, + std::shared_ptr radarProductManager) +{ + return Level2ProductView::Create(product, radarProductManager); +} + } // namespace view } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/view/radar_product_view_factory.hpp b/scwx-qt/source/scwx/qt/view/radar_product_view_factory.hpp index 04e6031e..b00dd585 100644 --- a/scwx-qt/source/scwx/qt/view/radar_product_view_factory.hpp +++ b/scwx-qt/source/scwx/qt/view/radar_product_view_factory.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -27,7 +28,11 @@ private: public: static std::shared_ptr - Create(const std::string& productName, + Create(const std::string& productGroup, + const std::string& productName, + std::shared_ptr radarProductManager); + static std::shared_ptr + Create(common::Level2Product product, std::shared_ptr radarProductManager); }; diff --git a/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp b/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp index 0711a4eb..5db471fc 100644 --- a/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp +++ b/wxdata/source/scwx/wsr88d/rda/digital_radar_data.cpp @@ -146,7 +146,7 @@ const void* MomentDataBlock::data_moments() const switch (p->dataWordSize_) { case 8: dataMoments = p->momentGates8_.data(); break; - case 16: dataMoments = p->momentGates8_.data(); break; + case 16: dataMoments = p->momentGates16_.data(); break; default: dataMoments = nullptr; break; }