swift
aircraftsituationchange.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QPair>
7 #include <QtGlobal>
8 
9 #include "QStringBuilder"
10 
11 #include "config/buildconfig.h"
13 #include "misc/aviation/callsign.h"
14 #include "misc/comparefunctions.h"
15 #include "misc/math/mathutils.h"
16 #include "misc/pq/angle.h"
17 #include "misc/pq/length.h"
18 #include "misc/pq/units.h"
19 #include "misc/propertyindexref.h"
21 #include "misc/stringutils.h"
22 #include "misc/verify.h"
23 
24 using namespace swift::misc::physical_quantities;
25 using namespace swift::misc::math;
26 using namespace swift::config;
27 
28 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftSituationChange)
29 
30 namespace swift::misc::aviation
31 {
32  void CAircraftSituationChange::registerMetadata()
33  {
35  qRegisterMetaType<CAircraftSituationChange::GuessedSceneryDeviation>();
36  }
37 
38  CAircraftSituationChange::CAircraftSituationChange(const CAircraftSituationList &situations,
39  const physical_quantities::CLength &cg, bool isVtol,
40  bool alreadySortedLatestFirst, bool calcStdDeviations)
41  {
42  if (situations.size() < 2) { return; }
43  const CAircraftSituationList sorted(alreadySortedLatestFirst ? situations :
44  situations.getSortedAdjustedLatestFirst());
45 
46  if (CBuildConfig::isLocalDeveloperDebugBuild())
47  {
48  Q_ASSERT_X(sorted.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO,
49  "Wrong sort order or NULL position");
50  }
51 
52  const CAircraftSituation latest(sorted.front());
53  const CAircraftSituation oldest(sorted.back());
54  const CCallsign cs(latest.getCallsign());
55 
56  m_situationsCount = situations.size();
57  m_correspondingCallsign = cs;
58  m_timestampMSecsSinceEpoch = latest.getMSecsSinceEpoch();
59  m_timeOffsetMs = latest.getTimeOffsetMs();
60  m_oldestTimestampMSecsSinceEpoch = oldest.getMSecsSinceEpoch();
61  m_latestAdjustedTimestampMSecsSinceEpoch = latest.getAdjustedMSecsSinceEpoch();
62  m_oldestAdjustedTimestampMSecsSinceEpoch = oldest.getAdjustedMSecsSinceEpoch();
63  m_constAscending = sorted.isConstAscending(true);
64  m_constDescending = sorted.isConstDescending(true);
65  m_constOnGround = sorted.isConstOnGround();
66  m_constNotOnGround = sorted.isConstNotOnGround();
67  m_justTakeoff = sorted.isJustTakingOff(true);
68  m_justTouchdown = sorted.isJustTouchingDown(true);
69  m_constAccelerating = sorted.isConstAccelerating(true);
70  m_constDecelerating = sorted.isConstDecelarating(true);
71  m_containsPushBack = !isVtol && sorted.containsPushBack();
72 
73  if (sorted.size() >= 3)
74  {
75  const CAircraftSituationList sortedWithout = sorted.withoutFrontSituation();
76  m_wasNotOnGround = sortedWithout.isConstNotOnGround();
77  m_wasOnGround = sortedWithout.isConstOnGround();
78  }
79 
80  if (calcStdDeviations)
81  {
82  this->calculateStdDeviations(situations, cg);
83  m_rotateUp = sorted.front().getPitch() > (m_pitchMean + m_pitchStdDev);
84  }
85  else { m_rotateUp = sorted.isRotatingUp(true); }
86  }
87 
88  bool CAircraftSituationChange::guessOnGround(CAircraftSituation &situation,
89  const simulation::CAircraftModel &model) const
90  {
91  if (!situation.shouldGuessOnGround()) { return false; }
92 
93  // for debugging purposed
94  QString *details = /*CBuildConfig::isLocalDeveloperDebugBuild() ? &m_onGroundGuessingDetails :*/ nullptr;
95 
96  // Non VTOL aircraft have to move to be not on ground
97  const bool vtol = model.isVtol();
98  if (!vtol)
99  {
101  {
102  situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
103  if (details) { *details = QStringLiteral("No VTOL, push back"); }
104  return true;
105  }
106 
107  if (!situation.isMoving())
108  {
109  situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
110  if (details) { *details = QStringLiteral("No VTOL, not moving => on ground"); }
111  return true;
112  }
113  }
114 
115  // not on ground is default
116  situation.setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::OnGroundByGuessing });
117 
118  CLength cg = situation.hasCG() ? situation.getCG() : model.getCG();
119  CSpeed guessedRotateSpeed = CSpeed::null();
120  CSpeed sureRotateSpeed = CSpeed(130, CSpeedUnit::kts());
121  model.getAircraftIcaoCode().guessModelParameters(cg, guessedRotateSpeed);
122  if (!guessedRotateSpeed.isNull())
123  {
124  // does the value make any sense?
125  const bool validGuessedSpeed = (guessedRotateSpeed.value(CSpeedUnit::km_h()) > 5.0);
126  SWIFT_VERIFY_X(validGuessedSpeed, Q_FUNC_INFO, "Wrong guessed value for lift off");
127  if (!validGuessedSpeed) { guessedRotateSpeed = CSpeed(80, CSpeedUnit::kts()); } // fix
128  sureRotateSpeed = guessedRotateSpeed * 1.25;
129  }
130 
131  // "extreme" values for which we are surely not on ground
132  if (qAbs(situation.getPitch().value(CAngleUnit::deg())) > 20)
133  {
134  if (details) { *details = QStringLiteral("max.pitch"); }
135  return true;
136  } // some tail wheel aircraft already have 11° pitch on ground
137  if (qAbs(situation.getBank().value(CAngleUnit::deg())) > 10)
138  {
139  if (details) { *details = QStringLiteral("max.bank"); }
140  return true;
141  }
142  if (situation.getGroundSpeed() > sureRotateSpeed)
143  {
144  if (details) { *details = u"gs. > vr " % sureRotateSpeed.valueRoundedWithUnit(1); }
145  return true;
146  }
147 
148  // use the most accurate or reliable guesses here first
149  // ------------------------------------------------------
150  // by elevation
151  // we can detect "on ground" (underflow, near ground), but not "not on ground" because of overflow
152 
153  // we can detect on ground for underflow, but not for overflow (so we can not rely on NotOnGround)
154  COnGroundInfo og(cg, situation.getGroundDistance(cg));
155  if (og.getOnGround() == COnGroundInfo::OnGround)
156  {
157  if (details) { *details = QStringLiteral("elevation on ground"); }
158  og.setOnGroundDetails(COnGroundInfo::OnGroundByGuessing);
159  situation.setOnGroundInfo(og);
160  return true;
161  }
162 
163  if (!isNull())
164  {
165  if (!vtol && wasConstOnGround())
166  {
167  if (isRotatingUp())
168  {
169  // not OG
170  if (details) { *details = QStringLiteral("rotating up detected"); }
171  return true;
172  }
173 
174  // here we stick to ground until we detect rotate up
175  situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
176  if (details) { *details = QStringLiteral("waiting for rotating up"); }
177  return true;
178  }
179 
180  if (isConstAscending())
181  {
182  // not OG
183  if (details) { *details = QStringLiteral("const ascending"); }
184  return true;
185  }
186  }
187 
188  // on VTOL we stop here
189  if (vtol)
190  {
191  // no idea
192  situation.setOnGroundInfo({ COnGroundInfo::OnGroundSituationUnknown, COnGroundInfo::NotSetGroundDetails });
193  return false;
194  }
195 
196  // guessed speed null -> vtol
197  if (!guessedRotateSpeed.isNull())
198  {
199  // does the value make any sense?
200  if (situation.getGroundSpeed() < guessedRotateSpeed)
201  {
202  situation.setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
203  if (details)
204  {
205  *details = QStringLiteral("Guessing, max.guessed gs.") +
206  guessedRotateSpeed.valueRoundedWithUnit(CSpeedUnit::kts(), 1);
207  }
208  return true;
209  }
210  }
211 
212  // not sure, but this is a guess
213  if (details) { *details = QStringLiteral("Fall through"); }
214  return true;
215  }
216 
217  bool CAircraftSituationChange::hasSceneryDeviation() const { return !m_guessedSceneryDeviation.isNull(); }
218 
219  bool CAircraftSituationChange::hasElevationDevWithinAllowedRange() const
220  {
221  if (m_elvStdDev.isNull()) { return false; }
222  return m_elvStdDev < CAircraftSituation::allowedAltitudeDeviation();
223  }
224 
225  bool CAircraftSituationChange::hasAltitudeDevWithinAllowedRange() const
226  {
227  if (m_altStdDev.isNull()) { return false; }
228  return m_altStdDev < CAircraftSituation::allowedAltitudeDeviation();
229  }
230 
231  QString CAircraftSituationChange::convertToQString(bool i18n) const
232  {
233  Q_UNUSED(i18n)
234  static const QString null("null");
235  if (this->isNull()) { return null; }
236  return u"CS: '" % this->getCallsign().asString() % u" ' ts: " % this->getTimestampAndOffset(true) %
237  u" | situations:" % QString::number(m_situationsCount) % u" | ts adj.: " %
238  QString::number(m_oldestAdjustedTimestampMSecsSinceEpoch) % u'-' %
239  QString::number(m_latestAdjustedTimestampMSecsSinceEpoch) % u" | just takeoff: " %
240  boolToYesNo(this->isJustTakingOff()) % u" just touchdown: " % boolToYesNo(this->isJustTouchingDown()) %
241  u" | all gnd: " % boolToYesNo(this->isConstOnGround()) % u'/' % boolToYesNo(this->wasConstOnGround()) %
242  u" | all not gnd: " % boolToYesNo(this->isConstNotOnGround()) % u'/' %
243  boolToYesNo(this->wasConstNotOnGround()) % u" | ascending: " % boolToYesNo(this->isConstAscending()) %
244  u" descending: " % boolToYesNo(this->isConstDescending()) % u" | accelerating.: " %
245  boolToYesNo(this->isConstAccelerating()) % u" decelarating: " %
246  boolToYesNo(this->isConstDecelarating()) % u" | rotate up: " % boolToYesNo(this->isRotatingUp()) %
247  u" | push back: " % boolToYesNo(this->containsPushBack()) % u" | scenery delta: " %
248  m_guessedSceneryDeviation.valueRoundedWithUnit(1) % u" [" % this->getSceneryDeviationHintAsString() %
249  u"] | AGL delta: " % m_gndDistMean.valueRoundedWithUnit(1) % u'/' %
250  m_gndDistStdDev.valueRoundedWithUnit(1) % u" | std.dev/mean: pitch " %
251  m_pitchMean.valueRoundedWithUnit(1) % u'/' % m_pitchStdDev.valueRoundedWithUnit(1) % u" gs " %
252  m_gsMean.valueRoundedWithUnit(1) % u'/' % m_gsStdDev.valueRoundedWithUnit(1) % u" alt. " %
253  m_altMean.valueRoundedWithUnit(1) % u'/' % m_altStdDev.valueRoundedWithUnit(1) % u" elv. " %
254  m_elvMean.valueRoundedWithUnit(1) % u'/' % m_elvStdDev.valueRoundedWithUnit(1);
255  }
256 
257  QVariant CAircraftSituationChange::propertyByIndex(CPropertyIndexRef index) const
258  {
259  if (index.isMyself()) { return QVariant::fromValue(*this); }
261  {
263  }
264 
265  const ColumnIndex i = index.frontCasted<ColumnIndex>();
266  switch (i)
267  {
268  case IndexCallsign: return m_correspondingCallsign.propertyByIndex(index.copyFrontRemoved());
269  case IndexSituationsCount: return QVariant::fromValue(m_situationsCount);
270  case IndexConstAscending: return QVariant::fromValue(m_constAscending);
271  case IndexConstDescending: return QVariant::fromValue(m_constDescending);
272  case IndexConstNotOnGround: return QVariant::fromValue(m_constNotOnGround);
273  case IndexConstOnGround: return QVariant::fromValue(m_constOnGround);
274  case IndexIsNull: return QVariant::fromValue(this->isNull());
275  case IndexJustTakingOff: return QVariant::fromValue(m_justTakeoff);
276  case IndexJustTouchingDown: return QVariant::fromValue(m_justTouchdown);
277  case IndexRotatingUp: return QVariant::fromValue(m_rotateUp);
278  case IndexContainsPushBack: return QVariant::fromValue(m_containsPushBack);
279  case IndexAltitudeMean: return QVariant::fromValue(m_altMean);
280  case IndexAltitudeStdDev: return QVariant::fromValue(m_altStdDev);
281  case IndexElevationMean: return QVariant::fromValue(m_elvMean);
282  case IndexElevationStdDev: return QVariant::fromValue(m_elvStdDev);
283  default: return CValueObject::propertyByIndex(index);
284  }
285  }
286 
287  void CAircraftSituationChange::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
288  {
289  if (index.isMyself())
290  {
291  (*this) = variant.value<CAircraftSituationChange>();
292  return;
293  }
295  {
297  return;
298  }
299 
300  const ColumnIndex i = index.frontCasted<ColumnIndex>();
301  switch (i)
302  {
303  case IndexCallsign: m_correspondingCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
304  case IndexSituationsCount: m_situationsCount = variant.toInt(); break;
305  case IndexConstAscending: m_constAscending = variant.toBool(); break;
306  case IndexConstDescending: m_constDescending = variant.toBool(); break;
307  case IndexConstNotOnGround: m_constNotOnGround = variant.toBool(); break;
308  case IndexConstOnGround: m_constOnGround = variant.toBool(); break;
309  case IndexJustTakingOff: m_justTakeoff = variant.toBool(); break;
310  case IndexJustTouchingDown: m_justTouchdown = variant.toBool(); break;
311  case IndexRotatingUp: m_rotateUp = variant.toBool(); break;
312  case IndexContainsPushBack: m_containsPushBack = variant.toBool(); break;
313  case IndexIsNull:
314  case IndexAltitudeMean:
315  case IndexAltitudeStdDev:
316  case IndexElevationMean:
317  case IndexElevationStdDev: break; // read only
318  default: CValueObject::setPropertyByIndex(index, variant); break;
319  }
320  }
321 
322  int CAircraftSituationChange::comparePropertyByIndex(CPropertyIndexRef index,
323  const CAircraftSituationChange &compareValue) const
324  {
325  if (index.isMyself())
326  {
328  }
330  {
331  return ITimestampWithOffsetBased::comparePropertyByIndex(index, compareValue);
332  }
333 
334  const ColumnIndex i = index.frontCasted<ColumnIndex>();
335  switch (i)
336  {
337  case IndexCallsign:
338  return m_correspondingCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
339  case IndexSituationsCount:
340  return Compare::compare(this->getSituationsCount(), compareValue.getSituationsCount());
341  case IndexConstAscending: return Compare::compare(this->isConstAscending(), compareValue.isConstAscending());
342  case IndexConstDescending: return Compare::compare(this->isConstDescending(), compareValue.isConstDescending());
343  case IndexConstNotOnGround:
344  return Compare::compare(this->isConstNotOnGround(), compareValue.isConstNotOnGround());
345  case IndexConstOnGround: return Compare::compare(this->isConstOnGround(), compareValue.isConstOnGround());
346  case IndexJustTakingOff: return Compare::compare(this->isJustTakingOff(), compareValue.isJustTakingOff());
347  case IndexJustTouchingDown:
348  return Compare::compare(this->isJustTouchingDown(), compareValue.isJustTouchingDown());
349  case IndexRotatingUp: return Compare::compare(this->isRotatingUp(), compareValue.isRotatingUp());
350  case IndexContainsPushBack: return Compare::compare(this->containsPushBack(), compareValue.containsPushBack());
351  case IndexIsNull: return Compare::compare(this->isNull(), compareValue.isNull());
352  case IndexAltitudeMean:
353  return m_altMean.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.m_altMean);
354  case IndexAltitudeStdDev:
355  return m_altStdDev.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.m_altStdDev);
356  case IndexElevationMean:
357  return m_elvMean.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.m_elvMean);
358  case IndexElevationStdDev:
359  return m_elvStdDev.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.m_elvStdDev);
360  default: return CValueObject::comparePropertyByIndex(index, *this);
361  }
362  Q_ASSERT_X(false, Q_FUNC_INFO, "No comparison");
363  return 0;
364  }
365 
366  bool CAircraftSituationChange::calculateStdDeviations(const CAircraftSituationList &situations, const CLength &cg)
367  {
368  if (situations.isEmpty()) { return false; }
369 
370  const QPair<CSpeed, CSpeed> gsStdDevMean = situations.groundSpeedStandardDeviationAndMean();
371  m_gsStdDev = gsStdDevMean.first;
372  m_gsMean = gsStdDevMean.second;
373 
374  const QPair<CAngle, CAngle> pitchStdDevMean = situations.pitchStandardDeviationAndMean();
375  m_pitchStdDev = pitchStdDevMean.first;
376  m_pitchMean = pitchStdDevMean.second;
377 
378  const QList<double> altValues = situations.altitudeValues(CAltitude::defaultUnit());
379  if (altValues.size() == situations.size())
380  {
381  const QPair<double, double> altDevMean = CMathUtils::standardDeviationAndMean(altValues);
382  m_altStdDev = CAltitude(altDevMean.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
383  m_altMean = CAltitude(altDevMean.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
384  }
385 
386  const QList<double> elvValues = situations.elevationValues(CAltitude::defaultUnit());
387  if (elvValues.size() == situations.size())
388  {
389  const QPair<double, double> elvDevMean = CMathUtils::standardDeviationAndMean(elvValues);
390  m_elvStdDev = CAltitude(elvDevMean.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
391  m_elvMean = CAltitude(elvDevMean.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
392 
393  if (altValues.size() == situations.size())
394  {
395  QList<double> gndDistance;
396  for (int i = 0; i < altValues.size(); i++)
397  {
398  const double delta = altValues[i] - elvValues[i];
399  gndDistance.push_back(delta);
400  }
401  const QPair<double, double> gndDistanceDevMean = CMathUtils::standardDeviationAndMean(gndDistance);
402  m_gndDistStdDev = CLength(gndDistanceDevMean.first, CAltitude::defaultUnit());
403  m_gndDistMean = CLength(gndDistanceDevMean.second, CAltitude::defaultUnit());
404 
405  const auto gndDistMinMax = std::minmax_element(gndDistance.constBegin(), gndDistance.constEnd());
406  const double gndDistMin = *gndDistMinMax.first;
407  const double gndDistMax = *gndDistMinMax.second;
408  m_minGroundDistance = CLength(gndDistMin, CAltitude::defaultUnit());
409  m_maxGroundDistance = CLength(gndDistMax, CAltitude::defaultUnit());
410  this->guessSceneryDeviation(cg);
411  }
412  }
413  return true;
414  }
415 
416  const CAircraftSituationChange &CAircraftSituationChange::null()
417  {
418  static const CAircraftSituationChange null;
419  return null;
420  }
421 
422  const QString &CAircraftSituationChange::guessedSceneryDeviationToString(GuessedSceneryDeviation hint)
423  {
424  static const QString noInfo("no info");
425  static const QString completeOg("complete og");
426  static const QString wasOg("was og");
427  static const QString smallAGLDev("small AGL dev. near gnd.");
428 
429  switch (hint)
430  {
431  case AllOnGround: return completeOg;
432  case WasOnGround: return wasOg;
433  case SmallAGLDeviationNearGround: return smallAGLDev;
434  case NoDeviationInfo:
435  default: break;
436  }
437  return noInfo;
438  }
439 
440  void CAircraftSituationChange::setSceneryDeviation(const CLength &deviation, const CLength &cg,
442  {
443  m_guessedSceneryDeviation = deviation;
444  m_guessedSceneryDeviationCG = cg.isNull() ? CLength::null() : deviation - cg;
445  this->setSceneryDeviationHint(hint);
446  }
447 
448  void CAircraftSituationChange::guessSceneryDeviation(const CLength &cg)
449  {
450  m_guessedSceneryDeviation = CLength::null();
451  this->setSceneryDeviationHint(NoDeviationInfo);
452  if (m_gndDistStdDev.isNull()) { return; }
453  if (m_gndDistMean.isNull()) { return; }
454 
455  // only for a small deviation we can calculate scenery differemce
456  static const CLength maxDeviation(2, CLengthUnit::ft());
457 
458  // Small deviation means "const" AGL
459  if (m_gndDistStdDev <= maxDeviation)
460  {
461  do {
462  if (this->isConstOnGround())
463  {
464  this->setSceneryDeviation(m_gndDistMean, cg, AllOnGround);
465  break;
466  }
467  if (this->wasConstNotOnGround())
468  {
469  this->setSceneryDeviation(m_gndDistMean, cg, WasOnGround);
470  break;
471  }
472  if (!m_altStdDev.isNull() && m_altStdDev <= maxDeviation)
473  {
474  // small alt.deviation too!
475  if (!m_maxGroundDistance.isNull() && m_maxGroundDistance < cg)
476  {
477  if (this->isConstOnGround())
478  {
479  this->setSceneryDeviation(m_gndDistMean, cg, SmallAGLDeviationNearGround);
480  break;
481  }
482  }
483  }
484  }
485  while (false);
486  }
487  }
488 } // namespace swift::misc::aviation
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
reference front()
Access the first element.
Definition: sequence.h:225
reference back()
Access the last element.
Definition: sequence.h:249
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
qint64 getMSecsSinceEpoch() const
Timestamp as ms value.
qint64 getAdjustedMSecsSinceEpoch() const
Timestamp with offset added for interpolation.
static bool canHandleIndex(CPropertyIndexRef index)
Can given index be handled.
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
qint64 getTimeOffsetMs() const
Milliseconds to add to timestamp for interpolation.
int comparePropertyByIndex(CPropertyIndexRef index, const ITimestampWithOffsetBased &compareValue) const
Compare for index.
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
CONTAINER getSortedAdjustedLatestFirst() const
As sorted copy.
void guessModelParameters(physical_quantities::CLength &guessedCGOut, physical_quantities::CSpeed &guessedVRotateOut) const
Guess aircraft model parameters.
Value object about changes in situations.
int getSituationsCount() const
Basend on n situations.
bool containsPushBack() const
Contains any push back?
bool isConstDescending() const
Constantly descending?
bool isConstAscending() const
Constantly ascending?
const CCallsign & getCallsign() const
Get callsign.
GuessedSceneryDeviation
Hint about the guessed scenery deviation.
bool isJustTouchingDown() const
Is just touching down?
bool isConstOnGround() const
Are all situations on ground?
bool isConstNotOnGround() const
Are all situations not on ground?
Value object encapsulating information of an aircraft's situation.
bool shouldGuessOnGround() const
Should we guess on ground?
physical_quantities::CLength getGroundDistance(const physical_quantities::CLength &centerOfGravity) const
Distance to ground, null if impossible to calculate.
const CCallsign & getCallsign() const
Corresponding callsign.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
void setOnGroundInfo(const aviation::COnGroundInfo &info)
Set the on ground info.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
const physical_quantities::CAngle & getPitch() const
Get pitch.
bool isMoving() const
Is moving? Means ground speed > epsilon.
const physical_quantities::CLength & getCG() const
Get CG if any.
bool isJustTouchingDown(bool alreadySortedLatestFirst=false) const
Is just touching down?
CAircraftSituationList withoutFrontSituation() const
Remove the first situation.
bool isConstAccelerating(bool alreadySortedLatestFirst=false) const
Constantly accelerating?
bool isConstNotOnGround() const
Are all situations not on ground?
physical_quantities::CAnglePair pitchStandardDeviationAndMean() const
Pitch angles standard deviation and mean.
QList< double > elevationValues(const physical_quantities::CLengthUnit &unit) const
All elevation values.
bool isConstDecelarating(bool alreadySortedLatestFirst=false) const
Constantly decelarating?
bool isConstDescending(bool alreadySortedLatestFirst=false) const
Constantly descending?
bool isConstOnGround() const
Are all situations on ground?
bool isRotatingUp(bool alreadySortedLatestFirst=false) const
Is rotating up?
bool isJustTakingOff(bool alreadySortedLatestFirst=false) const
Is just taking off?
QList< double > altitudeValues(const physical_quantities::CLengthUnit &unit) const
All altitude values.
bool isSortedAdjustedLatestFirstWithoutNullPositions() const
Latest first and no null positions?
bool isConstAscending(bool alreadySortedLatestFirst=false) const
Constantly ascending?
bool containsPushBack() const
Contains any push back?
physical_quantities::CSpeedPair groundSpeedStandardDeviationAndMean() const
Ground speed standard deviation and mean.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
Value object encapsulating information of a callsign.
Definition: callsign.h:30
Information about the ground status.
Definition: ongroundinfo.h:19
void setOnGroundDetails(OnGroundDetails details)
When source of knowledge changes.
Definition: ongroundinfo.h:69
IsOnGround getOnGround() const
Is on ground?
static QPair< double, double > standardDeviationAndMean(const QList< double > &values)
Standard deviation (first) and mean (second)
Definition: mathutils.cpp:153
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
static void registerMetadata()
Register metadata.
Definition: mixinmetatype.h:56
static CAngleUnit deg()
Degrees.
Definition: units.h:278
Physical unit length (length)
Definition: length.h:18
static CLengthUnit ft()
Foot ft.
Definition: units.h:159
bool isNegativeWithEpsilonConsidered() const
Value <= 0 epsilon considered.
double value(MU unit) const
Value in given unit.
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".
static CSpeedUnit km_h()
Kilometer/hour km/h.
Definition: units.h:868
static CSpeedUnit kts()
Knots.
Definition: units.h:833
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
const physical_quantities::CLength & getCG() const
Get center of gravity.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Aircraft ICAO code.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
#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