diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index f0ff3018..3f7a49ed 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -77,6 +77,7 @@ public: void ConfigureMapLayout(); void ConnectMapSignals(); + void ConnectOtherSignals(); void HandleFocusChange(QWidget* focused); void SelectElevation(map::MapWidget* mapWidget, float elevation); void SelectRadarProduct(map::MapWidget* mapWidget, @@ -180,35 +181,7 @@ MainWindow::MainWindow(QWidget* parent) : } p->ConnectMapSignals(); - - connect(qApp, - &QApplication::focusChanged, - this, - [=](QWidget* /*old*/, QWidget* now) { p->HandleFocusChange(now); }); - connect(p->level2ProductsWidget_, - &ui::Level2ProductsWidget::RadarProductSelected, - this, - [&](common::RadarProductGroup group, - const std::string& productName, - int16_t productCode) { - p->SelectRadarProduct( - p->activeMap_, group, productName, productCode); - }); - connect(p->level3ProductsWidget_, - &ui::Level3ProductsWidget::RadarProductSelected, - this, - [&](common::RadarProductGroup group, - const std::string& productName, - int16_t productCode) { - p->SelectRadarProduct( - p->activeMap_, group, productName, productCode); - }); - connect(p->level2SettingsWidget_, - &ui::Level2SettingsWidget::ElevationSelected, - this, - [&](float elevation) - { p->SelectElevation(p->activeMap_, elevation); }); - + p->ConnectOtherSignals(); p->HandleFocusChange(p->activeMap_); } @@ -361,46 +334,87 @@ void MainWindowImpl::ConfigureMapLayout() void MainWindowImpl::ConnectMapSignals() { - std::for_each(maps_.cbegin(), - maps_.cend(), - [&](auto& mapWidget) - { - connect(mapWidget, - &map::MapWidget::MapParametersChanged, - this, - &MainWindowImpl::UpdateMapParameters); + for (const auto& mapWidget : maps_) + { + connect(mapWidget, + &map::MapWidget::MapParametersChanged, + this, + &MainWindowImpl::UpdateMapParameters); + connect( + mapWidget, + &map::MapWidget::MapParametersChanged, + this, + [&](double latitude, double longitude) + { + if (mapWidget == activeMap_) + { + emit mainWindow_->ActiveMapMoved(latitude, longitude); + } + }, + Qt::QueuedConnection); - connect( - mapWidget, - &map::MapWidget::RadarSweepUpdated, - this, - [&]() - { - if (mapWidget == activeMap_) - { - UpdateRadarProductSelection( - mapWidget->GetRadarProductGroup(), - mapWidget->GetRadarProductName()); - UpdateRadarProductSettings(); - UpdateRadarSite(); - UpdateVcp(); - } - }, - Qt::QueuedConnection); + connect( + mapWidget, + &map::MapWidget::RadarSweepUpdated, + this, + [&]() + { + if (mapWidget == activeMap_) + { + UpdateRadarProductSelection(mapWidget->GetRadarProductGroup(), + mapWidget->GetRadarProductName()); + UpdateRadarProductSettings(); + UpdateRadarSite(); + UpdateVcp(); + } + }, + Qt::QueuedConnection); - connect( - mapWidget, - &map::MapWidget::Level3ProductsChanged, - this, - [&]() - { - if (mapWidget == activeMap_) - { - UpdateAvailableLevel3Products(); - } - }, - Qt::QueuedConnection); - }); + connect( + mapWidget, + &map::MapWidget::Level3ProductsChanged, + this, + [&]() + { + if (mapWidget == activeMap_) + { + UpdateAvailableLevel3Products(); + } + }, + Qt::QueuedConnection); + } +} + +void MainWindowImpl::ConnectOtherSignals() +{ + connect(qApp, + &QApplication::focusChanged, + mainWindow_, + [=](QWidget* /*old*/, QWidget* now) { HandleFocusChange(now); }); + connect(level2ProductsWidget_, + &ui::Level2ProductsWidget::RadarProductSelected, + mainWindow_, + [&](common::RadarProductGroup group, + const std::string& productName, + int16_t productCode) { + SelectRadarProduct(activeMap_, group, productName, productCode); + }); + connect(level3ProductsWidget_, + &ui::Level3ProductsWidget::RadarProductSelected, + mainWindow_, + [&](common::RadarProductGroup group, + const std::string& productName, + int16_t productCode) { + SelectRadarProduct(activeMap_, group, productName, productCode); + }); + connect(level2SettingsWidget_, + &ui::Level2SettingsWidget::ElevationSelected, + mainWindow_, + [&](float elevation) { SelectElevation(activeMap_, elevation); }); + connect(mainWindow_, + &MainWindow::ActiveMapMoved, + radarSiteDialog_, + &ui::RadarSiteDialog::HandleMapUpdate); } void MainWindowImpl::HandleFocusChange(QWidget* focused) diff --git a/scwx-qt/source/scwx/qt/main/main_window.hpp b/scwx-qt/source/scwx/qt/main/main_window.hpp index 380a3830..d6d9a034 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.hpp +++ b/scwx-qt/source/scwx/qt/main/main_window.hpp @@ -28,6 +28,9 @@ public: void showEvent(QShowEvent* event) override; +signals: + void ActiveMapMoved(double latitude, double longitude); + private slots: void on_actionOpen_triggered(); void on_actionExit_triggered(); diff --git a/scwx-qt/source/scwx/qt/model/radar_site_model.cpp b/scwx-qt/source/scwx/qt/model/radar_site_model.cpp index 74491cc0..997a9dd3 100644 --- a/scwx-qt/source/scwx/qt/model/radar_site_model.cpp +++ b/scwx-qt/source/scwx/qt/model/radar_site_model.cpp @@ -4,6 +4,10 @@ #include #include +#include + +#include + namespace scwx { namespace qt @@ -14,7 +18,7 @@ namespace model static const std::string logPrefix_ = "scwx::qt::model::radar_site_model"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static constexpr size_t kNumColumns = 7u; +static constexpr size_t kNumColumns = 8u; class RadarSiteModelImpl { @@ -23,6 +27,12 @@ public: ~RadarSiteModelImpl() = default; QList> radarSites_; + + GeographicLib::Geodesic geodesic_; + + std::unordered_map distanceMap_; + scwx::common::DistanceType distanceDisplay_; + scwx::common::Coordinate previousPosition_; }; RadarSiteModel::RadarSiteModel(QObject* parent) : @@ -81,6 +91,26 @@ QVariant RadarSiteModel::data(const QModelIndex& index, int role) const } case 6: return QString::fromStdString(site->type_name()); + case 7: + if (role == Qt::DisplayRole) + { + if (p->distanceDisplay_ == scwx::common::DistanceType::Miles) + { + return QString("%1 mi").arg( + static_cast(p->distanceMap_.at(site->id()) * + scwx::common::kMilesPerMeter)); + } + else + { + return QString("%1 km").arg( + static_cast(p->distanceMap_.at(site->id()) * + scwx::common::kKilometersPerMeter)); + } + } + else + { + return p->distanceMap_.at(site->id()); + } default: break; } @@ -113,6 +143,8 @@ QVariant RadarSiteModel::headerData(int section, return tr("Longitude"); case 6: return tr("Type"); + case 7: + return tr("Distance"); default: break; } @@ -122,7 +154,30 @@ QVariant RadarSiteModel::headerData(int section, return QVariant(); } -RadarSiteModelImpl::RadarSiteModelImpl() : radarSites_ {} +void RadarSiteModel::HandleMapUpdate(double latitude, double longitude) +{ + logger_->trace("Handle map update: {}, {}", latitude, longitude); + + double distanceInMeters; + + for (const auto& site : p->radarSites_) + { + p->geodesic_.Inverse(latitude, + longitude, + site->latitude(), + site->longitude(), + distanceInMeters); + p->distanceMap_[site->id()] = distanceInMeters; + } +} + +RadarSiteModelImpl::RadarSiteModelImpl() : + radarSites_ {}, + geodesic_(GeographicLib::Constants::WGS84_a(), + GeographicLib::Constants::WGS84_f()), + distanceMap_ {}, + distanceDisplay_ {scwx::common::DistanceType::Miles}, + previousPosition_ {} { // Get all loaded radar sites std::vector> radarSites = @@ -131,6 +186,7 @@ RadarSiteModelImpl::RadarSiteModelImpl() : radarSites_ {} // Setup radar site list for (auto& site : radarSites) { + distanceMap_[site->id()] = 0.0; radarSites_.emplace_back(std::move(site)); } } diff --git a/scwx-qt/source/scwx/qt/model/radar_site_model.hpp b/scwx-qt/source/scwx/qt/model/radar_site_model.hpp index dad7a7cc..520be1b7 100644 --- a/scwx-qt/source/scwx/qt/model/radar_site_model.hpp +++ b/scwx-qt/source/scwx/qt/model/radar_site_model.hpp @@ -28,6 +28,8 @@ public: Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + void HandleMapUpdate(double latitude, double longitude); + private: std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/ui/radar_site_dialog.cpp b/scwx-qt/source/scwx/qt/ui/radar_site_dialog.cpp index 79b600a4..8cc3a527 100644 --- a/scwx-qt/source/scwx/qt/ui/radar_site_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/radar_site_dialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -23,7 +24,9 @@ public: explicit RadarSiteDialogImpl(RadarSiteDialog* self) : self_ {self}, radarSiteModel_ {new model::RadarSiteModel(self_)}, - proxyModel_ {new QSortFilterProxyModel(self_)} + proxyModel_ {new QSortFilterProxyModel(self_)}, + mapPosition_ {}, + mapUpdateDeferred_ {false} { proxyModel_->setSourceModel(radarSiteModel_); proxyModel_->setSortRole(common::SortRole); @@ -35,6 +38,9 @@ public: RadarSiteDialog* self_; model::RadarSiteModel* radarSiteModel_; QSortFilterProxyModel* proxyModel_; + + scwx::common::Coordinate mapPosition_; + bool mapUpdateDeferred_; }; RadarSiteDialog::RadarSiteDialog(QWidget* parent) : @@ -63,6 +69,32 @@ RadarSiteDialog::~RadarSiteDialog() delete ui; } +void RadarSiteDialog::showEvent(QShowEvent* event) +{ + if (p->mapUpdateDeferred_) + { + p->radarSiteModel_->HandleMapUpdate(p->mapPosition_.latitude_, + p->mapPosition_.longitude_); + p->mapUpdateDeferred_ = false; + } + + QDialog::showEvent(event); +} + +void RadarSiteDialog::HandleMapUpdate(double latitude, double longitude) +{ + p->mapPosition_ = {latitude, longitude}; + + if (isVisible()) + { + p->radarSiteModel_->HandleMapUpdate(latitude, longitude); + } + else + { + p->mapUpdateDeferred_ = true; + } +} + } // namespace ui } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/radar_site_dialog.hpp b/scwx-qt/source/scwx/qt/ui/radar_site_dialog.hpp index f8b3e5c6..c8ef4cd0 100644 --- a/scwx-qt/source/scwx/qt/ui/radar_site_dialog.hpp +++ b/scwx-qt/source/scwx/qt/ui/radar_site_dialog.hpp @@ -24,6 +24,12 @@ public: explicit RadarSiteDialog(QWidget* parent = nullptr); ~RadarSiteDialog(); +protected: + void showEvent(QShowEvent*) override; + +public slots: + void HandleMapUpdate(double latitude, double longitude); + private: std::unique_ptr p; Ui::RadarSiteDialog* ui; diff --git a/wxdata/include/scwx/common/geographic.hpp b/wxdata/include/scwx/common/geographic.hpp index 71065109..adf0a7f0 100644 --- a/wxdata/include/scwx/common/geographic.hpp +++ b/wxdata/include/scwx/common/geographic.hpp @@ -7,6 +7,9 @@ namespace scwx namespace common { +constexpr double kMilesPerMeter = 0.00062137119; +constexpr double kKilometersPerMeter = 0.001; + /** * @brief Coordinate type to hold latitude and longitude of a location. */ @@ -34,6 +37,12 @@ enum class DegreeStringType DegreesMinutesSeconds }; +enum class DistanceType +{ + Kilometers, + Miles +}; + std::string GetLatitudeString(double latitude, DegreeStringType type = DegreeStringType::Decimal);