diff --git a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp index 07881e75..fb826ca5 100644 --- a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp @@ -362,7 +362,8 @@ bool RadarProductLayer::RunMousePicking( if (code.has_value() && // code.value() != wsr88d::DataLevelCode::Blank && - code.value() != wsr88d::DataLevelCode::NoData) + code.value() != wsr88d::DataLevelCode::NoData && + code.value() != wsr88d::DataLevelCode::Topped) { // Level has associated data level code std::string codeName = wsr88d::GetDataLevelCodeName(code.value()); @@ -391,6 +392,7 @@ bool RadarProductLayer::RunMousePicking( // Level has associated data value float f = value.value(); std::string units {}; + std::string suffix {}; std::string hoverText; std::shared_ptr colorTable = @@ -403,6 +405,13 @@ bool RadarProductLayer::RunMousePicking( units = colorTable->units(); } + if (code.has_value() && + code.value() == wsr88d::DataLevelCode::Topped) + { + // Show " TOPPED" suffix for echo tops + suffix = " TOPPED"; + } + if (units.empty() || // units.starts_with("?") || // boost::iequals(units, "NONE") || @@ -411,17 +420,17 @@ bool RadarProductLayer::RunMousePicking( { // Don't display a units value that wasn't intended to be // displayed - hoverText = fmt::format("{}", f); + hoverText = fmt::format("{}{}", f, suffix); } else if (std::isalpha(units.at(0))) { // dBZ, Kts, etc. - hoverText = fmt::format("{} {}", f, units); + hoverText = fmt::format("{} {}{}", f, units, suffix); } else { // %, etc. - hoverText = fmt::format("{}{}", f, units); + hoverText = fmt::format("{}{}{}", f, units, suffix); } // Show the tooltip diff --git a/wxdata/include/scwx/common/products.hpp b/wxdata/include/scwx/common/products.hpp index a3e0d04c..97d9c324 100644 --- a/wxdata/include/scwx/common/products.hpp +++ b/wxdata/include/scwx/common/products.hpp @@ -48,6 +48,7 @@ enum class Level3ProductCategory SpecificDifferentialPhase, CorrelationCoefficient, VerticallyIntegratedLiquid, + EchoTops, HydrometeorClassification, PrecipitationAccumulation, Unknown diff --git a/wxdata/include/scwx/wsr88d/rpg/product_description_block.hpp b/wxdata/include/scwx/wsr88d/rpg/product_description_block.hpp index d7973026..81a05583 100644 --- a/wxdata/include/scwx/wsr88d/rpg/product_description_block.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/product_description_block.hpp @@ -70,6 +70,9 @@ public: float log_offset() const; float log_scale() const; + std::uint8_t data_mask() const; + std::uint8_t topped_mask() const; + units::angle::degrees elevation() const; bool IsCompressionEnabled() const; diff --git a/wxdata/include/scwx/wsr88d/wsr88d_types.hpp b/wxdata/include/scwx/wsr88d/wsr88d_types.hpp index ae63a155..d7608d84 100644 --- a/wxdata/include/scwx/wsr88d/wsr88d_types.hpp +++ b/wxdata/include/scwx/wsr88d/wsr88d_types.hpp @@ -21,6 +21,7 @@ enum class DataLevelCode NoAccumulation, RangeFolded, Reserved, + Topped, // Hydrometeor Classification Biological, diff --git a/wxdata/source/scwx/common/products.cpp b/wxdata/source/scwx/common/products.cpp index 102d92dd..f3ecd1e8 100644 --- a/wxdata/source/scwx/common/products.cpp +++ b/wxdata/source/scwx/common/products.cpp @@ -43,17 +43,19 @@ static const std::unordered_map level2Palette_ { {Level2Product::Unknown, "???"}}; static const std::unordered_map level3ProductCodeMap_ { - {30, "SW"}, {37, "NCR"}, {56, "SRM"}, {57, "NVL"}, {78, "N1P"}, - {79, "N3P"}, {80, "NTP"}, {81, "DPA"}, {82, "SPD"}, {94, "DR"}, - {99, "DV"}, {134, "DVL"}, {138, "DSP"}, {153, "SDR"}, {154, "SDV"}, - {159, "DZD"}, {161, "DCC"}, {163, "DKD"}, {165, "DHC"}, {166, "ML"}, - {169, "OHA"}, {170, "DAA"}, {172, "DTA"}, {173, "DUA"}, {174, "DOD"}, - {175, "DSD"}, {177, "HHC"}, {180, "TDR"}, {182, "TDV"}}; + {30, "SW"}, {37, "NCR"}, {41, "NET"}, {56, "SRM"}, {57, "NVL"}, + {78, "N1P"}, {79, "N3P"}, {80, "NTP"}, {81, "DPA"}, {82, "SPD"}, + {94, "DR"}, {99, "DV"}, {134, "DVL"}, {135, "EET"}, {138, "DSP"}, + {153, "SDR"}, {154, "SDV"}, {159, "DZD"}, {161, "DCC"}, {163, "DKD"}, + {165, "DHC"}, {166, "ML"}, {169, "OHA"}, {170, "DAA"}, {172, "DTA"}, + {173, "DUA"}, {174, "DOD"}, {175, "DSD"}, {177, "HHC"}, {180, "TDR"}, + {182, "TDV"}}; static const std::unordered_map level3ProductDescription_ { {"SW", "Spectrum Width"}, {"NCR", "Composite Reflectivity"}, + {"NET", "Echo Tops"}, {"SRM", "Storm Relative Mean Radial Velocity"}, {"NVL", "Vertically Integrated Liquid"}, {"N1P", "Surface Rainfall Accumulation (1 hr)"}, @@ -64,6 +66,7 @@ static const std::unordered_map {"DR", "Digital Reflectivity"}, {"DV", "Digital Velocity"}, {"DVL", "Digital Vertically Integrated Liquid"}, + {"EET", "Enhanced Echo Tops"}, {"DSP", "Digital Storm Total Precipitation"}, {"SDR", "Super-Resolution Reflectivity"}, {"SDV", "Super-Resolution Velocity"}, @@ -115,6 +118,10 @@ static const std::unordered_map> {"DVL", {"DVL"}}, {"NVL", {"NVL"}}, + // Echo Tops + {"EET", {"EET"}}, + {"NET", {"NET"}}, + // Hydrometeor Classification {"DHC", {"NXH", "NYH", "NZH", "N0H", "NAH", "N1H", "NBH", "N2H", "N3H"}}, {"HHC", {"HHC"}}, @@ -149,6 +156,7 @@ static const std::unordered_map {Level3ProductCategory::SpecificDifferentialPhase, "KDP"}, {Level3ProductCategory::CorrelationCoefficient, "CC"}, {Level3ProductCategory::VerticallyIntegratedLiquid, "VIL"}, + {Level3ProductCategory::EchoTops, "ET"}, {Level3ProductCategory::HydrometeorClassification, "HC"}, {Level3ProductCategory::PrecipitationAccumulation, "ACC"}, {Level3ProductCategory::Unknown, "?"}}; @@ -167,6 +175,7 @@ static const std::unordered_map "Correlation Coefficient"}, {Level3ProductCategory::VerticallyIntegratedLiquid, "Vertically Integrated Liquid"}, + {Level3ProductCategory::EchoTops, "Echo Tops"}, {Level3ProductCategory::HydrometeorClassification, "Hydrometeor Classification"}, {Level3ProductCategory::PrecipitationAccumulation, @@ -183,6 +192,7 @@ static const std::unordered_map> {Level3ProductCategory::SpecificDifferentialPhase, {"DKD"}}, {Level3ProductCategory::CorrelationCoefficient, {"DCC"}}, {Level3ProductCategory::VerticallyIntegratedLiquid, {"DVL", "NVL"}}, + {Level3ProductCategory::EchoTops, {"EET", "NET"}}, {Level3ProductCategory::HydrometeorClassification, {"DHC", "HHC"}}, {Level3ProductCategory::PrecipitationAccumulation, {"DAA", "DTA", "DUA"}}, {Level3ProductCategory::Unknown, {}}}; @@ -197,6 +207,7 @@ static const std::unordered_map {Level3ProductCategory::SpecificDifferentialPhase, "N0K"}, {Level3ProductCategory::CorrelationCoefficient, "N0C"}, {Level3ProductCategory::VerticallyIntegratedLiquid, "DVL"}, + {Level3ProductCategory::EchoTops, "EET"}, {Level3ProductCategory::HydrometeorClassification, "N0H"}, {Level3ProductCategory::PrecipitationAccumulation, "DAA"}}; diff --git a/wxdata/source/scwx/wsr88d/rpg/product_description_block.cpp b/wxdata/source/scwx/wsr88d/rpg/product_description_block.cpp index 4bcd24fb..0fb7a9fa 100644 --- a/wxdata/source/scwx/wsr88d/rpg/product_description_block.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/product_description_block.cpp @@ -370,6 +370,9 @@ uint16_t ProductDescriptionBlock::threshold() const case 177: threshold = 10; break; + + default: + break; } return threshold; @@ -418,6 +421,9 @@ float ProductDescriptionBlock::offset() const case 176: offset = util::DecodeFloat32(p->halfword(33), p->halfword(34)); break; + + default: + break; } return offset; @@ -473,6 +479,9 @@ float ProductDescriptionBlock::scale() const case 176: scale = util::DecodeFloat32(p->halfword(31), p->halfword(32)); break; + + default: + break; } return scale; @@ -586,6 +595,9 @@ uint16_t ProductDescriptionBlock::number_of_levels() const case 179: numberOfLevels = 71; break; + + default: + break; } return numberOfLevels; @@ -600,6 +612,9 @@ std::uint16_t ProductDescriptionBlock::log_start() const case 134: logStart = p->halfword(33); break; + + default: + break; } return logStart; @@ -614,6 +629,9 @@ float ProductDescriptionBlock::log_offset() const case 134: logOffset = util::DecodeFloat16(p->halfword(35)); break; + + default: + break; } return logOffset; @@ -628,11 +646,48 @@ float ProductDescriptionBlock::log_scale() const case 134: logScale = util::DecodeFloat16(p->halfword(34)); break; + + default: + break; } return logScale; } +std::uint8_t ProductDescriptionBlock::data_mask() const +{ + std::uint8_t dataMask = 0xff; + + switch (p->productCode_) + { + case 135: + dataMask = static_cast(p->halfword(31)); + break; + + default: + break; + } + + return dataMask; +} + +std::uint8_t ProductDescriptionBlock::topped_mask() const +{ + std::uint8_t toppedMask = 0x00; + + switch (p->productCode_) + { + case 135: + toppedMask = static_cast(p->halfword(34)); + break; + + default: + break; + } + + return toppedMask; +} + units::angle::degrees ProductDescriptionBlock::elevation() const { double elevation = 0.0; @@ -816,6 +871,10 @@ ProductDescriptionBlock::data_level_code(std::uint8_t level) const case 1: return DataLevelCode::BadData; default: + if (level & topped_mask()) + { + return DataLevelCode::Topped; + } break; } break; @@ -864,6 +923,8 @@ ProductDescriptionBlock::data_level_code(std::uint8_t level) const return DataLevelCode::UnknownClassification; case 150: return DataLevelCode::RangeFolded; + default: + break; } break; @@ -1032,6 +1093,10 @@ ProductDescriptionBlock::data_value(std::uint8_t level) const } break; + case 135: + level = level & data_mask(); + [[fallthrough]]; + default: f = level * dataScale + dataOffset; break;