swift
coordinategeodetic.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <cmath>
7 
8 #include <QStringBuilder>
9 #include <QtGlobal>
10 
11 #include "misc/logmessage.h"
12 #include "misc/verify.h"
13 
14 using namespace swift::misc::aviation;
15 using namespace swift::misc::physical_quantities;
16 using namespace swift::misc::math;
17 
18 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::geo, CCoordinateGeodetic)
19 
20 namespace swift::misc::geo
21 {
22  ICoordinateGeodetic::~ICoordinateGeodetic() {}
23 
24  QString CCoordinateGeodetic::convertToQString(bool i18n) const
25  {
26  return ICoordinateGeodetic::convertToQString(i18n);
27  }
28 
29  CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84,
30  const CAltitude &geodeticHeight)
31  {
32  const CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
33  const CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
34  return CCoordinateGeodetic(lat, lon, geodeticHeight);
35  }
36 
37  const CCoordinateGeodetic &CCoordinateGeodetic::null()
38  {
39  static const CCoordinateGeodetic n;
40  return n;
41  }
42 
43  CLength calculateGreatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
44  {
45  if (coordinate1.isNull() || coordinate2.isNull()) { return CLength::null(); }
46  // if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CLength(0, CLengthUnit::defaultUnit()); }
47  constexpr float earthRadiusMeters = 6371000.8f;
48 
49  const QVector3D v1 = coordinate1.normalVector();
50  const QVector3D v2 = coordinate2.normalVector();
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");
55 
56  const float d =
57  earthRadiusMeters * std::atan2(QVector3D::crossProduct(v1, v2).length(), QVector3D::dotProduct(v1, v2));
58 
59  SWIFT_VERIFY_X(!std::isnan(d), Q_FUNC_INFO, "Distance calculation: NaN in result");
60  if (std::isnan(d))
61  {
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();
66  }
67  return { static_cast<double>(d), CLengthUnit::m() };
68  }
69 
70  CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
71  {
72  if (coordinate1.isNull() || coordinate2.isNull()) { return CAngle::null(); }
73  // if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CAngle(0, CAngleUnit::defaultUnit()); } //
74  // null or 0?
75  static const QVector3D northPole { 0, 0, 1 };
76  const QVector3D c1 = QVector3D::crossProduct(coordinate1.normalVector(), coordinate2.normalVector());
77  const QVector3D c2 = QVector3D::crossProduct(coordinate1.normalVector(), northPole);
78  const QVector3D cross = QVector3D::crossProduct(c1, c2);
79  const float sinTheta = std::copysign(cross.length(), QVector3D::dotProduct(cross, coordinate1.normalVector()));
80  const float cosTheta = QVector3D::dotProduct(c1, c2);
81  const float theta = std::atan2(sinTheta, cosTheta);
82  return { static_cast<double>(theta), CAngleUnit::rad() };
83  }
84 
85  double calculateEuclideanDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
86  {
87  return static_cast<double>(coordinate1.normalVector().distanceToPoint(coordinate2.normalVector()));
88  }
89 
90  double calculateEuclideanDistanceSquared(const ICoordinateGeodetic &coordinate1,
91  const ICoordinateGeodetic &coordinate2)
92  {
93  return static_cast<double>((coordinate1.normalVector() - coordinate2.normalVector()).lengthSquared());
94  }
95 
96  bool ICoordinateGeodetic::equalNormalVectorDouble(const std::array<double, 3> &otherVector) const
97  {
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++)
101  {
102  const double d = thisVector[i] - otherVector[i];
103  if (qAbs(d) > epsilon) { return false; }
104  }
105  return true;
106  }
107 
108  bool ICoordinateGeodetic::equalNormalVectorDouble(const ICoordinateGeodetic &otherCoordinate) const
109  {
110  return this->equalNormalVectorDouble(otherCoordinate.normalVectorDouble());
111  }
112 
113  CLength ICoordinateGeodetic::calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
114  {
115  return geo::calculateGreatCircleDistance((*this), otherCoordinate);
116  }
117 
118  bool ICoordinateGeodetic::isWithinRange(const ICoordinateGeodetic &otherCoordinate, const CLength &range) const
119  {
120  if (range.isNull()) { return false; }
121  const CLength distance = this->calculateGreatCircleDistance(otherCoordinate);
122  if (distance.isNull()) { return false; }
123  return distance <= range;
124  }
125 
126  CAngle ICoordinateGeodetic::calculateBearing(const ICoordinateGeodetic &otherCoordinate) const
127  {
128  return geo::calculateBearing((*this), otherCoordinate);
129  }
130 
131  bool ICoordinateGeodetic::canHandleIndex(CPropertyIndexRef index)
132  {
133  const int i = index.frontCasted<int>();
134  return (i >= static_cast<int>(IndexLatitude)) && (i <= static_cast<int>(IndexNormalVector));
135  }
136 
137  QVariant ICoordinateGeodetic::propertyByIndex(swift::misc::CPropertyIndexRef index) const
138  {
139  if (!index.isMyself())
140  {
141  const ColumnIndex i = index.frontCasted<ColumnIndex>();
142  switch (i)
143  {
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());
150  case IndexNormalVector: return QVariant::fromValue(this->normalVector());
151  default: break;
152  }
153  }
154 
155  const QString m = QString("no property, index ").append(index.toQString());
156  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
157  return QVariant::fromValue(m);
158  }
159 
160  int ICoordinateGeodetic::comparePropertyByIndex(CPropertyIndexRef index,
161  const ICoordinateGeodetic &compareValue) const
162  {
163  if (!index.isMyself())
164  {
165  const ColumnIndex i = index.frontCasted<ColumnIndex>();
166  switch (i)
167  {
168  case IndexLatitude:
169  return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
170  case IndexLongitude:
171  return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
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(),
176  compareValue.geodeticHeight());
177  case IndexGeodeticHeightAsString:
178  return this->geodeticHeightAsString().compare(compareValue.geodeticHeightAsString());
179  default: break;
180  }
181  }
182 
183  const QString m = QString("no property, index ").append(index.toQString());
184  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
185  return 0;
186  }
187 
188  QString ICoordinateGeodetic::convertToQString(bool i18n) const
189  {
190  const CLatitude lat = this->latitude();
191  const CLongitude lng = this->longitude();
192  return QStringLiteral("Geodetic: {%1/%2, %3/%4, %5}")
193  .arg(lat.valueRoundedWithUnit(CAngleUnit::deg(), 6, i18n),
194  lat.valueRoundedWithUnit(CAngleUnit::rad(), 6, i18n),
195  lng.valueRoundedWithUnit(CAngleUnit::deg(), 6, i18n),
196  lng.valueRoundedWithUnit(CAngleUnit::rad(), 6, i18n),
197  this->geodeticHeight().valueRoundedWithUnit(CLengthUnit::ft(), 2, i18n));
198  }
199 
200  bool ICoordinateGeodetic::isNaNVector() const
201  {
202  const QVector3D v = this->normalVector();
203  return std::isnan(v.x()) || std::isnan(v.y()) || std::isnan(v.z());
204  }
205 
206  bool ICoordinateGeodetic::isNaNVectorDouble() const
207  {
208  const std::array<double, 3> v = this->normalVectorDouble();
209  return std::isnan(v[0]) || std::isnan(v[1]) || std::isnan(v[2]);
210  }
211 
212  bool ICoordinateGeodetic::isInfVector() const
213  {
214  const QVector3D v = this->normalVector();
215  return std::isinf(v.x()) || std::isinf(v.y()) || std::isinf(v.z());
216  }
217 
218  bool ICoordinateGeodetic::isInfVectorDouble() const
219  {
220  const std::array<double, 3> v = this->normalVectorDouble();
221  return std::isinf(v[0]) || std::isinf(v[1]) || std::isinf(v[2]);
222  }
223 
224  bool ICoordinateGeodetic::isValidVectorRange() const
225  {
226  // inf is out of range, comparing nans is always false
227  const std::array<double, 3> v = this->normalVectorDouble();
228  return isValidVector(v);
229  }
230 
231  bool ICoordinateGeodetic::isValidVector(const std::array<double, 3> &v)
232  {
233  constexpr double l = 1.00001; // because of interpolation
234  return v[0] <= l && v[1] <= l && v[2] <= l && v[0] >= -l && v[1] >= -l && v[2] >= -l;
235  }
236 
237  int CCoordinateGeodetic::clampVector()
238  {
239  int c = 0;
240  if (m_x < -1.0)
241  {
242  m_x = -1.0;
243  c++;
244  }
245  else if (m_x > 1.0)
246  {
247  m_x = 1.0;
248  c++;
249  }
250  if (m_y < -1.0)
251  {
252  m_y = -1.0;
253  c++;
254  }
255  else if (m_y > 1.0)
256  {
257  m_y = 1.0;
258  c++;
259  }
260  if (m_z < -1.0)
261  {
262  m_z = -1.0;
263  c++;
264  }
265  else if (m_z > 1.0)
266  {
267  m_z = 1.0;
268  c++;
269  }
270  return c;
271  }
272 
273  QVariant CCoordinateGeodetic::propertyByIndex(swift::misc::CPropertyIndexRef index) const
274  {
275  if (index.isMyself()) { return QVariant::fromValue(*this); }
276  return (ICoordinateGeodetic::canHandleIndex(index)) ? ICoordinateGeodetic::propertyByIndex(index) :
278  }
279 
280  void CCoordinateGeodetic::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
281  {
282  if (index.isMyself())
283  {
284  (*this) = variant.value<CCoordinateGeodetic>();
285  return;
286  }
288  switch (i)
289  {
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;
297  default: CValueObject::setPropertyByIndex(index, variant); break;
298  }
299  }
300 
301  int CCoordinateGeodetic::comparePropertyByIndex(CPropertyIndexRef index,
302  const CCoordinateGeodetic &compareValue) const
303  {
304  return ICoordinateGeodetic::canHandleIndex(index) ?
305  ICoordinateGeodetic::comparePropertyByIndex(index, compareValue) :
306  CValueObject::comparePropertyByIndex(index, compareValue);
307  }
308 
309  CCoordinateGeodetic::CCoordinateGeodetic(const std::array<double, 3> &normalVector)
310  {
311  this->setNormalVector(normalVector);
312  }
313 
314  CCoordinateGeodetic::CCoordinateGeodetic(const CLatitude &latitude, const CLongitude &longitude)
315  : CCoordinateGeodetic(latitude, longitude, CAltitude::null())
316  {
317  // void
318  }
319 
321  const CAltitude &geodeticHeight)
322  : m_x(latitude.cos() * longitude.cos()), m_y(latitude.cos() * longitude.sin()), m_z(latitude.sin()),
323  m_geodeticHeight(geodeticHeight)
324  {}
325 
326  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees)
327  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
328  { 0, nullptr })
329  {}
330 
331  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet)
332  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
333  { heightFeet, CLengthUnit::ft() })
334  {}
335 
337  : m_geodeticHeight(coordinate.geodeticHeight())
338  {
339  this->setNormalVector(coordinate.normalVectorDouble());
340  }
341 
343  {
344  if (this->isNull()) { return CCoordinateGeodetic::null(); }
345  if (distance.isNull() || distance.isNegativeWithEpsilonConsidered() || relBearing.isNull())
346  {
347  return CCoordinateGeodetic::null();
348  }
349  if (distance.isZeroEpsilonConsidered()) { return *this; }
350 
351  // http://www.movable-type.co.uk/scripts/latlong.html#destPoint
352  // https://stackoverflow.com/a/879531/356726
353  // https://www.cosmocode.de/en/blog/gohr/2010-06/29-calculate-a-destination-coordinate-based-on-distance-and-bearing-in-php
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;
359 
360  const double newLatRad =
361  asin(sin(startLatRad) * cos(distRatio) + cos(startLatRad) * sin(distRatio) * cos(bearingRad));
362  double newLngRad = 0;
363 
364  constexpr double epsilon = 1E-06;
365  if (cos(newLatRad) == 0 || qAbs(cos(newLatRad)) < epsilon)
366  newLngRad = startLngRad;
367  else
368  {
369  // λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
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; // normalize +-180deg
373  }
374 
375  CCoordinateGeodetic copy = *this;
376  const CLatitude lat(newLatRad, CAngleUnit::rad());
377  const CLongitude lng(newLngRad, CAngleUnit::rad());
378  copy.setLatLong(lat, lng);
379  return copy;
380  }
381 
383  {
384  return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() };
385  }
386 
388  {
389  // in mathematics atan2 of 0,0 is undefined, with IEEE floating-point atan2(0,0) is either 0 or ±180°
390  return { std::atan2(m_y, m_x), CAngleUnit::rad() };
391  }
392 
394  {
395  return { static_cast<float>(m_x), static_cast<float>(m_y), static_cast<float>(m_z) };
396  }
397 
398  std::array<double, 3> CCoordinateGeodetic::normalVectorDouble() const { return { { m_x, m_y, m_z } }; }
399 
400  void CCoordinateGeodetic::setLatitude(const CLatitude &latitude) { this->setLatLong(latitude, this->longitude()); }
401 
403 
405  {
406  this->setLatLong(this->latitude(), longitude);
407  }
408 
410  {
412  }
413 
414  void CCoordinateGeodetic::setLatLong(const CLatitude &latitude, const CLongitude &longitude)
415  {
416  m_x = latitude.cos() * longitude.cos();
417  m_y = latitude.cos() * longitude.sin();
418  m_z = latitude.sin();
419  }
420 
421  void CCoordinateGeodetic::setLatLongFromWgs84(const QString &latitude, const QString &longitude)
422  {
423  this->setLatitudeFromWgs84(latitude);
424  this->setLongitudeFromWgs84(longitude);
425  }
426 
428 
429  void CCoordinateGeodetic::setNormalVector(const std::array<double, 3> &normalVector)
430  {
431  Q_ASSERT_X(normalVector.size() == 3, Q_FUNC_INFO, "Wrong vector size");
432  m_x = normalVector[0];
433  m_y = normalVector[1];
434  m_z = normalVector[2];
435  }
436 
438  {
439  m_geodeticHeight.switchUnit(unit);
440  return *this;
441  }
442 
444  {
445  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
446  return m_relativeDistance;
447  }
448 
449  CLength
451  {
452  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
453  m_relativeBearing = geo::calculateBearing(*this, position);
454  return m_relativeDistance;
455  }
456 
458  {
460  if (!index.isMyself())
461  {
462  const ColumnIndex i = index.frontCasted<ColumnIndex>();
463  switch (i)
464  {
465  case IndexRelativeBearing: return this->getRelativeBearing().propertyByIndex(index.copyFrontRemoved());
466  case IndexRelativeDistance: return this->getRelativeDistance().propertyByIndex(index.copyFrontRemoved());
467  default: break;
468  }
469  }
470  const QString m = QString("no property, index ").append(index.toQString());
471  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
472  return QVariant::fromValue(m);
473  }
474 
476  {
477  if (ICoordinateGeodetic::canHandleIndex(index)) { return; }
478  if (!index.isMyself())
479  {
480  const ColumnIndex i = index.frontCasted<ColumnIndex>();
481  switch (i)
482  {
483  case IndexRelativeBearing: m_relativeBearing.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
484  case IndexRelativeDistance: m_relativeDistance.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
485  default:
486  const QString m = QString("no property, index ").append(index.toQString());
487  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
488  break;
489  }
490  }
491  }
492 
493  int
495  const ICoordinateWithRelativePosition &compareValue) const
496  {
498  {
499  return ICoordinateGeodetic::comparePropertyByIndex(index, compareValue);
500  }
501  if (!index.isMyself())
502  {
503  const ColumnIndex i = index.frontCasted<ColumnIndex>();
504  switch (i)
505  {
506  case IndexRelativeBearing:
508  compareValue.getRelativeBearing());
509  case IndexRelativeDistance:
511  compareValue.getRelativeDistance());
512  default:
513  const QString m = QString("no property, index ").append(index.toQString());
514  Q_ASSERT_X(false, Q_FUNC_INFO, m.toLocal8Bit().constData());
515  Q_UNUSED(m)
516  break;
517  }
518  }
519  return 0;
520  }
521 
523  {
524  return m_relativeBearing.toQString(i18n) % u' ' % m_relativeDistance.toQString(i18n) % u' ' %
526  }
527 
529 
531  {
532  if (ICoordinateGeodetic::canHandleIndex(index)) { return true; }
533  const int i = index.frontCasted<int>();
534  return (i >= static_cast<int>(IndexRelativeDistance)) && (i <= static_cast<int>(IndexRelativeBearing));
535  }
536 } // namespace swift::misc::geo
Class for emitting a log message.
Definition: logmessage.h:27
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.
Definition: altitude.h:52
CAltitude & switchUnit(const physical_quantities::CLengthUnit &newUnit)
Value in switched unit.
Definition: altitude.cpp:71
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.
Definition: earthangle.cpp:64
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.
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.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
Definition: mixinindex.h:185
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:158
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:165
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:74
Physical unit angle (radians, degrees)
Definition: angle.h:23
double cos() const
Cosine of angle.
Definition: angle.cpp:75
double sin() const
Sine of angle.
Definition: angle.cpp:73
Physical unit length (length)
Definition: length.h:18
Specialized class for distance units (meter, foot, nautical miles).
Definition: units.h:95
bool isNegativeWithEpsilonConsidered() const
Value <= 0 epsilon considered.
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
T value() const &const
QVector3D crossProduct(QVector3D v1, QVector3D v2)
float dotProduct(QVector3D v1, QVector3D v2)
float length() const const
float x() const const
float y() const const
float z() const const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26