From 969f448bf4c35b486f64488ed87052299d9baf4e Mon Sep 17 00:00:00 2001 From: Sven Czarnian Date: Mon, 22 Nov 2021 16:17:20 +0100 Subject: [PATCH] define the geographic library --- include/aman/types/GeoCoordinate.h | 91 ++++++++++++++++++++++++++++++ src/types/GeoCoordinate.cpp | 89 +++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 include/aman/types/GeoCoordinate.h create mode 100644 src/types/GeoCoordinate.cpp diff --git a/include/aman/types/GeoCoordinate.h b/include/aman/types/GeoCoordinate.h new file mode 100644 index 0000000..ccb9492 --- /dev/null +++ b/include/aman/types/GeoCoordinate.h @@ -0,0 +1,91 @@ +/* + * @brief Defines a geo-referenced coordinate + * @file types/GeoCoordinate.h + * @author Sven Czarnian + * @copyright Copyright 2020-2021 Sven Czarnian + * @license This project is published under the GNU General Public License v3 (GPLv3) + */ + +#pragma once + +#include + +#include + +namespace aman { + /** + * @brief Describes a geo-reference coordinate with longitude and latitude + * @ingroup types + */ + class GeoCoordinate { + private: + Angle m_longitude; + Angle m_latitude; + + public: + /** + * @brief Creates a coordinate with zero-values + */ + GeoCoordinate() noexcept; + /** + * @brief Creates a coordinate with initial values + * @param[in] longitude The initial longitudinal value + * @param[in] latitude The initial latitudinal value + */ + GeoCoordinate(const Angle& longitude, const Angle& latitude) noexcept; + + /** + * @brief Checks if two positions are equal + * @param[in] other The other coordinate instance + * @return True if this instance is equal to the other instance, else false + */ + bool operator==(const GeoCoordinate& other) const; + /** + * @brief Checks if two positions are not equal + * @param[in] other The other coordinate instance + * @return True if this instance is not equal to the other instance, else false + */ + bool operator!=(const GeoCoordinate& other) const; + + /** + * @brief Returns the longitudinal component + * @return The constant reference to the longitudinal component + */ + const Angle& longitude() const noexcept; + /** + * @brief Returns the longitudinal component + * @return The reference to the longitudinal component + */ + Angle& longitude() noexcept; + /** + * @brief Returns the latitudinal component + * @return The constant reference to the latitudinal component + */ + const Angle& latitude() const noexcept; + /** + * @brief Returns the latitudinal component + * @return The reference to the latitudinal component + */ + Angle& latitude() noexcept; + /** + * @brief Calculates the coordinate from this coordinate and based on a heading and a distance + * The function uses the haversine-formular and calculates the coordinate based on the great circle distance + * @param[in] heading The heading from this coordinate to the next one + * @param[in] distance The distance from this coordinate to the next one + * @return The resulting coordinate which is based on the heading and the distance + */ + GeoCoordinate projection(const Angle& heading, const Length& distance) const; + /** + * @brief Calculates the great circle distance between this coordinate and the other + * @param[in] other The other coordinate + * @return The great circle distance between this coordinate and the other + */ + Length distanceTo(const GeoCoordinate& other) const; + /** + * @brief Calculates the bearing between this coordinate and the other + * @param[in] other The other coordinate + * @return The bearing between this coordinate and the other + */ + Angle bearingTo(const GeoCoordinate& other) const; + }; +} diff --git a/src/types/GeoCoordinate.cpp b/src/types/GeoCoordinate.cpp new file mode 100644 index 0000000..1ccd74c --- /dev/null +++ b/src/types/GeoCoordinate.cpp @@ -0,0 +1,89 @@ +/* + * Author: + * Sven Czarnian + * Brief: + * Implements the coordinate to abstract global coordinates + * Copyright: + * 2020-2021 Sven Czarnian + * License: + * GNU General Public License v3 (GPLv3) + */ + +#include + +#include +#include + +#include +#include +#include + +using namespace aman; + +static constexpr float MinutesToHours = 60.0f; +static constexpr float SecondsToHours = 3600.0f; +static constexpr float MillisecondsToHours = 3600000.0f; +static constexpr float MaxAngle = 360.0f; + +GeoCoordinate::GeoCoordinate() noexcept : + m_longitude(0.0f), + m_latitude(0.0f) { } + +GeoCoordinate::GeoCoordinate(const Angle& longitude, const Angle& latitude) noexcept : + m_longitude(longitude), + m_latitude(latitude) { } + +bool GeoCoordinate::operator==(const GeoCoordinate& other) const { + return this->m_longitude == other.m_longitude && this->m_latitude == other.m_latitude; +} + +bool GeoCoordinate::operator!=(const GeoCoordinate& other) const { + return false == this->operator==(other); +} + +const Angle& GeoCoordinate::longitude() const noexcept { + return this->m_longitude; +} + +Angle& GeoCoordinate::longitude() noexcept { + return this->m_longitude; +} + +const Angle& GeoCoordinate::latitude() const noexcept { + return this->m_latitude; +} + +Angle& GeoCoordinate::latitude() noexcept { + return this->m_latitude; +} + +GeoCoordinate GeoCoordinate::projection(const Angle& heading, const Length& distance) const { + float lat = 0.0f, lon = 0.0f; + GeographicLib::Geodesic::WGS84().Direct(this->latitude().convert(degree), this->longitude().convert(degree), + heading.convert(degree), distance.convert(metre), lat, lon); + return GeoCoordinate(lon * degree, lat * degree); +} + +Length GeoCoordinate::distanceTo(const GeoCoordinate& other) const { + float distance = 0.0f; + GeographicLib::Geodesic::WGS84().Inverse(this->latitude().convert(degree), this->longitude().convert(degree), + other.latitude().convert(degree), other.longitude().convert(degree), + distance); + return distance * metre; +} + +Angle GeoCoordinate::bearingTo(const GeoCoordinate& other) const { + float azimuth0 = 0.0f, azimuth1 = 0.0f; + GeographicLib::Geodesic::WGS84().Inverse(this->latitude().convert(degree), this->longitude().convert(degree), + other.latitude().convert(degree), other.longitude().convert(degree), + azimuth0, azimuth1); + + std::ignore = azimuth1; + + while (0.0f > azimuth0) + azimuth0 += MaxAngle; + while (MaxAngle < azimuth0) + azimuth0 += MaxAngle; + + return azimuth0 * degree; +}