mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:30:05 +00:00 
			
		
		
		
	Add new AlertLayerHandler
This commit is contained in:
		
							parent
							
								
									044e6d6885
								
							
						
					
					
						commit
						0fa3f2162b
					
				
					 2 changed files with 178 additions and 8 deletions
				
			
		|  | @ -1,6 +1,15 @@ | |||
| #include <scwx/qt/map/alert_layer.hpp> | ||||
| #include <scwx/qt/manager/text_event_manager.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| #include <unordered_set> | ||||
| 
 | ||||
| #include <boost/container/stable_vector.hpp> | ||||
| #include <boost/container_hash/hash.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -11,6 +20,81 @@ namespace map | |||
| static const std::string logPrefix_ = "scwx::qt::map::alert_layer"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| template<class Key> | ||||
| struct AlertTypeHash; | ||||
| 
 | ||||
| template<> | ||||
| struct AlertTypeHash<std::pair<awips::Phenomenon, bool>> | ||||
| { | ||||
|    size_t operator()(const std::pair<awips::Phenomenon, bool>& x) const; | ||||
| }; | ||||
| 
 | ||||
| class AlertLayerHandler : QObject | ||||
| { | ||||
|    Q_OBJECT | ||||
| public: | ||||
|    struct SegmentRecord | ||||
|    { | ||||
|       std::shared_ptr<const awips::Segment>            segment_; | ||||
|       types::TextEventKey                              key_; | ||||
|       std::shared_ptr<const awips::TextProductMessage> message_; | ||||
|       std::chrono::system_clock::time_point            segmentBegin_; | ||||
|       std::chrono::system_clock::time_point            segmentEnd_; | ||||
| 
 | ||||
|       SegmentRecord( | ||||
|          const std::shared_ptr<const awips::Segment>&            segment, | ||||
|          const types::TextEventKey&                              key, | ||||
|          const std::shared_ptr<const awips::TextProductMessage>& message) : | ||||
|           segment_ {segment}, | ||||
|           key_ {key}, | ||||
|           message_ {message}, | ||||
|           segmentBegin_ {segment->event_begin()}, | ||||
|           segmentEnd_ {segment->event_end()} | ||||
|       { | ||||
|       } | ||||
|    }; | ||||
| 
 | ||||
|    explicit AlertLayerHandler() | ||||
|    { | ||||
|       connect(textEventManager_.get(), | ||||
|               &manager::TextEventManager::AlertUpdated, | ||||
|               this, | ||||
|               [this](const types::TextEventKey& key, std::size_t messageIndex) | ||||
|               { HandleAlert(key, messageIndex); }); | ||||
|    } | ||||
|    ~AlertLayerHandler() | ||||
|    { | ||||
|       disconnect(textEventManager_.get(), nullptr, this, nullptr); | ||||
| 
 | ||||
|       std::unique_lock lock(alertMutex_); | ||||
|    } | ||||
| 
 | ||||
|    // NOTE: iterators are no longer stable if the stable vector moves
 | ||||
|    std::unordered_map< | ||||
|       std::pair<awips::Phenomenon, bool>, | ||||
|       boost::container::stable_vector<std::shared_ptr<SegmentRecord>>, | ||||
|       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       segmentsByType_ {}; | ||||
| 
 | ||||
|    std::unordered_map< | ||||
|       types::TextEventKey, | ||||
|       boost::container::stable_vector<std::shared_ptr<SegmentRecord>>, | ||||
|       types::TextEventHash<types::TextEventKey>> | ||||
|       segmentsByKey_ {}; | ||||
| 
 | ||||
|    void HandleAlert(const types::TextEventKey& key, size_t messageIndex); | ||||
| 
 | ||||
|    static AlertLayerHandler& Instance(); | ||||
| 
 | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_ { | ||||
|       manager::TextEventManager::Instance()}; | ||||
| 
 | ||||
|    std::mutex alertMutex_ {}; | ||||
| 
 | ||||
| signals: | ||||
|    void AlertsUpdated(awips::Phenomenon phenomenon, bool alertActive); | ||||
| }; | ||||
| 
 | ||||
| class AlertLayer::Impl | ||||
| { | ||||
| public: | ||||
|  | @ -71,6 +155,91 @@ bool AlertLayer::RunMousePicking( | |||
|                                      eventHandler); | ||||
| } | ||||
| 
 | ||||
| void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, | ||||
|                                     size_t                     messageIndex) | ||||
| { | ||||
|    logger_->trace("HandleAlert: {}", key.ToString()); | ||||
| 
 | ||||
|    std::unordered_set<std::pair<awips::Phenomenon, bool>, | ||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       alertsUpdated {}; | ||||
| 
 | ||||
|    auto message = textEventManager_->message_list(key).at(messageIndex); | ||||
| 
 | ||||
|    // Determine start time for first segment
 | ||||
|    std::chrono::system_clock::time_point segmentBegin {}; | ||||
|    if (message->segment_count() > 0) | ||||
|    { | ||||
|       segmentBegin = message->segment(0)->event_begin(); | ||||
|    } | ||||
| 
 | ||||
|    // Take a unique mutex before modifying segments
 | ||||
|    std::unique_lock lock {alertMutex_}; | ||||
| 
 | ||||
|    // Update any existing segments with new end time
 | ||||
|    auto& segmentsForKey = segmentsByKey_[key]; | ||||
|    for (auto& segmentRecord : segmentsForKey) | ||||
|    { | ||||
|       if (segmentRecord->segmentEnd_ > segmentBegin) | ||||
|       { | ||||
|          segmentRecord->segmentEnd_ = segmentBegin; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    // Process new segments
 | ||||
|    for (auto& segment : message->segments()) | ||||
|    { | ||||
|       if (!segment->codedLocation_.has_value()) | ||||
|       { | ||||
|          // Cannot handle a segment without a location
 | ||||
|          continue; | ||||
|       } | ||||
| 
 | ||||
|       auto&             vtec       = segment->header_->vtecString_.front(); | ||||
|       auto              action     = vtec.pVtec_.action(); | ||||
|       awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); | ||||
|       auto              eventEnd   = vtec.pVtec_.event_end(); | ||||
|       bool alertActive             = (action != awips::PVtec::Action::Canceled); | ||||
| 
 | ||||
|       auto& segmentsForType = segmentsByType_[{key.phenomenon_, alertActive}]; | ||||
| 
 | ||||
|       // Insert segment into lists
 | ||||
|       std::shared_ptr<SegmentRecord> segmentRecord = | ||||
|          std::make_shared<SegmentRecord>(segment, key, message); | ||||
| 
 | ||||
|       segmentsForKey.push_back(segmentRecord); | ||||
|       segmentsForType.push_back(segmentRecord); | ||||
| 
 | ||||
|       alertsUpdated.emplace(phenomenon, alertActive); | ||||
|    } | ||||
| 
 | ||||
|    // Release the lock after completing segment updates
 | ||||
|    lock.unlock(); | ||||
| 
 | ||||
|    for (auto& alert : alertsUpdated) | ||||
|    { | ||||
|       // Emit signal for each updated alert type
 | ||||
|       Q_EMIT AlertsUpdated(alert.first, alert.second); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| AlertLayerHandler& AlertLayerHandler::Instance() | ||||
| { | ||||
|    static AlertLayerHandler alertLayerHandler_ {}; | ||||
|    return alertLayerHandler_; | ||||
| } | ||||
| 
 | ||||
| size_t AlertTypeHash<std::pair<awips::Phenomenon, bool>>::operator()( | ||||
|    const std::pair<awips::Phenomenon, bool>& x) const | ||||
| { | ||||
|    size_t seed = 0; | ||||
|    boost::hash_combine(seed, x.first); | ||||
|    boost::hash_combine(seed, x.second); | ||||
|    return seed; | ||||
| } | ||||
| 
 | ||||
| } // namespace map
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
| 
 | ||||
| #include "alert_layer.moc" | ||||
|  |  | |||
|  | @ -48,18 +48,19 @@ static const std::vector<awips::Phenomenon> kAlertPhenomena_ { | |||
|    awips::Phenomenon::Tornado}; | ||||
| 
 | ||||
| template<class Key> | ||||
| struct AlertTypeHash; | ||||
| struct AlertTypeOldHash; | ||||
| 
 | ||||
| template<> | ||||
| struct AlertTypeHash<std::pair<awips::Phenomenon, bool>> | ||||
| struct AlertTypeOldHash<std::pair<awips::Phenomenon, bool>> | ||||
| { | ||||
|    size_t operator()(const std::pair<awips::Phenomenon, bool>& x) const; | ||||
| }; | ||||
| 
 | ||||
| class AlertLayerOldHandler : public QObject | ||||
| { | ||||
|    Q_OBJECT public : | ||||
|        explicit AlertLayerOldHandler() : | ||||
|    Q_OBJECT | ||||
| public: | ||||
|    explicit AlertLayerOldHandler() : | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        alertUpdateTimer_ {scwx::util::io_context()}, | ||||
|        alertSourceMap_ {}, | ||||
|  | @ -98,7 +99,7 @@ class AlertLayerOldHandler : public QObject | |||
|    boost::asio::steady_timer alertUpdateTimer_; | ||||
|    std::unordered_map<std::pair<awips::Phenomenon, bool>, | ||||
|                       QVariantMap, | ||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|                       AlertTypeOldHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       alertSourceMap_; | ||||
|    std::unordered_multimap<types::TextEventKey, | ||||
|                            std::tuple<awips::Phenomenon, | ||||
|  | @ -195,7 +196,7 @@ void AlertLayerOldHandler::HandleAlert(const types::TextEventKey& key, | |||
| 
 | ||||
|    auto message = textEventManager_->message_list(key).at(messageIndex); | ||||
|    std::unordered_set<std::pair<awips::Phenomenon, bool>, | ||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|                       AlertTypeOldHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       alertsUpdated {}; | ||||
| 
 | ||||
|    // Take a unique lock before modifying feature lists
 | ||||
|  | @ -274,7 +275,7 @@ void AlertLayerOldHandler::UpdateAlerts() | |||
|    std::unique_lock lock(alertMutex_); | ||||
| 
 | ||||
|    std::unordered_set<std::pair<awips::Phenomenon, bool>, | ||||
|                       AlertTypeHash<std::pair<awips::Phenomenon, bool>>> | ||||
|                       AlertTypeOldHash<std::pair<awips::Phenomenon, bool>>> | ||||
|       alertsUpdated {}; | ||||
| 
 | ||||
|    // Evaluate each rendered feature for expiration
 | ||||
|  | @ -481,7 +482,7 @@ static QString GetSuffix(awips::Phenomenon phenomenon, bool alertActive) | |||
|       .arg(alertActive); | ||||
| } | ||||
| 
 | ||||
| size_t AlertTypeHash<std::pair<awips::Phenomenon, bool>>::operator()( | ||||
| size_t AlertTypeOldHash<std::pair<awips::Phenomenon, bool>>::operator()( | ||||
|    const std::pair<awips::Phenomenon, bool>& x) const | ||||
| { | ||||
|    size_t seed = 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat