mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 08:10:05 +00:00
145 lines
3.6 KiB
C++
145 lines
3.6 KiB
C++
#include <scwx/common/geographic.hpp>
|
|
#include <scwx/common/characters.hpp>
|
|
|
|
#include <numbers>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
namespace scwx
|
|
{
|
|
namespace common
|
|
{
|
|
|
|
static std::string GetDegreeString(double degrees,
|
|
DegreeStringType type,
|
|
const std::string& suffix);
|
|
|
|
units::degrees<float> GetAngleDelta(units::degrees<float> angle1,
|
|
units::degrees<float> angle2)
|
|
{
|
|
// Normalize angles to [0, 360)
|
|
while (angle1.value() < 0.0f)
|
|
{
|
|
angle1 += units::degrees<float> {360.0f};
|
|
}
|
|
while (angle2.value() < 0.0f)
|
|
{
|
|
angle2 += units::degrees<float> {360.0f};
|
|
}
|
|
angle1 = units::degrees<float> {std::fmod(angle1.value(), 360.f)};
|
|
angle2 = units::degrees<float> {std::fmod(angle2.value(), 360.f)};
|
|
|
|
// Calculate the absolute difference
|
|
auto delta = angle1 - angle2;
|
|
if (delta < units::degrees<float> {0.0f})
|
|
{
|
|
delta *= -1.0f;
|
|
}
|
|
|
|
// Account for wrapping
|
|
delta = std::min(delta, units::degrees<float> {360.0f} - delta);
|
|
|
|
return delta;
|
|
}
|
|
|
|
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 {};
|
|
|
|
if (latitude > 0.0)
|
|
{
|
|
suffix = " N";
|
|
}
|
|
else if (latitude < 0.0)
|
|
{
|
|
suffix = " S";
|
|
}
|
|
|
|
return GetDegreeString(latitude, type, suffix);
|
|
}
|
|
|
|
std::string GetLongitudeString(double longitude, DegreeStringType type)
|
|
{
|
|
std::string suffix {};
|
|
|
|
if (longitude > 0.0)
|
|
{
|
|
suffix = " E";
|
|
}
|
|
else if (longitude < 0.0)
|
|
{
|
|
suffix = " W";
|
|
}
|
|
|
|
return GetDegreeString(longitude, type, suffix);
|
|
}
|
|
|
|
static std::string GetDegreeString(double degrees,
|
|
DegreeStringType type,
|
|
const std::string& suffix)
|
|
{
|
|
std::string degreeString {};
|
|
|
|
degrees = std::fabs(degrees);
|
|
|
|
switch (type)
|
|
{
|
|
case DegreeStringType::Decimal:
|
|
degreeString =
|
|
fmt::format("{:.6f}{}{}", degrees, Unicode::kDegree, suffix);
|
|
break;
|
|
case DegreeStringType::DegreesMinutesSeconds:
|
|
{
|
|
uint32_t dd = static_cast<uint32_t>(degrees);
|
|
degrees = (degrees - dd) * 60.0;
|
|
uint32_t mm = static_cast<uint32_t>(degrees);
|
|
double ss = (degrees - mm) * 60.0;
|
|
degreeString = fmt::format(
|
|
"{}{} {}' {:.2f}\"{}", dd, Unicode::kDegree, mm, ss, suffix);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return degreeString;
|
|
}
|
|
|
|
} // namespace common
|
|
} // namespace scwx
|