mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 21:10:04 +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