251 lines
9.3 KiB
C++

#ifndef GERMANAIRLINESVA_UTILITIES_GEODATA_H
#define GERMANAIRLINESVA_UTILITIES_GEODATA_H
#define M_PI 3.14159265358979323846
#define BUFSIZE 1024
#define MD5LEN 16
#define EARTH_M 6371000
#include <cmath>
namespace germanairlinesva
{
namespace utilities
{
namespace geodata
{
#pragma pack(push)
#pragma pack(1)
struct point {
double latitude;
double longitude;
};
#pragma pack(pop)
#pragma pack(push)
#pragma pack(1)
struct box {
struct point topLeft;
struct point topRight;
struct point bottomRight;
struct point bottomLeft;
};
#pragma pack(pop)
static inline double toMetre(double value) { return value * 0.3048; }
static inline double toFeet(double value) { return value * 3.280839895; }
static inline double toDegrees(double value) { return value * 180 / M_PI; }
static inline double toRadians(double value) { return value * M_PI / 180; }
static inline double normalizeD(double value)
{
return fmod(value + 360, 360);
}
static inline double normalizeR(double value)
{
return value < 0 ? 2 * M_PI + value : value;
}
// Input and Output in degrees
static inline double bearingDD(double fromLatitude,
double fromLongitude,
double toLatitude,
double toLongitude)
{
double y = sin(toRadians(toLongitude) - toRadians(fromLongitude)) *
cos(toRadians(toLatitude));
double x = cos(toRadians(fromLatitude)) * sin(toRadians(toLatitude)) -
sin(toRadians(fromLatitude)) * cos(toRadians(toLatitude)) *
cos(toRadians(toLongitude) - toRadians(fromLongitude));
return normalizeD(toDegrees(atan2(y, x)));
}
// Input in degrees, Output in radians
static inline double bearingDR(double fromLatitude,
double fromLongitude,
double toLatitude,
double toLongitude)
{
double y = sin(toRadians(toLongitude) - toRadians(fromLongitude)) *
cos(toRadians(toLatitude));
double x = cos(toRadians(fromLatitude)) * sin(toRadians(toLatitude)) -
sin(toRadians(fromLatitude)) * cos(toRadians(toLatitude)) *
cos(toRadians(toLongitude) - toRadians(fromLongitude));
return normalizeR(atan2(y, x));
}
// Input in degrees, Output in metres
static inline double distanceEarthD(double fromLatitude,
double fromLongitude,
double toLatitude,
double toLongitude)
{
double lat1r, lon1r, lat2r, lon2r, u, v;
lat1r = toRadians(fromLatitude);
lon1r = toRadians(fromLongitude);
lat2r = toRadians(toLatitude);
lon2r = toRadians(toLongitude);
u = sin((lat2r - lat1r) / 2);
v = sin((lon2r - lon1r) / 2);
return 2.0 * EARTH_M *
asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v));
}
// Input in degrees, Output in metres
static inline double distanceEarthP(point from, point to)
{
double lat1r, lon1r, lat2r, lon2r, u, v;
lat1r = toRadians(from.latitude);
lon1r = toRadians(from.longitude);
lat2r = toRadians(to.latitude);
lon2r = toRadians(to.longitude);
u = sin((lat2r - lat1r) / 2);
v = sin((lon2r - lon1r) / 2);
return 2.0 * EARTH_M *
asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v));
}
// Input and Output in degrees
static inline struct point calculatePointDD(struct point coordinates,
double bearing,
double distance)
{
double r_latitude = toRadians(coordinates.latitude);
double r_longitude = toRadians(coordinates.longitude);
double r_bearing = toRadians(bearing);
double newLatitude =
std::asin(std::sin(r_latitude) * std::cos(distance / EARTH_M) +
std::cos(r_latitude) * std::sin(distance / EARTH_M) *
std::cos(r_bearing));
double newLongitude =
r_longitude +
std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) *
std::cos(r_latitude),
std::cos(distance / EARTH_M) -
std::sin(r_latitude) * std::sin(newLatitude));
return {toDegrees(newLatitude), toDegrees(newLongitude)};
}
// Input in degrees, Output in radians
static inline struct point calculatePointDR(struct point coordinates,
double bearing,
double distance)
{
double r_latitude = toRadians(coordinates.latitude);
double r_longitude = toRadians(coordinates.longitude);
double r_bearing = toRadians(bearing);
double newLatitude =
std::asin(std::sin(r_latitude) * std::cos(distance / EARTH_M) +
std::cos(r_latitude) * std::sin(distance / EARTH_M) *
std::cos(r_bearing));
double newLongitude =
r_longitude +
std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) *
std::cos(r_latitude),
std::cos(distance / EARTH_M) -
std::sin(r_latitude) * std::sin(newLatitude));
return {newLatitude, newLongitude};
}
// LAT/LON in radians, BEARING/Output in degrees
static inline struct point calculatePointRD(struct point coordinates,
double bearing,
double distance)
{
double r_bearing = toRadians(bearing);
double newLatitude = std::asin(
std::sin(coordinates.latitude) * std::cos(distance / EARTH_M) +
std::cos(coordinates.latitude) * std::sin(distance / EARTH_M) *
std::cos(r_bearing));
double newLongitude =
coordinates.longitude +
std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) *
std::cos(coordinates.latitude),
std::cos(distance / EARTH_M) -
std::sin(coordinates.latitude) *
std::sin(newLatitude));
return {toDegrees(newLatitude), toDegrees(newLongitude)};
}
// LAT/LON/Output in radians, BEARING in degrees
static inline struct point calculatePointRR(struct point coordinates,
double bearing,
double distance)
{
double r_bearing = toRadians(bearing);
double newLatitude = std::asin(
std::sin(coordinates.latitude) * std::cos(distance / EARTH_M) +
std::cos(coordinates.latitude) * std::sin(distance / EARTH_M) *
std::cos(r_bearing));
double newLongitude =
coordinates.longitude +
std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) *
std::cos(coordinates.latitude),
std::cos(distance / EARTH_M) -
std::sin(coordinates.latitude) *
std::sin(newLatitude));
return {newLatitude, newLongitude};
}
// Input in degrees, calculate from center
static inline box calculateBoxDD(struct point center,
double bearing,
double length,
double width)
{
struct point primaryCenter =
calculatePointDR(center, bearing, -length / 2);
struct point secondaryCenter =
calculatePointDR(center, bearing, length / 2);
double offsetHeadingNorth =
bearing - 90 > 0 ? bearing - 90 : bearing - 90 + 360;
struct point primaryTop =
calculatePointRD(primaryCenter, offsetHeadingNorth, width / 2);
struct point primaryBottom =
calculatePointRD(primaryCenter, offsetHeadingNorth, -width / 2);
struct point secondaryTop =
calculatePointRD(secondaryCenter, offsetHeadingNorth, width / 2);
struct point secondaryBottom =
calculatePointRD(secondaryCenter, offsetHeadingNorth, -width / 2);
return {primaryTop, secondaryTop, secondaryBottom, primaryBottom};
}
// Input in degrees, calculate from start end
static inline box calculateBoxDD(struct point start,
struct point end,
double bearing,
double width)
{
double offsetHeadingNorth =
bearing - 90 > 0 ? bearing - 90 : bearing - 90 + 360;
struct point primaryTop =
calculatePointDD(start, offsetHeadingNorth, width / 2);
struct point primaryBottom =
calculatePointDD(start, offsetHeadingNorth, -width / 2);
struct point secondaryTop =
calculatePointDD(end, offsetHeadingNorth, width / 2);
struct point secondaryBottom =
calculatePointDD(end, offsetHeadingNorth, -width / 2);
return {primaryTop, secondaryTop, secondaryBottom, primaryBottom};
}
} // namespace geodata
} // namespace utilities
} // namespace germanairlinesva
#endif