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  QString CCoordinateGeodetic::convertToQString(bool i18n) const
23  {
24  return ICoordinateGeodetic::convertToQString(i18n);
25  }
26 
27  CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84,
28  const CAltitude &geodeticHeight)
29  {
30  const CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
31  const CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
32  return { lat, lon, geodeticHeight };
33  }
34 
35  const CCoordinateGeodetic &CCoordinateGeodetic::null()
36  {
37  static const CCoordinateGeodetic n;
38  return n;
39  }
40 
41  CLength calculateGreatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
42  {
43  if (coordinate1.isNull() || coordinate2.isNull()) { return CLength::null(); }
44  // if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CLength(0, CLengthUnit::defaultUnit()); }
45  constexpr float earthRadiusMeters = 6371000.8f;
46 
47  const QVector3D v1 = coordinate1.normalVector();
48  const QVector3D v2 = coordinate2.normalVector();
49  Q_ASSERT_X(std::isfinite(v1.x()) && std::isfinite(v1.y()) && std::isfinite(v1.z()), Q_FUNC_INFO,
50  "Distance calculation: v1 non-finite argument");
51  Q_ASSERT_X(std::isfinite(v2.x()) && std::isfinite(v2.y()) && std::isfinite(v2.z()), Q_FUNC_INFO,
52  "Distance calculation: v2 non-finite argument");
53 
54  const float d =
55  earthRadiusMeters * std::atan2(QVector3D::crossProduct(v1, v2).length(), QVector3D::dotProduct(v1, v2));
56 
57  SWIFT_VERIFY_X(!std::isnan(d), Q_FUNC_INFO, "Distance calculation: NaN in result");
58  if (std::isnan(d))
59  {
60  CLogMessage().debug(u"Distance calculation: NaN in result (given arguments %1 %2 %3; %4 %5 %6)")
61  << static_cast<double>(v1.x()) << static_cast<double>(v1.y()) << static_cast<double>(v1.z())
62  << static_cast<double>(v2.x()) << static_cast<double>(v2.y()) << static_cast<double>(v2.z());
63  return CLength::null();
64  }
65  return { static_cast<double>(d), CLengthUnit::m() };
66  }
67 
68  CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
69  {
70  if (coordinate1.isNull() || coordinate2.isNull()) { return CAngle::null(); }
71  // if (coordinate1.equalNormalVectorDouble(coordinate2)) { return CAngle(0, CAngleUnit::defaultUnit()); } //
72  // null or 0?
73  static const QVector3D northPole { 0, 0, 1 };
74  const QVector3D c1 = QVector3D::crossProduct(coordinate1.normalVector(), coordinate2.normalVector());
75  const QVector3D c2 = QVector3D::crossProduct(coordinate1.normalVector(), northPole);
76  const QVector3D cross = QVector3D::crossProduct(c1, c2);
77  const float sinTheta = std::copysign(cross.length(), QVector3D::dotProduct(cross, coordinate1.normalVector()));
78  const float cosTheta = QVector3D::dotProduct(c1, c2);
79  const float theta = std::atan2(sinTheta, cosTheta);
80  return { static_cast<double>(theta), CAngleUnit::rad() };
81  }
82 
83  double calculateEuclideanDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
84  {
85  return static_cast<double>(coordinate1.normalVector().distanceToPoint(coordinate2.normalVector()));
86  }
87 
88  double calculateEuclideanDistanceSquared(const ICoordinateGeodetic &coordinate1,
89  const ICoordinateGeodetic &coordinate2)
90  {
91  return static_cast<double>((coordinate1.normalVector() - coordinate2.normalVector()).lengthSquared());
92  }
93 
94  bool ICoordinateGeodetic::equalNormalVectorDouble(const std::array<double, 3> &otherVector) const
95  {
96  static const double epsilon = std::numeric_limits<double>::epsilon();
97  const std::array<double, 3> thisVector = this->normalVectorDouble();
98  for (unsigned int i = 0; i < otherVector.size(); i++)
99  {
100  const double d = thisVector[i] - otherVector[i];
101  if (qAbs(d) > epsilon) { return false; }
102  }
103  return true;
104  }
105 
106  bool ICoordinateGeodetic::equalNormalVectorDouble(const ICoordinateGeodetic &otherCoordinate) const
107  {
108  return this->equalNormalVectorDouble(otherCoordinate.normalVectorDouble());
109  }
110 
111  CLength ICoordinateGeodetic::calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
112  {
113  return geo::calculateGreatCircleDistance((*this), otherCoordinate);
114  }
115 
116  bool ICoordinateGeodetic::isWithinRange(const ICoordinateGeodetic &otherCoordinate, const CLength &range) const
117  {
118  if (range.isNull()) { return false; }
119  const CLength distance = this->calculateGreatCircleDistance(otherCoordinate);
120  if (distance.isNull()) { return false; }
121  return distance <= range;
122  }
123 
124  CAngle ICoordinateGeodetic::calculateBearing(const ICoordinateGeodetic &otherCoordinate) const
125  {
126  return geo::calculateBearing((*this), otherCoordinate);
127  }
128 
129  bool ICoordinateGeodetic::canHandleIndex(CPropertyIndexRef index)
130  {
131  const int i = index.frontCasted<int>();
132  return (i >= static_cast<int>(IndexLatitude)) && (i <= static_cast<int>(IndexNormalVector));
133  }
134 
135  QVariant ICoordinateGeodetic::propertyByIndex(swift::misc::CPropertyIndexRef index) const
136  {
137  if (!index.isMyself())
138  {
139  const auto i = index.frontCasted<ColumnIndex>();
140  switch (i)
141  {
142  case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
143  case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
144  case IndexLatitudeAsString: return { this->latitudeAsString() };
145  case IndexLongitudeAsString: return { this->longitudeAsString() };
146  case IndexGeodeticHeight: return this->geodeticHeight().propertyByIndex(index.copyFrontRemoved());
147  case IndexGeodeticHeightAsString: return { this->geodeticHeightAsString() };
148  case IndexNormalVector: return QVariant::fromValue(this->normalVector());
149  default: break;
150  }
151  }
152 
153  const QString m = QString("no property, index ").append(index.toQString());
154  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
155  return QVariant::fromValue(m);
156  }
157 
158  int ICoordinateGeodetic::comparePropertyByIndex(CPropertyIndexRef index,
159  const ICoordinateGeodetic &compareValue) const
160  {
161  if (!index.isMyself())
162  {
163  const auto i = index.frontCasted<ColumnIndex>();
164  switch (i)
165  {
166  case IndexLatitude:
167  return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
168  case IndexLongitude:
169  return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
170  case IndexLatitudeAsString: return this->latitudeAsString().compare(compareValue.latitudeAsString());
171  case IndexLongitudeAsString: return this->longitudeAsString().compare(compareValue.longitudeAsString());
172  case IndexGeodeticHeight:
173  return this->geodeticHeight().comparePropertyByIndex(index.copyFrontRemoved(),
174  compareValue.geodeticHeight());
175  case IndexGeodeticHeightAsString:
176  return this->geodeticHeightAsString().compare(compareValue.geodeticHeightAsString());
177  default: break;
178  }
179  }
180 
181  const QString m = QString("no property, index ").append(index.toQString());
182  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
183  return 0;
184  }
185 
186  QString ICoordinateGeodetic::convertToQString(bool i18n) const
187  {
188  const CLatitude lat = this->latitude();
189  const CLongitude lng = this->longitude();
190  return QStringLiteral("Geodetic: {%1/%2, %3/%4, %5}")
191  .arg(lat.valueRoundedWithUnit(CAngleUnit::deg(), 6, i18n),
192  lat.valueRoundedWithUnit(CAngleUnit::rad(), 6, i18n),
193  lng.valueRoundedWithUnit(CAngleUnit::deg(), 6, i18n),
194  lng.valueRoundedWithUnit(CAngleUnit::rad(), 6, i18n),
195  this->geodeticHeight().valueRoundedWithUnit(CLengthUnit::ft(), 2, i18n));
196  }
197 
198  bool ICoordinateGeodetic::isNaNVector() const
199  {
200  const QVector3D v = this->normalVector();
201  return std::isnan(v.x()) || std::isnan(v.y()) || std::isnan(v.z());
202  }
203 
204  bool ICoordinateGeodetic::isNaNVectorDouble() const
205  {
206  const std::array<double, 3> v = this->normalVectorDouble();
207  return std::isnan(v[0]) || std::isnan(v[1]) || std::isnan(v[2]);
208  }
209 
210  bool ICoordinateGeodetic::isInfVector() const
211  {
212  const QVector3D v = this->normalVector();
213  return std::isinf(v.x()) || std::isinf(v.y()) || std::isinf(v.z());
214  }
215 
216  bool ICoordinateGeodetic::isInfVectorDouble() const
217  {
218  const std::array<double, 3> v = this->normalVectorDouble();
219  return std::isinf(v[0]) || std::isinf(v[1]) || std::isinf(v[2]);
220  }
221 
222  bool ICoordinateGeodetic::isValidVectorRange() const
223  {
224  // inf is out of range, comparing nans is always false
225  const std::array<double, 3> v = this->normalVectorDouble();
226  return isValidVector(v);
227  }
228 
229  bool ICoordinateGeodetic::isValidVector(const std::array<double, 3> &v)
230  {
231  constexpr double l = 1.00001; // because of interpolation
232  return v[0] <= l && v[1] <= l && v[2] <= l && v[0] >= -l && v[1] >= -l && v[2] >= -l;
233  }
234 
235  int CCoordinateGeodetic::clampVector()
236  {
237  int c = 0;
238  if (m_x < -1.0)
239  {
240  m_x = -1.0;
241  c++;
242  }
243  else if (m_x > 1.0)
244  {
245  m_x = 1.0;
246  c++;
247  }
248  if (m_y < -1.0)
249  {
250  m_y = -1.0;
251  c++;
252  }
253  else if (m_y > 1.0)
254  {
255  m_y = 1.0;
256  c++;
257  }
258  if (m_z < -1.0)
259  {
260  m_z = -1.0;
261  c++;
262  }
263  else if (m_z > 1.0)
264  {
265  m_z = 1.0;
266  c++;
267  }
268  return c;
269  }
270 
271  QVariant CCoordinateGeodetic::propertyByIndex(swift::misc::CPropertyIndexRef index) const
272  {
273  if (index.isMyself()) { return QVariant::fromValue(*this); }
274  return (ICoordinateGeodetic::canHandleIndex(index)) ? ICoordinateGeodetic::propertyByIndex(index) :
276  }
277 
278  void CCoordinateGeodetic::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
279  {
280  if (index.isMyself())
281  {
282  (*this) = variant.value<CCoordinateGeodetic>();
283  return;
284  }
285  const auto i = index.frontCasted<ICoordinateGeodetic::ColumnIndex>();
286  switch (i)
287  {
288  case IndexGeodeticHeight: m_geodeticHeight.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
289  case IndexLatitude: this->setLatitude(variant.value<CLatitude>()); break;
290  case IndexLongitude: this->setLongitude(variant.value<CLongitude>()); break;
291  case IndexLatitudeAsString: this->setLatitude(CLatitude::fromWgs84(variant.toString())); break;
292  case IndexLongitudeAsString: this->setLongitude(CLongitude::fromWgs84(variant.toString())); break;
293  case IndexGeodeticHeightAsString: m_geodeticHeight.parseFromString(variant.toString()); break;
294  case IndexNormalVector: this->setNormalVector(variant.value<QVector3D>()); break;
295  default: CValueObject::setPropertyByIndex(index, variant); break;
296  }
297  }
298 
299  int CCoordinateGeodetic::comparePropertyByIndex(CPropertyIndexRef index,
300  const CCoordinateGeodetic &compareValue) const
301  {
302  return ICoordinateGeodetic::canHandleIndex(index) ?
303  ICoordinateGeodetic::comparePropertyByIndex(index, compareValue) :
304  CValueObject::comparePropertyByIndex(index, compareValue);
305  }
306 
307  CCoordinateGeodetic::CCoordinateGeodetic(const std::array<double, 3> &normalVector)
308  {
309  this->setNormalVector(normalVector);
310  }
311 
312  CCoordinateGeodetic::CCoordinateGeodetic(const CLatitude &latitude, const CLongitude &longitude)
313  : CCoordinateGeodetic(latitude, longitude, CAltitude::null())
314  {
315  // void
316  }
317 
319  const CAltitude &geodeticHeight)
320  : m_x(latitude.cos() * longitude.cos()), m_y(latitude.cos() * longitude.sin()), m_z(latitude.sin()),
321  m_geodeticHeight(geodeticHeight)
322  {}
323 
324  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees)
325  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
326  { 0, nullptr })
327  {}
328 
329  CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet)
330  : CCoordinateGeodetic({ latitudeDegrees, CAngleUnit::deg() }, { longitudeDegrees, CAngleUnit::deg() },
331  { heightFeet, CLengthUnit::ft() })
332  {}
333 
335  : m_geodeticHeight(coordinate.geodeticHeight())
336  {
337  this->setNormalVector(coordinate.normalVectorDouble());
338  }
339 
341  {
342  if (this->isNull()) { return CCoordinateGeodetic::null(); }
343  if (distance.isNull() || distance.isNegativeWithEpsilonConsidered() || relBearing.isNull())
344  {
345  return CCoordinateGeodetic::null();
346  }
347  if (distance.isZeroEpsilonConsidered()) { return *this; }
348 
349  // http://www.movable-type.co.uk/scripts/latlong.html#destPoint
350  // https://stackoverflow.com/a/879531/356726
351  // https://www.cosmocode.de/en/blog/gohr/2010-06/29-calculate-a-destination-coordinate-based-on-distance-and-bearing-in-php
352  constexpr double earthRadiusMeters = 6371000.8;
353  const double startLatRad = this->latitude().value(CAngleUnit::rad());
354  const double startLngRad = this->longitude().value(CAngleUnit::rad());
355  const double bearingRad = relBearing.value(CAngleUnit::rad());
356  const double distRatio = distance.value(CLengthUnit::m()) / earthRadiusMeters;
357 
358  const double newLatRad =
359  asin(sin(startLatRad) * cos(distRatio) + cos(startLatRad) * sin(distRatio) * cos(bearingRad));
360  double newLngRad = 0;
361 
362  constexpr double epsilon = 1E-06;
363  if (cos(newLatRad) == 0 || qAbs(cos(newLatRad)) < epsilon)
364  newLngRad = startLngRad;
365  else
366  {
367  // λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
368  newLngRad = startLngRad + atan2(sin(bearingRad) * sin(distRatio) * cos(startLatRad),
369  cos(distRatio) - sin(startLatRad) * sin(newLatRad));
370  newLngRad = fmod(newLngRad + 3 * M_PI, 2 * M_PI) - M_PI; // normalize +-180deg
371  }
372 
373  CCoordinateGeodetic copy = *this;
374  const CLatitude lat(newLatRad, CAngleUnit::rad());
375  const CLongitude lng(newLngRad, CAngleUnit::rad());
376  copy.setLatLong(lat, lng);
377  return copy;
378  }
379 
381  {
382  return { std::atan2(m_z, std::hypot(m_x, m_y)), CAngleUnit::rad() };
383  }
384 
386  {
387  // in mathematics atan2 of 0,0 is undefined, with IEEE floating-point atan2(0,0) is either 0 or ±180°
388  return { std::atan2(m_y, m_x), CAngleUnit::rad() };
389  }
390 
392  {
393  return { static_cast<float>(m_x), static_cast<float>(m_y), static_cast<float>(m_z) };
394  }
395 
396  std::array<double, 3> CCoordinateGeodetic::normalVectorDouble() const { return { { m_x, m_y, m_z } }; }
397 
398  void CCoordinateGeodetic::setLatitude(const CLatitude &latitude) { this->setLatLong(latitude, this->longitude()); }
399 
401 
403  {
404  this->setLatLong(this->latitude(), longitude);
405  }
406 
408  {
410  }
411 
412  void CCoordinateGeodetic::setLatLong(const CLatitude &latitude, const CLongitude &longitude)
413  {
414  m_x = latitude.cos() * longitude.cos();
415  m_y = latitude.cos() * longitude.sin();
416  m_z = latitude.sin();
417  }
418 
419  void CCoordinateGeodetic::setLatLongFromWgs84(const QString &latitude, const QString &longitude)
420  {
421  this->setLatitudeFromWgs84(latitude);
422  this->setLongitudeFromWgs84(longitude);
423  }
424 
426 
427  void CCoordinateGeodetic::setNormalVector(const std::array<double, 3> &normalVector)
428  {
429  Q_ASSERT_X(normalVector.size() == 3, Q_FUNC_INFO, "Wrong vector size");
430  m_x = normalVector[0];
431  m_y = normalVector[1];
432  m_z = normalVector[2];
433  }
434 
436  {
437  m_geodeticHeight.switchUnit(unit);
438  return *this;
439  }
440 
442  {
443  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
444  return m_relativeDistance;
445  }
446 
447  CLength
449  {
450  m_relativeDistance = geo::calculateGreatCircleDistance(*this, position);
451  m_relativeBearing = geo::calculateBearing(*this, position);
452  return m_relativeDistance;
453  }
454 
456  {
458  if (!index.isMyself())
459  {
460  const auto i = index.frontCasted<ColumnIndex>();
461  switch (i)
462  {
463  case IndexRelativeBearing: return this->getRelativeBearing().propertyByIndex(index.copyFrontRemoved());
464  case IndexRelativeDistance: return this->getRelativeDistance().propertyByIndex(index.copyFrontRemoved());
465  default: break;
466  }
467  }
468  const QString m = QString("no property, index ").append(index.toQString());
469  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
470  return QVariant::fromValue(m);
471  }
472 
474  {
475  if (ICoordinateGeodetic::canHandleIndex(index)) { return; }
476  if (!index.isMyself())
477  {
478  const auto i = index.frontCasted<ColumnIndex>();
479  switch (i)
480  {
481  case IndexRelativeBearing: m_relativeBearing.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
482  case IndexRelativeDistance: m_relativeDistance.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
483  default:
484  const QString m = QString("no property, index ").append(index.toQString());
485  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(m));
486  break;
487  }
488  }
489  }
490 
491  int
493  const ICoordinateWithRelativePosition &compareValue) const
494  {
496  {
497  return ICoordinateGeodetic::comparePropertyByIndex(index, compareValue);
498  }
499  if (!index.isMyself())
500  {
501  const auto i = index.frontCasted<ColumnIndex>();
502  switch (i)
503  {
504  case IndexRelativeBearing:
506  compareValue.getRelativeBearing());
507  case IndexRelativeDistance:
509  compareValue.getRelativeDistance());
510  default:
511  const QString m = QString("no property, index ").append(index.toQString());
512  Q_ASSERT_X(false, Q_FUNC_INFO, m.toLocal8Bit().constData());
513  Q_UNUSED(m)
514  break;
515  }
516  }
517  return 0;
518  }
519 
521  {
522  return m_relativeBearing.toQString(i18n) % u' ' % m_relativeDistance.toQString(i18n) % u' ' %
524  }
525 
527  {
528  if (ICoordinateGeodetic::canHandleIndex(index)) { return true; }
529  const int i = index.frontCasted<int>();
530  return (i >= static_cast<int>(IndexRelativeDistance)) && (i <= static_cast<int>(IndexRelativeBearing));
531  }
532 } // 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
std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
CCoordinateGeodetic()=default
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.
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.
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.
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