From 094d286b418afbf3cd85f11b18b527551e033adf Mon Sep 17 00:00:00 2001 From: AdenKoperczak Date: Mon, 7 Apr 2025 12:36:06 -0400 Subject: [PATCH] fully working merging of data from last and current scan --- .../scwx/qt/manager/radar_product_manager.cpp | 76 +------ .../scwx/qt/view/level2_product_view.cpp | 3 +- wxdata/include/scwx/wsr88d/ar2v_file.hpp | 3 +- .../aws_level2_chunks_data_provider.cpp | 4 +- wxdata/source/scwx/wsr88d/ar2v_file.cpp | 207 +++++++++++------- 5 files changed, 140 insertions(+), 153 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp index e6ede7b4..12cf9d61 100644 --- a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp @@ -1520,87 +1520,17 @@ RadarProductManager::GetLevel2Data(wsr88d::rda::DataBlockType dataBlockType, std::vector elevationCuts {}; std::chrono::system_clock::time_point foundTime {}; - auto records = p->GetLevel2ProductRecords(time); - //TODO decide when to use chunked vs archived data. - if (true) + if constexpr (true) { auto currentFile = std::dynamic_pointer_cast( p->level2ChunksProviderManager_->provider_->LoadLatestObject()); - auto lastFile = std::dynamic_pointer_cast( - p->level2ChunksProviderManager_->provider_->LoadSecondLatestObject()); - auto radarFile = - std::make_shared(currentFile, lastFile); std::tie(radarData, elevationCut, elevationCuts) = - radarFile->GetElevationScan(dataBlockType, elevation, time); - - /* - auto currentFile = std::dynamic_pointer_cast( - p->level2ChunksProviderManager_->provider_->LoadLatestObject()); - std::shared_ptr currentRadarData = nullptr; - float currentElevationCut = 0.0f; - std::vector currentElevationCuts; - if (currentFile != nullptr) - { - std::tie(currentRadarData, currentElevationCut, currentElevationCuts) = - currentFile->GetElevationScan(dataBlockType, elevation, time); - } - - std::shared_ptr lastRadarData = nullptr; - float lastElevationCut = 0.0f; - std::vector lastElevationCuts; - auto lastFile = std::dynamic_pointer_cast( - p->level2ChunksProviderManager_->provider_->LoadSecondLatestObject()); - if (lastFile != nullptr) - { - std::tie(lastRadarData, lastElevationCut, lastElevationCuts) = - lastFile->GetElevationScan(dataBlockType, elevation, time); - } - - if (currentRadarData != nullptr) - { - if (lastRadarData != nullptr) - { - auto& radarData0 = (*currentRadarData)[0]; - auto collectionTime = std::chrono::floor( - scwx::util::TimePoint(radarData0->modified_julian_date(), - radarData0->collection_time())); - - // TODO merge data - radarData = currentRadarData; - elevationCut = currentElevationCut; - elevationCuts = std::move(currentElevationCuts); - foundTime = collectionTime; - } - else - { - auto& radarData0 = (*currentRadarData)[0]; - auto collectionTime = std::chrono::floor( - scwx::util::TimePoint(radarData0->modified_julian_date(), - radarData0->collection_time())); - - radarData = currentRadarData; - elevationCut = currentElevationCut; - elevationCuts = std::move(currentElevationCuts); - foundTime = collectionTime; - } - } - else if (lastRadarData != nullptr) - { - auto& radarData0 = (*lastRadarData)[0]; - auto collectionTime = std::chrono::floor( - scwx::util::TimePoint(radarData0->modified_julian_date(), - radarData0->collection_time())); - - radarData = lastRadarData; - elevationCut = lastElevationCut; - elevationCuts = std::move(lastElevationCuts); - foundTime = collectionTime; - } - */ + currentFile->GetElevationScan(dataBlockType, elevation, time); } else { + auto records = p->GetLevel2ProductRecords(time); for (auto& recordPair : records) { auto& record = recordPair.second; diff --git a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp index 69f0dbf2..9ead358b 100644 --- a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp +++ b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp @@ -561,8 +561,7 @@ void Level2ProductView::ComputeSweep() Q_EMIT SweepNotComputed(types::NoUpdateReason::NotLoaded); return; } - // TODO do not do this when updating from live data - if (false && (radarData == p->elevationScan_) && + if ((radarData == p->elevationScan_) && smoothingEnabled == p->lastSmoothingEnabled_ && (showSmoothedRangeFolding == p->lastShowSmoothedRangeFolding_ || !smoothingEnabled)) diff --git a/wxdata/include/scwx/wsr88d/ar2v_file.hpp b/wxdata/include/scwx/wsr88d/ar2v_file.hpp index 9afca516..64319283 100644 --- a/wxdata/include/scwx/wsr88d/ar2v_file.hpp +++ b/wxdata/include/scwx/wsr88d/ar2v_file.hpp @@ -32,7 +32,8 @@ public: Ar2vFile(Ar2vFile&&) noexcept; Ar2vFile& operator=(Ar2vFile&&) noexcept; - Ar2vFile(std::shared_ptr current, std::shared_ptr last); + Ar2vFile(const std::shared_ptr& current, + const std::shared_ptr& last); std::uint32_t julian_date() const; std::uint32_t milliseconds() const; diff --git a/wxdata/source/scwx/provider/aws_level2_chunks_data_provider.cpp b/wxdata/source/scwx/provider/aws_level2_chunks_data_provider.cpp index ef5c392e..0b18113f 100644 --- a/wxdata/source/scwx/provider/aws_level2_chunks_data_provider.cpp +++ b/wxdata/source/scwx/provider/aws_level2_chunks_data_provider.cpp @@ -637,7 +637,9 @@ AwsLevel2ChunksDataProvider::LoadObjectByTime( std::shared_ptr AwsLevel2ChunksDataProvider::LoadLatestObject() { - return p->currentScan_.nexradFile_; + return std::make_shared(p->currentScan_.nexradFile_, + p->lastScan_.nexradFile_); + //return p->currentScan_.nexradFile_; } std::shared_ptr diff --git a/wxdata/source/scwx/wsr88d/ar2v_file.cpp b/wxdata/source/scwx/wsr88d/ar2v_file.cpp index a5f46731..7e7e14e9 100644 --- a/wxdata/source/scwx/wsr88d/ar2v_file.cpp +++ b/wxdata/source/scwx/wsr88d/ar2v_file.cpp @@ -9,7 +9,6 @@ #include #include -#include #if defined(_MSC_VER) # pragma warning(push) @@ -559,114 +558,171 @@ bool IsRadarDataIncomplete( return angleDelta > kIncompleteDataAngleThreshold_; } -Ar2vFile::Ar2vFile(std::shared_ptr current, - std::shared_ptr last) : - Ar2vFile() +Ar2vFile::Ar2vFile(const std::shared_ptr& current, + const std::shared_ptr& last) : + Ar2vFile() { - /*p->vcpData_ = std::make_shared( - *current->vcp_data());*/ - p->vcpData_ = nullptr; // TODO - /* - use index_ to go through each block type, and elevation. - get the latest time. - if the latest time is not complete, get the previous time (possibly in - last), and merge - */ + // This is only used to index right now, so not a huge deal + p->vcpData_ = nullptr; - if (current == nullptr) + // Reconstruct index from the other's indexes + if (current != nullptr) { - return; - } - - for (const auto& type : current->p->index_) - { - for (const auto& elevation : type.second) + for (const auto& type : current->p->index_) { - const auto& mostRecent = elevation.second.crbegin(); - if (mostRecent == elevation.second.crend()) + for (const auto& elevation : type.second) { - continue; - } - - if (IsRadarDataIncomplete(mostRecent->second)) - { - std::shared_ptr secondMostRecent = - nullptr; - auto maybe = elevation.second.rbegin(); - ++maybe; - - if (maybe == elevation.second.rend()) + // Get the most recent scan + const auto& mostRecent = elevation.second.crbegin(); + if (mostRecent == elevation.second.crend()) { - if (last == nullptr) + continue; + } + + // Merge this scan with the last one if it is incomplete + if (IsRadarDataIncomplete(mostRecent->second)) + { + std::shared_ptr secondMostRecent = nullptr; + + // check if this volume scan has an earlier elevation scan + auto maybe = elevation.second.rbegin(); // TODO name + ++maybe; + + if (maybe == elevation.second.rend()) { - // Nothing to merge with - p->index_[type.first][elevation.first][mostRecent->first] = - mostRecent->second; - continue; + if (last == nullptr) + { + // Nothing to merge with + p->index_[type.first][elevation.first][mostRecent->first] = + mostRecent->second; + continue; + } + + // get the scan from the last scan + auto elevationScan = + std::get>( + last->GetElevationScan( + type.first, elevation.first, {})); + if (elevationScan == nullptr) + { + // Nothing to merge with + p->index_[type.first][elevation.first][mostRecent->first] = + mostRecent->second; + continue; + } + + secondMostRecent = elevationScan; + } + else + { + secondMostRecent = maybe->second; } - auto elevationScan = - std::get>( - last->GetElevationScan(type.first, elevation.first, {})); - if (elevationScan == nullptr) + // Make the new scan + auto newScan = std::make_shared(); + + // Copy over the new radials + for (const auto& radial : *(mostRecent->second)) { - // Nothing to merge with - p->index_[type.first][elevation.first][mostRecent->first] = - mostRecent->second; - continue; + (*newScan)[radial.first] = radial.second; } - secondMostRecent = elevationScan; + /* Correctly order the old radials. The radials need to be in + * order for the rendering to work, and the index needs to start + * at 0 and increase by one from there. Since the new radial + * should have index 0, the old radial needs to be reshaped to + * match the new radials indexing. + */ + + const double lowestAzm = + mostRecent->second->cbegin()->second->azimuth_angle().value(); + const double heighestAzm = mostRecent->second->crbegin() + ->second->azimuth_angle() + .value(); + std::uint16_t index = mostRecent->second->crbegin()->first + 1; + + // Sort by the azimuth. Makes the rest of this way easier + auto secondMostRecentAzmMap = + std::map>(); + for (const auto& radial : *secondMostRecent) + { + secondMostRecentAzmMap[radial.second->azimuth_angle() + .value()] = radial.second; + } + + if (lowestAzm <= heighestAzm) // New scan does not contain 0/360 + { + // Get the radials following the new radials + for (const auto& radial : secondMostRecentAzmMap) + { + if (radial.first > heighestAzm) + { + (*newScan)[index] = radial.second; + ++index; + } + } + // Get the radials before the new radials + for (const auto& radial : secondMostRecentAzmMap) + { + if (radial.first < lowestAzm) + { + (*newScan)[index] = radial.second; + ++index; + } + else + { + break; + } + } + } + else // New scan includes 0/360 + { + // The radials will already be in the right order + for (const auto& radial : secondMostRecentAzmMap) + { + if (radial.first > heighestAzm && radial.first < lowestAzm) + { + (*newScan)[index] = radial.second; + ++index; + } + } + } + + p->index_[type.first][elevation.first][mostRecent->first] = + newScan; } else { - secondMostRecent = maybe->second; + p->index_[type.first][elevation.first][mostRecent->first] = + mostRecent->second; } - - auto newScan = std::make_shared(); - - // Convert old into new coords - logger_->error( - "old {}, new {}", - secondMostRecent->cbegin()->second->azimuth_angle().value(), - mostRecent->second->cbegin()->second->azimuth_angle().value()); - // TODO Ordering these correctly - for (const auto& radial : *secondMostRecent) - { - (*newScan)[radial.first] = radial.second; - } - for (const auto& radial : *(mostRecent->second)) - { - (*newScan)[radial.first] = radial.second; - } - - p->index_[type.first][elevation.first][mostRecent->first] = - newScan; - } - else - { - p->index_[type.first][elevation.first][mostRecent->first] = - mostRecent->second; } } } - // Go though last, adding other elevations TODO + // Go though last, adding other elevations if (last != nullptr) { for (const auto& type : last->p->index_) { + // Find the highest elevation this type has for the current scan + // Start below any reasonable elevation + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) float highestCurrentElevation = -90; const auto& maybe1 = p->index_.find(type.first); if (maybe1 != p->index_.cend()) { const auto& maybe2 = maybe1->second.crbegin(); if (maybe2 != maybe1->second.crend()) { - highestCurrentElevation = maybe2->first + 0.01; + // Add a slight offset to ensure good floating point compare. + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + highestCurrentElevation = maybe2->first + 0.01f; } } + for (const auto& elevation : type.second) { + // Only add elevations above the current scan's elevation if (elevation.first > highestCurrentElevation) { const auto& mostRecent = elevation.second.crbegin(); @@ -680,7 +736,6 @@ Ar2vFile::Ar2vFile(std::shared_ptr current, } } } - } } // namespace wsr88d