mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 15:00:06 +00:00 
			
		
		
		
	Level 3 radial view
This commit is contained in:
		
							parent
							
								
									4412914089
								
							
						
					
					
						commit
						ab83b50e0a
					
				
					 5 changed files with 620 additions and 2 deletions
				
			
		|  | @ -105,9 +105,11 @@ set(SRC_UTIL source/scwx/qt/util/font.cpp | ||||||
|              source/scwx/qt/util/font_buffer.cpp |              source/scwx/qt/util/font_buffer.cpp | ||||||
|              source/scwx/qt/util/json.cpp) |              source/scwx/qt/util/json.cpp) | ||||||
| set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp | set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp | ||||||
|  |              source/scwx/qt/view/level3_radial_view.hpp | ||||||
|              source/scwx/qt/view/radar_product_view.hpp |              source/scwx/qt/view/radar_product_view.hpp | ||||||
|              source/scwx/qt/view/radar_product_view_factory.hpp) |              source/scwx/qt/view/radar_product_view_factory.hpp) | ||||||
| set(SRC_VIEW source/scwx/qt/view/level2_product_view.cpp | set(SRC_VIEW source/scwx/qt/view/level2_product_view.cpp | ||||||
|  |              source/scwx/qt/view/level3_radial_view.cpp | ||||||
|              source/scwx/qt/view/radar_product_view.cpp |              source/scwx/qt/view/radar_product_view.cpp | ||||||
|              source/scwx/qt/view/radar_product_view_factory.cpp) |              source/scwx/qt/view/radar_product_view_factory.cpp) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -440,8 +440,6 @@ void Level2ProductView::ComputeSweep() | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    // Compute threshold at which to display an individual bin
 |    // Compute threshold at which to display an individual bin
 | ||||||
|    const float    scale        = momentData0->scale(); |  | ||||||
|    const float    offset       = momentData0->offset(); |  | ||||||
|    const uint16_t snrThreshold = momentData0->snr_threshold_raw(); |    const uint16_t snrThreshold = momentData0->snr_threshold_raw(); | ||||||
| 
 | 
 | ||||||
|    // Azimuth resolution spacing:
 |    // Azimuth resolution spacing:
 | ||||||
|  |  | ||||||
							
								
								
									
										549
									
								
								scwx-qt/source/scwx/qt/view/level3_radial_view.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										549
									
								
								scwx-qt/source/scwx/qt/view/level3_radial_view.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,549 @@ | ||||||
|  | #include <scwx/qt/view/level3_radial_view.hpp> | ||||||
|  | #include <scwx/common/constants.hpp> | ||||||
|  | #include <scwx/util/threads.hpp> | ||||||
|  | #include <scwx/util/time.hpp> | ||||||
|  | #include <scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp> | ||||||
|  | #include <scwx/wsr88d/rpg/graphic_product_message.hpp> | ||||||
|  | 
 | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <boost/range/irange.hpp> | ||||||
|  | #include <boost/timer/timer.hpp> | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace view | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | static const std::string logPrefix_ = "[scwx::qt::view::level3_radial_view] "; | ||||||
|  | 
 | ||||||
|  | static constexpr uint16_t RANGE_FOLDED      = 1u; | ||||||
|  | static constexpr uint32_t VERTICES_PER_BIN  = 6u; | ||||||
|  | static constexpr uint32_t VALUES_PER_VERTEX = 2u; | ||||||
|  | 
 | ||||||
|  | class Level3RadialViewImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |    explicit Level3RadialViewImpl( | ||||||
|  |       const std::string&                            product, | ||||||
|  |       std::shared_ptr<manager::RadarProductManager> radarProductManager) : | ||||||
|  |        product_ {product}, | ||||||
|  |        radarProductManager_ {radarProductManager}, | ||||||
|  |        selectedTime_ {}, | ||||||
|  |        graphicMessage_ {nullptr}, | ||||||
|  |        latitude_ {}, | ||||||
|  |        longitude_ {}, | ||||||
|  |        range_ {}, | ||||||
|  |        vcp_ {}, | ||||||
|  |        sweepTime_ {}, | ||||||
|  |        colorTable_ {}, | ||||||
|  |        colorTableLut_ {}, | ||||||
|  |        colorTableMin_ {2}, | ||||||
|  |        colorTableMax_ {254} | ||||||
|  |    { | ||||||
|  |    } | ||||||
|  |    ~Level3RadialViewImpl() = default; | ||||||
|  | 
 | ||||||
|  |    std::string                                   product_; | ||||||
|  |    std::shared_ptr<manager::RadarProductManager> radarProductManager_; | ||||||
|  | 
 | ||||||
|  |    float                                 selectedElevation_; | ||||||
|  |    std::chrono::system_clock::time_point selectedTime_; | ||||||
|  | 
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::GraphicProductMessage> graphicMessage_; | ||||||
|  | 
 | ||||||
|  |    std::vector<float>   vertices_; | ||||||
|  |    std::vector<uint8_t> dataMoments8_; | ||||||
|  | 
 | ||||||
|  |    float    latitude_; | ||||||
|  |    float    longitude_; | ||||||
|  |    float    range_; | ||||||
|  |    uint16_t vcp_; | ||||||
|  | 
 | ||||||
|  |    std::chrono::system_clock::time_point sweepTime_; | ||||||
|  | 
 | ||||||
|  |    std::shared_ptr<common::ColorTable>    colorTable_; | ||||||
|  |    std::vector<boost::gil::rgba8_pixel_t> colorTableLut_; | ||||||
|  |    uint16_t                               colorTableMin_; | ||||||
|  |    uint16_t                               colorTableMax_; | ||||||
|  | 
 | ||||||
|  |    std::shared_ptr<common::ColorTable> savedColorTable_; | ||||||
|  |    float                               savedScale_; | ||||||
|  |    float                               savedOffset_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Level3RadialView::Level3RadialView( | ||||||
|  |    const std::string&                            product, | ||||||
|  |    std::shared_ptr<manager::RadarProductManager> radarProductManager) : | ||||||
|  |     p(std::make_unique<Level3RadialViewImpl>(product, radarProductManager)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | Level3RadialView::~Level3RadialView() = default; | ||||||
|  | 
 | ||||||
|  | const std::vector<boost::gil::rgba8_pixel_t>& | ||||||
|  | Level3RadialView::color_table() const | ||||||
|  | { | ||||||
|  |    if (p->colorTableLut_.size() == 0) | ||||||
|  |    { | ||||||
|  |       return RadarProductView::color_table(); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       return p->colorTableLut_; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t Level3RadialView::color_table_min() const | ||||||
|  | { | ||||||
|  |    if (p->colorTableLut_.size() == 0) | ||||||
|  |    { | ||||||
|  |       return RadarProductView::color_table_min(); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       return p->colorTableMin_; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t Level3RadialView::color_table_max() const | ||||||
|  | { | ||||||
|  |    if (p->colorTableLut_.size() == 0) | ||||||
|  |    { | ||||||
|  |       return RadarProductView::color_table_max(); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       return p->colorTableMax_; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float Level3RadialView::range() const | ||||||
|  | { | ||||||
|  |    return p->range_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::chrono::system_clock::time_point Level3RadialView::sweep_time() const | ||||||
|  | { | ||||||
|  |    return p->sweepTime_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t Level3RadialView::vcp() const | ||||||
|  | { | ||||||
|  |    return p->vcp_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const std::vector<float>& Level3RadialView::vertices() const | ||||||
|  | { | ||||||
|  |    return p->vertices_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | common::RadarProductGroup Level3RadialView::GetRadarProductGroup() const | ||||||
|  | { | ||||||
|  |    return common::RadarProductGroup::Level3; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string Level3RadialView::GetRadarProductName() const | ||||||
|  | { | ||||||
|  |    return p->product_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::tuple<const void*, size_t, size_t> Level3RadialView::GetMomentData() const | ||||||
|  | { | ||||||
|  |    const void* data; | ||||||
|  |    size_t      dataSize; | ||||||
|  |    size_t      componentSize; | ||||||
|  | 
 | ||||||
|  |    data          = p->dataMoments8_.data(); | ||||||
|  |    dataSize      = p->dataMoments8_.size() * sizeof(uint8_t); | ||||||
|  |    componentSize = 1; | ||||||
|  | 
 | ||||||
|  |    return std::tie(data, dataSize, componentSize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::LoadColorTable( | ||||||
|  |    std::shared_ptr<common::ColorTable> colorTable) | ||||||
|  | { | ||||||
|  |    p->colorTable_ = colorTable; | ||||||
|  |    UpdateColorTable(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::SelectElevation(float elevation) | ||||||
|  | { | ||||||
|  |    p->selectedElevation_ = elevation; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::SelectTime(std::chrono::system_clock::time_point time) | ||||||
|  | { | ||||||
|  |    p->selectedTime_ = time; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::Update() | ||||||
|  | { | ||||||
|  |    util::async([=]() { ComputeSweep(); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::UpdateColorTable() | ||||||
|  | { | ||||||
|  |    if (p->graphicMessage_ == nullptr || //
 | ||||||
|  |        p->colorTable_ == nullptr ||     //
 | ||||||
|  |        !p->colorTable_->IsValid()) | ||||||
|  |    { | ||||||
|  |       // Nothing to update
 | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::ProductDescriptionBlock> descriptionBlock = | ||||||
|  |       p->graphicMessage_->description_block(); | ||||||
|  | 
 | ||||||
|  |    if (descriptionBlock == nullptr) | ||||||
|  |    { | ||||||
|  |       // No description block
 | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    float    offset    = descriptionBlock->offset(); | ||||||
|  |    float    scale     = descriptionBlock->scale(); | ||||||
|  |    uint16_t threshold = descriptionBlock->threshold(); | ||||||
|  | 
 | ||||||
|  |    if (p->savedColorTable_ == p->colorTable_ && //
 | ||||||
|  |        p->savedOffset_ == offset &&             //
 | ||||||
|  |        p->savedScale_ == scale) | ||||||
|  |    { | ||||||
|  |       // The color table LUT does not need updated
 | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // If the threshold is 2, the range min should be set to 1 for range folding
 | ||||||
|  |    uint16_t rangeMin = std::min<uint16_t>(1, threshold); | ||||||
|  |    uint16_t rangeMax = descriptionBlock->number_of_levels(); | ||||||
|  | 
 | ||||||
|  |    boost::integer_range<uint16_t> dataRange = | ||||||
|  |       boost::irange<uint16_t>(rangeMin, rangeMax + 1); | ||||||
|  | 
 | ||||||
|  |    std::vector<boost::gil::rgba8_pixel_t>& lut = p->colorTableLut_; | ||||||
|  |    lut.resize(rangeMax - rangeMin + 1); | ||||||
|  |    lut.shrink_to_fit(); | ||||||
|  | 
 | ||||||
|  |    std::for_each(std::execution::par_unseq, | ||||||
|  |                  dataRange.begin(), | ||||||
|  |                  dataRange.end(), | ||||||
|  |                  [&](uint16_t i) | ||||||
|  |                  { | ||||||
|  |                     if (i == RANGE_FOLDED && threshold > RANGE_FOLDED) | ||||||
|  |                     { | ||||||
|  |                        lut[i - *dataRange.begin()] = p->colorTable_->rf_color(); | ||||||
|  |                     } | ||||||
|  |                     else | ||||||
|  |                     { | ||||||
|  |                        float f; | ||||||
|  | 
 | ||||||
|  |                        // Different products use different scale/offset formulas
 | ||||||
|  |                        switch (descriptionBlock->product_code()) | ||||||
|  |                        { | ||||||
|  |                        case 159: | ||||||
|  |                        case 161: | ||||||
|  |                        case 163: | ||||||
|  |                        case 167: | ||||||
|  |                        case 168: | ||||||
|  |                        case 170: | ||||||
|  |                        case 172: | ||||||
|  |                        case 173: | ||||||
|  |                        case 174: | ||||||
|  |                        case 175: | ||||||
|  |                        case 176: | ||||||
|  |                           f = (i - offset) / scale; | ||||||
|  |                           break; | ||||||
|  | 
 | ||||||
|  |                        default: | ||||||
|  |                           f = i * scale + offset; | ||||||
|  |                           break; | ||||||
|  |                        } | ||||||
|  | 
 | ||||||
|  |                        lut[i - *dataRange.begin()] = p->colorTable_->Color(f); | ||||||
|  |                     } | ||||||
|  |                  }); | ||||||
|  | 
 | ||||||
|  |    p->colorTableMin_ = rangeMin; | ||||||
|  |    p->colorTableMax_ = rangeMax; | ||||||
|  | 
 | ||||||
|  |    p->savedColorTable_ = p->colorTable_; | ||||||
|  |    p->savedOffset_     = offset; | ||||||
|  |    p->savedScale_      = scale; | ||||||
|  | 
 | ||||||
|  |    emit ColorTableUpdated(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Level3RadialView::ComputeSweep() | ||||||
|  | { | ||||||
|  |    BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "ComputeSweep()"; | ||||||
|  | 
 | ||||||
|  |    boost::timer::cpu_timer timer; | ||||||
|  | 
 | ||||||
|  |    std::scoped_lock sweepLock(sweep_mutex()); | ||||||
|  | 
 | ||||||
|  |    // Retrieve message from Radar Product Manager
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::Level3Message> message = | ||||||
|  |       p->radarProductManager_->GetLevel3Data(p->product_, p->selectedTime_); | ||||||
|  | 
 | ||||||
|  |    // A message with radial data should be a Graphic Product Message
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::GraphicProductMessage> gpm = | ||||||
|  |       std::dynamic_pointer_cast<wsr88d::rpg::GraphicProductMessage>(message); | ||||||
|  |    if (gpm == nullptr) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) | ||||||
|  |          << logPrefix_ << "Graphic Product Message not found"; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  |    else if (gpm == p->graphicMessage_) | ||||||
|  |    { | ||||||
|  |       // Skip if this is the message we previously processed
 | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  |    p->graphicMessage_ = gpm; | ||||||
|  | 
 | ||||||
|  |    // A message with radial data should have a Product Description Block and
 | ||||||
|  |    // Product Symbology Block
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::ProductDescriptionBlock> descriptionBlock = | ||||||
|  |       message->description_block(); | ||||||
|  |    std::shared_ptr<wsr88d::rpg::ProductSymbologyBlock> symbologyBlock = | ||||||
|  |       gpm->symbology_block(); | ||||||
|  |    if (descriptionBlock == nullptr || symbologyBlock == nullptr) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Missing blocks"; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // A valid message should have a positive number of layers
 | ||||||
|  |    uint16_t numberOfLayers = symbologyBlock->number_of_layers(); | ||||||
|  |    if (numberOfLayers < 1) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) | ||||||
|  |          << logPrefix_ << "No layers present in symbology block"; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // A message with radial data should either have a Digital Radial Data Array
 | ||||||
|  |    // Packet, or a Radial Data Array Packet (TODO)
 | ||||||
|  |    std::shared_ptr<wsr88d::rpg::DigitalRadialDataArrayPacket> digitalData = | ||||||
|  |       nullptr; | ||||||
|  | 
 | ||||||
|  |    for (uint16_t layer = 0; layer < numberOfLayers; layer++) | ||||||
|  |    { | ||||||
|  |       std::vector<std::shared_ptr<wsr88d::rpg::Packet>> packetList = | ||||||
|  |          symbologyBlock->packet_list(layer); | ||||||
|  | 
 | ||||||
|  |       for (auto it = packetList.begin(); it != packetList.end(); it++) | ||||||
|  |       { | ||||||
|  |          digitalData = std::dynamic_pointer_cast< | ||||||
|  |             wsr88d::rpg::DigitalRadialDataArrayPacket>(*it); | ||||||
|  | 
 | ||||||
|  |          if (digitalData != nullptr) | ||||||
|  |          { | ||||||
|  |             break; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (digitalData != nullptr) | ||||||
|  |       { | ||||||
|  |          break; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (digitalData == nullptr) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(debug) | ||||||
|  |          << logPrefix_ << "No digital radial data array found"; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (digitalData->i_center_of_sweep() != 0 || | ||||||
|  |        digitalData->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() << ")"; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    // Assume the number of radials should be 360 or 720
 | ||||||
|  |    const size_t radials = digitalData->number_of_radials(); | ||||||
|  |    if (radials != 360 && radials != 720) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) | ||||||
|  |          << logPrefix_ << "Unsupported number of radials: " << radials; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    const common::RadialSize radialSize = | ||||||
|  |       (radials == common::MAX_0_5_DEGREE_RADIALS) ? | ||||||
|  |          common::RadialSize::_0_5Degree : | ||||||
|  |          common::RadialSize::_1Degree; | ||||||
|  |    const std::vector<float>& coordinates = | ||||||
|  |       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(); | ||||||
|  |    if (gates < 1) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) | ||||||
|  |          << logPrefix_ << "No range bins in radial data"; | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    p->latitude_  = descriptionBlock->latitude_of_radar(); | ||||||
|  |    p->longitude_ = descriptionBlock->longitude_of_radar(); | ||||||
|  |    p->range_     = descriptionBlock->range(); | ||||||
|  |    p->sweepTime_ = | ||||||
|  |       util::TimePoint(descriptionBlock->volume_scan_date(), | ||||||
|  |                       descriptionBlock->volume_scan_start_time() * 1000); | ||||||
|  |    p->vcp_ = descriptionBlock->volume_coverage_pattern(); | ||||||
|  | 
 | ||||||
|  |    // Calculate vertices
 | ||||||
|  |    timer.start(); | ||||||
|  | 
 | ||||||
|  |    // Setup vertex vector
 | ||||||
|  |    std::vector<float>& vertices = p->vertices_; | ||||||
|  |    size_t              vIndex   = 0; | ||||||
|  |    vertices.clear(); | ||||||
|  |    vertices.resize(radials * gates * VERTICES_PER_BIN * VALUES_PER_VERTEX); | ||||||
|  | 
 | ||||||
|  |    // Setup data moment vector
 | ||||||
|  |    std::vector<uint8_t>& dataMoments8 = p->dataMoments8_; | ||||||
|  |    size_t                mIndex       = 0; | ||||||
|  | 
 | ||||||
|  |    dataMoments8.resize(radials * gates * VERTICES_PER_BIN); | ||||||
|  | 
 | ||||||
|  |    // Compute threshold at which to display an individual bin
 | ||||||
|  |    const float    scale        = descriptionBlock->scale(); | ||||||
|  |    const float    offset       = descriptionBlock->offset(); | ||||||
|  |    const uint16_t snrThreshold = descriptionBlock->threshold(); | ||||||
|  | 
 | ||||||
|  |    // Determine which radial to start at
 | ||||||
|  |    const float    radialMultiplier = radials / 360.0f; | ||||||
|  |    const float    startAngle       = digitalData->start_angle(0); | ||||||
|  |    const uint16_t startRadial = std::lroundf(startAngle * radialMultiplier); | ||||||
|  | 
 | ||||||
|  |    for (uint16_t radial = 0; radial < digitalData->number_of_radials(); | ||||||
|  |         radial++) | ||||||
|  |    { | ||||||
|  |       const auto dataMomentsArray8 = digitalData->level(radial); | ||||||
|  | 
 | ||||||
|  |       // Compute gate interval
 | ||||||
|  |       const uint16_t dataMomentInterval  = descriptionBlock->x_resolution_raw(); | ||||||
|  |       const uint16_t dataMomentIntervalH = dataMomentInterval / 2; | ||||||
|  |       const uint16_t dataMomentRange     = dataMomentIntervalH; | ||||||
|  | 
 | ||||||
|  |       // Compute gate size (number of base 250m gates per bin)
 | ||||||
|  |       const uint16_t gateSize = std::max<uint16_t>(1, dataMomentInterval / 250); | ||||||
|  | 
 | ||||||
|  |       // Compute gate range [startGate, endGate)
 | ||||||
|  |       const uint16_t startGate = 0; | ||||||
|  |       const uint16_t endGate   = std::min<uint16_t>( | ||||||
|  |          startGate + gates * gateSize, common::MAX_DATA_MOMENT_GATES); | ||||||
|  | 
 | ||||||
|  |       for (uint16_t gate = startGate, i = 0; gate + gateSize <= endGate; | ||||||
|  |            gate += gateSize, ++i) | ||||||
|  |       { | ||||||
|  |          size_t vertexCount = (gate > 0) ? 6 : 3; | ||||||
|  | 
 | ||||||
|  |          // Store data moment value
 | ||||||
|  |          uint8_t dataValue = dataMomentsArray8[i]; | ||||||
|  |          if (dataValue < snrThreshold && dataValue != RANGE_FOLDED) | ||||||
|  |          { | ||||||
|  |             continue; | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |          for (size_t m = 0; m < vertexCount; m++) | ||||||
|  |          { | ||||||
|  |             dataMoments8[mIndex++] = dataMomentsArray8[i]; | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |          // Store vertices
 | ||||||
|  |          if (gate > 0) | ||||||
|  |          { | ||||||
|  |             const uint16_t baseCoord = gate - 1; | ||||||
|  | 
 | ||||||
|  |             size_t offset1 = ((startRadial + radial) % radials * | ||||||
|  |                                  common::MAX_DATA_MOMENT_GATES + | ||||||
|  |                               baseCoord) * | ||||||
|  |                              2; | ||||||
|  |             size_t offset2 = offset1 + gateSize * 2; | ||||||
|  |             size_t offset3 = (((startRadial + radial + 1) % radials) * | ||||||
|  |                                  common::MAX_DATA_MOMENT_GATES + | ||||||
|  |                               baseCoord) * | ||||||
|  |                              2; | ||||||
|  |             size_t offset4 = offset3 + gateSize * 2; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset1]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset1 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset2]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset3]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset3 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset3]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset3 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset4]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset4 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset2]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertexCount = 6; | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             const uint16_t baseCoord = gate; | ||||||
|  | 
 | ||||||
|  |             size_t offset1 = ((startRadial + radial) % radials * | ||||||
|  |                                  common::MAX_DATA_MOMENT_GATES + | ||||||
|  |                               baseCoord) * | ||||||
|  |                              2; | ||||||
|  |             size_t offset2 = (((startRadial + radial + 1) % radials) * | ||||||
|  |                                  common::MAX_DATA_MOMENT_GATES + | ||||||
|  |                               baseCoord) * | ||||||
|  |                              2; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = p->latitude_; | ||||||
|  |             vertices[vIndex++] = p->longitude_; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset1]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset1 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertices[vIndex++] = coordinates[offset2]; | ||||||
|  |             vertices[vIndex++] = coordinates[offset2 + 1]; | ||||||
|  | 
 | ||||||
|  |             vertexCount = 3; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |    vertices.resize(vIndex); | ||||||
|  |    vertices.shrink_to_fit(); | ||||||
|  | 
 | ||||||
|  |    dataMoments8.resize(mIndex); | ||||||
|  |    dataMoments8.shrink_to_fit(); | ||||||
|  | 
 | ||||||
|  |    timer.stop(); | ||||||
|  |    BOOST_LOG_TRIVIAL(debug) | ||||||
|  |       << logPrefix_ << "Vertices calculated in " << timer.format(6, "%ws"); | ||||||
|  | 
 | ||||||
|  |    UpdateColorTable(); | ||||||
|  | 
 | ||||||
|  |    emit SweepComputed(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::shared_ptr<Level3RadialView> Level3RadialView::Create( | ||||||
|  |    const std::string&                            product, | ||||||
|  |    std::shared_ptr<manager::RadarProductManager> radarProductManager) | ||||||
|  | { | ||||||
|  |    return std::make_shared<Level3RadialView>(product, radarProductManager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace view
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
							
								
								
									
										64
									
								
								scwx-qt/source/scwx/qt/view/level3_radial_view.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								scwx-qt/source/scwx/qt/view/level3_radial_view.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <scwx/common/color_table.hpp> | ||||||
|  | #include <scwx/common/products.hpp> | ||||||
|  | #include <scwx/qt/manager/radar_product_manager.hpp> | ||||||
|  | #include <scwx/qt/view/radar_product_view.hpp> | ||||||
|  | 
 | ||||||
|  | #include <chrono> | ||||||
|  | #include <memory> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace view | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | class Level3RadialViewImpl; | ||||||
|  | 
 | ||||||
|  | class Level3RadialView : public RadarProductView | ||||||
|  | { | ||||||
|  |    Q_OBJECT | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |    explicit Level3RadialView( | ||||||
|  |       const std::string&                            product, | ||||||
|  |       std::shared_ptr<manager::RadarProductManager> radarProductManager); | ||||||
|  |    ~Level3RadialView(); | ||||||
|  | 
 | ||||||
|  |    const std::vector<boost::gil::rgba8_pixel_t>& color_table() const override; | ||||||
|  |    uint16_t                              color_table_min() const override; | ||||||
|  |    uint16_t                              color_table_max() const override; | ||||||
|  |    float                                 range() const override; | ||||||
|  |    std::chrono::system_clock::time_point sweep_time() const override; | ||||||
|  |    uint16_t                              vcp() const override; | ||||||
|  |    const std::vector<float>&             vertices() const override; | ||||||
|  | 
 | ||||||
|  |    void LoadColorTable(std::shared_ptr<common::ColorTable> colorTable) override; | ||||||
|  |    void SelectElevation(float elevation) override; | ||||||
|  |    void SelectTime(std::chrono::system_clock::time_point time) override; | ||||||
|  |    void Update() override; | ||||||
|  | 
 | ||||||
|  |    common::RadarProductGroup GetRadarProductGroup() const override; | ||||||
|  |    std::string               GetRadarProductName() const override; | ||||||
|  |    std::tuple<const void*, size_t, size_t> GetMomentData() const override; | ||||||
|  | 
 | ||||||
|  |    static std::shared_ptr<Level3RadialView> | ||||||
|  |    Create(const std::string&                            product, | ||||||
|  |           std::shared_ptr<manager::RadarProductManager> radarProductManager); | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |    void UpdateColorTable() override; | ||||||
|  | 
 | ||||||
|  | protected slots: | ||||||
|  |    void ComputeSweep() override; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |    std::unique_ptr<Level3RadialViewImpl> p; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace view
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include <scwx/qt/view/radar_product_view_factory.hpp> | #include <scwx/qt/view/radar_product_view_factory.hpp> | ||||||
| #include <scwx/qt/view/level2_product_view.hpp> | #include <scwx/qt/view/level2_product_view.hpp> | ||||||
|  | #include <scwx/qt/view/level3_radial_view.hpp> | ||||||
| 
 | 
 | ||||||
| #include <boost/log/trivial.hpp> | #include <boost/log/trivial.hpp> | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +41,10 @@ std::shared_ptr<RadarProductView> RadarProductViewFactory::Create( | ||||||
|          view = Create(product, elevation, radarProductManager); |          view = Create(product, elevation, radarProductManager); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
|  |    else if (productGroup == common::RadarProductGroup::Level3) | ||||||
|  |    { | ||||||
|  |       view = Level3RadialView::Create(productName, radarProductManager); | ||||||
|  |    } | ||||||
|    else |    else | ||||||
|    { |    { | ||||||
|       BOOST_LOG_TRIVIAL(warning) |       BOOST_LOG_TRIVIAL(warning) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat