mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 04:30:05 +00:00 
			
		
		
		
	Centroid calculation for alert distance
This commit is contained in:
		
							parent
							
								
									a3d007d8c4
								
							
						
					
					
						commit
						5784abc117
					
				
					 3 changed files with 91 additions and 19 deletions
				
			
		|  | @ -48,6 +48,10 @@ public: | |||
| 
 | ||||
|    GeographicLib::Geodesic geodesic_; | ||||
| 
 | ||||
|    std::unordered_map<types::TextEventKey, | ||||
|                       common::Coordinate, | ||||
|                       types::TextEventHash<types::TextEventKey>> | ||||
|       centroidMap_; | ||||
|    std::unordered_map<types::TextEventKey, | ||||
|                       double, | ||||
|                       types::TextEventHash<types::TextEventKey>> | ||||
|  | @ -173,30 +177,43 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey) | |||
| 
 | ||||
|    double distanceInMeters; | ||||
| 
 | ||||
|    if (!p->textEventKeys_.contains(alertKey)) | ||||
|    { | ||||
|       beginInsertRows(QModelIndex(), 0, 0); | ||||
|    // Get the most recent segment for the event
 | ||||
|    auto alertMessages = | ||||
|       manager::TextEventManager::Instance().message_list(alertKey); | ||||
|    std::shared_ptr<const awips::Segment> alertSegment = | ||||
|       alertMessages.back()->segments().back(); | ||||
| 
 | ||||
|       p->textEventKeys_.push_back(alertKey); | ||||
|    if (alertSegment->codedLocation_.has_value()) | ||||
|    { | ||||
|       // Update centroid and distance
 | ||||
|       common::Coordinate centroid = | ||||
|          common::GetCentroid(alertSegment->codedLocation_->coordinates()); | ||||
| 
 | ||||
|       p->geodesic_.Inverse(p->previousPosition_.latitude_, | ||||
|                            p->previousPosition_.longitude_, | ||||
|                            0.0, // TODO: textEvent->latitude(),
 | ||||
|                            0.0, // TODO: textEvent->longitude(),
 | ||||
|                            centroid.latitude_, | ||||
|                            centroid.longitude_, | ||||
|                            distanceInMeters); | ||||
| 
 | ||||
|       p->distanceMap_[alertKey] = distanceInMeters; | ||||
|       p->centroidMap_.insert_or_assign(alertKey, centroid); | ||||
|       p->distanceMap_.insert_or_assign(alertKey, distanceInMeters); | ||||
|    } | ||||
|    else if (!p->centroidMap_.contains(alertKey)) | ||||
|    { | ||||
|       // The alert has no location, so provide a default
 | ||||
|       p->centroidMap_.insert_or_assign(alertKey, common::Coordinate {0.0, 0.0}); | ||||
|       p->distanceMap_.insert_or_assign(alertKey, 0.0); | ||||
|    } | ||||
| 
 | ||||
|    // Update row
 | ||||
|    if (!p->textEventKeys_.contains(alertKey)) | ||||
|    { | ||||
|       beginInsertRows(QModelIndex(), 0, 0); | ||||
|       p->textEventKeys_.push_back(alertKey); | ||||
|       endInsertRows(); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       p->geodesic_.Inverse(p->previousPosition_.latitude_, | ||||
|                            p->previousPosition_.longitude_, | ||||
|                            0.0, // TODO: textEvent->latitude(),
 | ||||
|                            0.0, // TODO: textEvent->longitude(),
 | ||||
|                            distanceInMeters); | ||||
| 
 | ||||
|       const int   row         = p->textEventKeys_.indexOf(alertKey); | ||||
|       QModelIndex topLeft     = createIndex(row, kFirstColumn); | ||||
|       QModelIndex bottomRight = createIndex(row, kLastColumn); | ||||
|  | @ -213,12 +230,17 @@ void AlertModel::HandleMapUpdate(double latitude, double longitude) | |||
| 
 | ||||
|    for (const auto& textEvent : p->textEventKeys_) | ||||
|    { | ||||
|       p->geodesic_.Inverse(latitude, | ||||
|                            longitude, | ||||
|                            0.0, // TODO: textEvent->latitude(),
 | ||||
|                            0.0, // TODO: textEvent->longitude(),
 | ||||
|                            distanceInMeters); | ||||
|       p->distanceMap_[textEvent] = distanceInMeters; | ||||
|       auto& centroid = p->centroidMap_.at(textEvent); | ||||
| 
 | ||||
|       if (centroid != common::Coordinate {0.0, 0.0}) | ||||
|       { | ||||
|          p->geodesic_.Inverse(latitude, | ||||
|                               longitude, | ||||
|                               centroid.latitude_, | ||||
|                               centroid.longitude_, | ||||
|                               distanceInMeters); | ||||
|          p->distanceMap_.insert_or_assign(textEvent, distanceInMeters); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    p->previousPosition_ = {latitude, longitude}; | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
|  | @ -43,6 +44,16 @@ enum class DistanceType | |||
|    Miles | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Calculate the geographic midpoint of a set of coordinates. Uses Method A | ||||
|  * described at http://www.geomidpoint.com/calculation.html.
 | ||||
|  * | ||||
|  * @param coordinates Set of unique coordinates | ||||
|  * | ||||
|  * @return Centroid | ||||
|  */ | ||||
| Coordinate GetCentroid(const std::vector<Coordinate>& coordinates); | ||||
| 
 | ||||
| std::string | ||||
| GetLatitudeString(double           latitude, | ||||
|                   DegreeStringType type = DegreeStringType::Decimal); | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include <scwx/common/characters.hpp> | ||||
| 
 | ||||
| #include <format> | ||||
| #include <numbers> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
|  | @ -12,6 +13,44 @@ static std::string GetDegreeString(double             degrees, | |||
|                                    DegreeStringType   type, | ||||
|                                    const std::string& suffix); | ||||
| 
 | ||||
| Coordinate GetCentroid(const std::vector<Coordinate>& coordinates) | ||||
| { | ||||
|    double x = 0.0; | ||||
|    double y = 0.0; | ||||
|    double z = 0.0; | ||||
| 
 | ||||
|    for (const Coordinate& c : coordinates) | ||||
|    { | ||||
|       // Convert latitude and longitude to radians
 | ||||
|       double latitudeRadians  = c.latitude_ * std::numbers::pi / 180.0; | ||||
|       double longitudeRadians = c.longitude_ * std::numbers::pi / 180.0; | ||||
| 
 | ||||
|       // Convert latitude and longitude to Cartesian coordinates
 | ||||
|       double x1 = std::cos(latitudeRadians) * std::cos(longitudeRadians); | ||||
|       double y1 = std::cos(latitudeRadians) * std::sin(longitudeRadians); | ||||
|       double z1 = std::sin(latitudeRadians); | ||||
| 
 | ||||
|       // Combine with accumulators
 | ||||
|       x += x1; | ||||
|       y += y1; | ||||
|       z += z1; | ||||
|    } | ||||
| 
 | ||||
|    // Compute averages
 | ||||
|    x /= coordinates.size(); | ||||
|    y /= coordinates.size(); | ||||
|    z /= coordinates.size(); | ||||
| 
 | ||||
|    // Convert Cartesian coordinates back to latitude and longitude
 | ||||
|    double hyp              = std::sqrt(x * x + y * y); | ||||
|    double latitudeRadians  = std::atan2(z, hyp); | ||||
|    double longitudeRadians = std::atan2(y, x); | ||||
| 
 | ||||
|    // Return latitude and longitude in degrees
 | ||||
|    return {latitudeRadians * 180.0 / std::numbers::pi, | ||||
|            longitudeRadians * 180.0 / std::numbers::pi}; | ||||
| } | ||||
| 
 | ||||
| std::string GetLatitudeString(double latitude, DegreeStringType type) | ||||
| { | ||||
|    std::string suffix {}; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat