You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
7.6 KiB
C

/**********************************************************************************
* MIT License *
* *
* Copyright (c) 2018-2020 Vahan Aghajanyan <vahancho@gmail.com> *
* *
* Geodesy tools for conversions between (historical) datums *
* (c) Chris Veness 2005-2019 *
* www.movable-type.co.uk/scripts/latlong-convert-coords.html *
* www.movable-type.co.uk/scripts/geodesy-library.html#latlon-ellipsoidal-datum *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *
* of this software and associated documentation files (the "Software"), to deal *
* in the Software without restriction, including without limitation the rights *
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in all *
* copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
* SOFTWARE. *
***********************************************************************************/
#ifndef ELLIPSOIDAL_POINT_H
#define ELLIPSOIDAL_POINT_H
#include <memory>
#include "point.h"
#include "datum.h"
namespace erkir
{
namespace cartesian
{
class Point;
}
namespace ellipsoidal
{
//! Implements geodetic point based on ellipsoidal earth model.
/*!
Includes ellipsoid parameters and datums for different coordinate systems, and methods for
converting between them and to Cartesian coordinates.
*/
class ERKIR_EXPORT Point : public erkir::Point
{
public:
//! Constructs a point with the given \p latitude, \p longitude \p height above ellipsoid in metres and \p datum.
Point(const Latitude &latitude, const Longitude &longitude, double height = 0.0,
const Datum &datum = {Datum::Type::WGS84});
/// Return the datum.
Datum datum() const;
/// Returns height above the ellipsoid.
double height() const;
/// Converts 'this' point's coordinate system to new one.
/*!
\param toDatum Datum this coordinate is to be converted to.
\returns Reference to this point converted to new datum.
\example
Point pWGS84(51.47788, -0.00147, Datum::Type::WGS84);
auto pOSGB = pWGS84.toDatum(Datum::Type::OSGB36); // 51.4773°N, 000.0001°E
*/
Point &toDatum(Datum::Type toDatum);
/// Converts 'this' point from (geodetic) coordinates to (geocentric) Cartesian (x/y/z) coordinates.
/*!
\returns Cartesian point equivalent to lat/lon point, with x, y, z in metres from earth centre.
*/
std::unique_ptr<cartesian::Point> toCartesianPoint();
/*!
Returns the distance between 'this' point and destination point along a geodesic on the
surface of the ellipsoid, using Vincenty inverse solution.
\param point Latitude/longitude of destination point.
\returns Distance in metres between points or NaN if failed to converge.
\example
auto p1 = Point(50.06632, -5.71475);
auto p2 = Point(58.64402, -3.07009);
auto d = p1.distanceTo(p2); // 969,954.166 m
*/
double distanceTo(const Point &point) const;
/*!
Returns the destination point having travelled the given distance along a geodesic given by
initial bearing from 'this' point, using Vincenty direct solution.
\param distance Distance travelled along the geodesic in metres.
\param initialBearing Initial bearing in degrees from north.
\returns Destination point.
\example
auto p1 = Point(-37.95103, 144.42487);
auto p2 = p1.destinationPoint(54972.271, 306.86816); // 37.6528°S, 143.9265°E
*/
Point destinationPoint(double distance, double initialBearing) const;
/*!
Returns the initial bearing (forward azimuth) to travel along a geodesic from this point to
the given point, using Vincenty inverse solution.
\param point Latitude/longitude of destination point.
\returns Initial bearing in degrees from north (0°..360°) or NaN if failed to converge.
\example
auto p1 = Point(50.06632, -5.71475);
auto p2 = Point(58.64402, -3.07009);
auto b1 = p1.initialBearingTo(p2); // 9.1419°
*/
double initialBearingTo(const Point &point) const;
/*!
Returns the final bearing (reverse azimuth) having travelled along a geodesic from 'this'
point to the given point, using Vincenty inverse solution.
\param point Latitude/longitude of destination point.
\returns Final bearing in degrees from north (0°..360°) or NaN if failed to converge.
\example
auto p1 = Point(50.06632, -5.71475);
auto p2 = Point(58.64402, -3.07009);
auto b2 = p1.finalBearingTo(p2); // 11.2972°
*/
double finalBearingTo(const Point &point) const;
/*!
Returns the final bearing (reverse azimuth) having travelled along a geodesic given by initial
bearing for a given distance from 'this' point, using Vincenty direct solution.
\param distance Distance travelled along the geodesic in metres.
\param initialBearing Initial bearing in degrees from north.
\returns Final bearing in degrees from north (0°..360°).
\example
auto p1 = Point(-37.95103, 144.42487);
auto b2 = p1.finalBearingOn(54972.271, 306.86816); // 307.1736°
*/
double finalBearingOn(double distance, double initialBearing) const;
private:
enum class DirectField
{
Point,
FinalBearing
};
//!Vincenty direct calculation.
/*!
Ellipsoid parameters are taken from datum of 'this' point. Height is ignored.
\param distance Distance along bearing in metres.
\param initialBearing Initial bearing in degrees from north.
\returns Object including point (destination point), finalBearing.
\throws Formula failed to converge.
*/
std::tuple<Point, double> direct(double distance, double initialBearing) const;
enum class InverseField
{
Distance,
InitialBearing,
FinalBearing
};
//! Vincenty inverse calculation.
/*!
Ellipsoid parameters are taken from datum of 'this' point. Height is ignored.
\param point Latitude/longitude of destination point.
\returns Object including distance, initialBearing, finalBearing.
\throws Invalid point.
\throws Points must be on surface of ellipsoid.
\throws Formula failed to converge.
*/
std::tuple<double, double, double> inverse(const Point &point) const;
double m_height{ 0.0 };
Datum m_datum;
};
} // ellipsoidal
} // erkir
#endif // ELLIPSOIDAL_POINT_H