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  // *INDENT-OFF*
241  if (m_x < -1.0)
242  {
243  m_x = -1.0;
244  c++;
245  }
246  else if (m_x > 1.0)
247  {
248  m_x = 1.0;
249  c++;
250  }
251  if (m_y < -1.0)
252  {
253  m_y = -1.0;
254  c++;
255  }
256  else if (m_y > 1.0)
257  {
258  m_y = 1.0;
259  c++;
260  }
261  if (m_z < -1.0)
262  {
263  m_z = -1.0;
264  c++;
265  }
266  else if (m_z > 1.0)
267  {
268  m_z = 1.0;
269  c++;
270  }
271  // *INDENT-ON*
272  return c;
273  }
274 
275  QVariant CCoordinateGeodetic::propertyByIndex(swift::misc::CPropertyIndexRef index) const
276  {
277  if (index.isMyself()) { return QVariant::fromValue(*this); }
278  return (ICoordinateGeodetic::canHandleIndex(index)) ? ICoordinateGeodetic::propertyByIndex(index) :
280  }
281 
282  void CCoordinateGeodetic::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
283  {
284  if (index.isMyself())
285  {
286  (*this) = variant.value<CCoordinateGeodetic>();
287  return;
288  }
290  switch (i)
291  {
292  case IndexGeodeticHeight: m_geodeticHeight.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
293  case IndexLatitude: this->setLatitude(variant.value<CLatitude>()); break;
294  case IndexLongitude: this->setLongitude(variant.value<CLongitude>()); break;
295  case IndexLatitudeAsString: this->setLatitude(CLatitude::fromWgs84(variant.toString())); break;
296  case IndexLongitudeAsString: this->setLongitude(CLongitude::fromWgs84(variant.toString())); break;
297  case IndexGeodeticHeightAsString: m_geodeticHeight.parseFromString(variant.toString()); break;
298  case IndexNormalVector: this->setNormalVector(variant.value<QVector3D>()); break;
299  default: CValueObject::setPropertyByIndex(index, variant); break;
300  }
301  }
302 
303  int CCoordinateGeodetic::comparePropertyByIndex(CPropertyIndexRef index,
304  const CCoordinateGeodetic &compareValue) const
305  {
306  return ICoordinateGeodetic::canHandleIndex(index) ?
307  ICoordinateGeodetic::comparePropertyByIndex(index, compareValue) :
308  CValueObject::comparePropertyByIndex(index, compareValue);
309  }
310 
311  CCoordinateGeodetic::CCoordinateGeodetic(const std::array<double, 3> &normalVector)
312  {
313  this->setNormalVector(normalVector);
314  }
315 
316  CCoordinateGeodetic::CCoordinateGeodetic(const CLatitude &latitude, const CLongitude &longitude)
317  : CCoordinateGeodetic(latitude, longitude, CAltitude::null())
318  {
319  // void
320  }
321 
323  const CAltitude &geodeticHeight)
324  : m_x(latitude.cos() * longitude.cos()), m_y(latitude.cos() * longitude.sin()), m_z(latitude.sin()),
325  m_geodeticHeight(geodeticHeight)
326  {}
327 
328  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees)
329  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
330  { 0, nullptr })
331  {}
332 
333  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet)
334  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
335  { heightFeet, CLengthUnit::ft() })
336  {}
337 
339  : m_geodeticHeight(coordinate.geodeticHeight())
340  {
341  this->setNormalVector(coordinate.normalVectorDouble());
342  }
343 
345  {
346  if (this->isNull()) { return CCoordinateGeodetic::null(); }
347  if (distance.isNull() || distance.isNegativeWithEpsilonConsidered() || relBearing.isNull())
348  {
349  return CCoordinateGeodetic::null();
350  }
351  if (distance.isZeroEpsilonConsidered()) { return *this; }
352 
353  // http://www.movable-type.co.uk/scripts/latlong.html#destPoint
354  // https://stackoverflow.com/a/879531/356726
355  // https://www.cosmocode.de/en/blog/gohr/2010-06/29-calculate-a-destination-coordinate-based-on-distance-and-bearing-in-php
356  constexpr double earthRadiusMeters = 6371000.8;
357  const double startLatRad = this->latitude().value(CAngleUnit::rad());
358  const double startLngRad = this->longitude().value(CAngleUnit::rad());
359  const double bearingRad = relBearing.value(CAngleUnit::rad());
360  const double distRatio = distance.value(CLengthUnit::m()) / earthRadiusMeters;
361 
362  const double newLatRad =
363  asin(sin(startLatRad) * cos(distRatio) + cos(startLatRad) * sin(distRatio) * cos(bearingRad));
364  double newLngRad = 0;
365 
366  constexpr double epsilon = 1E-06;
367  if (cos(newLatRad) == 0 || qAbs(cos(newLatRad)) < epsilon)
368  newLngRad = startLngRad;
369  else
370  {
371  // λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
372  newLngRad = startLngRad + atan2(sin(bearingRad) * sin(distRatio) * cos(startLatRad),
373  cos(distRatio) - sin(startLatRad) * sin(newLatRad));
374  newLngRad = fmod(newLngRad + 3 * M_PI, 2 * M_PI) - M_PI; // normalize +-180deg
375  }
376 
377  CCoordinateGeodetic copy = *this;
378  const CLatitude lat(newLatRad, CAngleUnit::rad());
379  const CLongitude lng(newLngRad, CAngleUnit::rad());
380  copy.setLatLong(lat, lng);
381  return copy;
382  }
383 
385  {
386  return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() };
387  }
388 
390  {
391  // in mathematics atan2 of 0,0 is undefined, with IEEE floating-point atan2(0,0) is either 0 or ±180°
392  return { std::atan2(m_y, m_x), CAngleUnit::rad() };
393  }
394 
396  {
397  return { static_cast<float>(m_x), static_cast<float>(m_y), static_cast<float>(m_z) };
398  }
399 
400  std::array<double, 3> CCoordinateGeodetic::normalVectorDouble() const { return { { m_x, m_y, m_z } }; }
401 
402  void CCoordinateGeodetic::setLatitude(const CLatitude &latitude) { this->setLatLong(latitude, this->longitude()); }
403 
405 
407  {
408  this->setLatLong(this->latitude(), longitude);
409  }
410 
412  {
414  }
415 
416  void CCoordinateGeodetic::setLatLong(const CLatitude &latitude, const CLongitude &longitude)
417  {
418  m_x = latitude.cos() * longitude.cos();
419  m_y = latitude.cos() * longitude.sin();
420  m_z = latitude.sin();
421  }
422 
423  void CCoordinateGeodetic::setLatLongFromWgs84(const QString &latitude, const QString &longitude)
424  {
425  this->setLatitudeFromWgs84(latitude);
426  this->setLongitudeFromWgs84(longitude);
427  }
428 
430 
431  void CCoordinateGeodetic::setNormalVector(const std::array<double, 3> &normalVector)
432  {
433  Q_ASSERT_X(normalVector.size() == 3, Q_FUNC_INFO, "Wrong vector size");
434  m_x = normalVector[0];
435  m_y = normalVector[1];
436  m_z = normalVector[2];
437  }
438 
440  {
441  m_geodeticHeight.switchUnit(unit);
442  return *this;
443  }
444 
446  {
447  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
448  return m_relativeDistance;
449  }
450 
451  CLength
453  {
454  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
455  m_relativeBearing = geo::calculateBearing(*this, position);
456  return m_relativeDistance;
457  }
458 
460  {
462  if (!index.isMyself())
463  {
464  const ColumnIndex i = index.frontCasted<ColumnIndex>();
465  switch (i)
466  {
467  case IndexRelativeBearing: return this->getRelativeBearing().propertyByIndex(index.copyFrontRemoved());
468  case IndexRelativeDistance: return this->getRelativeDistance().propertyByIndex(index.copyFrontRemoved());
469  default: break;
470  }
471  }
472  const QString m = QString("no property, index ").append(index.toQString());
473  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
474  return QVariant::fromValue(m);
475  }
476 
478  {
479  if (ICoordinateGeodetic::canHandleIndex(index)) { return; }
480  if (!index.isMyself())
481  {
482  const ColumnIndex i = index.frontCasted<ColumnIndex>();
483  switch (i)
484  {
485  case IndexRelativeBearing: m_relativeBearing.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
486  case IndexRelativeDistance: m_relativeDistance.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
487  default:
488  const QString m = QString("no property, index ").append(index.toQString());
489  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
490  break;
491  }
492  }
493  }
494 
495  int
497  const ICoordinateWithRelativePosition &compareValue) const
498  {
500  {
501  return ICoordinateGeodetic::comparePropertyByIndex(index, compareValue);
502  }
503  if (!index.isMyself())
504  {
505  const ColumnIndex i = index.frontCasted<ColumnIndex>();
506  switch (i)
507  {
508  case IndexRelativeBearing:
510  compareValue.getRelativeBearing());
511  case IndexRelativeDistance:
513  compareValue.getRelativeDistance());
514  default:
515  const QString m = QString("no property, index ").append(index.toQString());
516  Q_ASSERT_X(false, Q_FUNC_INFO, m.toLocal8Bit().constData());
517  Q_UNUSED(m)
518  break;
519  }
520  }
521  return 0;
522  }
523 
525  {
526  return m_relativeBearing.toQString(i18n) % u' ' % m_relativeDistance.toQString(i18n) % u' ' %
528  }
529 
531 
533  {
534  if (ICoordinateGeodetic::canHandleIndex(index)) { return true; }
535  const int i = index.frontCasted<int>();
536  return (i >= static_cast<int>(IndexRelativeDistance)) && (i <= static_cast<int>(IndexRelativeBearing));
537  }
538 } // 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:187
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:160
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:167
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
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.
#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