Ref T717, calculate a new position in distance from given position

This commit is contained in:
Klaus Basan
2019-09-10 22:32:45 +02:00
parent d47ec7533f
commit 028cf032d7
2 changed files with 48 additions and 10 deletions

View File

@@ -50,7 +50,7 @@ namespace BlackMisc
{ {
if (coordinate1.isNull() || coordinate2.isNull()) { return CLength::null(); } if (coordinate1.isNull() || coordinate2.isNull()) { return CLength::null(); }
// if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CLength(0, CLengthUnit::defaultUnit()); } // if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CLength(0, CLengthUnit::defaultUnit()); }
static const float earthRadiusMeters = 6371000.8f; constexpr float earthRadiusMeters = 6371000.8f;
const QVector3D v1 = coordinate1.normalVector(); const QVector3D v1 = coordinate1.normalVector();
const QVector3D v2 = coordinate2.normalVector(); const QVector3D v2 = coordinate2.normalVector();
@@ -299,6 +299,41 @@ namespace BlackMisc
this->setNormalVector(coordinate.normalVectorDouble()); this->setNormalVector(coordinate.normalVectorDouble());
} }
CCoordinateGeodetic CCoordinateGeodetic::calculatePosition(const CLength &distance, const CAngle &relBearing) const
{
if (this->isNull()) { return CCoordinateGeodetic::null(); }
if (distance.isNull() || distance.isNegativeWithEpsilonConsidered() || relBearing.isNull()) { return CCoordinateGeodetic::null(); }
if (distance.isZeroEpsilonConsidered()) { return *this; }
// http://www.movable-type.co.uk/scripts/latlong.html#destPoint
// https://stackoverflow.com/a/879531/356726
// https://www.cosmocode.de/en/blog/gohr/2010-06/29-calculate-a-destination-coordinate-based-on-distance-and-bearing-in-php
constexpr double earthRadiusMeters = 6371000.8;
const double startLatRad = this->latitude().value(CAngleUnit::rad());
const double startLngRad = this->longitude().value(CAngleUnit::rad());
const double bearingRad = relBearing.value(CAngleUnit::rad());
const double distRatio = distance.value(CLengthUnit::m()) / earthRadiusMeters;
const double newLatRad = asin(sin(startLatRad) * cos(distRatio) + cos(startLatRad) * sin(distRatio) * cos(bearingRad));
double newLngRad = 0;
constexpr double epsilon = 1E-06;
if (cos(newLatRad) == 0 || qAbs(cos(newLatRad)) < epsilon)
newLngRad = startLngRad;
else
{
// λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
newLngRad = startLngRad + atan2(sin(bearingRad) * sin(distRatio) * cos(startLatRad), cos(distRatio) - sin(startLatRad) * sin(newLatRad));
newLngRad = fmod(newLngRad + 3 * M_PI, 2 * M_PI) - M_PI; // normalize +-180deg
}
CCoordinateGeodetic copy = *this;
const CLatitude lat(newLatRad, CAngleUnit::rad());
const CLongitude lng(newLngRad, CAngleUnit::rad());
copy.setLatLong(lat, lng);
return copy;
}
CLatitude CCoordinateGeodetic::latitude() const CLatitude CCoordinateGeodetic::latitude() const
{ {
return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() }; return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() };

View File

@@ -247,6 +247,9 @@ namespace BlackMisc
//! Constructor by interface //! Constructor by interface
CCoordinateGeodetic(const ICoordinateGeodetic &coordinate); CCoordinateGeodetic(const ICoordinateGeodetic &coordinate);
//! Calculate a position in distance/bearing
CCoordinateGeodetic calculatePosition(const PhysicalQuantities::CLength &distance, const PhysicalQuantities::CAngle &relBearing) const;
//! \copydoc ICoordinateGeodetic::latitude //! \copydoc ICoordinateGeodetic::latitude
virtual CLatitude latitude() const override; virtual CLatitude latitude() const override;