8 #include <QStringBuilder>
14 using namespace swift::misc::aviation;
15 using namespace swift::misc::physical_quantities;
16 using namespace swift::misc::math;
20 namespace swift::misc::geo
22 ICoordinateGeodetic::~ICoordinateGeodetic() {}
24 QString CCoordinateGeodetic::convertToQString(
bool i18n)
const
26 return ICoordinateGeodetic::convertToQString(i18n);
32 const CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
33 const CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
45 if (coordinate1.
isNull() || coordinate2.
isNull()) {
return CLength::null(); }
47 constexpr
float earthRadiusMeters = 6371000.8f;
51 Q_ASSERT_X(std::isfinite(v1.
x()) && std::isfinite(v1.
y()) && std::isfinite(v1.
z()), Q_FUNC_INFO,
52 "Distance calculation: v1 non-finite argument");
53 Q_ASSERT_X(std::isfinite(v2.
x()) && std::isfinite(v2.
y()) && std::isfinite(v2.
z()), Q_FUNC_INFO,
54 "Distance calculation: v2 non-finite argument");
59 SWIFT_VERIFY_X(!std::isnan(d), Q_FUNC_INFO,
"Distance calculation: NaN in result");
62 CLogMessage().
debug(u
"Distance calculation: NaN in result (given arguments %1 %2 %3; %4 %5 %6)")
63 <<
static_cast<double>(v1.
x()) <<
static_cast<double>(v1.
y()) <<
static_cast<double>(v1.
z())
64 <<
static_cast<double>(v2.
x()) <<
static_cast<double>(v2.
y()) <<
static_cast<double>(v2.
z());
65 return CLength::null();
67 return {
static_cast<double>(d), CLengthUnit::m() };
70 CAngle calculateBearing(
const ICoordinateGeodetic &coordinate1,
const ICoordinateGeodetic &coordinate2)
72 if (coordinate1.isNull() || coordinate2.isNull()) {
return CAngle::null(); }
75 static const QVector3D northPole { 0, 0, 1 };
81 const float theta = std::atan2(sinTheta, cosTheta);
82 return {
static_cast<double>(theta), CAngleUnit::rad() };
85 double calculateEuclideanDistance(
const ICoordinateGeodetic &coordinate1,
const ICoordinateGeodetic &coordinate2)
87 return static_cast<double>(coordinate1.normalVector().distanceToPoint(coordinate2.normalVector()));
90 double calculateEuclideanDistanceSquared(
const ICoordinateGeodetic &coordinate1,
91 const ICoordinateGeodetic &coordinate2)
93 return static_cast<double>((coordinate1.normalVector() - coordinate2.normalVector()).lengthSquared());
96 bool ICoordinateGeodetic::equalNormalVectorDouble(
const std::array<double, 3> &otherVector)
const
98 static const double epsilon = std::numeric_limits<double>::epsilon();
99 const std::array<double, 3> thisVector = this->normalVectorDouble();
100 for (
unsigned int i = 0; i < otherVector.size(); i++)
102 const double d = thisVector[i] - otherVector[i];
103 if (qAbs(d) > epsilon) {
return false; }
115 return geo::calculateGreatCircleDistance((*
this), otherCoordinate);
120 if (range.
isNull()) {
return false; }
121 const CLength distance = this->calculateGreatCircleDistance(otherCoordinate);
122 if (distance.
isNull()) {
return false; }
123 return distance <= range;
128 return geo::calculateBearing((*
this), otherCoordinate);
134 return (i >=
static_cast<int>(IndexLatitude)) && (i <=
static_cast<int>(IndexNormalVector));
144 case IndexLatitude:
return this->latitude().propertyByIndex(index.
copyFrontRemoved());
145 case IndexLongitude:
return this->longitude().propertyByIndex(index.
copyFrontRemoved());
146 case IndexLatitudeAsString:
return QVariant(this->latitudeAsString());
147 case IndexLongitudeAsString:
return QVariant(this->longitudeAsString());
148 case IndexGeodeticHeight:
return this->geodeticHeight().propertyByIndex(index.
copyFrontRemoved());
149 case IndexGeodeticHeightAsString:
return QVariant(this->geodeticHeightAsString());
172 case IndexLatitudeAsString:
return this->latitudeAsString().compare(compareValue.
latitudeAsString());
173 case IndexLongitudeAsString:
return this->longitudeAsString().compare(compareValue.
longitudeAsString());
174 case IndexGeodeticHeight:
175 return this->geodeticHeight().comparePropertyByIndex(index.
copyFrontRemoved(),
177 case IndexGeodeticHeightAsString:
188 QString ICoordinateGeodetic::convertToQString(
bool i18n)
const
192 return QStringLiteral(
"Geodetic: {%1/%2, %3/%4, %5}")
197 this->geodeticHeight().valueRoundedWithUnit(CLengthUnit::ft(), 2, i18n));
200 bool ICoordinateGeodetic::isNaNVector()
const
202 const QVector3D v = this->normalVector();
203 return std::isnan(v.
x()) || std::isnan(v.
y()) || std::isnan(v.
z());
206 bool ICoordinateGeodetic::isNaNVectorDouble()
const
208 const std::array<double, 3> v = this->normalVectorDouble();
209 return std::isnan(v[0]) || std::isnan(v[1]) || std::isnan(v[2]);
212 bool ICoordinateGeodetic::isInfVector()
const
214 const QVector3D v = this->normalVector();
215 return std::isinf(v.
x()) || std::isinf(v.
y()) || std::isinf(v.
z());
218 bool ICoordinateGeodetic::isInfVectorDouble()
const
220 const std::array<double, 3> v = this->normalVectorDouble();
221 return std::isinf(v[0]) || std::isinf(v[1]) || std::isinf(v[2]);
224 bool ICoordinateGeodetic::isValidVectorRange()
const
227 const std::array<double, 3> v = this->normalVectorDouble();
228 return isValidVector(v);
231 bool ICoordinateGeodetic::isValidVector(
const std::array<double, 3> &v)
233 constexpr
double l = 1.00001;
234 return v[0] <= l && v[1] <= l && v[2] <= l && v[0] >= -l && v[1] >= -l && v[2] >= -l;
237 int CCoordinateGeodetic::clampVector()
276 return (ICoordinateGeodetic::canHandleIndex(index)) ? ICoordinateGeodetic::propertyByIndex(index) :
290 case IndexGeodeticHeight: m_geodeticHeight.setPropertyByIndex(index.
copyFrontRemoved(), variant);
break;
291 case IndexLatitude: this->setLatitude(variant.
value<
CLatitude>());
break;
292 case IndexLongitude: this->setLongitude(variant.
value<
CLongitude>());
break;
293 case IndexLatitudeAsString: this->setLatitude(CLatitude::fromWgs84(variant.
toString()));
break;
294 case IndexLongitudeAsString: this->setLongitude(CLongitude::fromWgs84(variant.
toString()));
break;
295 case IndexGeodeticHeightAsString: m_geodeticHeight.parseFromString(variant.
toString());
break;
296 case IndexNormalVector: this->setNormalVector(variant.
value<
QVector3D>());
break;
304 return ICoordinateGeodetic::canHandleIndex(index) ?
305 ICoordinateGeodetic::comparePropertyByIndex(index, compareValue) :
309 CCoordinateGeodetic::CCoordinateGeodetic(
const std::array<double, 3> &normalVector)
311 this->setNormalVector(normalVector);
322 : m_x(latitude.cos() * longitude.cos()), m_y(latitude.cos() * longitude.sin()), m_z(latitude.sin()),
323 m_geodeticHeight(geodeticHeight)
327 :
CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
332 :
CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
333 { heightFeet, CLengthUnit::ft() })
337 : m_geodeticHeight(coordinate.geodeticHeight())
354 constexpr
double earthRadiusMeters = 6371000.8;
355 const double startLatRad = this->
latitude().
value(CAngleUnit::rad());
356 const double startLngRad = this->
longitude().
value(CAngleUnit::rad());
357 const double bearingRad = relBearing.
value(CAngleUnit::rad());
358 const double distRatio = distance.
value(CLengthUnit::m()) / earthRadiusMeters;
360 const double newLatRad =
361 asin(sin(startLatRad) * cos(distRatio) + cos(startLatRad) * sin(distRatio) * cos(bearingRad));
362 double newLngRad = 0;
364 constexpr
double epsilon = 1E-06;
365 if (cos(newLatRad) == 0 || qAbs(cos(newLatRad)) < epsilon)
366 newLngRad = startLngRad;
370 newLngRad = startLngRad + atan2(sin(bearingRad) * sin(distRatio) * cos(startLatRad),
371 cos(distRatio) - sin(startLatRad) * sin(newLatRad));
372 newLngRad = fmod(newLngRad + 3 * M_PI, 2 * M_PI) - M_PI;
376 const CLatitude lat(newLatRad, CAngleUnit::rad());
377 const CLongitude lng(newLngRad, CAngleUnit::rad());
384 return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() };
390 return { std::atan2(m_y, m_x), CAngleUnit::rad() };
395 return {
static_cast<float>(m_x),
static_cast<float>(m_y),
static_cast<float>(m_z) };
431 Q_ASSERT_X(
normalVector.size() == 3, Q_FUNC_INFO,
"Wrong vector size");
506 case IndexRelativeBearing:
509 case IndexRelativeDistance:
534 return (i >=
static_cast<int>(IndexRelativeDistance)) && (i <=
static_cast<int>(IndexRelativeBearing));
Class for emitting a log message.
Derived & debug()
Set the severity to debug.
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
QString toQString(bool i18n=false) const
Cast as QString.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
Altitude as used in aviation, can be AGL or MSL altitude.
CAltitude & switchUnit(const physical_quantities::CLengthUnit &newUnit)
Value in switched unit.
void setLatLongFromWgs84(const QString &latitude, const QString &longitude)
Set latitude and longitude.
void setLatitude(const CLatitude &latitude)
Set latitude.
static const CCoordinateGeodetic & null()
null coordinate
virtual CLatitude latitude() const
Latitude.
virtual std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
CCoordinateGeodetic()
Default constructor (null coordinate)
CCoordinateGeodetic calculatePosition(const physical_quantities::CLength &distance, const physical_quantities::CAngle &relBearing) const
Calculate a position in distance/bearing.
CCoordinateGeodetic & switchUnit(const physical_quantities::CLengthUnit &unit)
Switch unit of height.
virtual bool isNull() const
Is null?
void setGeodeticHeightToNull()
Set height to NULL.
void setGeodeticHeight(const aviation::CAltitude &height)
Set height (ellipsoidal or geodetic height)
void setLatLong(const CLatitude &latitude, const CLongitude &longitude)
Set latitude and longitude.
virtual QVector3D normalVector() const
Normal vector.
void setNormalVector(const QVector3D &normal)
Set normal vector.
void setLatitudeFromWgs84(const QString &wgs)
Set latitude.
void setLongitudeFromWgs84(const QString &wgs)
Set longitude.
virtual CLongitude longitude() const
Longitude.
void setLongitude(const CLongitude &longitude)
Set longitude.
static CLatitude fromWgs84(const QString &wgsCoordinate)
Latitude / Longitude from a WGS string such as.
Geodetic coordinate, a position in 3D space relative to the reference geoid.
virtual QVector3D normalVector() const =0
Normal vector.
int comparePropertyByIndex(CPropertyIndexRef index, const ICoordinateGeodetic &compareValue) const
Compare for index.
QString convertToQString(bool i18n=false) const
Cast as QString.
virtual CLongitude longitude() const =0
Longitude.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
virtual std::array< double, 3 > normalVectorDouble() const =0
Normal vector with double precision.
ColumnIndex
Properties by index.
static bool canHandleIndex(CPropertyIndexRef index)
Can given index be handled?
QString longitudeAsString() const
Longitude as string.
virtual bool isNull() const
Is null, means vector x, y, z == 0.
virtual const aviation::CAltitude & geodeticHeight() const =0
Height, ellipsoidal or geodetic height (used in GPS)
QString latitudeAsString() const
Latitude as string.
QString geodeticHeightAsString() const
Height as string.
virtual CLatitude latitude() const =0
Latitude.
Interface (actually more an abstract class) of coordinates and relative position to something (normal...
const physical_quantities::CLength & getRelativeDistance() const
Get the distance.
static bool canHandleIndex(CPropertyIndexRef index)
Can given index be handled?
const physical_quantities::CAngle & getRelativeBearing() const
Get the relative bearing.
physical_quantities::CAngle m_relativeBearing
temporary stored value
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
physical_quantities::CLength calculcateAndUpdateRelativeDistance(const geo::ICoordinateGeodetic &position)
Calculcate distance, set it, and return distance.
physical_quantities::CLength m_relativeDistance
temporary stored value
physical_quantities::CLength calculcateAndUpdateRelativeDistanceAndBearing(const geo::ICoordinateGeodetic &position)
Calculcate distance and bearing to plane, set it, and return distance.
int comparePropertyByIndex(CPropertyIndexRef index, const ICoordinateWithRelativePosition &compareValue) const
Compare for index.
QString convertToQString(bool i18n=false) const
Cast as QString.
ICoordinateWithRelativePosition()
Constructor.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
QString toQString(bool i18n=false) const
Cast as QString.
Physical unit angle (radians, degrees)
double cos() const
Cosine of angle.
double sin() const
Sine of angle.
Physical unit length (length)
Specialized class for distance units (meter, foot, nautical miles).
bool isNegativeWithEpsilonConsidered() const
Value <= 0 epsilon considered.
bool isNull() const
Is quantity null?
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const PQ &pq) const
Compare for index.
double value(MU unit) const
Value in given unit.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
bool isZeroEpsilonConsidered() const
Quantity value <= epsilon.
const char * constData() const const
QString & append(QChar ch)
QByteArray toLocal8Bit() const const
QVariant fromValue(T &&value)
QString toString() const const
QVector3D crossProduct(QVector3D v1, QVector3D v2)
float dotProduct(QVector3D v1, QVector3D v2)
float length() const const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.