Files
qt5-legatus-legacy/Lts/Common/LtsCoordTrans/lts_coord_trans.h
T
2026-08-13 18:33:10 +02:00

356 lines
11 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Provide some coordinate translation functions on top of GeographicLib
* $Id$
* $HeadURL$
* $Author$
*
* Created by Christian Ehrlicher, SLSE, 2016-08-31
*/
#pragma once
#include <LtsCoordTrans/ltscoordtrans_export.h>
#include <string>
#include <cmath>
#include <QVector>
class QPointF;
class QRectF;
class QSize;
class QString;
namespace LtsCoordTrans
{
/**
* What do we want to achieve:
* - internally our coordinates are represented as geographic coordinates
* (lat/lon, wgs84, radian)
* - convert them to a user-readable format which is (currently) MGRS
* - convert to/from a metric offset relative to a base point from/to
* geographic coordinates (e.g. for equipment in training area, for calculations)
* - calculate a base point from a given geogrphic coordinate (base point
* should be on an mgrs intersection (e.g. 32UPD 0 0)
*
* a nice view of utm and mgrs square could be found here:
* https://mappingsupport.com/p2/coordinates-mgrs-gissurfer-maps.html
*/
// some helper functions
inline Q_CONSTEXPR double pi() { return M_PI; }
inline Q_CONSTEXPR double deg2rad() { return pi() / 180.; }
inline Q_CONSTEXPR double rad2deg() { return 1. / deg2rad(); }
struct LTSCOORDTRANS_EXPORT UtmCoordinate
{
int zone = -1;
bool northp = true;
double x = 0.; // in meter
double y = 0.; // in meter
UtmCoordinate() = default;
UtmCoordinate(int zone_, double x_, double y_, bool northp_ = true)
: zone(zone_)
, northp(northp_)
, x(x_)
, y(y_)
{}
/**
* @brief Checks if the UtmCoordinate is properly initialized (just checks the zone)
* @return if UtmCoordinate is valid
*/
bool isValid() const { return zone > 0 && zone <= 60; }
/**
* @brief Convert the utm coordinate into a mgrs string (prettified - with spaces)
* @param prec precision to use (default: 5)
* @param withSpaces Insert spaces between mgrs parts
* @return mgrs string (empty if conversion did not work)
*/
QString mgrs(int prec = 5, bool withSpaces = true) const;
QPointF toPoint() const;
/**
* @brief Convert the utm coordinate to geographic coordinate, add offset if desired
* @param offsetX the possible x offset (east) to the utm coordinate
* @param offsetY the possible y offset (north) to the utm coorinate
* @return
*/
QPointF geographic(double offsetX = 0., double offsetY = 0.) const;
/**
* @brief overload of QPointF geographic(double, double) const
*/
QPointF geographic(const QPointF &offset) const;
/**
* @brief Get relative Position of coordinate to other coordinate
* @param other Coordinate to get the offset to.
* @return
*/
QPointF relativeTo(const UtmCoordinate &other) const;
/**
* @brief convert a geographic coordinate into a utm coordinate
* @param lon longitude in radian
* @param lat latitude in radian
* @param setZone override default zone (needed e.g. to be sure that every utm coord in an vector gets the same utm zone)
* @return BasePointInformation for conversions from/to relative coordinates
*/
static UtmCoordinate fromGeographic(double lon, double lat, int setZone = -1);
/**
* @brief overload of UtmCoordinate fromGeographic(double, double, bool)
*/
static UtmCoordinate fromGeographic(const QPointF &lonLat, int setZone = -1);
/**
* @brief convert a mgrs coordinate into a utm coordinate
* @param mgrs coordinate to convert
*/
static UtmCoordinate fromMgrs(const QString &mgrs);
};
/**
* @brief convert lon/lat coordinates to mgrs. Shortcut for UtmCoordinate::fromGeographic().mgrs()
* @param lon longitude in radian
* @param lat latitude in radian
* @param prec the precision for the mgrs string
* @param withSpaces Insert spaces between mgrs parts
* @return mgrs as one string with spaces
*/
LTSCOORDTRANS_EXPORT QString mgrsFromGeographic(double lon, double lat, int prec = 5, bool withSpaces = true);
/**
* @brief convert a mgrs string into geographic coordinates. Shortcut for UtmCoordinate::fromMgrs().geographic()
* @param mgrs coordinate to convert
* @return geographic coordinate (invalid QPointF on conversion errror)
*/
LTSCOORDTRANS_EXPORT QPointF geographicFromMgrs(const QString &mgrs);
/**
* @brief addMarginToArea add a margin in meter to a north _orientated_ area
* @param rect_LatLon_radiant rect top be increased
* @param marginMeter margin to be added
* @return increase Area
*/
LTSCOORDTRANS_EXPORT QRectF addMarginToArea(const QRectF &rect_LatLon_radiant, const QSize &marginMeter);
/**
* Return all MGRS squares covered by the current exercise area
* @param rect the rectangle to retriebe the mgrs squares for (in geographic coordinates)
* @param setAsDefaultSquares if true, then set the calculated squares as default squares returned by defaultMgrsSquares()
* @param setAsPreferedSquare if true, then set the center square as prefered square returned by preferedMgrsSquare()
* @return all current available mgrs squares
*/
LTSCOORDTRANS_EXPORT QVector<UtmCoordinate> getMgrsSquares(const QRectF &rect, bool setAsDefaultSquares, bool setAsPreferedSquare, bool setAsSquareWithMargin = false);
/**
* @brief getMgrsSquaresInternal
* @param rect
* @return
*/
QVector<UtmCoordinate> getMgrsSquaresInternal(const QRectF &rect);
/**
* @brief getMgrsSurroundingSquares
* @param geoRect
* @param offsetMeter
* @return
*/
QStringList getMgrsSurroundingSquares(const QRectF &geoRect, const QSize &offsetMeter);
/**
* @brief defaultMgrsSquareWithOffsets
* @return
*/
LTSCOORDTRANS_EXPORT QVector<UtmCoordinate> defaultMgrsSquareWithOffsets();
/**
* @brief Set default MGRS squares to use if getMgrsSquares() is not possible
*/
LTSCOORDTRANS_EXPORT void setDefaultMgrsSquares(const QVector<QString> &squares);
/**
* @brief Return previously set default squares (e.g. for LtsCoordWidget)
* @return all available mgrs squares for the rect set with getMgrsSquares()
*/
LTSCOORDTRANS_EXPORT QVector<UtmCoordinate> defaultMgrsSquares();
/**
* @brief Return previously set prefered square (e.g. for LtsCoordWidget)
* @return prefered mgrs square (center) of the rect set with getMgrsSquares()
*/
LTSCOORDTRANS_EXPORT UtmCoordinate preferedMgrsSquare();
/**
* @brief Convert lon/lat/altitude to geocentric coordinates, output in x,y,z
* @param lon longitude in radian
* @param lat latitude in radian
* @param altitude in meter above ground
* @param xOut geocentric x-coordinate
* @param yOut geocentric y-coordinate
* @param zOut geocentric z-coordinate
* @return true on success
*/
LTSCOORDTRANS_EXPORT bool lonLatAltToGeocentric(double lon, double lat, double altitude, double &xOut, double &yOut, double &zOut);
/**
* @brief Convert geocentric coordinates to lon/lat/altitude output in lon,lat,altiude
* @param x geocentric x-coordinate
* @param y geocentric y-coordinate
* @param z geocentric z-coordinate
* @param lon longitude in radian
* @param lat latitude in radian
* @param altitude in meter above ground
* @return true on success
*/
LTSCOORDTRANS_EXPORT bool geocentric2LonLatAlt(double x, double y, double z,
double &lon, double &lat, double &altitude);
/**
* Overload of double squareDistance(const double lon1, const double lat1, const double lon2, const double lat2)
*/
inline double squareDistance(const UtmCoordinate &p1, const UtmCoordinate &p2)
{
if (p1.zone != p2.zone)
{
Q_ASSERT(false);
return std::nan("");
}
return std::pow(p1.x - p2.x, 2) + std::pow(p1.y - p2.y, 2);
}
/**
* Overload of double squareDistance(const double lon1, const double lat1, const double lon2, const double lat2)
*/
LTSCOORDTRANS_EXPORT double squareDistance(const QPointF &p1, const QPointF &p2);
/**
* @brief Calculate the square distance between two geographicPoints in meter
* @param lon1 longitude of the first point
* @param lat1 latitude of the first point
* @param lon2 longitude of the second point
* @param lat2 latitude of the second point
* @return distance between the two points in meter
*/
inline double squareDistance(const double lon1, const double lat1, const double lon2, const double lat2)
{
const auto p1(UtmCoordinate::fromGeographic(lon1, lat1));
const auto p2(UtmCoordinate::fromGeographic(lon2, lat2, p1.zone));
return squareDistance(p1, p2);
}
/**
* Overload of double squareDistance(const double lon1, const double lat1, const double lon2, const double lat2)
*/
inline double squareDistance(const UtmCoordinate &p1, const double lon2, const double lat2)
{
const auto p2(UtmCoordinate::fromGeographic(lon2, lat2, p1.zone));
return squareDistance(p1, p2);
}
/**
* Overload of double distance(const double lon1, const double lat1, const double lon2, const double lat2)
*/
inline double distance(const UtmCoordinate &p1, const UtmCoordinate &p2)
{
if (p1.zone != p2.zone)
{
Q_ASSERT(false);
return std::nan("");
}
return sqrt(squareDistance(p1, p2));
}
/**
* Overload of double distance(const double lon1, const double lat1, const double lon2, const double lat2)
*/
LTSCOORDTRANS_EXPORT double distance(const QPointF &p1, const QPointF &p2);
/**
* @brief Calculate the distance between two geographicPoints in meter
* @param lon1 longitude of the first point
* @param lat1 latitude of the first point
* @param lon2 longitude of the second point
* @param lat2 latitude of the second point
* @return distance between the two points in meter
*/
inline double distance(const double lon1, const double lat1, const double lon2, const double lat2)
{
return sqrt(squareDistance(lon1, lat1, lon2, lat2));
}
inline double distance(const UtmCoordinate &p1, const double lon2, const double lat2)
{
return sqrt(squareDistance(p1, lon2, lat2));
}
// for debugging purpose:
LTSCOORDTRANS_EXPORT void dumpConversionCounter();
LTSCOORDTRANS_EXPORT long getConversionCounter_MGRS_Forward();
LTSCOORDTRANS_EXPORT long getConversionCounter_MGRS_Reverse();
LTSCOORDTRANS_EXPORT long getConversionCounter_WGS84_Forward();
LTSCOORDTRANS_EXPORT long getConversionCounter_WGS84_Reverse();
LTSCOORDTRANS_EXPORT long getConversionCounter_UTMUPS_Forward();
LTSCOORDTRANS_EXPORT long getConversionCounter_UTMUPS_Reverse();
LTSCOORDTRANS_EXPORT std::ostream &operator<< (std::ostream &stream,
const UtmCoordinate &coord);
//
// class UtmCoordinate3D
//
/*!
* \brief The class UtmCoordinate3D add just a zValue to its baseClass UtmCoordinate
*/
class LTSCOORDTRANS_EXPORT UtmCoordinate3D : public LtsCoordTrans::UtmCoordinate
{
using BaseClass = LtsCoordTrans::UtmCoordinate;
public:
UtmCoordinate3D()
{
reset();
}
explicit UtmCoordinate3D(const LtsCoordTrans::UtmCoordinate &utm2d, double _zValue = std::nan(""))
:BaseClass()
{
zone = utm2d.zone;
northp = utm2d.northp;
x = utm2d.x;
y = utm2d.y;
zValue = _zValue;
}
void reset()
{
zone = -1;
northp = true;
// To be consistent with LtsCoordinate:
// For elevation a value of '0' should be valid.
// So an invalid zValue has to be different: choose NaN
// To be consistent to default constructor of Core::GeoPosition, the (invalid) default value for lon, lat is '0':
x = 0.; // in meter
y = 0.; // in meter
zValue = std::nan("");
}
double z() const { return zValue; }
protected:
double zValue{std::nan("")};
};
} // namespace LtsCoordTrans