Update RPG to Build 23.0

This commit is contained in:
Dan Paulat 2025-05-16 23:50:42 -05:00
parent ef7caf5519
commit e49adafda9
6 changed files with 299 additions and 24 deletions

View file

@ -0,0 +1,48 @@
#pragma once
#include <scwx/wsr88d/rpg/packet.hpp>
#include <cstdint>
#include <memory>
namespace scwx::wsr88d::rpg
{
class DigitalRasterDataArrayPacket : public Packet
{
public:
explicit DigitalRasterDataArrayPacket();
~DigitalRasterDataArrayPacket();
DigitalRasterDataArrayPacket(const DigitalRasterDataArrayPacket&) = delete;
DigitalRasterDataArrayPacket&
operator=(const DigitalRasterDataArrayPacket&) = delete;
DigitalRasterDataArrayPacket(DigitalRasterDataArrayPacket&&) noexcept;
DigitalRasterDataArrayPacket&
operator=(DigitalRasterDataArrayPacket&&) noexcept;
[[nodiscard]] std::uint16_t packet_code() const override;
[[nodiscard]] std::uint16_t i_coordinate_start() const;
[[nodiscard]] std::uint16_t j_coordinate_start() const;
[[nodiscard]] std::uint16_t i_scale_factor() const;
[[nodiscard]] std::uint16_t j_scale_factor() const;
[[nodiscard]] std::uint16_t number_of_cells() const;
[[nodiscard]] std::uint16_t number_of_rows() const;
[[nodiscard]] std::uint16_t number_of_bytes_in_row(std::uint16_t r) const;
[[nodiscard]] const std::vector<std::uint8_t>& level(std::uint16_t r) const;
[[nodiscard]] std::size_t data_size() const override;
bool Parse(std::istream& is) override;
static std::shared_ptr<DigitalRasterDataArrayPacket>
Create(std::istream& is);
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace scwx::wsr88d::rpg

View file

@ -0,0 +1,220 @@
#include <scwx/wsr88d/rpg/digital_raster_data_array_packet.hpp>
#include <scwx/util/logger.hpp>
#include <istream>
#include <string>
namespace scwx::wsr88d::rpg
{
static const std::string logPrefix_ =
"scwx::wsr88d::rpg::digital_raster_data_array_packet";
static const auto logger_ = util::Logger::Create(logPrefix_);
class DigitalRasterDataArrayPacket::Impl
{
public:
struct Row
{
std::uint16_t numberOfBytes_ {0};
std::vector<std::uint8_t> level_ {};
};
explicit Impl() = default;
~Impl() = default;
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
Impl(const Impl&&) = delete;
Impl& operator=(const Impl&&) = delete;
std::uint16_t packetCode_ {0};
std::uint16_t iCoordinateStart_ {0};
std::uint16_t jCoordinateStart_ {0};
std::uint16_t iScaleFactor_ {0};
std::uint16_t jScaleFactor_ {0};
std::uint16_t numberOfCells_ {0};
std::uint16_t numberOfRows_ {0};
std::uint16_t numberOfBytesInRow_ {0};
// Repeat for each row
std::vector<Row> row_ {};
std::size_t dataSize_ {0};
};
DigitalRasterDataArrayPacket::DigitalRasterDataArrayPacket() :
p(std::make_unique<Impl>())
{
}
DigitalRasterDataArrayPacket::~DigitalRasterDataArrayPacket() = default;
DigitalRasterDataArrayPacket::DigitalRasterDataArrayPacket(
DigitalRasterDataArrayPacket&&) noexcept = default;
DigitalRasterDataArrayPacket& DigitalRasterDataArrayPacket::operator=(
DigitalRasterDataArrayPacket&&) noexcept = default;
std::uint16_t DigitalRasterDataArrayPacket::packet_code() const
{
return p->packetCode_;
}
std::uint16_t DigitalRasterDataArrayPacket::i_coordinate_start() const
{
return p->iCoordinateStart_;
}
std::uint16_t DigitalRasterDataArrayPacket::j_coordinate_start() const
{
return p->jCoordinateStart_;
}
std::uint16_t DigitalRasterDataArrayPacket::i_scale_factor() const
{
return p->iScaleFactor_;
}
std::uint16_t DigitalRasterDataArrayPacket::j_scale_factor() const
{
return p->jScaleFactor_;
}
std::uint16_t DigitalRasterDataArrayPacket::number_of_cells() const
{
return p->numberOfCells_;
}
std::uint16_t DigitalRasterDataArrayPacket::number_of_rows() const
{
return p->numberOfRows_;
}
std::uint16_t
DigitalRasterDataArrayPacket::number_of_bytes_in_row(std::uint16_t r) const
{
return p->row_[r].numberOfBytes_;
}
const std::vector<std::uint8_t>&
DigitalRasterDataArrayPacket::level(std::uint16_t r) const
{
return p->row_[r].level_;
}
bool DigitalRasterDataArrayPacket::Parse(std::istream& is)
{
bool blockValid = true;
std::size_t bytesRead = 0;
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers)
is.read(reinterpret_cast<char*>(&p->packetCode_), 2);
is.read(reinterpret_cast<char*>(&p->iCoordinateStart_), 2);
is.read(reinterpret_cast<char*>(&p->jCoordinateStart_), 2);
is.read(reinterpret_cast<char*>(&p->iScaleFactor_), 2);
is.read(reinterpret_cast<char*>(&p->jScaleFactor_), 2);
is.read(reinterpret_cast<char*>(&p->numberOfCells_), 2);
is.read(reinterpret_cast<char*>(&p->numberOfRows_), 2);
bytesRead += 14;
p->packetCode_ = ntohs(p->packetCode_);
p->iCoordinateStart_ = ntohs(p->iCoordinateStart_);
p->jCoordinateStart_ = ntohs(p->jCoordinateStart_);
p->iScaleFactor_ = ntohs(p->iScaleFactor_);
p->jScaleFactor_ = ntohs(p->jScaleFactor_);
p->numberOfCells_ = ntohs(p->numberOfCells_);
p->numberOfRows_ = ntohs(p->numberOfRows_);
if (is.eof())
{
logger_->debug("Reached end of file");
blockValid = false;
}
else
{
if (p->packetCode_ != 33)
{
logger_->warn("Invalid packet code: {}", p->packetCode_);
blockValid = false;
}
if (p->numberOfCells_ < 1 || p->numberOfCells_ > 1840)
{
logger_->warn("Invalid number of cells: {}", p->numberOfCells_);
blockValid = false;
}
if (p->numberOfRows_ < 1 || p->numberOfRows_ > 464)
{
logger_->warn("Invalid number of rows: {}", p->numberOfRows_);
blockValid = false;
}
}
if (blockValid)
{
p->row_.resize(p->numberOfRows_);
for (std::uint16_t r = 0; r < p->numberOfRows_; r++)
{
auto& row = p->row_[r];
is.read(reinterpret_cast<char*>(&row.numberOfBytes_), 2);
bytesRead += 2;
row.numberOfBytes_ = ntohs(row.numberOfBytes_);
if (row.numberOfBytes_ < 1 || row.numberOfBytes_ > 1840)
{
logger_->warn(
"Invalid number of bytes: {} (Row {})", row.numberOfBytes_, r);
blockValid = false;
break;
}
else if (row.numberOfBytes_ < p->numberOfCells_)
{
logger_->warn("Number of bytes < number of cells: {} < {} (Row {})",
row.numberOfBytes_,
p->numberOfCells_,
r);
blockValid = false;
break;
}
// Read raster bins
std::size_t dataSize = p->numberOfCells_;
row.level_.resize(dataSize);
is.read(reinterpret_cast<char*>(row.level_.data()),
static_cast<std::streamsize>(dataSize));
is.seekg(static_cast<std::streamoff>(row.numberOfBytes_ - dataSize),
std::ios_base::cur);
bytesRead += row.numberOfBytes_;
}
}
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)
p->dataSize_ = bytesRead;
if (!ValidateMessage(is, bytesRead))
{
blockValid = false;
}
return blockValid;
}
std::shared_ptr<DigitalRasterDataArrayPacket>
DigitalRasterDataArrayPacket::Create(std::istream& is)
{
std::shared_ptr<DigitalRasterDataArrayPacket> packet =
std::make_shared<DigitalRasterDataArrayPacket>();
if (!packet->Parse(is))
{
packet.reset();
}
return packet;
}
} // namespace scwx::wsr88d::rpg

View file

@ -119,9 +119,14 @@ static const std::unordered_map<int, CreateLevel3MessageFunction> //
{182, GraphicProductMessage::Create},
{184, GraphicProductMessage::Create},
{186, GraphicProductMessage::Create},
{189, GraphicProductMessage::Create},
{190, GraphicProductMessage::Create},
{191, GraphicProductMessage::Create},
{192, GraphicProductMessage::Create},
{193, GraphicProductMessage::Create},
{195, GraphicProductMessage::Create},
{196, GraphicProductMessage::Create},
{197, GraphicProductMessage::Create},
{202, GraphicProductMessage::Create}};
std::shared_ptr<Level3Message> Level3MessageFactory::Create(std::istream& is)

View file

@ -5,6 +5,7 @@
#include <scwx/wsr88d/rpg/cell_trend_volume_scan_times.hpp>
#include <scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp>
#include <scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp>
#include <scwx/wsr88d/rpg/digital_raster_data_array_packet.hpp>
#include <scwx/wsr88d/rpg/generic_data_packet.hpp>
#include <scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp>
#include <scwx/wsr88d/rpg/linked_contour_vector_packet.hpp>
@ -69,6 +70,7 @@ static const std::unordered_map<unsigned int, CreateMessageFunction> create_ {
{26, PointGraphicSymbolPacket::Create},
{28, GenericDataPacket::Create},
{29, GenericDataPacket::Create},
{33, DigitalRasterDataArrayPacket::Create},
{0x0802, SetColorLevelPacket::Create},
{0x0E03, LinkedContourVectorPacket::Create},
{0x3501, UnlinkedContourVectorPacket::Create},

View file

@ -21,28 +21,13 @@ static const std::string logPrefix_ =
static const auto logger_ = util::Logger::Create(logPrefix_);
static const std::set<int> compressedProducts_ = {
32, 94, 99, 134, 135, 138, 149, 152, 153, 154, 155,
159, 161, 163, 165, 167, 168, 170, 172, 173, 174, 175,
176, 177, 178, 179, 180, 182, 186, 193, 195, 202};
32, 94, 99, 113, 134, 135, 138, 149, 152, 153, 154, 155, 159,
161, 163, 165, 167, 168, 170, 172, 173, 174, 175, 176, 177, 178,
179, 180, 182, 186, 189, 190, 191, 192, 193, 195, 197, 202};
static const std::set<int> uncodedDataLevelProducts_ = {32,
34,
81,
93,
94,
99,
134,
135,
138,
153,
154,
155,
159,
161,
163,
177,
193,
195};
static const std::set<int> uncodedDataLevelProducts_ = {
32, 34, 81, 93, 94, 99, 134, 135, 138, 153, 154, 155,
159, 161, 163, 177, 189, 190, 191, 192, 193, 195, 197};
static const std::unordered_map<int, unsigned int> rangeMap_ {
{19, 230}, {20, 460}, {27, 230}, {30, 230}, {31, 230}, {32, 230},
@ -57,7 +42,8 @@ static const std::unordered_map<int, unsigned int> rangeMap_ {
{163, 300}, {165, 300}, {166, 230}, {167, 300}, {168, 300}, {169, 230},
{170, 230}, {171, 230}, {172, 230}, {173, 230}, {174, 230}, {175, 230},
{176, 230}, {177, 230}, {178, 300}, {179, 300}, {180, 89}, {181, 89},
{182, 89}, {184, 89}, {186, 417}, {193, 460}, {195, 460}, {196, 50}};
{182, 89}, {184, 89}, {186, 417}, {193, 460}, {195, 460}, {196, 50},
{197, 230}};
static const std::unordered_map<int, unsigned int> xResolutionMap_ {
{19, 1000}, {20, 2000}, {27, 1000}, {30, 1000}, {31, 2000}, {32, 1000},
@ -71,7 +57,7 @@ static const std::unordered_map<int, unsigned int> xResolutionMap_ {
{166, 250}, {167, 250}, {168, 250}, {169, 2000}, {170, 250}, {171, 2000},
{172, 250}, {173, 250}, {174, 250}, {175, 250}, {176, 250}, {177, 250},
{178, 1000}, {179, 1000}, {180, 150}, {181, 150}, {182, 150}, {184, 150},
{186, 300}, {193, 250}, {195, 1000}};
{186, 300}, {193, 250}, {195, 1000}, {197, 250}};
static const std::unordered_map<int, unsigned int> yResolutionMap_ {{37, 1000},
{38, 4000},
@ -86,7 +72,11 @@ static const std::unordered_map<int, unsigned int> yResolutionMap_ {{37, 1000},
{90, 4000},
{97, 1000},
{98, 4000},
{166, 250}};
{166, 250},
{189, 20},
{190, 20},
{191, 20},
{192, 20}};
// GR uses different internal units than defined units in level 3 products
static const std::unordered_map<std::int16_t, float> grScale_ {
@ -580,6 +570,10 @@ uint16_t ProductDescriptionBlock::number_of_levels() const
break;
case 134:
case 189:
case 190:
case 191:
case 192:
numberOfLevels = 256;
break;
@ -864,6 +858,10 @@ ProductDescriptionBlock::data_level_code(std::uint8_t level) const
case 163:
case 167:
case 168:
case 189:
case 190:
case 191:
case 192:
case 195:
switch (level)
{

View file

@ -147,6 +147,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/ccb_header.hpp
include/scwx/wsr88d/rpg/cell_trend_volume_scan_times.hpp
include/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp
include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp
include/scwx/wsr88d/rpg/digital_raster_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
@ -188,6 +189,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/ccb_header.cpp
source/scwx/wsr88d/rpg/cell_trend_volume_scan_times.cpp
source/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.cpp
source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp
source/scwx/wsr88d/rpg/digital_raster_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