mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 07:00:06 +00:00 
			
		
		
		
	Calculate level 2 coordinates every rendering frame
- More accurate bin rendering position - Eliminates "rocking" when animating - 40-45ms negative impact on rendering per frame (specific to my setup) Fixes #53
This commit is contained in:
		
							parent
							
								
									9536a1fdcb
								
							
						
					
					
						commit
						1c84b061dc
					
				
					 1 changed files with 111 additions and 26 deletions
				
			
		|  | @ -1,4 +1,5 @@ | ||||||
| #include <scwx/qt/view/level2_product_view.hpp> | #include <scwx/qt/view/level2_product_view.hpp> | ||||||
|  | #include <scwx/qt/util/geographic_lib.hpp> | ||||||
| #include <scwx/common/constants.hpp> | #include <scwx/common/constants.hpp> | ||||||
| #include <scwx/util/logger.hpp> | #include <scwx/util/logger.hpp> | ||||||
| #include <scwx/util/threads.hpp> | #include <scwx/util/threads.hpp> | ||||||
|  | @ -17,6 +18,10 @@ namespace view | ||||||
| static const std::string logPrefix_ = "scwx::qt::view::level2_product_view"; | static const std::string logPrefix_ = "scwx::qt::view::level2_product_view"; | ||||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||||
| 
 | 
 | ||||||
|  | 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 uint16_t RANGE_FOLDED      = 1u; | static constexpr uint16_t RANGE_FOLDED      = 1u; | ||||||
| static constexpr uint32_t VERTICES_PER_BIN  = 6u; | static constexpr uint32_t VERTICES_PER_BIN  = 6u; | ||||||
| static constexpr uint32_t VALUES_PER_VERTEX = 2u; | static constexpr uint32_t VALUES_PER_VERTEX = 2u; | ||||||
|  | @ -41,7 +46,9 @@ static const std::unordered_map<common::Level2Product, | ||||||
| class Level2ProductViewImpl | class Level2ProductViewImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit Level2ProductViewImpl(common::Level2Product product) : |    explicit Level2ProductViewImpl(Level2ProductView*    self, | ||||||
|  |                                   common::Level2Product product) : | ||||||
|  |        self_ {self}, | ||||||
|        product_ {product}, |        product_ {product}, | ||||||
|        selectedElevation_ {0.0f}, |        selectedElevation_ {0.0f}, | ||||||
|        elevationScan_ {nullptr}, |        elevationScan_ {nullptr}, | ||||||
|  | @ -61,13 +68,20 @@ public: | ||||||
|        savedScale_ {0.0f}, |        savedScale_ {0.0f}, | ||||||
|        savedOffset_ {0.0f} |        savedOffset_ {0.0f} | ||||||
|    { |    { | ||||||
|  |       coordinates_.resize(kMaxCoordinates_); | ||||||
|  | 
 | ||||||
|       SetProduct(product); |       SetProduct(product); | ||||||
|    } |    } | ||||||
|    ~Level2ProductViewImpl() = default; |    ~Level2ProductViewImpl() = default; | ||||||
| 
 | 
 | ||||||
|  |    void | ||||||
|  |    ComputeCoordinates(std::shared_ptr<wsr88d::rda::ElevationScan> radarData); | ||||||
|  | 
 | ||||||
|    void SetProduct(const std::string& productName); |    void SetProduct(const std::string& productName); | ||||||
|    void SetProduct(common::Level2Product product); |    void SetProduct(common::Level2Product product); | ||||||
| 
 | 
 | ||||||
|  |    Level2ProductView* self_; | ||||||
|  | 
 | ||||||
|    common::Level2Product      product_; |    common::Level2Product      product_; | ||||||
|    wsr88d::rda::DataBlockType dataBlockType_; |    wsr88d::rda::DataBlockType dataBlockType_; | ||||||
| 
 | 
 | ||||||
|  | @ -76,10 +90,11 @@ public: | ||||||
|    std::shared_ptr<wsr88d::rda::ElevationScan>   elevationScan_; |    std::shared_ptr<wsr88d::rda::ElevationScan>   elevationScan_; | ||||||
|    std::shared_ptr<wsr88d::rda::MomentDataBlock> momentDataBlock0_; |    std::shared_ptr<wsr88d::rda::MomentDataBlock> momentDataBlock0_; | ||||||
| 
 | 
 | ||||||
|    std::vector<float>    vertices_; |    std::vector<float>    coordinates_ {}; | ||||||
|    std::vector<uint8_t>  dataMoments8_; |    std::vector<float>    vertices_ {}; | ||||||
|    std::vector<uint16_t> dataMoments16_; |    std::vector<uint8_t>  dataMoments8_ {}; | ||||||
|    std::vector<uint8_t>  cfpMoments_; |    std::vector<uint16_t> dataMoments16_ {}; | ||||||
|  |    std::vector<uint8_t>  cfpMoments_ {}; | ||||||
| 
 | 
 | ||||||
|    float              latitude_; |    float              latitude_; | ||||||
|    float              longitude_; |    float              longitude_; | ||||||
|  | @ -104,7 +119,7 @@ Level2ProductView::Level2ProductView( | ||||||
|    common::Level2Product                         product, |    common::Level2Product                         product, | ||||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager) : |    std::shared_ptr<manager::RadarProductManager> radarProductManager) : | ||||||
|     RadarProductView(radarProductManager), |     RadarProductView(radarProductManager), | ||||||
|     p(std::make_unique<Level2ProductViewImpl>(product)) |     p(std::make_unique<Level2ProductViewImpl>(this, product)) | ||||||
| { | { | ||||||
|    ConnectRadarProductManager(); |    ConnectRadarProductManager(); | ||||||
| } | } | ||||||
|  | @ -413,16 +428,14 @@ void Level2ProductView::ComputeSweep() | ||||||
|       return; |       return; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    const size_t             radials = radarData->size(); |    const size_t radials = radarData->size(); | ||||||
|    const common::RadialSize radialSize = |  | ||||||
|       (radials == common::MAX_0_5_DEGREE_RADIALS) ? |  | ||||||
|          common::RadialSize::_0_5Degree : |  | ||||||
|          common::RadialSize::_1Degree; |  | ||||||
|    const std::vector<float>& coordinates = |  | ||||||
|       radarProductManager->coordinates(radialSize); |  | ||||||
| 
 | 
 | ||||||
|    auto radarData0      = (*radarData)[0]; |    p->ComputeCoordinates(radarData); | ||||||
|    auto momentData0     = radarData0->moment_data_block(p->dataBlockType_); | 
 | ||||||
|  |    const std::vector<float>& coordinates = p->coordinates_; | ||||||
|  | 
 | ||||||
|  |    auto& radarData0     = (*radarData)[0]; | ||||||
|  |    auto  momentData0    = radarData0->moment_data_block(p->dataBlockType_); | ||||||
|    p->elevationScan_    = radarData; |    p->elevationScan_    = radarData; | ||||||
|    p->momentDataBlock0_ = momentData0; |    p->momentDataBlock0_ = momentData0; | ||||||
| 
 | 
 | ||||||
|  | @ -442,8 +455,8 @@ void Level2ProductView::ComputeSweep() | ||||||
|    p->range_ = |    p->range_ = | ||||||
|       momentData0->data_moment_range() + |       momentData0->data_moment_range() + | ||||||
|       momentData0->data_moment_range_sample_interval() * (gates - 0.5f); |       momentData0->data_moment_range_sample_interval() * (gates - 0.5f); | ||||||
|    p->sweepTime_ = util::TimePoint(radarData0->modified_julian_date(), |    p->sweepTime_ = scwx::util::TimePoint(radarData0->modified_julian_date(), | ||||||
|                                    radarData0->collection_time()); |                                          radarData0->collection_time()); | ||||||
|    p->vcp_       = volumeData0->volume_coverage_pattern_number(); |    p->vcp_       = volumeData0->volume_coverage_pattern_number(); | ||||||
| 
 | 
 | ||||||
|    // Calculate vertices
 |    // Calculate vertices
 | ||||||
|  | @ -492,16 +505,10 @@ void Level2ProductView::ComputeSweep() | ||||||
|    const uint16_t snrThreshold = |    const uint16_t snrThreshold = | ||||||
|       std::max<int16_t>(2, momentData0->snr_threshold_raw()); |       std::max<int16_t>(2, momentData0->snr_threshold_raw()); | ||||||
| 
 | 
 | ||||||
|    // Azimuth resolution spacing:
 |    // Start radial is always 0, as coordinates are calculated for each sweep
 | ||||||
|    //   1 = 0.5 degrees
 |    constexpr std::uint16_t startRadial = 0u; | ||||||
|    //   2 = 1.0 degrees
 |  | ||||||
|    const float radialMultiplier = |  | ||||||
|       2.0f / std::clamp<int8_t>(radarData0->azimuth_resolution_spacing(), 1, 2); |  | ||||||
| 
 | 
 | ||||||
|    const float    startAngle  = radarData0->azimuth_angle(); |    for (auto& radialPair : *radarData) | ||||||
|    const uint16_t startRadial = std::lroundf(startAngle * radialMultiplier); |  | ||||||
| 
 |  | ||||||
|    for (auto radialPair : *radarData) |  | ||||||
|    { |    { | ||||||
|       uint16_t radial     = radialPair.first; |       uint16_t radial     = radialPair.first; | ||||||
|       auto     radialData = radialPair.second; |       auto     radialData = radialPair.second; | ||||||
|  | @ -685,6 +692,84 @@ void Level2ProductView::ComputeSweep() | ||||||
|    emit SweepComputed(); |    emit SweepComputed(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Level2ProductViewImpl::ComputeCoordinates( | ||||||
|  |    std::shared_ptr<wsr88d::rda::ElevationScan> radarData) | ||||||
|  | { | ||||||
|  |    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(); | ||||||
|  | 
 | ||||||
|  |    auto& radarData0  = (*radarData)[0]; | ||||||
|  |    auto  momentData0 = radarData0->moment_data_block(dataBlockType_); | ||||||
|  | 
 | ||||||
|  |    const std::uint16_t numRadials = | ||||||
|  |       static_cast<std::uint16_t>(radarData->size()); | ||||||
|  |    const std::uint16_t numRangeBins = | ||||||
|  |       momentData0->number_of_data_moment_gates(); | ||||||
|  | 
 | ||||||
|  |    auto radials = boost::irange<std::uint32_t>(0u, numRadials); | ||||||
|  |    auto gates   = boost::irange<std::uint32_t>(0u, numRangeBins); | ||||||
|  | 
 | ||||||
|  |    std::for_each( | ||||||
|  |       std::execution::par_unseq, | ||||||
|  |       radials.begin(), | ||||||
|  |       radials.end(), | ||||||
|  |       [&](std::uint32_t radial) | ||||||
|  |       { | ||||||
|  |          // Angles are ordered clockwise, delta should be positive
 | ||||||
|  |          float deltaAngle = | ||||||
|  |             (radial == 0) ? (*radarData)[0]->azimuth_angle() - | ||||||
|  |                                (*radarData)[numRadials - 1]->azimuth_angle() : | ||||||
|  |                             (*radarData)[radial]->azimuth_angle() - | ||||||
|  |                                (*radarData)[radial - 1]->azimuth_angle(); | ||||||
|  |          while (deltaAngle < 0.0f) | ||||||
|  |          { | ||||||
|  |             deltaAngle += 360.0f; | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |          const float angle = | ||||||
|  |             (*radarData)[radial]->azimuth_angle() - (deltaAngle * 0.5f); | ||||||
|  | 
 | ||||||
|  |          std::for_each(std::execution::par_unseq, | ||||||
|  |                        gates.begin(), | ||||||
|  |                        gates.end(), | ||||||
|  |                        [&](std::uint32_t gate) | ||||||
|  |                        { | ||||||
|  |                           const std::uint32_t radialGate = | ||||||
|  |                              radial * common::MAX_DATA_MOMENT_GATES + gate; | ||||||
|  |                           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<Level2ProductView> Level2ProductView::Create( | std::shared_ptr<Level2ProductView> Level2ProductView::Create( | ||||||
|    common::Level2Product                         product, |    common::Level2Product                         product, | ||||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager) |    std::shared_ptr<manager::RadarProductManager> radarProductManager) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat