356 lines
11 KiB
C++
Executable File
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
|