Skip to content

Commit

Permalink
Support level 3 radial counts other than 360/720
Browse files Browse the repository at this point in the history
Fixes #49
  • Loading branch information
dpaulat committed Jun 2, 2023
1 parent 869dee8 commit 9c44257
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 32 deletions.
149 changes: 127 additions & 22 deletions scwx-qt/source/scwx/qt/view/level3_radial_view.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <scwx/qt/view/level3_radial_view.hpp>
#include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/common/constants.hpp>
#include <scwx/util/logger.hpp>
#include <scwx/util/threads.hpp>
Expand All @@ -19,21 +20,37 @@ namespace view
static const std::string logPrefix_ = "scwx::qt::view::level3_radial_view";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);

static constexpr uint16_t RANGE_FOLDED = 1u;
static constexpr uint32_t VERTICES_PER_BIN = 6u;
static constexpr uint32_t VALUES_PER_VERTEX = 2u;
static constexpr std::uint32_t kMaxRadialGates_ =
common::MAX_0_5_DEGREE_RADIALS * common::MAX_DATA_MOMENT_GATES;
static constexpr std::uint32_t kMaxCoordinates_ = kMaxRadialGates_ * 2u;

static constexpr std::uint16_t RANGE_FOLDED = 1u;
static constexpr std::uint32_t VERTICES_PER_BIN = 6u;
static constexpr std::uint32_t VALUES_PER_VERTEX = 2u;

class Level3RadialViewImpl
{
public:
explicit Level3RadialViewImpl() :
latitude_ {}, longitude_ {}, range_ {}, vcp_ {}, sweepTime_ {}
explicit Level3RadialViewImpl(Level3RadialView* self) :
self_ {self},
latitude_ {},
longitude_ {},
range_ {},
vcp_ {},
sweepTime_ {}
{
coordinates_.resize(kMaxCoordinates_);
}
~Level3RadialViewImpl() = default;

std::vector<float> vertices_;
std::vector<std::uint8_t> dataMoments8_;
void ComputeCoordinates(
std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket> radialData);

Level3RadialView* self_;

std::vector<float> coordinates_ {};
std::vector<float> vertices_ {};
std::vector<std::uint8_t> dataMoments8_ {};

float latitude_;
float longitude_;
Expand All @@ -47,7 +64,7 @@ Level3RadialView::Level3RadialView(
const std::string& product,
std::shared_ptr<manager::RadarProductManager> radarProductManager) :
Level3ProductView(product, radarProductManager),
p(std::make_unique<Level3RadialViewImpl>())
p(std::make_unique<Level3RadialViewImpl>(this))
{
}

Expand Down Expand Up @@ -155,7 +172,7 @@ void Level3RadialView::ComputeSweep()
}

// A message with radial data should either have a Digital Radial Data
// Array Packet, or a Radial Data Array Packet (TODO)
// Array Packet, or a Radial Data Array Packet
std::shared_ptr<wsr88d::rpg::DigitalRadialDataArrayPacket>
digitalDataPacket = nullptr;
std::shared_ptr<wsr88d::rpg::RadialDataPacket> radialDataPacket = nullptr;
Expand Down Expand Up @@ -205,20 +222,32 @@ void Level3RadialView::ComputeSweep()
return;
}

// Assume the number of radials should be 360 or 720
const size_t radials = radialData->number_of_radials();
if (radials != 360 && radials != 720)
// Valid number of radials is 1-720
size_t radials = radialData->number_of_radials();
if (radials < 1 || radials > 720)
{
logger_->warn("Unsupported number of radials: {}", radials);
return;
}

const common::RadialSize radialSize =
(radials == common::MAX_0_5_DEGREE_RADIALS) ?
common::RadialSize::_0_5Degree :
common::RadialSize::_1Degree;
common::RadialSize radialSize;
if (radials == common::MAX_0_5_DEGREE_RADIALS)
{
radialSize = common::RadialSize::_0_5Degree;
}
else if (radials == common::MAX_1_DEGREE_RADIALS)
{
radialSize = common::RadialSize::_1Degree;
}
else
{
radialSize = common::RadialSize::NonStandard;
}

const std::vector<float>& coordinates =
radarProductManager->coordinates(radialSize);
(radialSize == common::RadialSize::NonStandard) ?
p->coordinates_ :
radarProductManager->coordinates(radialSize);

// There should be a positive number of range bins in radial data
const uint16_t gates = radialData->number_of_range_bins();
Expand All @@ -232,8 +261,8 @@ void Level3RadialView::ComputeSweep()
p->longitude_ = descriptionBlock->longitude_of_radar();
p->range_ = descriptionBlock->range();
p->sweepTime_ =
util::TimePoint(descriptionBlock->volume_scan_date(),
descriptionBlock->volume_scan_start_time() * 1000);
scwx::util::TimePoint(descriptionBlock->volume_scan_date(),
descriptionBlock->volume_scan_start_time() * 1000);
p->vcp_ = descriptionBlock->volume_coverage_pattern();

// Calculate vertices
Expand All @@ -255,9 +284,18 @@ void Level3RadialView::ComputeSweep()
const uint16_t snrThreshold = descriptionBlock->threshold();

// Determine which radial to start at
const float radialMultiplier = radials / 360.0f;
const float startAngle = radialData->start_angle(0);
const uint16_t startRadial = std::lroundf(startAngle * radialMultiplier);
std::uint16_t startRadial;
if (radialSize == common::RadialSize::NonStandard)
{
p->ComputeCoordinates(radialData);
startRadial = 0;
}
else
{
const float radialMultiplier = radials / 360.0f;
const float startAngle = radialData->start_angle(0);
startRadial = std::lroundf(startAngle * radialMultiplier);
}

for (uint16_t radial = 0; radial < radialData->number_of_radials(); radial++)
{
Expand Down Expand Up @@ -371,6 +409,73 @@ void Level3RadialView::ComputeSweep()
emit SweepComputed();
}

void Level3RadialViewImpl::ComputeCoordinates(
std::shared_ptr<wsr88d::rpg::GenericRadialDataPacket> radialData)
{
logger_->debug("ComputeCoordinates()");

boost::timer::cpu_timer timer;

const GeographicLib::Geodesic& geodesic(
util::GeographicLib::DefaultGeodesic());

auto radarProductManager = self_->radar_product_manager();
auto radarSite = radarProductManager->radar_site();
const float gateSize = radarProductManager->gate_size();
const double radarLatitude = radarSite->latitude();
const double radarLongitude = radarSite->longitude();

// Calculate azimuth coordinates
timer.start();

const std::uint16_t numRadials = radialData->number_of_radials();
const std::uint16_t numRangeBins = radialData->number_of_range_bins();
const std::uint32_t numRadialGates = numRadials * numRangeBins;
const std::uint32_t maxRadialGates =
numRadials * common::MAX_DATA_MOMENT_GATES;

auto radialGates = boost::irange<uint32_t>(0, maxRadialGates);

std::for_each(
std::execution::par_unseq,
radialGates.begin(),
radialGates.end(),
[&](std::uint32_t radialGate)
{
const std::uint16_t gate = static_cast<std::uint16_t>(
radialGate % common::MAX_DATA_MOMENT_GATES);

if (gate >= numRadialGates)
{
return;
}

const std::uint16_t radial = static_cast<std::uint16_t>(
radialGate / common::MAX_DATA_MOMENT_GATES);

const float deltaAngle =
(radial == 0) ? radialData->start_angle(0) -
radialData->start_angle(numRadials - 1) :
radialData->delta_angle(radial);

const float angle =
radialData->start_angle(radial) - (deltaAngle * 0.5f);
const float range = (gate + 1) * gateSize;
const std::size_t offset = radialGate * 2;

double latitude;
double longitude;

geodesic.Direct(
radarLatitude, radarLongitude, angle, range, latitude, longitude);

coordinates_[offset] = latitude;
coordinates_[offset + 1] = longitude;
});
timer.stop();
logger_->debug("Coordinates calculated in {}", timer.format(6, "%ws"));
}

std::shared_ptr<Level3RadialView> Level3RadialView::Create(
const std::string& product,
std::shared_ptr<manager::RadarProductManager> radarProductManager)
Expand Down
3 changes: 2 additions & 1 deletion wxdata/include/scwx/common/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace common
enum class RadialSize
{
_0_5Degree,
_1Degree
_1Degree,
NonStandard
};

} // namespace common
Expand Down
19 changes: 10 additions & 9 deletions wxdata/include/scwx/wsr88d/rpg/generic_radial_data_packet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,20 @@ class GenericRadialDataPacket : public Packet
explicit GenericRadialDataPacket();
~GenericRadialDataPacket();

GenericRadialDataPacket(const GenericRadialDataPacket&) = delete;
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<uint8_t>& level(uint16_t r) const = 0;
virtual std::uint16_t index_of_first_range_bin() const = 0;
virtual std::int16_t i_center_of_sweep() const = 0;
virtual std::int16_t j_center_of_sweep() const = 0;
virtual std::uint16_t number_of_radials() const = 0;
virtual std::uint16_t number_of_range_bins() const = 0;
virtual float start_angle(std::uint16_t r) const = 0;
virtual float delta_angle(std::uint16_t r) const = 0;

virtual const std::vector<std::uint8_t>& level(std::uint16_t r) const = 0;

private:
std::unique_ptr<GenericRadialDataPacketImpl> p;
Expand Down

0 comments on commit 9c44257

Please sign in to comment.