mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:50:06 +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_; |    GeographicLib::Geodesic geodesic_; | ||||||
| 
 | 
 | ||||||
|  |    std::unordered_map<types::TextEventKey, | ||||||
|  |                       common::Coordinate, | ||||||
|  |                       types::TextEventHash<types::TextEventKey>> | ||||||
|  |       centroidMap_; | ||||||
|    std::unordered_map<types::TextEventKey, |    std::unordered_map<types::TextEventKey, | ||||||
|                       double, |                       double, | ||||||
|                       types::TextEventHash<types::TextEventKey>> |                       types::TextEventHash<types::TextEventKey>> | ||||||
|  | @ -173,30 +177,43 @@ void AlertModel::HandleAlert(const types::TextEventKey& alertKey) | ||||||
| 
 | 
 | ||||||
|    double distanceInMeters; |    double distanceInMeters; | ||||||
| 
 | 
 | ||||||
|    if (!p->textEventKeys_.contains(alertKey)) |    // Get the most recent segment for the event
 | ||||||
|    { |    auto alertMessages = | ||||||
|       beginInsertRows(QModelIndex(), 0, 0); |       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->geodesic_.Inverse(p->previousPosition_.latitude_, | ||||||
|                            p->previousPosition_.longitude_, |                            p->previousPosition_.longitude_, | ||||||
|                            0.0, // TODO: textEvent->latitude(),
 |                            centroid.latitude_, | ||||||
|                            0.0, // TODO: textEvent->longitude(),
 |                            centroid.longitude_, | ||||||
|                            distanceInMeters); |                            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(); |       endInsertRows(); | ||||||
|    } |    } | ||||||
|    else |    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); |       const int   row         = p->textEventKeys_.indexOf(alertKey); | ||||||
|       QModelIndex topLeft     = createIndex(row, kFirstColumn); |       QModelIndex topLeft     = createIndex(row, kFirstColumn); | ||||||
|       QModelIndex bottomRight = createIndex(row, kLastColumn); |       QModelIndex bottomRight = createIndex(row, kLastColumn); | ||||||
|  | @ -213,12 +230,17 @@ void AlertModel::HandleMapUpdate(double latitude, double longitude) | ||||||
| 
 | 
 | ||||||
|    for (const auto& textEvent : p->textEventKeys_) |    for (const auto& textEvent : p->textEventKeys_) | ||||||
|    { |    { | ||||||
|       p->geodesic_.Inverse(latitude, |       auto& centroid = p->centroidMap_.at(textEvent); | ||||||
|                            longitude, | 
 | ||||||
|                            0.0, // TODO: textEvent->latitude(),
 |       if (centroid != common::Coordinate {0.0, 0.0}) | ||||||
|                            0.0, // TODO: textEvent->longitude(),
 |       { | ||||||
|                            distanceInMeters); |          p->geodesic_.Inverse(latitude, | ||||||
|       p->distanceMap_[textEvent] = distanceInMeters; |                               longitude, | ||||||
|  |                               centroid.latitude_, | ||||||
|  |                               centroid.longitude_, | ||||||
|  |                               distanceInMeters); | ||||||
|  |          p->distanceMap_.insert_or_assign(textEvent, distanceInMeters); | ||||||
|  |       } | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->previousPosition_ = {latitude, longitude}; |    p->previousPosition_ = {latitude, longitude}; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <vector> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
| { | { | ||||||
|  | @ -43,6 +44,16 @@ enum class DistanceType | ||||||
|    Miles |    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 | std::string | ||||||
| GetLatitudeString(double           latitude, | GetLatitudeString(double           latitude, | ||||||
|                   DegreeStringType type = DegreeStringType::Decimal); |                   DegreeStringType type = DegreeStringType::Decimal); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| #include <scwx/common/characters.hpp> | #include <scwx/common/characters.hpp> | ||||||
| 
 | 
 | ||||||
| #include <format> | #include <format> | ||||||
|  | #include <numbers> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
| { | { | ||||||
|  | @ -12,6 +13,44 @@ static std::string GetDegreeString(double             degrees, | ||||||
|                                    DegreeStringType   type, |                                    DegreeStringType   type, | ||||||
|                                    const std::string& suffix); |                                    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 GetLatitudeString(double latitude, DegreeStringType type) | ||||||
| { | { | ||||||
|    std::string suffix {}; |    std::string suffix {}; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat