mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-07 11:05:33 +08:00
Ref T717, calculate a new position in distance from given position
This commit is contained in:
@@ -35,7 +35,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const CAltitude &geodeticHeight)
|
CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const CAltitude &geodeticHeight)
|
||||||
{
|
{
|
||||||
const CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
|
const CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
|
||||||
const CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
|
const CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
|
||||||
return CCoordinateGeodetic(lat, lon, geodeticHeight);
|
return CCoordinateGeodetic(lat, lon, geodeticHeight);
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
@@ -140,11 +140,11 @@ namespace BlackMisc
|
|||||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
|
case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
|
||||||
case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
|
case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
|
||||||
case IndexLatitudeAsString: return CVariant(this->latitudeAsString());
|
case IndexLatitudeAsString: return CVariant(this->latitudeAsString());
|
||||||
case IndexLongitudeAsString: return CVariant(this->longitudeAsString());
|
case IndexLongitudeAsString: return CVariant(this->longitudeAsString());
|
||||||
case IndexGeodeticHeight: return this->geodeticHeight().propertyByIndex(index.copyFrontRemoved());
|
case IndexGeodeticHeight: return this->geodeticHeight().propertyByIndex(index.copyFrontRemoved());
|
||||||
case IndexGeodeticHeightAsString: return CVariant(this->geodeticHeightAsString());
|
case IndexGeodeticHeightAsString: return CVariant(this->geodeticHeightAsString());
|
||||||
case IndexNormalVector: return CVariant::fromValue(this->normalVector());
|
case IndexNormalVector: return CVariant::fromValue(this->normalVector());
|
||||||
default: break;
|
default: break;
|
||||||
@@ -163,11 +163,11 @@ namespace BlackMisc
|
|||||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case IndexLatitude: return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
|
case IndexLatitude: return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
|
||||||
case IndexLongitude: return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
|
case IndexLongitude: return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
|
||||||
case IndexLatitudeAsString: return this->latitudeAsString().compare(compareValue.latitudeAsString());
|
case IndexLatitudeAsString: return this->latitudeAsString().compare(compareValue.latitudeAsString());
|
||||||
case IndexLongitudeAsString: return this->longitudeAsString().compare(compareValue.longitudeAsString());
|
case IndexLongitudeAsString: return this->longitudeAsString().compare(compareValue.longitudeAsString());
|
||||||
case IndexGeodeticHeight: return this->geodeticHeight().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.geodeticHeight());
|
case IndexGeodeticHeight: return this->geodeticHeight().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.geodeticHeight());
|
||||||
case IndexGeodeticHeightAsString: return this->geodeticHeightAsString().compare(compareValue.geodeticHeightAsString());
|
case IndexGeodeticHeightAsString: return this->geodeticHeightAsString().compare(compareValue.geodeticHeightAsString());
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -253,9 +253,9 @@ namespace BlackMisc
|
|||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case IndexGeodeticHeight: m_geodeticHeight.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
|
case IndexGeodeticHeight: m_geodeticHeight.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
|
||||||
case IndexLatitude: this->setLatitude(variant.value<CLatitude>()); break;
|
case IndexLatitude: this->setLatitude(variant.value<CLatitude>()); break;
|
||||||
case IndexLongitude: this->setLongitude(variant.value<CLongitude>()); break;
|
case IndexLongitude: this->setLongitude(variant.value<CLongitude>()); break;
|
||||||
case IndexLatitudeAsString: this->setLatitude(CLatitude::fromWgs84(variant.toQString())); break;
|
case IndexLatitudeAsString: this->setLatitude(CLatitude::fromWgs84(variant.toQString())); break;
|
||||||
case IndexLongitudeAsString: this->setLongitude(CLongitude::fromWgs84(variant.toQString())); break;
|
case IndexLongitudeAsString: this->setLongitude(CLongitude::fromWgs84(variant.toQString())); break;
|
||||||
case IndexGeodeticHeightAsString: m_geodeticHeight.parseFromString(variant.toQString()); break;
|
case IndexGeodeticHeightAsString: m_geodeticHeight.parseFromString(variant.toQString()); break;
|
||||||
case IndexNormalVector: this->setNormalVector(variant.value<QVector3D>()); break;
|
case IndexNormalVector: this->setNormalVector(variant.value<QVector3D>()); break;
|
||||||
@@ -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() };
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user