mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-29 22:50:05 +00:00
Merge pull request #297 from dpaulat/feature/level2-sweeps
Intermediate Level 2 Sweeps
This commit is contained in:
commit
dbfacdfd28
10 changed files with 248 additions and 221 deletions
|
|
@ -241,7 +241,7 @@ public:
|
|||
|
||||
std::vector<map::MapWidget*> maps_;
|
||||
|
||||
std::chrono::system_clock::time_point volumeTime_ {};
|
||||
std::chrono::system_clock::time_point selectedTime_ {};
|
||||
|
||||
public slots:
|
||||
void UpdateMapParameters(double latitude,
|
||||
|
|
@ -997,22 +997,15 @@ void MainWindowImpl::ConnectAnimationSignals()
|
|||
|
||||
connect(timelineManager_.get(),
|
||||
&manager::TimelineManager::SelectedTimeUpdated,
|
||||
[this]()
|
||||
{
|
||||
for (auto map : maps_)
|
||||
{
|
||||
QMetaObject::invokeMethod(
|
||||
map, static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
}
|
||||
});
|
||||
connect(timelineManager_.get(),
|
||||
&manager::TimelineManager::VolumeTimeUpdated,
|
||||
[this](std::chrono::system_clock::time_point dateTime)
|
||||
{
|
||||
volumeTime_ = dateTime;
|
||||
selectedTime_ = dateTime;
|
||||
|
||||
for (auto map : maps_)
|
||||
{
|
||||
map->SelectTime(dateTime);
|
||||
QMetaObject::invokeMethod(
|
||||
map, static_cast<void (QWidget::*)()>(&QWidget::update));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1400,7 +1393,8 @@ void MainWindowImpl::SelectRadarProduct(map::MapWidget* mapWidget,
|
|||
UpdateRadarProductSettings();
|
||||
}
|
||||
|
||||
mapWidget->SelectRadarProduct(group, productName, productCode, volumeTime_);
|
||||
mapWidget->SelectRadarProduct(
|
||||
group, productName, productCode, selectedTime_);
|
||||
}
|
||||
|
||||
void MainWindowImpl::SetActiveMap(map::MapWidget* mapWidget)
|
||||
|
|
|
|||
|
|
@ -91,13 +91,7 @@ public:
|
|||
const std::string& radarId,
|
||||
common::RadarProductGroup group,
|
||||
const std::string& product) :
|
||||
radarId_ {radarId},
|
||||
group_ {group},
|
||||
product_ {product},
|
||||
refreshEnabled_ {false},
|
||||
refreshTimer_ {threadPool_},
|
||||
refreshTimerMutex_ {},
|
||||
provider_ {nullptr}
|
||||
radarId_ {radarId}, group_ {group}, product_ {product}
|
||||
{
|
||||
connect(this,
|
||||
&ProviderManager::NewDataAvailable,
|
||||
|
|
@ -115,10 +109,10 @@ public:
|
|||
const std::string radarId_;
|
||||
const common::RadarProductGroup group_;
|
||||
const std::string product_;
|
||||
bool refreshEnabled_;
|
||||
boost::asio::steady_timer refreshTimer_;
|
||||
std::mutex refreshTimerMutex_;
|
||||
std::shared_ptr<provider::NexradDataProvider> provider_;
|
||||
bool refreshEnabled_ {false};
|
||||
boost::asio::steady_timer refreshTimer_ {threadPool_};
|
||||
std::mutex refreshTimerMutex_ {};
|
||||
std::shared_ptr<provider::NexradDataProvider> provider_ {nullptr};
|
||||
|
||||
signals:
|
||||
void NewDataAvailable(common::RadarProductGroup group,
|
||||
|
|
@ -136,24 +130,8 @@ public:
|
|||
initialized_ {false},
|
||||
level3ProductsInitialized_ {false},
|
||||
radarSite_ {config::RadarSite::Get(radarId)},
|
||||
coordinates0_5Degree_ {},
|
||||
coordinates1Degree_ {},
|
||||
level2ProductRecords_ {},
|
||||
level2ProductRecentRecords_ {},
|
||||
level3ProductRecordsMap_ {},
|
||||
level3ProductRecentRecordsMap_ {},
|
||||
level2ProductRecordMutex_ {},
|
||||
level3ProductRecordMutex_ {},
|
||||
level2ProviderManager_ {std::make_shared<ProviderManager>(
|
||||
self_, radarId_, common::RadarProductGroup::Level2)},
|
||||
level3ProviderManagerMap_ {},
|
||||
level3ProviderManagerMutex_ {},
|
||||
initializeMutex_ {},
|
||||
level3ProductsInitializeMutex_ {},
|
||||
loadLevel2DataMutex_ {},
|
||||
loadLevel3DataMutex_ {},
|
||||
availableCategoryMap_ {},
|
||||
availableCategoryMutex_ {}
|
||||
self_, radarId_, common::RadarProductGroup::Level2)}
|
||||
{
|
||||
if (radarSite_ == nullptr)
|
||||
{
|
||||
|
|
@ -198,9 +176,9 @@ public:
|
|||
void RefreshData(std::shared_ptr<ProviderManager> providerManager);
|
||||
void RefreshDataSync(std::shared_ptr<ProviderManager> providerManager);
|
||||
|
||||
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||
std::chrono::system_clock::time_point>
|
||||
GetLevel2ProductRecord(std::chrono::system_clock::time_point time);
|
||||
std::map<std::chrono::system_clock::time_point,
|
||||
std::shared_ptr<types::RadarProductRecord>>
|
||||
GetLevel2ProductRecords(std::chrono::system_clock::time_point time);
|
||||
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||
std::chrono::system_clock::time_point>
|
||||
GetLevel3ProductRecord(const std::string& product,
|
||||
|
|
@ -247,30 +225,30 @@ public:
|
|||
std::shared_ptr<config::RadarSite> radarSite_;
|
||||
std::size_t cacheLimit_ {6u};
|
||||
|
||||
std::vector<float> coordinates0_5Degree_;
|
||||
std::vector<float> coordinates1Degree_;
|
||||
std::vector<float> coordinates0_5Degree_ {};
|
||||
std::vector<float> coordinates1Degree_ {};
|
||||
|
||||
RadarProductRecordMap level2ProductRecords_;
|
||||
RadarProductRecordList level2ProductRecentRecords_;
|
||||
RadarProductRecordMap level2ProductRecords_ {};
|
||||
RadarProductRecordList level2ProductRecentRecords_ {};
|
||||
std::unordered_map<std::string, RadarProductRecordMap>
|
||||
level3ProductRecordsMap_;
|
||||
level3ProductRecordsMap_ {};
|
||||
std::unordered_map<std::string, RadarProductRecordList>
|
||||
level3ProductRecentRecordsMap_;
|
||||
std::shared_mutex level2ProductRecordMutex_;
|
||||
std::shared_mutex level3ProductRecordMutex_;
|
||||
level3ProductRecentRecordsMap_ {};
|
||||
std::shared_mutex level2ProductRecordMutex_ {};
|
||||
std::shared_mutex level3ProductRecordMutex_ {};
|
||||
|
||||
std::shared_ptr<ProviderManager> level2ProviderManager_;
|
||||
std::unordered_map<std::string, std::shared_ptr<ProviderManager>>
|
||||
level3ProviderManagerMap_;
|
||||
std::shared_mutex level3ProviderManagerMutex_;
|
||||
level3ProviderManagerMap_ {};
|
||||
std::shared_mutex level3ProviderManagerMutex_ {};
|
||||
|
||||
std::mutex initializeMutex_;
|
||||
std::mutex level3ProductsInitializeMutex_;
|
||||
std::mutex loadLevel2DataMutex_;
|
||||
std::mutex loadLevel3DataMutex_;
|
||||
std::mutex initializeMutex_ {};
|
||||
std::mutex level3ProductsInitializeMutex_ {};
|
||||
std::mutex loadLevel2DataMutex_ {};
|
||||
std::mutex loadLevel3DataMutex_ {};
|
||||
|
||||
common::Level3ProductCategoryMap availableCategoryMap_;
|
||||
std::shared_mutex availableCategoryMutex_;
|
||||
common::Level3ProductCategoryMap availableCategoryMap_ {};
|
||||
std::shared_mutex availableCategoryMutex_ {};
|
||||
|
||||
std::unordered_map<boost::uuids::uuid,
|
||||
std::shared_ptr<ProviderManager>,
|
||||
|
|
@ -1173,60 +1151,91 @@ void RadarProductManagerImpl::PopulateProductTimes(
|
|||
});
|
||||
}
|
||||
|
||||
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||
std::chrono::system_clock::time_point>
|
||||
RadarProductManagerImpl::GetLevel2ProductRecord(
|
||||
std::map<std::chrono::system_clock::time_point,
|
||||
std::shared_ptr<types::RadarProductRecord>>
|
||||
RadarProductManagerImpl::GetLevel2ProductRecords(
|
||||
std::chrono::system_clock::time_point time)
|
||||
{
|
||||
std::shared_ptr<types::RadarProductRecord> record {nullptr};
|
||||
RadarProductRecordMap::const_pointer recordPtr {nullptr};
|
||||
std::chrono::system_clock::time_point recordTime {time};
|
||||
std::map<std::chrono::system_clock::time_point,
|
||||
std::shared_ptr<types::RadarProductRecord>>
|
||||
records {};
|
||||
std::vector<RadarProductRecordMap::const_pointer> recordPtrs {};
|
||||
|
||||
// Ensure Level 2 product records are updated
|
||||
PopulateLevel2ProductTimes(time);
|
||||
|
||||
if (!level2ProductRecords_.empty() &&
|
||||
time == std::chrono::system_clock::time_point {})
|
||||
{
|
||||
// If a default-initialized time point is given, return the latest record
|
||||
recordPtr = &(*level2ProductRecords_.rbegin());
|
||||
}
|
||||
else
|
||||
{
|
||||
recordPtr =
|
||||
scwx::util::GetBoundedElementPointer(level2ProductRecords_, time);
|
||||
}
|
||||
std::shared_lock lock {level2ProductRecordMutex_};
|
||||
|
||||
if (recordPtr != nullptr)
|
||||
{
|
||||
// Don't check for an exact time match for level 2 products
|
||||
recordTime = recordPtr->first;
|
||||
record = recordPtr->second.lock();
|
||||
}
|
||||
if (!level2ProductRecords_.empty() &&
|
||||
time == std::chrono::system_clock::time_point {})
|
||||
{
|
||||
// If a default-initialized time point is given, return the latest
|
||||
// record
|
||||
recordPtrs.push_back(&(*level2ProductRecords_.rbegin()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the requested record
|
||||
auto recordIt =
|
||||
scwx::util::GetBoundedElementIterator(level2ProductRecords_, time);
|
||||
|
||||
if (recordPtr != nullptr && 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>(radarId_);
|
||||
|
||||
QObject::connect(
|
||||
request.get(),
|
||||
&request::NexradFileRequest::RequestComplete,
|
||||
self_,
|
||||
[this](std::shared_ptr<request::NexradFileRequest> request)
|
||||
if (recordIt != level2ProductRecords_.cend())
|
||||
{
|
||||
if (request->radar_product_record() != nullptr)
|
||||
{
|
||||
Q_EMIT self_->DataReloaded(request->radar_product_record());
|
||||
}
|
||||
});
|
||||
recordPtrs.push_back(&(*(recordIt)));
|
||||
|
||||
self_->LoadLevel2Data(recordTime, request);
|
||||
// The requested time may be in the previous record, so get that too
|
||||
if (recordIt != level2ProductRecords_.cbegin())
|
||||
{
|
||||
recordPtrs.push_back(&(*(--recordIt)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {record, recordTime};
|
||||
// For each record pointer
|
||||
for (auto& recordPtr : recordPtrs)
|
||||
{
|
||||
std::shared_ptr<types::RadarProductRecord> record {nullptr};
|
||||
std::chrono::system_clock::time_point recordTime {time};
|
||||
|
||||
if (recordPtr != nullptr)
|
||||
{
|
||||
// Don't check for an exact time match for level 2 products
|
||||
recordTime = recordPtr->first;
|
||||
record = recordPtr->second.lock();
|
||||
}
|
||||
|
||||
if (recordPtr != nullptr && 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>(radarId_);
|
||||
|
||||
QObject::connect(
|
||||
request.get(),
|
||||
&request::NexradFileRequest::RequestComplete,
|
||||
self_,
|
||||
[this](std::shared_ptr<request::NexradFileRequest> request)
|
||||
{
|
||||
if (request->radar_product_record() != nullptr)
|
||||
{
|
||||
Q_EMIT self_->DataReloaded(request->radar_product_record());
|
||||
}
|
||||
});
|
||||
|
||||
self_->LoadLevel2Data(recordTime, request);
|
||||
}
|
||||
|
||||
if (record != nullptr)
|
||||
{
|
||||
// Return valid records
|
||||
records.insert_or_assign(recordTime, record);
|
||||
}
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
std::tuple<std::shared_ptr<types::RadarProductRecord>,
|
||||
|
|
@ -1399,19 +1408,46 @@ RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType,
|
|||
{
|
||||
std::shared_ptr<wsr88d::rda::ElevationScan> radarData = nullptr;
|
||||
float elevationCut = 0.0f;
|
||||
std::vector<float> elevationCuts;
|
||||
std::vector<float> elevationCuts {};
|
||||
std::chrono::system_clock::time_point foundTime {};
|
||||
|
||||
std::shared_ptr<types::RadarProductRecord> record;
|
||||
std::tie(record, time) = p->GetLevel2ProductRecord(time);
|
||||
auto records = p->GetLevel2ProductRecords(time);
|
||||
|
||||
if (record != nullptr)
|
||||
for (auto& recordPair : records)
|
||||
{
|
||||
std::tie(radarData, elevationCut, elevationCuts) =
|
||||
record->level2_file()->GetElevationScan(
|
||||
dataBlockType, elevation, time);
|
||||
auto& record = recordPair.second;
|
||||
|
||||
if (record != nullptr)
|
||||
{
|
||||
std::shared_ptr<wsr88d::rda::ElevationScan> recordRadarData = nullptr;
|
||||
float recordElevationCut = 0.0f;
|
||||
std::vector<float> recordElevationCuts;
|
||||
|
||||
std::tie(recordRadarData, recordElevationCut, recordElevationCuts) =
|
||||
record->level2_file()->GetElevationScan(
|
||||
dataBlockType, elevation, time);
|
||||
|
||||
if (recordRadarData != nullptr)
|
||||
{
|
||||
auto& radarData0 = (*recordRadarData)[0];
|
||||
auto collectionTime =
|
||||
scwx::util::TimePoint(radarData0->modified_julian_date(),
|
||||
radarData0->collection_time());
|
||||
|
||||
// Find the newest radar data, not newer than the selected time
|
||||
if (radarData == nullptr ||
|
||||
(collectionTime <= time && foundTime < collectionTime))
|
||||
{
|
||||
radarData = recordRadarData;
|
||||
elevationCut = recordElevationCut;
|
||||
elevationCuts = std::move(recordElevationCuts);
|
||||
foundTime = collectionTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {radarData, elevationCut, elevationCuts, time};
|
||||
return {radarData, elevationCut, elevationCuts, foundTime};
|
||||
}
|
||||
|
||||
std::tuple<std::shared_ptr<wsr88d::rpg::Level3Message>,
|
||||
|
|
@ -1449,7 +1485,7 @@ std::vector<std::string> RadarProductManager::GetLevel3Products()
|
|||
|
||||
void RadarProductManager::SetCacheLimit(size_t cacheLimit)
|
||||
{
|
||||
p->cacheLimit_ = cacheLimit;
|
||||
p->cacheLimit_ = std::max<std::size_t>(cacheLimit, 6u);
|
||||
}
|
||||
|
||||
void RadarProductManager::UpdateAvailableProducts()
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Set the maximum number of products of each type that may be cached.
|
||||
* The cache limit cannot be set lower than 6.
|
||||
*
|
||||
* @param [in] cacheLimit The maximum number of products of each type
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -336,10 +336,10 @@ void TimelineManager::ReceiveMapWidgetPainted(std::size_t mapIndex)
|
|||
std::unique_lock lock {p->radarSweepMonitorMutex_};
|
||||
|
||||
// If the radar sweep has been updated
|
||||
if (p->radarSweepsUpdated_.contains(mapIndex))
|
||||
if (p->radarSweepsUpdated_.contains(mapIndex) &&
|
||||
!p->radarSweepsComplete_.contains(mapIndex))
|
||||
{
|
||||
// Mark the radar sweep complete
|
||||
p->radarSweepsUpdated_.erase(mapIndex);
|
||||
p->radarSweepsComplete_.insert(mapIndex);
|
||||
|
||||
// If all sweeps have completed rendering
|
||||
|
|
@ -466,20 +466,12 @@ void TimelineManager::Impl::PlaySync()
|
|||
|
||||
// Select the time
|
||||
auto selectTimeStart = std::chrono::steady_clock::now();
|
||||
auto [volumeTimeUpdated, selectedTimeUpdated] = SelectTime(newTime);
|
||||
SelectTime(newTime);
|
||||
auto selectTimeEnd = std::chrono::steady_clock::now();
|
||||
auto elapsedTime = selectTimeEnd - selectTimeStart;
|
||||
|
||||
if (volumeTimeUpdated)
|
||||
{
|
||||
// Wait for radar sweeps to update
|
||||
RadarSweepMonitorWait(radarSweepMonitorLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable radar sweep monitor
|
||||
RadarSweepMonitorDisable();
|
||||
}
|
||||
// Wait for radar sweeps to update
|
||||
RadarSweepMonitorWait(radarSweepMonitorLock);
|
||||
|
||||
// Calculate the interval until the next update, prior to selecting
|
||||
std::chrono::milliseconds interval;
|
||||
|
|
@ -639,79 +631,63 @@ void TimelineManager::Impl::Step(Direction direction)
|
|||
// Take a lock for time selection
|
||||
std::unique_lock lock {selectTimeMutex_};
|
||||
|
||||
// Determine time to get active volume times
|
||||
std::chrono::system_clock::time_point queryTime = adjustedTime_;
|
||||
if (queryTime == std::chrono::system_clock::time_point {})
|
||||
std::chrono::system_clock::time_point newTime = selectedTime_;
|
||||
|
||||
if (newTime == std::chrono::system_clock::time_point {})
|
||||
{
|
||||
queryTime = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
// Request active volume times
|
||||
auto radarProductManager =
|
||||
manager::RadarProductManager::Instance(radarSite_);
|
||||
auto volumeTimes = radarProductManager->GetActiveVolumeTimes(queryTime);
|
||||
|
||||
if (volumeTimes.empty())
|
||||
{
|
||||
logger_->debug("No products to step through");
|
||||
return;
|
||||
}
|
||||
|
||||
// Dynamically update maximum cached volume scans
|
||||
UpdateCacheLimit(radarProductManager, volumeTimes);
|
||||
|
||||
std::set<std::chrono::system_clock::time_point>::const_iterator it;
|
||||
|
||||
if (adjustedTime_ == std::chrono::system_clock::time_point {})
|
||||
{
|
||||
// If the adjusted time is live, get the last element in the set
|
||||
it = std::prev(volumeTimes.cend());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the current element in the set
|
||||
it = scwx::util::GetBoundedElementIterator(volumeTimes, adjustedTime_);
|
||||
}
|
||||
|
||||
if (it == volumeTimes.cend())
|
||||
{
|
||||
// Should not get here, but protect against an error
|
||||
logger_->error("No suitable volume time found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (direction == Direction::Back)
|
||||
{
|
||||
// Only if we aren't at the beginning of the volume times set
|
||||
if (it != volumeTimes.cbegin())
|
||||
if (direction == Direction::Back)
|
||||
{
|
||||
// Select the previous time
|
||||
adjustedTime_ = *(--it);
|
||||
selectedTime_ = adjustedTime_;
|
||||
|
||||
logger_->debug("Volume time updated: {}",
|
||||
scwx::util::TimeString(adjustedTime_));
|
||||
|
||||
Q_EMIT self_->LiveStateUpdated(false);
|
||||
Q_EMIT self_->VolumeTimeUpdated(adjustedTime_);
|
||||
Q_EMIT self_->SelectedTimeUpdated(adjustedTime_);
|
||||
newTime = std::chrono::floor<std::chrono::minutes>(
|
||||
std::chrono::system_clock::now());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cannot step forward any further
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Unlock prior to selecting time
|
||||
lock.unlock();
|
||||
|
||||
// Lock radar sweep monitor
|
||||
std::unique_lock radarSweepMonitorLock {radarSweepMonitorMutex_};
|
||||
|
||||
// Attempt to step forward or backward up to 30 minutes until an update is
|
||||
// received on at least one map
|
||||
for (std::size_t i = 0; i < 30; ++i)
|
||||
{
|
||||
// Only if we aren't at the end of the volume times set
|
||||
if (it != std::prev(volumeTimes.cend()))
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// Increment/decrement selected time by one minute
|
||||
if (direction == Direction::Back)
|
||||
{
|
||||
// Select the next time
|
||||
adjustedTime_ = *(++it);
|
||||
selectedTime_ = adjustedTime_;
|
||||
newTime -= 1min;
|
||||
}
|
||||
else
|
||||
{
|
||||
newTime += 1min;
|
||||
|
||||
logger_->debug("Volume time updated: {}",
|
||||
scwx::util::TimeString(adjustedTime_));
|
||||
// If the new time is more than 2 minutes in the future, stop stepping
|
||||
if (newTime > std::chrono::system_clock::now() + 2min)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT self_->LiveStateUpdated(false);
|
||||
Q_EMIT self_->VolumeTimeUpdated(adjustedTime_);
|
||||
Q_EMIT self_->SelectedTimeUpdated(adjustedTime_);
|
||||
// Reset radar sweep monitor in preparation for update
|
||||
RadarSweepMonitorReset();
|
||||
|
||||
// Select the time
|
||||
SelectTime(newTime);
|
||||
|
||||
// Wait for radar sweeps to update
|
||||
RadarSweepMonitorWait(radarSweepMonitorLock);
|
||||
|
||||
// Check for updates
|
||||
if (!radarSweepsUpdated_.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ AnimationDockWidget::AnimationDockWidget(QWidget* parent) :
|
|||
QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
|
||||
QDate currentDate = currentDateTime.date();
|
||||
QTime currentTime = currentDateTime.time();
|
||||
currentTime = currentTime.addSecs(-currentTime.second() + 59);
|
||||
|
||||
ui->dateEdit->setDate(currentDate);
|
||||
ui->timeEdit->setTime(currentTime);
|
||||
ui->dateEdit->setMaximumDate(currentDateTime.date());
|
||||
|
|
|
|||
|
|
@ -182,12 +182,9 @@ void Level2ProductView::ConnectRadarProductManager()
|
|||
[this](std::shared_ptr<types::RadarProductRecord> record)
|
||||
{
|
||||
if (record->radar_product_group() ==
|
||||
common::RadarProductGroup::Level2 &&
|
||||
std::chrono::floor<std::chrono::seconds>(record->time()) ==
|
||||
selected_time())
|
||||
common::RadarProductGroup::Level2)
|
||||
{
|
||||
// If the data associated with the currently selected time is
|
||||
// reloaded, update the view
|
||||
// If level 2 data associated was reloaded, update the view
|
||||
Update();
|
||||
}
|
||||
});
|
||||
|
|
@ -500,7 +497,7 @@ void Level2ProductView::UpdateColorTableLut()
|
|||
|
||||
void Level2ProductView::ComputeSweep()
|
||||
{
|
||||
logger_->debug("ComputeSweep()");
|
||||
logger_->trace("ComputeSweep()");
|
||||
|
||||
boost::timer::cpu_timer timer;
|
||||
|
||||
|
|
@ -517,17 +514,10 @@ void Level2ProductView::ComputeSweep()
|
|||
|
||||
std::shared_ptr<wsr88d::rda::ElevationScan> radarData;
|
||||
std::chrono::system_clock::time_point requestedTime {selected_time()};
|
||||
std::chrono::system_clock::time_point foundTime;
|
||||
std::tie(radarData, p->elevationCut_, p->elevationCuts_, foundTime) =
|
||||
std::tie(radarData, p->elevationCut_, p->elevationCuts_, std::ignore) =
|
||||
radarProductManager->GetLevel2Data(
|
||||
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)
|
||||
{
|
||||
Q_EMIT SweepNotComputed(types::NoUpdateReason::NotLoaded);
|
||||
|
|
@ -539,6 +529,8 @@ void Level2ProductView::ComputeSweep()
|
|||
return;
|
||||
}
|
||||
|
||||
logger_->debug("Computing Sweep");
|
||||
|
||||
std::size_t radials = radarData->crbegin()->first + 1;
|
||||
std::size_t vertexRadials = radials;
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ std::tuple<const void*, size_t, size_t> Level3RadialView::GetMomentData() const
|
|||
|
||||
void Level3RadialView::ComputeSweep()
|
||||
{
|
||||
logger_->debug("ComputeSweep()");
|
||||
logger_->trace("ComputeSweep()");
|
||||
|
||||
boost::timer::cpu_timer timer;
|
||||
|
||||
|
|
@ -185,6 +185,8 @@ void Level3RadialView::ComputeSweep()
|
|||
return;
|
||||
}
|
||||
|
||||
logger_->debug("Computing Sweep");
|
||||
|
||||
// A message with radial data should either have a Digital Radial Data
|
||||
// Array Packet, or a Radial Data Array Packet
|
||||
std::shared_ptr<wsr88d::rpg::DigitalRadialDataArrayPacket>
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ std::tuple<const void*, size_t, size_t> Level3RasterView::GetMomentData() const
|
|||
|
||||
void Level3RasterView::ComputeSweep()
|
||||
{
|
||||
logger_->debug("ComputeSweep()");
|
||||
logger_->trace("ComputeSweep()");
|
||||
|
||||
boost::timer::cpu_timer timer;
|
||||
|
||||
|
|
@ -169,6 +169,8 @@ void Level3RasterView::ComputeSweep()
|
|||
return;
|
||||
}
|
||||
|
||||
logger_->debug("Computing Sweep");
|
||||
|
||||
// A message with raster data should have a Raster Data Packet
|
||||
std::shared_ptr<wsr88d::rpg::RasterDataPacket> rasterData = nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ AwsNexradDataProvider::GetTimePointsByDate(
|
|||
std::shared_lock lock(p->objectsMutex_);
|
||||
|
||||
// Is the date present in the date list?
|
||||
bool currentDatePresent;
|
||||
auto currentDateIterator =
|
||||
std::find(p->objectDates_.cbegin(), p->objectDates_.cend(), day);
|
||||
if (currentDateIterator == p->objectDates_.cend())
|
||||
|
|
@ -199,6 +200,12 @@ AwsNexradDataProvider::GetTimePointsByDate(
|
|||
|
||||
// Re-lock mutex
|
||||
lock.lock();
|
||||
|
||||
currentDatePresent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDatePresent = true;
|
||||
}
|
||||
|
||||
// Determine objects to retrieve
|
||||
|
|
@ -216,7 +223,7 @@ AwsNexradDataProvider::GetTimePointsByDate(
|
|||
|
||||
// If we haven't updated the most recently queried dates yet, because the
|
||||
// date was already cached, update
|
||||
if (currentDateIterator != p->objectDates_.cend())
|
||||
if (currentDatePresent)
|
||||
{
|
||||
p->UpdateObjectDates(date);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,9 @@ public:
|
|||
std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>> radarData_ {};
|
||||
|
||||
std::map<rda::DataBlockType,
|
||||
std::map<std::uint16_t, std::shared_ptr<rda::ElevationScan>>>
|
||||
std::map<std::uint16_t,
|
||||
std::map<std::chrono::system_clock::time_point,
|
||||
std::shared_ptr<rda::ElevationScan>>>>
|
||||
index_ {};
|
||||
|
||||
std::list<std::stringstream> rawRecords_ {};
|
||||
|
|
@ -130,9 +132,9 @@ std::shared_ptr<const rda::VolumeCoveragePatternData> Ar2vFile::vcp_data() const
|
|||
}
|
||||
|
||||
std::tuple<std::shared_ptr<rda::ElevationScan>, float, std::vector<float>>
|
||||
Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
|
||||
float elevation,
|
||||
std::chrono::system_clock::time_point /*time*/) const
|
||||
Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
|
||||
float elevation,
|
||||
std::chrono::system_clock::time_point time) const
|
||||
{
|
||||
logger_->debug("GetElevationScan: {} degrees", elevation);
|
||||
|
||||
|
|
@ -152,6 +154,7 @@ Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
|
|||
std::uint16_t lowerBound = scans.cbegin()->first;
|
||||
std::uint16_t upperBound = scans.crbegin()->first;
|
||||
|
||||
// Find closest elevation match
|
||||
for (auto& scan : scans)
|
||||
{
|
||||
if (scan.first > lowerBound && scan.first <= codedElevation)
|
||||
|
|
@ -173,15 +176,25 @@ Ar2vFile::GetElevationScan(rda::DataBlockType dataBlockType,
|
|||
std::abs(static_cast<std::int32_t>(codedElevation) -
|
||||
static_cast<std::int32_t>(upperBound));
|
||||
|
||||
if (lowerDelta < upperDelta)
|
||||
// Select closest elevation match
|
||||
std::uint16_t elevationIndex =
|
||||
(lowerDelta < upperDelta) ? lowerBound : upperBound;
|
||||
elevationCut = elevationIndex / scaleFactor;
|
||||
|
||||
// Select closest time match, not newer than the selected time
|
||||
std::chrono::system_clock::time_point foundTime {};
|
||||
auto& elevationScans = scans.at(elevationIndex);
|
||||
|
||||
for (auto& scan : elevationScans)
|
||||
{
|
||||
elevationScan = scans.at(lowerBound);
|
||||
elevationCut = lowerBound / scaleFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
elevationScan = scans.at(upperBound);
|
||||
elevationCut = upperBound / scaleFactor;
|
||||
auto& scanTime = scan.first;
|
||||
|
||||
if (elevationScan == nullptr ||
|
||||
(scanTime <= time && scanTime > foundTime))
|
||||
{
|
||||
elevationScan = scan.second;
|
||||
foundTime = scanTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -460,8 +473,8 @@ void Ar2vFileImpl::IndexFile()
|
|||
waveformType = vcpData_->waveform_type(elevationCut.first);
|
||||
}
|
||||
else if ((digitalRadarData0 =
|
||||
std::dynamic_pointer_cast<rda::DigitalRadarData>(
|
||||
(*elevationCut.second)[0])) != nullptr)
|
||||
std::dynamic_pointer_cast<rda::DigitalRadarData>(radial0)) !=
|
||||
nullptr)
|
||||
{
|
||||
elevationAngle = digitalRadarData0->elevation_angle_raw();
|
||||
}
|
||||
|
|
@ -488,8 +501,10 @@ void Ar2vFileImpl::IndexFile()
|
|||
|
||||
if (momentData != nullptr)
|
||||
{
|
||||
// TODO: Handle multiple elevation scans
|
||||
index_[dataBlockType][elevationAngle] = elevationCut.second;
|
||||
auto time = util::TimePoint(radial0->modified_julian_date(),
|
||||
radial0->collection_time());
|
||||
|
||||
index_[dataBlockType][elevationAngle][time] = elevationCut.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue