mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-11-01 12:50:06 +00:00
Merge pull request #30 from dpaulat/feature/garbage-collect
Feature/garbage collect
This commit is contained in:
commit
a851918ec2
22 changed files with 639 additions and 166 deletions
|
|
@ -357,6 +357,11 @@ void MainWindow::on_actionImGuiDebug_triggered()
|
||||||
p->imGuiDebugDialog_->show();
|
p->imGuiDebugDialog_->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionDumpRadarProductRecords_triggered()
|
||||||
|
{
|
||||||
|
manager::RadarProductManager::DumpRecords();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionUserManual_triggered()
|
void MainWindow::on_actionUserManual_triggered()
|
||||||
{
|
{
|
||||||
QDesktopServices::openUrl(QUrl {"https://supercell-wx.readthedocs.io/"});
|
QDesktopServices::openUrl(QUrl {"https://supercell-wx.readthedocs.io/"});
|
||||||
|
|
@ -392,6 +397,67 @@ void MainWindow::on_resourceTreeExpandAllButton_clicked()
|
||||||
ui->resourceTreeView->expandAll();
|
ui->resourceTreeView->expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_resourceTreeView_doubleClicked(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
std::string selectedString {index.data().toString().toStdString()};
|
||||||
|
std::chrono::system_clock::time_point time {};
|
||||||
|
|
||||||
|
logger_->debug("Selecting resource: {}",
|
||||||
|
index.data().toString().toStdString());
|
||||||
|
|
||||||
|
static const std::string timeFormat {"%Y-%m-%d %H:%M:%S"};
|
||||||
|
|
||||||
|
std::istringstream in {selectedString};
|
||||||
|
in >> std::chrono::parse(timeFormat, time);
|
||||||
|
|
||||||
|
if (in.fail())
|
||||||
|
{
|
||||||
|
// Not a time string, ignore double-click
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex parent1 = index.parent();
|
||||||
|
QModelIndex parent2 = parent1.parent();
|
||||||
|
QModelIndex parent3 = parent2.parent();
|
||||||
|
|
||||||
|
std::string radarSite {};
|
||||||
|
std::string groupName {};
|
||||||
|
std::string product {};
|
||||||
|
|
||||||
|
if (!parent2.isValid())
|
||||||
|
{
|
||||||
|
// A time entry should be at the third or fourth level
|
||||||
|
logger_->error("Unexpected resource data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent3.isValid())
|
||||||
|
{
|
||||||
|
// Level 3 Product
|
||||||
|
radarSite = parent3.data().toString().toStdString();
|
||||||
|
groupName = parent2.data().toString().toStdString();
|
||||||
|
product = parent1.data().toString().toStdString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Level 2 Product
|
||||||
|
radarSite = parent2.data().toString().toStdString();
|
||||||
|
groupName = parent1.data().toString().toStdString();
|
||||||
|
// No product index
|
||||||
|
}
|
||||||
|
|
||||||
|
common::RadarProductGroup group = common::GetRadarProductGroup(groupName);
|
||||||
|
|
||||||
|
// Update radar site if different from currently selected
|
||||||
|
if (p->activeMap_->GetRadarSite()->id() != radarSite)
|
||||||
|
{
|
||||||
|
p->activeMap_->SelectRadarSite(radarSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the updated radar product
|
||||||
|
p->activeMap_->SelectRadarProduct(group, product, 0, time);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindowImpl::ConfigureMapLayout()
|
void MainWindowImpl::ConfigureMapLayout()
|
||||||
{
|
{
|
||||||
auto& generalSettings = manager::SettingsManager::general_settings();
|
auto& generalSettings = manager::SettingsManager::general_settings();
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ private slots:
|
||||||
void on_actionSettings_triggered();
|
void on_actionSettings_triggered();
|
||||||
void on_actionExit_triggered();
|
void on_actionExit_triggered();
|
||||||
void on_actionImGuiDebug_triggered();
|
void on_actionImGuiDebug_triggered();
|
||||||
|
void on_actionDumpRadarProductRecords_triggered();
|
||||||
void on_actionUserManual_triggered();
|
void on_actionUserManual_triggered();
|
||||||
void on_actionDiscord_triggered();
|
void on_actionDiscord_triggered();
|
||||||
void on_actionGitHubRepository_triggered();
|
void on_actionGitHubRepository_triggered();
|
||||||
|
|
@ -44,6 +45,7 @@ private slots:
|
||||||
void on_radarSiteSelectButton_clicked();
|
void on_radarSiteSelectButton_clicked();
|
||||||
void on_resourceTreeCollapseAllButton_clicked();
|
void on_resourceTreeCollapseAllButton_clicked();
|
||||||
void on_resourceTreeExpandAllButton_clicked();
|
void on_resourceTreeExpandAllButton_clicked();
|
||||||
|
void on_resourceTreeView_doubleClicked(const QModelIndex& index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<MainWindowImpl> p;
|
std::unique_ptr<MainWindowImpl> p;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@
|
||||||
<string>&Debug</string>
|
<string>&Debug</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionImGuiDebug"/>
|
<addaction name="actionImGuiDebug"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionDumpRadarProductRecords"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuView"/>
|
<addaction name="menuView"/>
|
||||||
|
|
@ -397,6 +399,11 @@
|
||||||
<string>&GitHub Repository</string>
|
<string>&GitHub Repository</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionDumpRadarProductRecords">
|
||||||
|
<property name="text">
|
||||||
|
<string>Dump Radar &Product Records</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../scwx-qt.qrc"/>
|
<include location="../../../../scwx-qt.qrc"/>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#pragma warning(push, 0)
|
#pragma warning(push, 0)
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
#include <boost/range/irange.hpp>
|
#include <boost/range/irange.hpp>
|
||||||
#include <boost/timer/timer.hpp>
|
#include <boost/timer/timer.hpp>
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
|
|
@ -36,8 +37,10 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
typedef std::function<std::shared_ptr<wsr88d::NexradFile>()>
|
typedef std::function<std::shared_ptr<wsr88d::NexradFile>()>
|
||||||
CreateNexradFileFunction;
|
CreateNexradFileFunction;
|
||||||
typedef std::map<std::chrono::system_clock::time_point,
|
typedef std::map<std::chrono::system_clock::time_point,
|
||||||
std::shared_ptr<types::RadarProductRecord>>
|
std::weak_ptr<types::RadarProductRecord>>
|
||||||
RadarProductRecordMap;
|
RadarProductRecordMap;
|
||||||
|
typedef std::list<std::shared_ptr<types::RadarProductRecord>>
|
||||||
|
RadarProductRecordList;
|
||||||
|
|
||||||
static constexpr uint32_t NUM_RADIAL_GATES_0_5_DEGREE =
|
static constexpr uint32_t NUM_RADIAL_GATES_0_5_DEGREE =
|
||||||
common::MAX_0_5_DEGREE_RADIALS * common::MAX_DATA_MOMENT_GATES;
|
common::MAX_0_5_DEGREE_RADIALS * common::MAX_DATA_MOMENT_GATES;
|
||||||
|
|
@ -54,7 +57,7 @@ static constexpr std::chrono::seconds kRetryInterval_ {15};
|
||||||
|
|
||||||
static std::unordered_map<std::string, std::weak_ptr<RadarProductManager>>
|
static std::unordered_map<std::string, std::weak_ptr<RadarProductManager>>
|
||||||
instanceMap_;
|
instanceMap_;
|
||||||
static std::mutex instanceMutex_;
|
static std::shared_mutex instanceMutex_;
|
||||||
|
|
||||||
static std::unordered_map<std::string,
|
static std::unordered_map<std::string,
|
||||||
std::shared_ptr<types::RadarProductRecord>>
|
std::shared_ptr<types::RadarProductRecord>>
|
||||||
|
|
@ -123,7 +126,9 @@ public:
|
||||||
coordinates0_5Degree_ {},
|
coordinates0_5Degree_ {},
|
||||||
coordinates1Degree_ {},
|
coordinates1Degree_ {},
|
||||||
level2ProductRecords_ {},
|
level2ProductRecords_ {},
|
||||||
|
level2ProductRecentRecords_ {},
|
||||||
level3ProductRecordsMap_ {},
|
level3ProductRecordsMap_ {},
|
||||||
|
level3ProductRecentRecordsMap_ {},
|
||||||
level2ProductRecordMutex_ {},
|
level2ProductRecordMutex_ {},
|
||||||
level3ProductRecordMutex_ {},
|
level3ProductRecordMutex_ {},
|
||||||
level2ProviderManager_ {std::make_shared<ProviderManager>(
|
level2ProviderManager_ {std::make_shared<ProviderManager>(
|
||||||
|
|
@ -159,6 +164,10 @@ public:
|
||||||
auto& [key, providerManager] = p;
|
auto& [key, providerManager] = p;
|
||||||
providerManager->Disable();
|
providerManager->Disable();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Lock other mutexes before destroying, ensure loading is complete
|
||||||
|
std::unique_lock loadLevel2DataLock {loadLevel2DataMutex_};
|
||||||
|
std::unique_lock loadLevel3DataLock {loadLevel3DataMutex_};
|
||||||
}
|
}
|
||||||
|
|
||||||
RadarProductManager* self_;
|
RadarProductManager* self_;
|
||||||
|
|
@ -166,17 +175,22 @@ public:
|
||||||
std::shared_ptr<ProviderManager>
|
std::shared_ptr<ProviderManager>
|
||||||
GetLevel3ProviderManager(const std::string& product);
|
GetLevel3ProviderManager(const std::string& product);
|
||||||
|
|
||||||
void EnableRefresh(std::shared_ptr<ProviderManager> providerManager,
|
void EnableRefresh(boost::uuids::uuid uuid,
|
||||||
|
std::shared_ptr<ProviderManager> providerManager,
|
||||||
bool enabled);
|
bool enabled);
|
||||||
void RefreshData(std::shared_ptr<ProviderManager> providerManager);
|
void RefreshData(std::shared_ptr<ProviderManager> providerManager);
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
GetLevel2ProductRecord(std::chrono::system_clock::time_point time);
|
GetLevel2ProductRecord(std::chrono::system_clock::time_point time);
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
GetLevel3ProductRecord(const std::string& product,
|
GetLevel3ProductRecord(const std::string& product,
|
||||||
std::chrono::system_clock::time_point time);
|
std::chrono::system_clock::time_point time);
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::shared_ptr<types::RadarProductRecord>
|
||||||
StoreRadarProductRecord(std::shared_ptr<types::RadarProductRecord> record);
|
StoreRadarProductRecord(std::shared_ptr<types::RadarProductRecord> record);
|
||||||
|
void UpdateRecentRecords(RadarProductRecordList& recentList,
|
||||||
|
std::shared_ptr<types::RadarProductRecord> record);
|
||||||
|
|
||||||
void LoadProviderData(std::chrono::system_clock::time_point time,
|
void LoadProviderData(std::chrono::system_clock::time_point time,
|
||||||
std::shared_ptr<ProviderManager> providerManager,
|
std::shared_ptr<ProviderManager> providerManager,
|
||||||
|
|
@ -200,9 +214,11 @@ public:
|
||||||
std::vector<float> coordinates1Degree_;
|
std::vector<float> coordinates1Degree_;
|
||||||
|
|
||||||
RadarProductRecordMap level2ProductRecords_;
|
RadarProductRecordMap level2ProductRecords_;
|
||||||
|
RadarProductRecordList level2ProductRecentRecords_;
|
||||||
std::unordered_map<std::string, RadarProductRecordMap>
|
std::unordered_map<std::string, RadarProductRecordMap>
|
||||||
level3ProductRecordsMap_;
|
level3ProductRecordsMap_;
|
||||||
|
std::unordered_map<std::string, RadarProductRecordList>
|
||||||
|
level3ProductRecentRecordsMap_;
|
||||||
std::shared_mutex level2ProductRecordMutex_;
|
std::shared_mutex level2ProductRecordMutex_;
|
||||||
std::shared_mutex level3ProductRecordMutex_;
|
std::shared_mutex level3ProductRecordMutex_;
|
||||||
|
|
||||||
|
|
@ -218,6 +234,12 @@ public:
|
||||||
|
|
||||||
common::Level3ProductCategoryMap availableCategoryMap_;
|
common::Level3ProductCategoryMap availableCategoryMap_;
|
||||||
std::shared_mutex availableCategoryMutex_;
|
std::shared_mutex availableCategoryMutex_;
|
||||||
|
|
||||||
|
std::unordered_map<boost::uuids::uuid,
|
||||||
|
std::shared_ptr<ProviderManager>,
|
||||||
|
boost::hash<boost::uuids::uuid>>
|
||||||
|
refreshMap_ {};
|
||||||
|
std::mutex refreshMapMutex_ {};
|
||||||
};
|
};
|
||||||
|
|
||||||
RadarProductManager::RadarProductManager(const std::string& radarId) :
|
RadarProductManager::RadarProductManager(const std::string& radarId) :
|
||||||
|
|
@ -248,6 +270,8 @@ std::string ProviderManager::name() const
|
||||||
|
|
||||||
void ProviderManager::Disable()
|
void ProviderManager::Disable()
|
||||||
{
|
{
|
||||||
|
logger_->debug("Disabling refresh: {}", name());
|
||||||
|
|
||||||
std::unique_lock lock(refreshTimerMutex_);
|
std::unique_lock lock(refreshTimerMutex_);
|
||||||
refreshEnabled_ = false;
|
refreshEnabled_ = false;
|
||||||
refreshTimer_.cancel();
|
refreshTimer_.cancel();
|
||||||
|
|
@ -266,6 +290,61 @@ void RadarProductManager::Cleanup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RadarProductManager::DumpRecords()
|
||||||
|
{
|
||||||
|
scwx::util::async(
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
logger_->info("Record Dump");
|
||||||
|
|
||||||
|
std::shared_lock instanceLock {instanceMutex_};
|
||||||
|
for (auto& instance : instanceMap_)
|
||||||
|
{
|
||||||
|
auto radarProductManager = instance.second.lock();
|
||||||
|
if (radarProductManager != nullptr)
|
||||||
|
{
|
||||||
|
logger_->info(" {}", radarProductManager->radar_site()->id());
|
||||||
|
logger_->info(" Level 2");
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_lock level2ProductLock {
|
||||||
|
radarProductManager->p->level2ProductRecordMutex_};
|
||||||
|
|
||||||
|
for (auto& record :
|
||||||
|
radarProductManager->p->level2ProductRecords_)
|
||||||
|
{
|
||||||
|
logger_->info(" {}{}",
|
||||||
|
scwx::util::TimeString(record.first),
|
||||||
|
record.second.expired() ? " (expired)" : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger_->info(" Level 3");
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_lock level3ProductLock {
|
||||||
|
radarProductManager->p->level3ProductRecordMutex_};
|
||||||
|
|
||||||
|
for (auto& recordMap :
|
||||||
|
radarProductManager->p->level3ProductRecordsMap_)
|
||||||
|
{
|
||||||
|
// Product Name
|
||||||
|
logger_->info(" {}", recordMap.first);
|
||||||
|
|
||||||
|
for (auto& record : recordMap.second)
|
||||||
|
{
|
||||||
|
logger_->info(" {}{}",
|
||||||
|
scwx::util::TimeString(record.first),
|
||||||
|
record.second.expired() ? " (expired)" :
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<float>&
|
const std::vector<float>&
|
||||||
RadarProductManager::coordinates(common::RadialSize radialSize) const
|
RadarProductManager::coordinates(common::RadialSize radialSize) const
|
||||||
{
|
{
|
||||||
|
|
@ -413,11 +492,12 @@ RadarProductManagerImpl::GetLevel3ProviderManager(const std::string& product)
|
||||||
|
|
||||||
void RadarProductManager::EnableRefresh(common::RadarProductGroup group,
|
void RadarProductManager::EnableRefresh(common::RadarProductGroup group,
|
||||||
const std::string& product,
|
const std::string& product,
|
||||||
bool enabled)
|
bool enabled,
|
||||||
|
boost::uuids::uuid uuid)
|
||||||
{
|
{
|
||||||
if (group == common::RadarProductGroup::Level2)
|
if (group == common::RadarProductGroup::Level2)
|
||||||
{
|
{
|
||||||
p->EnableRefresh(p->level2ProviderManager_, enabled);
|
p->EnableRefresh(uuid, p->level2ProviderManager_, enabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -437,16 +517,65 @@ void RadarProductManager::EnableRefresh(common::RadarProductGroup group,
|
||||||
availableProducts.cend(),
|
availableProducts.cend(),
|
||||||
product) != availableProducts.cend())
|
product) != availableProducts.cend())
|
||||||
{
|
{
|
||||||
p->EnableRefresh(providerManager, enabled);
|
p->EnableRefresh(uuid, providerManager, enabled);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadarProductManagerImpl::EnableRefresh(
|
void RadarProductManagerImpl::EnableRefresh(
|
||||||
std::shared_ptr<ProviderManager> providerManager, bool enabled)
|
boost::uuids::uuid uuid,
|
||||||
|
std::shared_ptr<ProviderManager> providerManager,
|
||||||
|
bool enabled)
|
||||||
{
|
{
|
||||||
if (providerManager->refreshEnabled_ != enabled)
|
// Lock the refresh map
|
||||||
|
std::unique_lock lock {refreshMapMutex_};
|
||||||
|
|
||||||
|
auto currentProviderManager = refreshMap_.find(uuid);
|
||||||
|
if (currentProviderManager != refreshMap_.cend())
|
||||||
|
{
|
||||||
|
// If the enabling refresh for a different product, or disabling refresh
|
||||||
|
if (currentProviderManager->second != providerManager || !enabled)
|
||||||
|
{
|
||||||
|
// Determine number of entries in the map for the current provider
|
||||||
|
// manager
|
||||||
|
auto currentProviderManagerCount = std::count_if(
|
||||||
|
refreshMap_.cbegin(),
|
||||||
|
refreshMap_.cend(),
|
||||||
|
[&](const auto& provider)
|
||||||
|
{ return provider.second == currentProviderManager->second; });
|
||||||
|
|
||||||
|
// If this is the last reference to the provider in the refresh map
|
||||||
|
if (currentProviderManagerCount == 1)
|
||||||
|
{
|
||||||
|
// Disable current provider
|
||||||
|
currentProviderManager->second->Disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dissociate uuid from current provider manager
|
||||||
|
refreshMap_.erase(currentProviderManager);
|
||||||
|
|
||||||
|
// If we are enabling a new provider manager
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
// Associate uuid to providerManager
|
||||||
|
refreshMap_.emplace(uuid, providerManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (enabled)
|
||||||
|
{
|
||||||
|
// We are enabling a new provider manager
|
||||||
|
// Associate uuid to provider manager
|
||||||
|
refreshMap_.emplace(uuid, providerManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the refresh map mutex
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
// We have already handled a disable request by this point. If enabling, and
|
||||||
|
// the provider manager refresh isn't already enabled, enable it.
|
||||||
|
if (enabled && providerManager->refreshEnabled_ != enabled)
|
||||||
{
|
{
|
||||||
providerManager->refreshEnabled_ = enabled;
|
providerManager->refreshEnabled_ = enabled;
|
||||||
|
|
||||||
|
|
@ -475,7 +604,7 @@ void RadarProductManagerImpl::RefreshData(
|
||||||
|
|
||||||
std::chrono::milliseconds interval = kRetryInterval_;
|
std::chrono::milliseconds interval = kRetryInterval_;
|
||||||
|
|
||||||
if (newObjects > 0)
|
if (totalObjects > 0)
|
||||||
{
|
{
|
||||||
std::string key = providerManager->provider_->FindLatestKey();
|
std::string key = providerManager->provider_->FindLatestKey();
|
||||||
auto latestTime =
|
auto latestTime =
|
||||||
|
|
@ -491,10 +620,14 @@ void RadarProductManagerImpl::RefreshData(
|
||||||
interval = kRetryInterval_;
|
interval = kRetryInterval_;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit providerManager->NewDataAvailable(
|
if (newObjects > 0)
|
||||||
providerManager->group_, providerManager->product_, latestTime);
|
{
|
||||||
|
emit providerManager->NewDataAvailable(providerManager->group_,
|
||||||
|
providerManager->product_,
|
||||||
|
latestTime);
|
||||||
}
|
}
|
||||||
else if (providerManager->refreshEnabled_ && totalObjects == 0)
|
}
|
||||||
|
else if (providerManager->refreshEnabled_)
|
||||||
{
|
{
|
||||||
logger_->info("[{}] No data found, disabling refresh",
|
logger_->info("[{}] No data found, disabling refresh",
|
||||||
providerManager->name());
|
providerManager->name());
|
||||||
|
|
@ -561,11 +694,14 @@ void RadarProductManagerImpl::LoadProviderData(
|
||||||
|
|
||||||
auto it = recordMap.find(time);
|
auto it = recordMap.find(time);
|
||||||
if (it != recordMap.cend())
|
if (it != recordMap.cend())
|
||||||
|
{
|
||||||
|
existingRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (existingRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Data previously loaded, loading from data cache");
|
"Data previously loaded, loading from data cache");
|
||||||
|
}
|
||||||
existingRecord = it->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -727,38 +863,70 @@ void RadarProductManagerImpl::LoadNexradFile(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
RadarProductManagerImpl::GetLevel2ProductRecord(
|
RadarProductManagerImpl::GetLevel2ProductRecord(
|
||||||
std::chrono::system_clock::time_point time)
|
std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
std::shared_ptr<types::RadarProductRecord> record;
|
std::shared_ptr<types::RadarProductRecord> record {nullptr};
|
||||||
|
RadarProductRecordMap::const_pointer recordPtr {nullptr};
|
||||||
|
std::chrono::system_clock::time_point recordTime {time};
|
||||||
|
|
||||||
if (!level2ProductRecords_.empty() &&
|
if (!level2ProductRecords_.empty() &&
|
||||||
time == std::chrono::system_clock::time_point {})
|
time == std::chrono::system_clock::time_point {})
|
||||||
{
|
{
|
||||||
// If a default-initialized time point is given, return the latest record
|
// If a default-initialized time point is given, return the latest record
|
||||||
record = level2ProductRecords_.rbegin()->second;
|
recordPtr = &(*level2ProductRecords_.rbegin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Round to minutes
|
recordPtr =
|
||||||
record = scwx::util::GetBoundedElementValue(level2ProductRecords_, time);
|
scwx::util::GetBoundedElementPointer(level2ProductRecords_, time);
|
||||||
|
}
|
||||||
|
|
||||||
// Does the record contain the time we are looking for?
|
if (recordPtr != nullptr)
|
||||||
if (record != nullptr && (time < record->level2_file()->start_time()))
|
|
||||||
{
|
{
|
||||||
record = nullptr;
|
if (time == std::chrono::system_clock::time_point {} ||
|
||||||
|
time == recordPtr->first)
|
||||||
|
{
|
||||||
|
recordTime = recordPtr->first;
|
||||||
|
record = recordPtr->second.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
if (record == nullptr &&
|
||||||
|
recordTime != std::chrono::system_clock::time_point {})
|
||||||
|
{
|
||||||
|
// Product is expired, reload it
|
||||||
|
std::shared_ptr<request::NexradFileRequest> request =
|
||||||
|
std::make_shared<request::NexradFileRequest>();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
request.get(),
|
||||||
|
&request::NexradFileRequest::RequestComplete,
|
||||||
|
self_,
|
||||||
|
[this](std::shared_ptr<request::NexradFileRequest> request)
|
||||||
|
{
|
||||||
|
if (request->radar_product_record() != nullptr)
|
||||||
|
{
|
||||||
|
emit self_->DataReloaded(request->radar_product_record());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self_->LoadLevel2Data(recordTime, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {record, recordTime};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
RadarProductManagerImpl::GetLevel3ProductRecord(
|
RadarProductManagerImpl::GetLevel3ProductRecord(
|
||||||
const std::string& product, std::chrono::system_clock::time_point time)
|
const std::string& product, std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
std::shared_ptr<types::RadarProductRecord> record = nullptr;
|
std::shared_ptr<types::RadarProductRecord> record {nullptr};
|
||||||
|
RadarProductRecordMap::const_pointer recordPtr {nullptr};
|
||||||
|
std::chrono::system_clock::time_point recordTime {time};
|
||||||
|
|
||||||
std::unique_lock lock {level3ProductRecordMutex_};
|
std::unique_lock lock {level3ProductRecordMutex_};
|
||||||
|
|
||||||
|
|
@ -770,15 +938,50 @@ RadarProductManagerImpl::GetLevel3ProductRecord(
|
||||||
{
|
{
|
||||||
// If a default-initialized time point is given, return the latest
|
// If a default-initialized time point is given, return the latest
|
||||||
// record
|
// record
|
||||||
record = it->second.rbegin()->second;
|
recordPtr = &(*it->second.rbegin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
record = scwx::util::GetBoundedElementValue(it->second, time);
|
recordPtr = scwx::util::GetBoundedElementPointer(it->second, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return record;
|
// Lock is no longer needed
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if (recordPtr != nullptr)
|
||||||
|
{
|
||||||
|
if (time == std::chrono::system_clock::time_point {} ||
|
||||||
|
time == recordPtr->first)
|
||||||
|
{
|
||||||
|
recordTime = recordPtr->first;
|
||||||
|
record = recordPtr->second.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record == nullptr &&
|
||||||
|
recordTime != std::chrono::system_clock::time_point {})
|
||||||
|
{
|
||||||
|
// Product is expired, reload it
|
||||||
|
std::shared_ptr<request::NexradFileRequest> request =
|
||||||
|
std::make_shared<request::NexradFileRequest>();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
request.get(),
|
||||||
|
&request::NexradFileRequest::RequestComplete,
|
||||||
|
self_,
|
||||||
|
[this](std::shared_ptr<request::NexradFileRequest> request)
|
||||||
|
{
|
||||||
|
if (request->radar_product_record() != nullptr)
|
||||||
|
{
|
||||||
|
emit self_->DataReloaded(request->radar_product_record());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self_->LoadLevel3Data(product, recordTime, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {record, recordTime};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord>
|
std::shared_ptr<types::RadarProductRecord>
|
||||||
|
|
@ -787,7 +990,7 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
{
|
{
|
||||||
logger_->debug("StoreRadarProductRecord()");
|
logger_->debug("StoreRadarProductRecord()");
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord> storedRecord = record;
|
std::shared_ptr<types::RadarProductRecord> storedRecord = nullptr;
|
||||||
|
|
||||||
auto timeInSeconds =
|
auto timeInSeconds =
|
||||||
std::chrono::time_point_cast<std::chrono::seconds,
|
std::chrono::time_point_cast<std::chrono::seconds,
|
||||||
|
|
@ -799,16 +1002,23 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
|
|
||||||
auto it = level2ProductRecords_.find(timeInSeconds);
|
auto it = level2ProductRecords_.find(timeInSeconds);
|
||||||
if (it != level2ProductRecords_.cend())
|
if (it != level2ProductRecords_.cend())
|
||||||
|
{
|
||||||
|
storedRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (storedRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Level 2 product previously loaded, loading from cache");
|
"Level 2 product previously loaded, loading from cache");
|
||||||
|
|
||||||
storedRecord = it->second;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (storedRecord == nullptr)
|
||||||
{
|
{
|
||||||
|
storedRecord = record;
|
||||||
level2ProductRecords_[timeInSeconds] = record;
|
level2ProductRecords_[timeInSeconds] = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateRecentRecords(level2ProductRecentRecords_, storedRecord);
|
||||||
}
|
}
|
||||||
else if (record->radar_product_group() == common::RadarProductGroup::Level3)
|
else if (record->radar_product_group() == common::RadarProductGroup::Level3)
|
||||||
{
|
{
|
||||||
|
|
@ -818,24 +1028,59 @@ RadarProductManagerImpl::StoreRadarProductRecord(
|
||||||
|
|
||||||
auto it = productMap.find(timeInSeconds);
|
auto it = productMap.find(timeInSeconds);
|
||||||
if (it != productMap.cend())
|
if (it != productMap.cend())
|
||||||
|
{
|
||||||
|
storedRecord = it->second.lock();
|
||||||
|
|
||||||
|
if (storedRecord != nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug(
|
logger_->debug(
|
||||||
"Level 3 product previously loaded, loading from cache");
|
"Level 3 product previously loaded, loading from cache");
|
||||||
|
|
||||||
storedRecord = it->second;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (storedRecord == nullptr)
|
||||||
{
|
{
|
||||||
|
storedRecord = record;
|
||||||
productMap[timeInSeconds] = record;
|
productMap[timeInSeconds] = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateRecentRecords(
|
||||||
|
level3ProductRecentRecordsMap_[record->radar_product()], storedRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
return storedRecord;
|
return storedRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RadarProductManagerImpl::UpdateRecentRecords(
|
||||||
|
RadarProductRecordList& recentList,
|
||||||
|
std::shared_ptr<types::RadarProductRecord> record)
|
||||||
|
{
|
||||||
|
static constexpr std::size_t kRecentListMaxSize_ {2u};
|
||||||
|
|
||||||
|
auto it = std::find(recentList.cbegin(), recentList.cend(), record);
|
||||||
|
if (it != recentList.cbegin() && it != recentList.cend())
|
||||||
|
{
|
||||||
|
// If the record exists beyond the front of the list, remove it
|
||||||
|
recentList.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recentList.size() == 0 || it != recentList.cbegin())
|
||||||
|
{
|
||||||
|
// Add the record to the front of the list, unless it's already there
|
||||||
|
recentList.push_front(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (recentList.size() > kRecentListMaxSize_)
|
||||||
|
{
|
||||||
|
// Remove from the end of the list while it's too big
|
||||||
|
recentList.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
||||||
float,
|
float,
|
||||||
std::vector<float>>
|
std::vector<float>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
||||||
float elevation,
|
float elevation,
|
||||||
std::chrono::system_clock::time_point time)
|
std::chrono::system_clock::time_point time)
|
||||||
|
|
@ -844,8 +1089,8 @@ RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
||||||
float elevationCut = 0.0f;
|
float elevationCut = 0.0f;
|
||||||
std::vector<float> elevationCuts;
|
std::vector<float> elevationCuts;
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord> record =
|
std::shared_ptr<types::RadarProductRecord> record;
|
||||||
p->GetLevel2ProductRecord(time);
|
std::tie(record, time) = p->GetLevel2ProductRecord(time);
|
||||||
|
|
||||||
if (record != nullptr)
|
if (record != nullptr)
|
||||||
{
|
{
|
||||||
|
|
@ -854,24 +1099,25 @@ RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
||||||
dataBlockType, elevation, time);
|
dataBlockType, elevation, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::tie(radarData, elevationCut, elevationCuts);
|
return {radarData, elevationCut, elevationCuts, time};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<wsr88d::rpg::Level3Message>
|
std::tuple<std::shared_ptr<wsr88d::rpg::Level3Message>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
RadarProductManager::GetLevel3Data(const std::string& product,
|
RadarProductManager::GetLevel3Data(const std::string& product,
|
||||||
std::chrono::system_clock::time_point time)
|
std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
std::shared_ptr<wsr88d::rpg::Level3Message> message = nullptr;
|
std::shared_ptr<wsr88d::rpg::Level3Message> message = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<types::RadarProductRecord> record =
|
std::shared_ptr<types::RadarProductRecord> record;
|
||||||
p->GetLevel3ProductRecord(product, time);
|
std::tie(record, time) = p->GetLevel3ProductRecord(product, time);
|
||||||
|
|
||||||
if (record != nullptr)
|
if (record != nullptr)
|
||||||
{
|
{
|
||||||
message = record->level3_file()->message();
|
message = record->level3_file()->message();
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return {message, time};
|
||||||
}
|
}
|
||||||
|
|
||||||
common::Level3ProductCategoryMap
|
common::Level3ProductCategoryMap
|
||||||
|
|
@ -970,7 +1216,7 @@ RadarProductManager::Instance(const std::string& radarSite)
|
||||||
bool instanceCreated = false;
|
bool instanceCreated = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(instanceMutex_);
|
std::unique_lock lock {instanceMutex_};
|
||||||
|
|
||||||
// Look up instance weak pointer
|
// Look up instance weak pointer
|
||||||
auto it = instanceMap_.find(radarSite);
|
auto it = instanceMap_.find(radarSite);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/uuid/nil_generator.hpp>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace scwx
|
namespace scwx
|
||||||
|
|
@ -33,23 +34,63 @@ public:
|
||||||
|
|
||||||
static void Cleanup();
|
static void Cleanup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug function to dump currently loaded products to the log.
|
||||||
|
*/
|
||||||
|
static void DumpRecords();
|
||||||
|
|
||||||
const std::vector<float>& coordinates(common::RadialSize radialSize) const;
|
const std::vector<float>& coordinates(common::RadialSize radialSize) const;
|
||||||
float gate_size() const;
|
float gate_size() const;
|
||||||
std::shared_ptr<config::RadarSite> radar_site() const;
|
std::shared_ptr<config::RadarSite> radar_site() const;
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables or disables refresh associated with a unique identifier
|
||||||
|
* (UUID) for a given radar product group and product.
|
||||||
|
*
|
||||||
|
* Only a single product refresh can be enabled for a given UUID. If a second
|
||||||
|
* product refresh is enabled for the same UUID, the first product refresh is
|
||||||
|
* disabled (unless still enabled under a different UUID).
|
||||||
|
*
|
||||||
|
* @param [in] group Radar product group
|
||||||
|
* @param [in] product Radar product name
|
||||||
|
* @param [in] enabled Whether to enable refresh
|
||||||
|
* @param [in] uuid Unique identifier. Default is boost::uuids::nil_uuid().
|
||||||
|
*/
|
||||||
void EnableRefresh(common::RadarProductGroup group,
|
void EnableRefresh(common::RadarProductGroup group,
|
||||||
const std::string& product,
|
const std::string& product,
|
||||||
bool enabled);
|
bool enabled,
|
||||||
|
boost::uuids::uuid uuid = boost::uuids::nil_uuid());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get level 2 radar data for a data block type, elevation, and time.
|
||||||
|
*
|
||||||
|
* @param [in] dataBlockType Data block type
|
||||||
|
* @param [in] elevation Elevation tilt
|
||||||
|
* @param [in] time Radar product time
|
||||||
|
*
|
||||||
|
* @return Level 2 radar data, selected elevation cut, available elevation
|
||||||
|
* cuts and selected time
|
||||||
|
*/
|
||||||
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
std::tuple<std::shared_ptr<wsr88d::rda::ElevationScan>,
|
||||||
float,
|
float,
|
||||||
std::vector<float>>
|
std::vector<float>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
||||||
float elevation,
|
float elevation,
|
||||||
std::chrono::system_clock::time_point time = {});
|
std::chrono::system_clock::time_point time = {});
|
||||||
|
|
||||||
std::shared_ptr<wsr88d::rpg::Level3Message>
|
/**
|
||||||
|
* @brief Get level 3 message data for a product and time.
|
||||||
|
*
|
||||||
|
* @param [in] product Radar product name
|
||||||
|
* @param [in] time Radar product time
|
||||||
|
*
|
||||||
|
* @return Level 3 message data and selected time
|
||||||
|
*/
|
||||||
|
std::tuple<std::shared_ptr<wsr88d::rpg::Level3Message>,
|
||||||
|
std::chrono::system_clock::time_point>
|
||||||
GetLevel3Data(const std::string& product,
|
GetLevel3Data(const std::string& product,
|
||||||
std::chrono::system_clock::time_point time = {});
|
std::chrono::system_clock::time_point time = {});
|
||||||
|
|
||||||
|
|
@ -76,6 +117,7 @@ public:
|
||||||
void UpdateAvailableProducts();
|
void UpdateAvailableProducts();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void DataReloaded(std::shared_ptr<types::RadarProductRecord> record);
|
||||||
void Level3ProductsChanged();
|
void Level3ProductsChanged();
|
||||||
void NewDataAvailable(common::RadarProductGroup group,
|
void NewDataAvailable(common::RadarProductGroup group,
|
||||||
const std::string& product,
|
const std::string& product,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
#include <backends/imgui_impl_opengl3.h>
|
||||||
#include <backends/imgui_impl_qt.hpp>
|
#include <backends/imgui_impl_qt.hpp>
|
||||||
|
#include <boost/uuid/random_generator.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
@ -58,6 +59,7 @@ class MapWidgetImpl : public QObject
|
||||||
public:
|
public:
|
||||||
explicit MapWidgetImpl(MapWidget* widget,
|
explicit MapWidgetImpl(MapWidget* widget,
|
||||||
const QMapLibreGL::Settings& settings) :
|
const QMapLibreGL::Settings& settings) :
|
||||||
|
uuid_ {boost::uuids::random_generator()()},
|
||||||
context_ {std::make_shared<MapContext>()},
|
context_ {std::make_shared<MapContext>()},
|
||||||
widget_ {widget},
|
widget_ {widget},
|
||||||
settings_(settings),
|
settings_(settings),
|
||||||
|
|
@ -126,6 +128,8 @@ public:
|
||||||
common::Level2Product
|
common::Level2Product
|
||||||
GetLevel2ProductOrDefault(const std::string& productName) const;
|
GetLevel2ProductOrDefault(const std::string& productName) const;
|
||||||
|
|
||||||
|
boost::uuids::uuid uuid_;
|
||||||
|
|
||||||
std::shared_ptr<MapContext> context_;
|
std::shared_ptr<MapContext> context_;
|
||||||
|
|
||||||
MapWidget* widget_;
|
MapWidget* widget_;
|
||||||
|
|
@ -303,7 +307,7 @@ std::shared_ptr<config::RadarSite> MapWidget::GetRadarSite() const
|
||||||
return radarSite;
|
return radarSite;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MapWidget::GetVcp() const
|
std::uint16_t MapWidget::GetVcp() const
|
||||||
{
|
{
|
||||||
auto radarProductView = p->context_->radar_product_view();
|
auto radarProductView = p->context_->radar_product_view();
|
||||||
|
|
||||||
|
|
@ -313,7 +317,7 @@ uint16_t MapWidget::GetVcp() const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
return 0u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,7 +334,8 @@ void MapWidget::SelectElevation(float elevation)
|
||||||
|
|
||||||
void MapWidget::SelectRadarProduct(common::RadarProductGroup group,
|
void MapWidget::SelectRadarProduct(common::RadarProductGroup group,
|
||||||
const std::string& product,
|
const std::string& product,
|
||||||
int16_t productCode)
|
std::int16_t productCode,
|
||||||
|
std::chrono::system_clock::time_point time)
|
||||||
{
|
{
|
||||||
bool radarProductViewCreated = false;
|
bool radarProductViewCreated = false;
|
||||||
|
|
||||||
|
|
@ -380,8 +385,8 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group,
|
||||||
|
|
||||||
if (radarProductView != nullptr)
|
if (radarProductView != nullptr)
|
||||||
{
|
{
|
||||||
// Always select the latest product available
|
// Select the time associated with the request
|
||||||
radarProductView->SelectTime({});
|
radarProductView->SelectTime(time);
|
||||||
|
|
||||||
if (radarProductViewCreated)
|
if (radarProductViewCreated)
|
||||||
{
|
{
|
||||||
|
|
@ -399,7 +404,8 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group,
|
||||||
|
|
||||||
if (p->autoRefreshEnabled_)
|
if (p->autoRefreshEnabled_)
|
||||||
{
|
{
|
||||||
p->radarProductManager_->EnableRefresh(group, productName, true);
|
p->radarProductManager_->EnableRefresh(
|
||||||
|
group, productName, true, p->uuid_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -485,7 +491,8 @@ void MapWidget::SetAutoRefresh(bool enabled)
|
||||||
p->radarProductManager_->EnableRefresh(
|
p->radarProductManager_->EnableRefresh(
|
||||||
radarProductView->GetRadarProductGroup(),
|
radarProductView->GetRadarProductGroup(),
|
||||||
radarProductView->GetRadarProductName(),
|
radarProductView->GetRadarProductName(),
|
||||||
true);
|
true,
|
||||||
|
p->uuid_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,23 @@ public:
|
||||||
common::RadarProductGroup GetRadarProductGroup() const;
|
common::RadarProductGroup GetRadarProductGroup() const;
|
||||||
std::string GetRadarProductName() const;
|
std::string GetRadarProductName() const;
|
||||||
std::shared_ptr<config::RadarSite> GetRadarSite() const;
|
std::shared_ptr<config::RadarSite> GetRadarSite() const;
|
||||||
uint16_t GetVcp() const;
|
std::uint16_t GetVcp() const;
|
||||||
|
|
||||||
void SelectElevation(float elevation);
|
void SelectElevation(float elevation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selects a radar product.
|
||||||
|
*
|
||||||
|
* @param [in] group Radar product group
|
||||||
|
* @param [in] product Radar product name
|
||||||
|
* @param [in] productCode Radar product code (optional)
|
||||||
|
* @paran [in] time Product time. Default is the latest available.
|
||||||
|
*/
|
||||||
void SelectRadarProduct(common::RadarProductGroup group,
|
void SelectRadarProduct(common::RadarProductGroup group,
|
||||||
const std::string& product,
|
const std::string& product,
|
||||||
int16_t productCode);
|
std::int16_t productCode = 0,
|
||||||
|
std::chrono::system_clock::time_point time = {});
|
||||||
|
|
||||||
void SelectRadarProduct(std::shared_ptr<types::RadarProductRecord> record);
|
void SelectRadarProduct(std::shared_ptr<types::RadarProductRecord> record);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,16 @@ RadarProductModelImpl::RadarProductModelImpl(RadarProductModel* self) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find existing time item (e.g., 2023-04-10 10:11:12)
|
||||||
|
const QString timeString =
|
||||||
|
QString::fromStdString(util::TimeString(latestTime));
|
||||||
|
TreeItem* timeItem = productItem->FindChild(0, timeString);
|
||||||
|
|
||||||
|
if (timeItem == nullptr)
|
||||||
|
{
|
||||||
// Create leaf item for product time
|
// Create leaf item for product time
|
||||||
model_->AppendRow(productItem,
|
model_->AppendRow(productItem, new TreeItem {timeString});
|
||||||
new TreeItem {QString::fromStdString(
|
}
|
||||||
util::TimeString(latestTime))});
|
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,7 @@ void Level2ProductsWidgetImpl::UpdateProductSelection(
|
||||||
{
|
{
|
||||||
const std::string& productName = common::GetLevel2Name(product);
|
const std::string& productName = common::GetLevel2Name(product);
|
||||||
|
|
||||||
std::for_each(std::execution::par_unseq,
|
std::for_each(productButtons_.cbegin(),
|
||||||
productButtons_.cbegin(),
|
|
||||||
productButtons_.cend(),
|
productButtons_.cend(),
|
||||||
[&](auto& toolButton)
|
[&](auto& toolButton)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ public:
|
||||||
|
|
||||||
void NormalizeElevationButtons();
|
void NormalizeElevationButtons();
|
||||||
void SelectElevation(float elevation);
|
void SelectElevation(float elevation);
|
||||||
void UpdateSettings();
|
|
||||||
|
|
||||||
Level2SettingsWidget* self_;
|
Level2SettingsWidget* self_;
|
||||||
QLayout* layout_;
|
QLayout* layout_;
|
||||||
|
|
@ -135,8 +134,7 @@ void Level2SettingsWidget::UpdateElevationSelection(float elevation)
|
||||||
QString buttonText {QString::number(elevation, 'f', 1) +
|
QString buttonText {QString::number(elevation, 'f', 1) +
|
||||||
common::Characters::DEGREE};
|
common::Characters::DEGREE};
|
||||||
|
|
||||||
std::for_each(std::execution::par_unseq,
|
std::for_each(p->elevationButtons_.cbegin(),
|
||||||
p->elevationButtons_.cbegin(),
|
|
||||||
p->elevationButtons_.cend(),
|
p->elevationButtons_.cend(),
|
||||||
[&](auto& toolButton)
|
[&](auto& toolButton)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -258,8 +258,7 @@ void Level3ProductsWidgetImpl::UpdateCategorySelection(
|
||||||
{
|
{
|
||||||
const std::string& categoryName = common::GetLevel3CategoryName(category);
|
const std::string& categoryName = common::GetLevel3CategoryName(category);
|
||||||
|
|
||||||
std::for_each(std::execution::par_unseq,
|
std::for_each(categoryButtons_.cbegin(),
|
||||||
categoryButtons_.cbegin(),
|
|
||||||
categoryButtons_.cend(),
|
categoryButtons_.cend(),
|
||||||
[&](auto& toolButton)
|
[&](auto& toolButton)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ public:
|
||||||
explicit Level2ProductViewImpl(common::Level2Product product) :
|
explicit Level2ProductViewImpl(common::Level2Product product) :
|
||||||
product_ {product},
|
product_ {product},
|
||||||
selectedElevation_ {0.0f},
|
selectedElevation_ {0.0f},
|
||||||
selectedTime_ {},
|
|
||||||
elevationScan_ {nullptr},
|
elevationScan_ {nullptr},
|
||||||
momentDataBlock0_ {nullptr},
|
momentDataBlock0_ {nullptr},
|
||||||
latitude_ {},
|
latitude_ {},
|
||||||
|
|
@ -73,7 +72,6 @@ public:
|
||||||
wsr88d::rda::DataBlockType dataBlockType_;
|
wsr88d::rda::DataBlockType dataBlockType_;
|
||||||
|
|
||||||
float selectedElevation_;
|
float selectedElevation_;
|
||||||
std::chrono::system_clock::time_point selectedTime_;
|
|
||||||
|
|
||||||
std::shared_ptr<wsr88d::rda::ElevationScan> elevationScan_;
|
std::shared_ptr<wsr88d::rda::ElevationScan> elevationScan_;
|
||||||
std::shared_ptr<wsr88d::rda::MomentDataBlock> momentDataBlock0_;
|
std::shared_ptr<wsr88d::rda::MomentDataBlock> momentDataBlock0_;
|
||||||
|
|
@ -108,9 +106,36 @@ Level2ProductView::Level2ProductView(
|
||||||
RadarProductView(radarProductManager),
|
RadarProductView(radarProductManager),
|
||||||
p(std::make_unique<Level2ProductViewImpl>(product))
|
p(std::make_unique<Level2ProductViewImpl>(product))
|
||||||
{
|
{
|
||||||
|
ConnectRadarProductManager();
|
||||||
}
|
}
|
||||||
Level2ProductView::~Level2ProductView() = default;
|
Level2ProductView::~Level2ProductView() = default;
|
||||||
|
|
||||||
|
void Level2ProductView::ConnectRadarProductManager()
|
||||||
|
{
|
||||||
|
connect(radar_product_manager().get(),
|
||||||
|
&manager::RadarProductManager::DataReloaded,
|
||||||
|
this,
|
||||||
|
[this](std::shared_ptr<types::RadarProductRecord> record)
|
||||||
|
{
|
||||||
|
if (record->radar_product_group() ==
|
||||||
|
common::RadarProductGroup::Level2 &&
|
||||||
|
record->time() == selected_time())
|
||||||
|
{
|
||||||
|
// If the data associated with the currently selected time is
|
||||||
|
// reloaded, update the view
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Level2ProductView::DisconnectRadarProductManager()
|
||||||
|
{
|
||||||
|
disconnect(radar_product_manager().get(),
|
||||||
|
&manager::RadarProductManager::DataReloaded,
|
||||||
|
this,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<boost::gil::rgba8_pixel_t>&
|
const std::vector<boost::gil::rgba8_pixel_t>&
|
||||||
Level2ProductView::color_table() const
|
Level2ProductView::color_table() const
|
||||||
{
|
{
|
||||||
|
|
@ -243,11 +268,6 @@ void Level2ProductView::SelectProduct(const std::string& productName)
|
||||||
p->SetProduct(productName);
|
p->SetProduct(productName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level2ProductView::SelectTime(std::chrono::system_clock::time_point time)
|
|
||||||
{
|
|
||||||
p->selectedTime_ = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Level2ProductViewImpl::SetProduct(const std::string& productName)
|
void Level2ProductViewImpl::SetProduct(const std::string& productName)
|
||||||
{
|
{
|
||||||
SetProduct(common::GetLevel2Product(productName));
|
SetProduct(common::GetLevel2Product(productName));
|
||||||
|
|
@ -376,9 +396,18 @@ void Level2ProductView::ComputeSweep()
|
||||||
radar_product_manager();
|
radar_product_manager();
|
||||||
|
|
||||||
std::shared_ptr<wsr88d::rda::ElevationScan> radarData;
|
std::shared_ptr<wsr88d::rda::ElevationScan> radarData;
|
||||||
std::tie(radarData, p->elevationCut_, p->elevationCuts_) =
|
std::chrono::system_clock::time_point requestedTime {selected_time()};
|
||||||
|
std::chrono::system_clock::time_point foundTime;
|
||||||
|
std::tie(radarData, p->elevationCut_, p->elevationCuts_, foundTime) =
|
||||||
radarProductManager->GetLevel2Data(
|
radarProductManager->GetLevel2Data(
|
||||||
p->dataBlockType_, p->selectedElevation_, p->selectedTime_);
|
p->dataBlockType_, p->selectedElevation_, requestedTime);
|
||||||
|
|
||||||
|
// If a different time was found than what was requested, update it
|
||||||
|
if (requestedTime != foundTime)
|
||||||
|
{
|
||||||
|
SelectTime(foundTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (radarData == nullptr || radarData == p->elevationScan_)
|
if (radarData == nullptr || radarData == p->elevationScan_)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -28,31 +28,34 @@ public:
|
||||||
~Level2ProductView();
|
~Level2ProductView();
|
||||||
|
|
||||||
const std::vector<boost::gil::rgba8_pixel_t>& color_table() const override;
|
const std::vector<boost::gil::rgba8_pixel_t>& color_table() const override;
|
||||||
uint16_t color_table_min() const override;
|
std::uint16_t color_table_min() const override;
|
||||||
uint16_t color_table_max() const override;
|
std::uint16_t color_table_max() const override;
|
||||||
float elevation() const override;
|
float elevation() const override;
|
||||||
float range() const override;
|
float range() const override;
|
||||||
std::chrono::system_clock::time_point sweep_time() const override;
|
std::chrono::system_clock::time_point sweep_time() const override;
|
||||||
uint16_t vcp() const override;
|
std::uint16_t vcp() const override;
|
||||||
const std::vector<float>& vertices() const override;
|
const std::vector<float>& vertices() const override;
|
||||||
|
|
||||||
void LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) override;
|
void LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) override;
|
||||||
void SelectElevation(float elevation) override;
|
void SelectElevation(float elevation) override;
|
||||||
void SelectProduct(const std::string& productName) override;
|
void SelectProduct(const std::string& productName) override;
|
||||||
void SelectTime(std::chrono::system_clock::time_point time) override;
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
||||||
common::RadarProductGroup GetRadarProductGroup() const override;
|
common::RadarProductGroup GetRadarProductGroup() const override;
|
||||||
std::string GetRadarProductName() const override;
|
std::string GetRadarProductName() const override;
|
||||||
std::vector<float> GetElevationCuts() const override;
|
std::vector<float> GetElevationCuts() const override;
|
||||||
std::tuple<const void*, size_t, size_t> GetMomentData() const override;
|
std::tuple<const void*, std::size_t, std::size_t>
|
||||||
std::tuple<const void*, size_t, size_t> GetCfpMomentData() const override;
|
GetMomentData() const override;
|
||||||
|
std::tuple<const void*, std::size_t, std::size_t>
|
||||||
|
GetCfpMomentData() const override;
|
||||||
|
|
||||||
static std::shared_ptr<Level2ProductView>
|
static std::shared_ptr<Level2ProductView>
|
||||||
Create(common::Level2Product product,
|
Create(common::Level2Product product,
|
||||||
std::shared_ptr<manager::RadarProductManager> radarProductManager);
|
std::shared_ptr<manager::RadarProductManager> radarProductManager);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void ConnectRadarProductManager() override;
|
||||||
|
void DisconnectRadarProductManager() override;
|
||||||
void UpdateColorTable() override;
|
void UpdateColorTable() override;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,37 @@ Level3ProductView::Level3ProductView(
|
||||||
RadarProductView(radarProductManager),
|
RadarProductView(radarProductManager),
|
||||||
p(std::make_unique<Level3ProductViewImpl>(product))
|
p(std::make_unique<Level3ProductViewImpl>(product))
|
||||||
{
|
{
|
||||||
|
ConnectRadarProductManager();
|
||||||
}
|
}
|
||||||
Level3ProductView::~Level3ProductView() = default;
|
Level3ProductView::~Level3ProductView() = default;
|
||||||
|
|
||||||
|
void Level3ProductView::ConnectRadarProductManager()
|
||||||
|
{
|
||||||
|
connect(radar_product_manager().get(),
|
||||||
|
&manager::RadarProductManager::DataReloaded,
|
||||||
|
this,
|
||||||
|
[this](std::shared_ptr<types::RadarProductRecord> record)
|
||||||
|
{
|
||||||
|
if (record->radar_product_group() ==
|
||||||
|
common::RadarProductGroup::Level3 &&
|
||||||
|
record->radar_product() == p->product_ &&
|
||||||
|
record->time() == selected_time())
|
||||||
|
{
|
||||||
|
// If the data associated with the currently selected time is
|
||||||
|
// reloaded, update the view
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Level3ProductView::DisconnectRadarProductManager()
|
||||||
|
{
|
||||||
|
disconnect(radar_product_manager().get(),
|
||||||
|
&manager::RadarProductManager::DataReloaded,
|
||||||
|
this,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<boost::gil::rgba8_pixel_t>&
|
const std::vector<boost::gil::rgba8_pixel_t>&
|
||||||
Level3ProductView::color_table() const
|
Level3ProductView::color_table() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ public:
|
||||||
virtual ~Level3ProductView();
|
virtual ~Level3ProductView();
|
||||||
|
|
||||||
const std::vector<boost::gil::rgba8_pixel_t>& color_table() const override;
|
const std::vector<boost::gil::rgba8_pixel_t>& color_table() const override;
|
||||||
uint16_t color_table_min() const override;
|
std::uint16_t color_table_min() const override;
|
||||||
uint16_t color_table_max() const override;
|
std::uint16_t color_table_max() const override;
|
||||||
|
|
||||||
void LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) override;
|
void LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
|
@ -45,6 +45,8 @@ protected:
|
||||||
void set_graphic_product_message(
|
void set_graphic_product_message(
|
||||||
std::shared_ptr<wsr88d::rpg::GraphicProductMessage> gpm);
|
std::shared_ptr<wsr88d::rpg::GraphicProductMessage> gpm);
|
||||||
|
|
||||||
|
void ConnectRadarProductManager() override;
|
||||||
|
void DisconnectRadarProductManager() override;
|
||||||
void UpdateColorTable() override;
|
void UpdateColorTable() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -27,25 +27,18 @@ class Level3RadialViewImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Level3RadialViewImpl() :
|
explicit Level3RadialViewImpl() :
|
||||||
selectedTime_ {},
|
latitude_ {}, longitude_ {}, range_ {}, vcp_ {}, sweepTime_ {}
|
||||||
latitude_ {},
|
|
||||||
longitude_ {},
|
|
||||||
range_ {},
|
|
||||||
vcp_ {},
|
|
||||||
sweepTime_ {}
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~Level3RadialViewImpl() = default;
|
~Level3RadialViewImpl() = default;
|
||||||
|
|
||||||
std::chrono::system_clock::time_point selectedTime_;
|
|
||||||
|
|
||||||
std::vector<float> vertices_;
|
std::vector<float> vertices_;
|
||||||
std::vector<uint8_t> dataMoments8_;
|
std::vector<std::uint8_t> dataMoments8_;
|
||||||
|
|
||||||
float latitude_;
|
float latitude_;
|
||||||
float longitude_;
|
float longitude_;
|
||||||
float range_;
|
float range_;
|
||||||
uint16_t vcp_;
|
std::uint16_t vcp_;
|
||||||
|
|
||||||
std::chrono::system_clock::time_point sweepTime_;
|
std::chrono::system_clock::time_point sweepTime_;
|
||||||
};
|
};
|
||||||
|
|
@ -92,11 +85,6 @@ std::tuple<const void*, size_t, size_t> Level3RadialView::GetMomentData() const
|
||||||
return std::tie(data, dataSize, componentSize);
|
return std::tie(data, dataSize, componentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level3RadialView::SelectTime(std::chrono::system_clock::time_point time)
|
|
||||||
{
|
|
||||||
p->selectedTime_ = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Level3RadialView::ComputeSweep()
|
void Level3RadialView::ComputeSweep()
|
||||||
{
|
{
|
||||||
logger_->debug("ComputeSweep()");
|
logger_->debug("ComputeSweep()");
|
||||||
|
|
@ -109,9 +97,18 @@ void Level3RadialView::ComputeSweep()
|
||||||
radar_product_manager();
|
radar_product_manager();
|
||||||
|
|
||||||
// Retrieve message from Radar Product Manager
|
// Retrieve message from Radar Product Manager
|
||||||
std::shared_ptr<wsr88d::rpg::Level3Message> message =
|
std::shared_ptr<wsr88d::rpg::Level3Message> message;
|
||||||
radarProductManager->GetLevel3Data(GetRadarProductName(),
|
std::chrono::system_clock::time_point requestedTime {selected_time()};
|
||||||
p->selectedTime_);
|
std::chrono::system_clock::time_point foundTime;
|
||||||
|
std::tie(message, foundTime) =
|
||||||
|
radarProductManager->GetLevel3Data(GetRadarProductName(), requestedTime);
|
||||||
|
|
||||||
|
// If a different time was found than what was requested, update it
|
||||||
|
if (requestedTime != foundTime)
|
||||||
|
{
|
||||||
|
SelectTime(foundTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (message == nullptr)
|
if (message == nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug("Level 3 data not found");
|
logger_->debug("Level 3 data not found");
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,11 @@ public:
|
||||||
|
|
||||||
float range() const override;
|
float range() const override;
|
||||||
std::chrono::system_clock::time_point sweep_time() const override;
|
std::chrono::system_clock::time_point sweep_time() const override;
|
||||||
uint16_t vcp() const override;
|
std::uint16_t vcp() const override;
|
||||||
const std::vector<float>& vertices() const override;
|
const std::vector<float>& vertices() const override;
|
||||||
|
|
||||||
void SelectTime(std::chrono::system_clock::time_point time) override;
|
std::tuple<const void*, std::size_t, std::size_t>
|
||||||
|
GetMomentData() const override;
|
||||||
std::tuple<const void*, size_t, size_t> GetMomentData() const override;
|
|
||||||
|
|
||||||
static std::shared_ptr<Level3RadialView>
|
static std::shared_ptr<Level3RadialView>
|
||||||
Create(const std::string& product,
|
Create(const std::string& product,
|
||||||
|
|
|
||||||
|
|
@ -27,18 +27,11 @@ class Level3RasterViewImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Level3RasterViewImpl() :
|
explicit Level3RasterViewImpl() :
|
||||||
selectedTime_ {},
|
latitude_ {}, longitude_ {}, range_ {}, vcp_ {}, sweepTime_ {}
|
||||||
latitude_ {},
|
|
||||||
longitude_ {},
|
|
||||||
range_ {},
|
|
||||||
vcp_ {},
|
|
||||||
sweepTime_ {}
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~Level3RasterViewImpl() = default;
|
~Level3RasterViewImpl() = default;
|
||||||
|
|
||||||
std::chrono::system_clock::time_point selectedTime_;
|
|
||||||
|
|
||||||
std::vector<float> vertices_;
|
std::vector<float> vertices_;
|
||||||
std::vector<uint8_t> dataMoments8_;
|
std::vector<uint8_t> dataMoments8_;
|
||||||
|
|
||||||
|
|
@ -92,11 +85,6 @@ std::tuple<const void*, size_t, size_t> Level3RasterView::GetMomentData() const
|
||||||
return std::tie(data, dataSize, componentSize);
|
return std::tie(data, dataSize, componentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level3RasterView::SelectTime(std::chrono::system_clock::time_point time)
|
|
||||||
{
|
|
||||||
p->selectedTime_ = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Level3RasterView::ComputeSweep()
|
void Level3RasterView::ComputeSweep()
|
||||||
{
|
{
|
||||||
logger_->debug("ComputeSweep()");
|
logger_->debug("ComputeSweep()");
|
||||||
|
|
@ -109,9 +97,18 @@ void Level3RasterView::ComputeSweep()
|
||||||
radar_product_manager();
|
radar_product_manager();
|
||||||
|
|
||||||
// Retrieve message from Radar Product Manager
|
// Retrieve message from Radar Product Manager
|
||||||
std::shared_ptr<wsr88d::rpg::Level3Message> message =
|
std::shared_ptr<wsr88d::rpg::Level3Message> message;
|
||||||
radarProductManager->GetLevel3Data(GetRadarProductName(),
|
std::chrono::system_clock::time_point requestedTime {selected_time()};
|
||||||
p->selectedTime_);
|
std::chrono::system_clock::time_point foundTime;
|
||||||
|
std::tie(message, foundTime) =
|
||||||
|
radarProductManager->GetLevel3Data(GetRadarProductName(), requestedTime);
|
||||||
|
|
||||||
|
// If a different time was found than what was requested, update it
|
||||||
|
if (requestedTime != foundTime)
|
||||||
|
{
|
||||||
|
SelectTime(foundTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (message == nullptr)
|
if (message == nullptr)
|
||||||
{
|
{
|
||||||
logger_->debug("Level 3 data not found");
|
logger_->debug("Level 3 data not found");
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,11 @@ public:
|
||||||
|
|
||||||
float range() const override;
|
float range() const override;
|
||||||
std::chrono::system_clock::time_point sweep_time() const override;
|
std::chrono::system_clock::time_point sweep_time() const override;
|
||||||
uint16_t vcp() const override;
|
std::uint16_t vcp() const override;
|
||||||
const std::vector<float>& vertices() const override;
|
const std::vector<float>& vertices() const override;
|
||||||
|
|
||||||
void SelectTime(std::chrono::system_clock::time_point time) override;
|
std::tuple<const void*, std::size_t, std::size_t>
|
||||||
|
GetMomentData() const override;
|
||||||
std::tuple<const void*, size_t, size_t> GetMomentData() const override;
|
|
||||||
|
|
||||||
static std::shared_ptr<Level3RasterView>
|
static std::shared_ptr<Level3RasterView>
|
||||||
Create(const std::string& product,
|
Create(const std::string& product,
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ static const std::string logPrefix_ = "scwx::qt::view::radar_product_view";
|
||||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
// Default color table should be transparent to prevent flicker
|
// Default color table should be transparent to prevent flicker
|
||||||
static const std::vector<boost::gil::rgba8_pixel_t> DEFAULT_COLOR_TABLE = {
|
static const std::vector<boost::gil::rgba8_pixel_t> kDefaultColorTable_ = {
|
||||||
boost::gil::rgba8_pixel_t(0, 128, 0, 0),
|
boost::gil::rgba8_pixel_t(0, 128, 0, 0),
|
||||||
boost::gil::rgba8_pixel_t(255, 192, 0, 0),
|
boost::gil::rgba8_pixel_t(255, 192, 0, 0),
|
||||||
boost::gil::rgba8_pixel_t(255, 0, 0, 0)};
|
boost::gil::rgba8_pixel_t(255, 0, 0, 0)};
|
||||||
static const uint16_t DEFAULT_COLOR_TABLE_MIN = 2u;
|
static const std::uint16_t kDefaultColorTableMin_ = 2u;
|
||||||
static const uint16_t DEFAULT_COLOR_TABLE_MAX = 255u;
|
static const std::uint16_t kDefaultColorTableMax_ = 255u;
|
||||||
|
|
||||||
class RadarProductViewImpl
|
class RadarProductViewImpl
|
||||||
{
|
{
|
||||||
|
|
@ -30,6 +30,7 @@ public:
|
||||||
std::shared_ptr<manager::RadarProductManager> radarProductManager) :
|
std::shared_ptr<manager::RadarProductManager> radarProductManager) :
|
||||||
initialized_ {false},
|
initialized_ {false},
|
||||||
sweepMutex_ {},
|
sweepMutex_ {},
|
||||||
|
selectedTime_ {},
|
||||||
radarProductManager_ {radarProductManager}
|
radarProductManager_ {radarProductManager}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +39,8 @@ public:
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
std::mutex sweepMutex_;
|
std::mutex sweepMutex_;
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point selectedTime_;
|
||||||
|
|
||||||
std::shared_ptr<manager::RadarProductManager> radarProductManager_;
|
std::shared_ptr<manager::RadarProductManager> radarProductManager_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -49,17 +52,17 @@ RadarProductView::~RadarProductView() = default;
|
||||||
const std::vector<boost::gil::rgba8_pixel_t>&
|
const std::vector<boost::gil::rgba8_pixel_t>&
|
||||||
RadarProductView::color_table() const
|
RadarProductView::color_table() const
|
||||||
{
|
{
|
||||||
return DEFAULT_COLOR_TABLE;
|
return kDefaultColorTable_;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t RadarProductView::color_table_min() const
|
std::uint16_t RadarProductView::color_table_min() const
|
||||||
{
|
{
|
||||||
return DEFAULT_COLOR_TABLE_MIN;
|
return kDefaultColorTableMin_;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t RadarProductView::color_table_max() const
|
std::uint16_t RadarProductView::color_table_max() const
|
||||||
{
|
{
|
||||||
return DEFAULT_COLOR_TABLE_MAX;
|
return kDefaultColorTableMax_;
|
||||||
}
|
}
|
||||||
|
|
||||||
float RadarProductView::elevation() const
|
float RadarProductView::elevation() const
|
||||||
|
|
@ -78,6 +81,11 @@ float RadarProductView::range() const
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point RadarProductView::selected_time() const
|
||||||
|
{
|
||||||
|
return p->selectedTime_;
|
||||||
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::time_point RadarProductView::sweep_time() const
|
std::chrono::system_clock::time_point RadarProductView::sweep_time() const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -91,7 +99,9 @@ std::mutex& RadarProductView::sweep_mutex()
|
||||||
void RadarProductView::set_radar_product_manager(
|
void RadarProductView::set_radar_product_manager(
|
||||||
std::shared_ptr<manager::RadarProductManager> radarProductManager)
|
std::shared_ptr<manager::RadarProductManager> radarProductManager)
|
||||||
{
|
{
|
||||||
|
DisconnectRadarProductManager();
|
||||||
p->radarProductManager_ = radarProductManager;
|
p->radarProductManager_ = radarProductManager;
|
||||||
|
ConnectRadarProductManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadarProductView::Initialize()
|
void RadarProductView::Initialize()
|
||||||
|
|
@ -103,6 +113,11 @@ void RadarProductView::Initialize()
|
||||||
|
|
||||||
void RadarProductView::SelectElevation(float /*elevation*/) {}
|
void RadarProductView::SelectElevation(float /*elevation*/) {}
|
||||||
|
|
||||||
|
void RadarProductView::SelectTime(std::chrono::system_clock::time_point time)
|
||||||
|
{
|
||||||
|
p->selectedTime_ = time;
|
||||||
|
}
|
||||||
|
|
||||||
bool RadarProductView::IsInitialized() const
|
bool RadarProductView::IsInitialized() const
|
||||||
{
|
{
|
||||||
return p->initialized_;
|
return p->initialized_;
|
||||||
|
|
@ -113,12 +128,12 @@ std::vector<float> RadarProductView::GetElevationCuts() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<const void*, size_t, size_t>
|
std::tuple<const void*, std::size_t, std::size_t>
|
||||||
RadarProductView::GetCfpMomentData() const
|
RadarProductView::GetCfpMomentData() const
|
||||||
{
|
{
|
||||||
const void* data = nullptr;
|
const void* data = nullptr;
|
||||||
size_t dataSize = 0;
|
std::size_t dataSize = 0;
|
||||||
size_t componentSize = 0;
|
std::size_t componentSize = 0;
|
||||||
|
|
||||||
return std::tie(data, dataSize, componentSize);
|
return std::tie(data, dataSize, componentSize);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,16 @@ public:
|
||||||
virtual ~RadarProductView();
|
virtual ~RadarProductView();
|
||||||
|
|
||||||
virtual const std::vector<boost::gil::rgba8_pixel_t>& color_table() const;
|
virtual const std::vector<boost::gil::rgba8_pixel_t>& color_table() const;
|
||||||
virtual uint16_t color_table_min() const;
|
virtual std::uint16_t color_table_min() const;
|
||||||
virtual uint16_t color_table_max() const;
|
virtual std::uint16_t color_table_max() const;
|
||||||
virtual float elevation() const;
|
virtual float elevation() const;
|
||||||
virtual float range() const;
|
virtual float range() const;
|
||||||
virtual std::chrono::system_clock::time_point sweep_time() const;
|
virtual std::chrono::system_clock::time_point sweep_time() const;
|
||||||
virtual uint16_t vcp() const = 0;
|
virtual std::uint16_t vcp() const = 0;
|
||||||
virtual const std::vector<float>& vertices() const = 0;
|
virtual const std::vector<float>& vertices() const = 0;
|
||||||
|
|
||||||
std::shared_ptr<manager::RadarProductManager> radar_product_manager() const;
|
std::shared_ptr<manager::RadarProductManager> radar_product_manager() const;
|
||||||
|
std::chrono::system_clock::time_point selected_time() const;
|
||||||
std::mutex& sweep_mutex();
|
std::mutex& sweep_mutex();
|
||||||
|
|
||||||
void set_radar_product_manager(
|
void set_radar_product_manager(
|
||||||
|
|
@ -49,7 +50,7 @@ public:
|
||||||
LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) = 0;
|
LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) = 0;
|
||||||
virtual void SelectElevation(float elevation);
|
virtual void SelectElevation(float elevation);
|
||||||
virtual void SelectProduct(const std::string& productName) = 0;
|
virtual void SelectProduct(const std::string& productName) = 0;
|
||||||
virtual void SelectTime(std::chrono::system_clock::time_point time) = 0;
|
void SelectTime(std::chrono::system_clock::time_point time);
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
|
|
||||||
bool IsInitialized() const;
|
bool IsInitialized() const;
|
||||||
|
|
@ -57,10 +58,14 @@ public:
|
||||||
virtual common::RadarProductGroup GetRadarProductGroup() const = 0;
|
virtual common::RadarProductGroup GetRadarProductGroup() const = 0;
|
||||||
virtual std::string GetRadarProductName() const = 0;
|
virtual std::string GetRadarProductName() const = 0;
|
||||||
virtual std::vector<float> GetElevationCuts() const;
|
virtual std::vector<float> GetElevationCuts() const;
|
||||||
virtual std::tuple<const void*, size_t, size_t> GetMomentData() const = 0;
|
virtual std::tuple<const void*, std::size_t, std::size_t>
|
||||||
virtual std::tuple<const void*, size_t, size_t> GetCfpMomentData() const;
|
GetMomentData() const = 0;
|
||||||
|
virtual std::tuple<const void*, std::size_t, std::size_t>
|
||||||
|
GetCfpMomentData() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void ConnectRadarProductManager() = 0;
|
||||||
|
virtual void DisconnectRadarProductManager() = 0;
|
||||||
virtual void UpdateColorTable() = 0;
|
virtual void UpdateColorTable() = 0;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ namespace scwx
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class Key, class T, class ReturnType = std::optional<T>>
|
template<class Key, class T, class ReturnType = std::map<Key, T>::const_pointer>
|
||||||
ReturnType GetBoundedElement(std::map<Key, T>& map, Key key)
|
ReturnType GetBoundedElementPointer(std::map<Key, T>& map, const Key& key)
|
||||||
{
|
{
|
||||||
ReturnType element;
|
ReturnType elementPtr {nullptr};
|
||||||
|
|
||||||
// Find the first element greater than the key requested
|
// Find the first element greater than the key requested
|
||||||
auto it = map.upper_bound(key);
|
auto it = map.upper_bound(key);
|
||||||
|
|
@ -24,26 +24,42 @@ ReturnType GetBoundedElement(std::map<Key, T>& map, Key key)
|
||||||
{
|
{
|
||||||
// Get the element immediately preceding, this the element we are
|
// Get the element immediately preceding, this the element we are
|
||||||
// looking for
|
// looking for
|
||||||
element = (--it)->second;
|
elementPtr = &(*(--it));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The current element is a good substitute
|
// The current element is a good substitute
|
||||||
element = it->second;
|
elementPtr = &(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (map.size() > 0)
|
else if (map.size() > 0)
|
||||||
{
|
{
|
||||||
// An element with a key greater was not found. If it exists, it must be
|
// An element with a key greater was not found. If it exists, it must be
|
||||||
// the last element.
|
// the last element.
|
||||||
element = map.rbegin()->second;
|
elementPtr = &(*map.rbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Key, class T, class ReturnType = std::optional<T>>
|
||||||
|
ReturnType GetBoundedElement(std::map<Key, T>& map, const Key& key)
|
||||||
|
{
|
||||||
|
ReturnType element;
|
||||||
|
|
||||||
|
typename std::map<Key, T>::pointer elementPtr =
|
||||||
|
GetBoundedElementPointer<Key, T, typename std::map<Key, T>::pointer>(map,
|
||||||
|
key);
|
||||||
|
if (elementPtr != nullptr)
|
||||||
|
{
|
||||||
|
element = elementPtr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Key, class T>
|
template<class Key, class T>
|
||||||
inline T GetBoundedElementValue(std::map<Key, T>& map, Key key)
|
inline T GetBoundedElementValue(std::map<Key, T>& map, const Key& key)
|
||||||
{
|
{
|
||||||
return GetBoundedElement<Key, T, T>(map, key);
|
return GetBoundedElement<Key, T, T>(map, key);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue