diff --git a/scwx-qt/source/scwx/qt/view/level3_radial_view.cpp b/scwx-qt/source/scwx/qt/view/level3_radial_view.cpp index a0953ec3..d147c580 100644 --- a/scwx-qt/source/scwx/qt/view/level3_radial_view.cpp +++ b/scwx-qt/source/scwx/qt/view/level3_radial_view.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -322,8 +323,10 @@ void Level3RadialView::ComputeSweep() // A message with radial data should either have a Digital Radial Data Array // Packet, or a Radial Data Array Packet (TODO) - std::shared_ptr digitalData = - nullptr; + std::shared_ptr + digitalDataPacket = nullptr; + std::shared_ptr radialDataPacket = nullptr; + std::shared_ptr radialData = nullptr; for (uint16_t layer = 0; layer < numberOfLayers; layer++) { @@ -332,40 +335,56 @@ void Level3RadialView::ComputeSweep() for (auto it = packetList.begin(); it != packetList.end(); it++) { - digitalData = std::dynamic_pointer_cast< + // Prefer Digital Radial Data to Radial Data + digitalDataPacket = std::dynamic_pointer_cast< wsr88d::rpg::DigitalRadialDataArrayPacket>(*it); - if (digitalData != nullptr) + if (digitalDataPacket != nullptr) { break; } + + // Otherwise, check for Radial Data + if (radialDataPacket == nullptr) + { + radialDataPacket = + std::dynamic_pointer_cast(*it); + } } - if (digitalData != nullptr) + if (digitalDataPacket != nullptr) { break; } } - if (digitalData == nullptr) + if (digitalDataPacket != nullptr) { - BOOST_LOG_TRIVIAL(debug) - << logPrefix_ << "No digital radial data array found"; + radialData = digitalDataPacket; + } + else if (radialDataPacket != nullptr) + { + radialData = radialDataPacket; + } + else + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "No radial data found"; return; } - if (digitalData->i_center_of_sweep() != 0 || - digitalData->j_center_of_sweep() != 0) + // Check if radial data is centered on the radar location + if (radialData->i_center_of_sweep() != 0 || + radialData->j_center_of_sweep() != 0) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "(i, j) is not centered on radar, display is inaccurate: (" - << digitalData->i_center_of_sweep() << ", " - << digitalData->j_center_of_sweep() << ")"; + << radialData->i_center_of_sweep() << ", " + << radialData->j_center_of_sweep() << ")"; } // Assume the number of radials should be 360 or 720 - const size_t radials = digitalData->number_of_radials(); + const size_t radials = radialData->number_of_radials(); if (radials != 360 && radials != 720) { BOOST_LOG_TRIVIAL(warning) @@ -381,7 +400,7 @@ void Level3RadialView::ComputeSweep() p->radarProductManager_->coordinates(radialSize); // There should be a positive number of range bins in radial data - const uint16_t gates = digitalData->number_of_range_bins(); + const uint16_t gates = radialData->number_of_range_bins(); if (gates < 1) { BOOST_LOG_TRIVIAL(warning) @@ -419,13 +438,12 @@ void Level3RadialView::ComputeSweep() // Determine which radial to start at const float radialMultiplier = radials / 360.0f; - const float startAngle = digitalData->start_angle(0); + const float startAngle = radialData->start_angle(0); const uint16_t startRadial = std::lroundf(startAngle * radialMultiplier); - for (uint16_t radial = 0; radial < digitalData->number_of_radials(); - radial++) + for (uint16_t radial = 0; radial < radialData->number_of_radials(); radial++) { - const auto dataMomentsArray8 = digitalData->level(radial); + const auto dataMomentsArray8 = radialData->level(radial); // Compute gate interval const uint16_t dataMomentInterval = descriptionBlock->x_resolution_raw(); @@ -449,7 +467,8 @@ void Level3RadialView::ComputeSweep() size_t vertexCount = (gate > 0) ? 6 : 3; // Store data moment value - uint8_t dataValue = dataMomentsArray8[i]; + uint8_t dataValue = + (i < dataMomentsArray8.size()) ? dataMomentsArray8[i] : 0; if (dataValue < snrThreshold && dataValue != RANGE_FOLDED) { continue; @@ -457,7 +476,7 @@ void Level3RadialView::ComputeSweep() for (size_t m = 0; m < vertexCount; m++) { - dataMoments8[mIndex++] = dataMomentsArray8[i]; + dataMoments8[mIndex++] = dataValue; } // Store vertices diff --git a/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp index 71b747ff..50c3e1bb 100644 --- a/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -14,7 +14,7 @@ namespace rpg class DigitalRadialDataArrayPacketImpl; -class DigitalRadialDataArrayPacket : public Packet +class DigitalRadialDataArrayPacket : public GenericRadialDataPacket { public: explicit DigitalRadialDataArrayPacket(); diff --git a/wxdata/include/scwx/wsr88d/rpg/generic_radial_data_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/generic_radial_data_packet.hpp new file mode 100644 index 00000000..3646148b --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/generic_radial_data_packet.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class GenericRadialDataPacketImpl; + +class GenericRadialDataPacket : public Packet +{ +public: + explicit GenericRadialDataPacket(); + ~GenericRadialDataPacket(); + + GenericRadialDataPacket(const GenericRadialDataPacket&) = delete; + GenericRadialDataPacket& operator=(const GenericRadialDataPacket&) = delete; + + GenericRadialDataPacket(GenericRadialDataPacket&&) noexcept; + GenericRadialDataPacket& operator=(GenericRadialDataPacket&&) noexcept; + + virtual int16_t i_center_of_sweep() const = 0; + virtual int16_t j_center_of_sweep() const = 0; + virtual uint16_t number_of_radials() const = 0; + virtual uint16_t number_of_range_bins() const = 0; + virtual float start_angle(uint16_t r) const = 0; + + virtual const std::vector& level(uint16_t r) const = 0; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp b/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp index 69296341..1ba8f41b 100644 --- a/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/radial_data_packet.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -14,7 +14,7 @@ namespace rpg class RadialDataPacketImpl; -class RadialDataPacket : public Packet +class RadialDataPacket : public GenericRadialDataPacket { public: explicit RadialDataPacket(); @@ -34,6 +34,10 @@ public: float scale_factor() const; uint16_t number_of_radials() const; + float start_angle(uint16_t r) const; + float delta_angle(uint16_t r) const; + const std::vector& level(uint16_t r) const; + size_t data_size() const override; bool Parse(std::istream& is) override; diff --git a/wxdata/source/scwx/wsr88d/rpg/generic_radial_data_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/generic_radial_data_packet.cpp new file mode 100644 index 00000000..51ed5db7 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/generic_radial_data_packet.cpp @@ -0,0 +1,37 @@ +#include + +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::generic_radial_data_packet] "; + +class GenericRadialDataPacketImpl +{ +public: + explicit GenericRadialDataPacketImpl() = default; + ~GenericRadialDataPacketImpl() = default; +}; + +GenericRadialDataPacket::GenericRadialDataPacket() : + p(std::make_unique()) +{ +} +GenericRadialDataPacket::~GenericRadialDataPacket() = default; + +GenericRadialDataPacket::GenericRadialDataPacket( + GenericRadialDataPacket&&) noexcept = default; +GenericRadialDataPacket& GenericRadialDataPacket::operator=( + GenericRadialDataPacket&&) noexcept = default; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp b/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp index 33fa8fbe..0913d390 100644 --- a/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/radial_data_packet.cpp @@ -24,9 +24,14 @@ public: uint16_t startAngle_; uint16_t angleDelta_; std::vector data_; + std::vector level_; Radial() : - numberOfRleHalfwords_ {0}, startAngle_ {0}, angleDelta_ {0}, data_ {} + numberOfRleHalfwords_ {0}, + startAngle_ {0}, + angleDelta_ {0}, + data_ {}, + level_ {} { } }; @@ -103,6 +108,21 @@ uint16_t RadialDataPacket::number_of_radials() const return p->numberOfRadials_; } +float RadialDataPacket::start_angle(uint16_t r) const +{ + return p->radial_[r].startAngle_ * 0.1f; +} + +float RadialDataPacket::delta_angle(uint16_t r) const +{ + return p->radial_[r].angleDelta_ * 0.1f; +} + +const std::vector& RadialDataPacket::level(uint16_t r) const +{ + return p->radial_[r].level_; +} + size_t RadialDataPacket::data_size() const { return p->dataSize_; @@ -197,6 +217,14 @@ bool RadialDataPacket::Parse(std::istream& is) { radial.data_.pop_back(); } + + radial.level_.resize(radial.data_.size()); + + std::transform(std::execution::par_unseq, + radial.data_.cbegin(), + radial.data_.cend(), + radial.level_.begin(), + [](uint8_t data) -> uint8_t { return data & 0x0f; }); } } diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index ad2f5c52..a1dcdd8c 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -80,6 +80,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/ccb_header.hpp include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp include/scwx/wsr88d/rpg/general_status_message.hpp include/scwx/wsr88d/rpg/generic_data_packet.hpp + include/scwx/wsr88d/rpg/generic_radial_data_packet.hpp include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp include/scwx/wsr88d/rpg/graphic_product_message.hpp include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp @@ -118,6 +119,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/ccb_header.cpp source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp source/scwx/wsr88d/rpg/general_status_message.cpp source/scwx/wsr88d/rpg/generic_data_packet.cpp + source/scwx/wsr88d/rpg/generic_radial_data_packet.cpp source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp source/scwx/wsr88d/rpg/graphic_product_message.cpp source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp