swift
aircraftsituation.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 <QtGlobal>
7 
8 #include "QStringBuilder"
9 
10 #include "config/buildconfig.h"
13 #include "misc/comparefunctions.h"
15 #include "misc/pq/length.h"
16 #include "misc/pq/units.h"
17 #include "misc/propertyindexref.h"
18 #include "misc/propertyindexvariantmap.h" // needed for mixin::Index::apply
19 #include "misc/stringutils.h"
20 #include "misc/verify.h"
21 
22 using namespace swift::misc::geo;
23 using namespace swift::misc::physical_quantities;
24 using namespace swift::config;
25 
26 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAircraftSituation)
27 
28 namespace swift::misc::aviation
29 {
30  const CLength &CAircraftSituation::allowedAltitudeDeviation()
31  {
32  // approx. 1 meter
33  static const CLength allowedStdDev(3, CLengthUnit::ft());
34  return allowedStdDev;
35  }
36 
37  CAircraftLights CAircraftSituation::guessLights() const
38  {
39  const bool isOnGround = this->isOnGround();
40  const double gsKts = getGroundSpeed().value(CSpeedUnit::kts());
41  CAircraftLights lights;
42  lights.setCabinOn(true);
43  lights.setRecognitionOn(true);
44 
45  // when first detected moving, lights on
46  if (isOnGround)
47  {
48  lights.setTaxiOn(true);
49  lights.setBeaconOn(true);
50  lights.setNavOn(true);
51 
52  if (gsKts > 30)
53  {
54  // mode accelaration for takeoff
55  lights.setTaxiOn(false);
56  lights.setLandingOn(true);
57  }
58  else if (gsKts > 5)
59  {
60  // mode taxi
61  lights.setTaxiOn(true);
62  lights.setLandingOn(false);
63  }
64  else
65  {
66  // slow movements or parking
67  lights.setTaxiOn(false);
68  lights.setLandingOn(false);
69  }
70  }
71  else
72  {
73  // not on ground
74  lights.setTaxiOn(false);
75  lights.setBeaconOn(true);
76  lights.setNavOn(true);
77  // landing lights for < 10000ft (normally MSL, here ignored)
78  lights.setLandingOn(getAltitude().value(CLengthUnit::ft()) < 10000);
79  }
80  return lights;
81  }
82 
83  void CAircraftSituation::registerMetadata()
84  {
86  qRegisterMetaType<CAircraftSituation::AltitudeCorrection>();
87  qRegisterMetaType<CAircraftSituation::GndElevationInfo>();
88  }
89 
90  CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign)
91  : m_correspondingCallsign(correspondingCallsign)
92  {}
93 
95  const CAngle &pitch, const CAngle &bank, const CSpeed &gs,
96  const CElevationPlane &groundElevation)
97  : m_position(position), m_groundElevationPlane(groundElevation),
98  m_heading(heading.normalizedToPlusMinus180Degrees()), m_pitch(pitch.normalizedToPlusMinus180Degrees()),
99  m_bank(bank.normalizedToPlusMinus180Degrees()), m_groundSpeed(gs)
100  {
101  m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar()));
102  }
103 
104  CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign, const CCoordinateGeodetic &position,
105  const CHeading &heading, const CAngle &pitch, const CAngle &bank,
106  const CSpeed &gs, const CElevationPlane &groundElevation)
107  : m_correspondingCallsign(correspondingCallsign), m_position(position), m_groundElevationPlane(groundElevation),
108  m_heading(heading.normalizedToPlusMinus180Degrees()), m_pitch(pitch.normalizedToPlusMinus180Degrees()),
109  m_bank(bank.normalizedToPlusMinus180Degrees()), m_groundSpeed(gs)
110  {
111  m_correspondingCallsign.setTypeHint(CCallsign::Aircraft);
112  m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar()));
113  }
114 
116  {
117  return u"ts: " % this->getFormattedTimestampAndOffset(true) % u" | " % m_position.toQString(i18n) %
118  u" | alt: " % this->getAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) % u' ' %
119  this->getCorrectedAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) % u"[cor] | og: " %
120  this->getOnGroundInfo().toQString(i18n) % u" | CG: " %
121  (m_cg.isNull() ? QStringLiteral("null") :
122  m_cg.valueRoundedWithUnit(CLengthUnit::m(), 1) % u' ' %
123  m_cg.valueRoundedWithUnit(CLengthUnit::ft(), 1)) %
124  u" | skip ng: " % boolToYesNo(this->canLikelySkipNearGroundInterpolation()) % u" | bank: " %
125  m_bank.toQString(i18n) % u" | pitch: " % m_pitch.toQString(i18n) % u" | heading: " %
126  m_heading.toQString(i18n) % u" | GS: " % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::kts(), 1, true) %
127  u' ' % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::m_s(), 1, true) % u" | elevation [" %
128  this->getGroundElevationInfoAsString() % u"]: " % (m_groundElevationPlane.toQString(i18n));
129  }
130 
132  {
133  static const QString under("underflow");
134  static const QString dragged("dragged to gnd");
135  static const QString no("no correction");
136  static const QString noElv("no elv.");
137  static const QString unknown("unknown");
138  static const QString agl("AGL");
139  switch (correction)
140  {
141  case Underflow: return under;
142  case DraggedToGround: return dragged;
143  case NoElevation: return noElv;
144  case NoCorrection: return no;
145  case AGL: return agl;
146  default: break;
147  }
148  return unknown;
149  }
150 
152  {
153  switch (correction)
154  {
155  case Underflow:
156  case DraggedToGround: return true;
157  case NoElevation:
158  case NoCorrection:
159  case AGL:
160  default: break;
161  }
162  return false;
163  }
164 
166  {
167  static const QString noDetails("no details");
168  static const QString unknown("unknown");
169  static const QString provider("provider");
170  static const QString change("situation change");
171  static const QString cache("cached");
172  static const QString test("test");
173  static const QString interpolated("interpolated");
174  static const QString extrapolated("extrapolated");
175  static const QString avg("average");
176 
177  switch (details)
178  {
179  case NoElevationInfo: return noDetails;
180  case FromProvider: return provider;
181  case SituationChange: return change;
182  case FromCache: return cache;
183  case Test: return test;
184  case Interpolated: return interpolated;
185  case Extrapolated: return extrapolated;
186  case Average: return avg;
187  default: break;
188  }
189  return unknown;
190  }
191 
193  {
194  static const CLength small(0.5, CLengthUnit::m());
195  return small;
196  }
197 
199  {
200  static const CAircraftSituation n;
201  return n;
202  }
203 
205  {
206  static const CLength cg(2.5, CLengthUnit::m());
207  return cg;
208  }
209 
211  const CAircraftSituation &oldSituation,
212  const CAircraftSituation &newSituation,
213  const CLength &distance)
214  {
215  if (oldSituation.isNull() || newSituation.isNull()) { return CElevationPlane::null(); }
216  if (!oldSituation.hasGroundElevation() || !newSituation.hasGroundElevation())
217  {
218  return CElevationPlane::null();
219  }
220  if (oldSituation.equalNormalVectorDouble(newSituation)) { return newSituation.getGroundElevationPlane(); }
221 
222  const double newElvFt = newSituation.getGroundElevation().value(CLengthUnit::ft());
223  const double oldElvFt = oldSituation.getGroundElevation().value(CLengthUnit::ft());
224  const double deltaElvFt = newElvFt - oldElvFt;
225  if (deltaElvFt > MaxDeltaElevationFt)
226  {
227  return CElevationPlane::null();
228  } // threshold, interpolation not possible
229 
230  if (!situation.isNull())
231  {
232  if (CBuildConfig::isLocalDeveloperDebugBuild())
233  {
234  Q_ASSERT_X(situation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
235  Q_ASSERT_X(oldSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
236  Q_ASSERT_X(newSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
237  }
238 
239  const double distanceSituationNewM =
240  situation.calculateGreatCircleDistance(newSituation).value(CLengthUnit::m());
241  if (distanceSituationNewM < 5.0) { return newSituation.getGroundElevationPlane(); }
242 
243  const double distanceOldNewM =
244  (distance.isNull() ? oldSituation.calculateGreatCircleDistance(newSituation) : distance)
245  .value(CLengthUnit::m());
246  if (distanceOldNewM < 5.0) { return oldSituation.getGroundElevationPlane(); }
247 
248  const double distRatio = distanceSituationNewM / distanceOldNewM;
249 
250  // very close to the situations we return their elevation
251  if (distRatio < 0.05) { return newSituation.getGroundElevationPlane(); }
252  if (distRatio > 0.95) { return oldSituation.getGroundElevationPlane(); }
253 
254  const double situationElvFt = newElvFt - distRatio * deltaElvFt;
255  return { situation, situationElvFt, CElevationPlane::singlePointRadius() };
256  }
257  else
258  {
259  const double elvSumFt = oldElvFt + newElvFt;
260  const double elvFt = 0.5 * elvSumFt;
261  return { newSituation, elvFt, CElevationPlane::singlePointRadius() };
262  }
263  }
264 
266  {
267  if (index.isMyself()) { return QVariant::fromValue(*this); }
269  {
271  }
272  if (ICoordinateGeodetic::canHandleIndex(index)) { return ICoordinateGeodetic::propertyByIndex(index); }
273 
274  const auto i = index.frontCasted<ColumnIndex>();
275  switch (i)
276  {
277  case IndexPosition: return m_position.propertyByIndex(index.copyFrontRemoved());
278  case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
279  case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
280  case IndexAltitude: return this->getAltitude().propertyByIndex(index.copyFrontRemoved());
281  case IndexHeading: return m_heading.propertyByIndex(index.copyFrontRemoved());
282  case IndexPitch: return m_pitch.propertyByIndex(index.copyFrontRemoved());
283  case IndexPBHInfo: return QVariant::fromValue(this->getPBHInfo());
284  case IndexVelocity: return QVariant::fromValue(this->getVelocity());
285  case IndexBank: return m_bank.propertyByIndex(index.copyFrontRemoved());
286  case IndexCG: return m_cg.propertyByIndex(index.copyFrontRemoved());
287  case IndexGroundSpeed: return m_groundSpeed.propertyByIndex(index.copyFrontRemoved());
288  case IndexGroundElevationPlane: return m_groundElevationPlane.propertyByIndex(index.copyFrontRemoved());
289  case IndexCallsign: return m_correspondingCallsign.propertyByIndex(index.copyFrontRemoved());
290  case IndexIsOnGroundInfo: return m_onGroundInfo.propertyByIndex(index.copyFrontRemoved());
291  case IndexGroundElevationInfo: return QVariant::fromValue(this->getGroundElevationInfo());
292  case IndexGroundElevationInfoTransferred: return QVariant::fromValue(this->isGroundElevationInfoTransferred());
293  case IndexGroundElevationInfoString: return QVariant::fromValue(this->getGroundElevationInfoAsString());
294  case IndexGroundElevationPlusInfo: return QVariant::fromValue(this->getGroundElevationAndInfo());
295  case IndexCanLikelySkipNearGroundInterpolation:
297  default: return CValueObject::propertyByIndex(index);
298  }
299  }
300 
302  {
303  if (index.isMyself())
304  {
305  (*this) = variant.value<CAircraftSituation>();
306  return;
307  }
309  {
311  return;
312  }
313 
314  const auto i = index.frontCasted<ColumnIndex>();
315  switch (i)
316  {
317  case IndexPosition: m_position.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
318  case IndexPitch: m_pitch.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
319  case IndexBank: m_bank.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
320  case IndexVelocity: m_velocity.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
321  case IndexCG: m_cg.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
322  case IndexGroundSpeed: m_groundSpeed.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
323  case IndexGroundElevationPlane:
324  m_groundElevationPlane.setPropertyByIndex(index.copyFrontRemoved(), variant);
325  break;
326  case IndexCallsign: m_correspondingCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
327  case IndexIsOnGroundInfo: m_onGroundInfo.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
328  case IndexGroundElevationInfo: m_elvInfo = variant.toInt(); break;
329  case IndexGroundElevationInfoTransferred: m_isElvInfoTransferred = variant.toBool(); break;
330  case IndexGroundElevationPlusInfo: break;
331  case IndexCanLikelySkipNearGroundInterpolation: break;
332  default: CValueObject::setPropertyByIndex(index, variant); break;
333  }
334  }
335 
337  const CAircraftSituation &compareValue) const
338  {
340  {
341  return ITimestampWithOffsetBased::comparePropertyByIndex(index, compareValue);
342  }
343  if (ICoordinateGeodetic::canHandleIndex(index))
344  {
345  return ICoordinateGeodetic::comparePropertyByIndex(index, compareValue);
346  }
347  const auto i = index.frontCasted<ColumnIndex>();
348  switch (i)
349  {
350  case IndexPosition:
351  return m_position.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPosition());
352  case IndexAltitude:
353  return this->getAltitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getAltitude());
354  case IndexVelocity:
355  return m_velocity.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getVelocity());
356  case IndexPBHInfo: // fall through
357  case IndexPitch: return m_pitch.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPitch());
358  case IndexBank: return m_bank.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getBank());
359  case IndexCG: return m_cg.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCG());
360  case IndexGroundSpeed:
361  return m_groundSpeed.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getGroundSpeed());
362  case IndexGroundElevationPlane:
363  case IndexGroundElevationPlusInfo:
364  {
365  const int c = m_groundElevationPlane.comparePropertyByIndex(index.copyFrontRemoved(),
366  compareValue.getGroundElevationPlane());
367  if (c != 0 || i == IndexGroundElevationPlane) { return c; }
368  return Compare::compare(this->getGroundElevationInfo(), compareValue.getGroundElevationInfo());
369  }
370  case IndexCallsign:
371  return m_correspondingCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
372  case IndexIsOnGroundInfo:
373  return m_onGroundInfo.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getOnGroundInfo());
374  case IndexGroundElevationInfo:
375  case IndexGroundElevationInfoString:
376  {
377  const int c = Compare::compare(this->getGroundElevationInfo(), compareValue.getGroundElevationInfo());
378  if (c != 0) { return c; }
379  }
380  [[fallthrough]];
381  case IndexGroundElevationInfoTransferred:
382  return Compare::compare(m_isElvInfoTransferred, compareValue.m_isElvInfoTransferred);
383  case IndexCanLikelySkipNearGroundInterpolation:
384  return Compare::compare(this->canLikelySkipNearGroundInterpolation(),
385  compareValue.canLikelySkipNearGroundInterpolation());
386  default: break;
387  }
388  const QString assertMsg("No comparison for index " + index.toQString());
389  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(assertMsg));
390  return 0;
391  }
392 
393  bool CAircraftSituation::isNull() const { return this->isPositionNull(); }
394 
396  bool transferred) const
397  {
398  if (otherInfo == NoElevationInfo || otherInfo == Test) { return false; }
399  const int otherInfoInt = static_cast<int>(otherInfo);
400  if (otherInfoInt > m_elvInfo) { return true; }
401  if (otherInfoInt == m_elvInfo)
402  {
403  if (m_isElvInfoTransferred == transferred) { return false; } // not better (equal)
404  return !transferred; // if not transferred it is better
405  }
406  return false;
407  }
408 
410  {
411  return this->getPitch() == other.getPitch() && this->getBank() == other.getBank() &&
412  this->getHeading() == other.getHeading();
413  }
414 
416  {
417  return this->equalNormalVectorDouble(other.normalVectorDouble()) && this->equalPbh(other);
418  }
419 
421  {
422  if (!this->equalPbhAndVector(other)) { return false; }
423  const int c = this->getAltitude().compare(other.getAltitude());
424  return c == 0;
425  }
426 
428  {
429  if (!this->equalPbhVectorAltitude(other)) { return false; }
430  const int c = this->getGroundElevation().compare(other.getGroundElevation());
431  return c == 0;
432  }
433 
435  {
436  m_position.setNull();
437  m_pressureAltitude.setNull();
438  m_heading.setNull();
439  m_pitch.setNull();
440  m_bank.setNull();
441  m_velocity = {};
442  m_groundElevationPlane.setNull();
443  m_groundSpeed.setNull();
444  m_onGroundInfo = {};
445  m_elvInfo = NoElevationInfo;
446  m_isElvInfoTransferred = false;
447  m_cg.setNull();
448  }
449 
451  {
452  return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts;
453  }
454 
456  {
457  return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork;
458  }
459 
461  {
462  if (this->hasInboundGroundDetails()) { return true; }
463  return m_onGroundInfo.getOnGround() != COnGroundInfo::OnGroundSituationUnknown &&
465  }
466 
468 
470  {
471  if (centerOfGravity.isNull() || !this->hasGroundElevation()) { return CLength::null(); }
472  const CAltitude groundPlusCG = this->getGroundElevation().withOffset(centerOfGravity);
473  const CLength groundDistance = (this->getAltitude() - groundPlusCG);
474  return groundDistance;
475  }
476 
478  {
479  return m_onGroundInfo.getGroundDetails() != COnGroundInfo::NotSetGroundDetails;
480  }
481 
482  COnGroundInfo CAircraftSituation::getOnGroundInfo() const { return m_onGroundInfo; }
483 
485  {
486  m_onGroundInfo.setOnGroundDetails(details);
487  }
488 
489  void CAircraftSituation::setOnGroundInfo(const aviation::COnGroundInfo &info) { m_onGroundInfo = info; }
490 
492  {
493  if (!this->hasGroundElevation()) { return NoElevationInfo; }
494  return static_cast<GndElevationInfo>(m_elvInfo);
495  }
496 
498  {
499  return m_isElvInfoTransferred ? u"tx: " % gndElevationInfoToString(this->getGroundElevationInfo()) :
501  }
502 
504  {
505  static const QString n("null");
506  if (m_groundElevationPlane.isNull()) { return n; }
507 
508  return m_groundElevationPlane.getAltitude().toQString(true) % u" [" % this->getGroundElevationInfoAsString() %
509  u']';
510  }
511 
513  const CLength &radius) const
514  {
515  if (!this->hasGroundElevation()) { return false; }
516 
517  // decide if transfer makes sense
518  // always transfer from provider, but do not override provider
519  if (transferToSituation.getGroundElevationInfo() == CAircraftSituation::FromProvider) { return false; }
521  transferToSituation.getGroundElevationInfo() == CAircraftSituation::FromCache)
522  {
523  return false;
524  }
525 
526  // distance
527  const CLength distance = this->getGroundElevationPlane().calculateGreatCircleDistance(transferToSituation);
528  const bool transferable = (distance <= radius);
529  return transferable;
530  }
531 
533  const CLength &radius) const
534  {
535  return transferToSituation.transferGroundElevationToMe(*this, radius, true);
536  }
537 
539  bool transferred)
540  {
541  if (!fromSituation.canTransferGroundElevation(*this, radius)) { return false; }
542  return this->setGroundElevation(fromSituation.getGroundElevationPlane(), fromSituation.getGroundElevationInfo(),
543  transferred);
544  }
545 
546  bool CAircraftSituation::transferGroundElevationToMe(const CAircraftSituation &fromSituation, bool transferred)
547  {
548  return this->setGroundElevation(fromSituation.getGroundElevationPlane(), fromSituation.getGroundElevationInfo(),
549  transferred);
550  }
551 
553  const CAircraftSituation &newSituation)
554  {
555  const CElevationPlane ep = CAircraftSituation::interpolatedElevation(*this, oldSituation, newSituation);
556  if (ep.isNull()) { return false; }
557  this->setGroundElevation(ep, Interpolated);
558  return true;
559  }
560 
562 
564  {
565  return m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts ||
567  }
568 
569  bool CAircraftSituation::setGroundElevation(const CAltitude &altitude, GndElevationInfo info, bool transferred)
570  {
571  bool set = false;
572  if (altitude.isNull())
573  {
574  m_groundElevationPlane = CElevationPlane::null();
575  m_isElvInfoTransferred = false;
576  this->setGroundElevationInfo(NoElevationInfo);
577  }
578  else
579  {
580  m_groundElevationPlane = CElevationPlane(*this);
581  m_groundElevationPlane.setSinglePointRadius();
582  m_isElvInfoTransferred = transferred;
583  m_groundElevationPlane.setGeodeticHeight(altitude.switchedUnit(this->getAltitudeUnit()));
584  this->setGroundElevationInfo(info);
585  set = true;
586  }
587  return set;
588  }
589 
591  bool transferred)
592  {
593  bool set = false;
594  if (elevationPlane.isNull())
595  {
596  m_groundElevationPlane = CElevationPlane::null();
597  m_isElvInfoTransferred = false;
598  this->setGroundElevationInfo(NoElevationInfo);
599  }
600  else
601  {
602  m_groundElevationPlane = elevationPlane;
603  m_groundElevationPlane.fixRadius();
604  m_isElvInfoTransferred = transferred;
605  this->setGroundElevationInfo(info);
606  Q_ASSERT_X(!m_groundElevationPlane.getRadius().isNull(), Q_FUNC_INFO, "Null radius");
607  m_groundElevationPlane.switchUnit(
608  this->getAltitudeOrDefaultUnit()); // we use ft as internal unit, no "must" but simplification
609  set = true;
610  }
611  return set;
612  }
613 
615  bool transferred)
616  {
617  if (elevationPlane.isNull()) { return false; }
618  const CLength distance = this->calculateGreatCircleDistance(elevationPlane);
619  if (distance > elevationPlane.getRadiusOrMinimumRadius()) { return false; }
620  if (m_groundElevationPlane.isNull() || this->isOtherElevationInfoBetter(info, transferred))
621  {
622  // better values
623  this->setGroundElevation(elevationPlane, info, transferred);
624  m_groundElevationPlane.setRadiusOrMinimumRadius(distance);
625  return true;
626  }
627  return false;
628  }
629 
631  {
632  m_groundElevationPlane = CElevationPlane::null();
633  this->setGroundElevationInfo(NoElevationInfo);
634  }
635 
637  {
638  if (this->getAltitude().isNull()) { return CLength::null(); }
639  if (this->getAltitude().getReferenceDatum() == CAltitude::AboveGround)
640  {
641  // we have a sure value explicitly set
642  return this->getAltitude();
643  }
644 
645  const CLength gh(this->getGroundElevation());
646  if (gh.isNull()) { return CLength::null(); }
647 
648  // sanity checks
649  if (std::isnan(gh.value()))
650  {
651  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "nan ground");
652  return CLength::null();
653  }
654  if (std::isnan(this->getAltitude().value()))
655  {
656  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "nan altitude");
657  return CLength::null();
658  }
659 
660  const CLength ag = this->getAltitude() - gh;
661  return ag;
662  }
663 
665  {
666  m_heading = heading.normalizedToPlusMinus180Degrees();
667  }
668 
670  {
671  if (this->getAltitude().isNull()) { return CAltitude::defaultUnit(); }
672  return m_position.geodeticHeight().getUnit();
673  }
674 
676  CAircraftSituation::AltitudeCorrection *correction) const
677  {
678  return this->getCorrectedAltitude(m_cg, enableDragToGround, correction);
679  }
680 
681  CAltitude CAircraftSituation::getCorrectedAltitude(const CLength &centerOfGravity, bool enableDragToGround,
682  AltitudeCorrection *correction) const
683  {
684  if (correction) { *correction = UnknownCorrection; }
685  if (!this->hasGroundElevation())
686  {
687  if (correction) { *correction = NoElevation; }
688  return this->getAltitude();
689  }
690 
691  // above ground
692  if (this->getAltitude().getReferenceDatum() == CAltitude::AboveGround)
693  {
694  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Unsupported");
695  if (correction) { *correction = AGL; }
696  return this->getAltitude();
697  }
698  else
699  {
700  const CAltitude groundPlusCG =
701  this->getGroundElevation().withOffset(centerOfGravity).switchedUnit(this->getAltitudeOrDefaultUnit());
702  if (groundPlusCG.isNull())
703  {
704  if (correction) { *correction = NoElevation; }
705  return this->getAltitude();
706  }
707  const CLength groundDistance = this->getAltitude() - groundPlusCG;
708  const bool underflow = groundDistance.isNegativeWithEpsilonConsidered();
709  if (underflow)
710  {
711  if (correction) { *correction = Underflow; }
712  return groundPlusCG;
713  }
714  const bool nearGround = groundDistance.abs() < deltaNearGround();
715  if (nearGround)
716  {
717  if (correction) { *correction = NoCorrection; }
718  return groundPlusCG;
719  }
720  const bool forceDragToGround = (enableDragToGround && isOnGround()) &&
721  (this->hasInboundGroundDetails() ||
723  if (forceDragToGround)
724  {
725  if (correction) { *correction = DraggedToGround; }
726  return groundPlusCG;
727  }
728 
729  if (correction) { *correction = NoCorrection; }
730  return this->getAltitude();
731  }
732  }
733 
735  {
736  return this->correctAltitude(m_cg, enableDragToGround);
737  }
738 
740  bool enableDragToGround)
741  {
742  CAircraftSituation::AltitudeCorrection altitudeCorrection = CAircraftSituation::UnknownCorrection;
743  this->setAltitude(this->getCorrectedAltitude(centerOfGravity, enableDragToGround, &altitudeCorrection));
744  this->setCG(centerOfGravity);
745  return altitudeCorrection;
746  }
747 
749  {
750  m_position.setGeodeticHeight(altitude.switchedUnit(CAltitude::defaultUnit()));
751  }
752 
754  {
755  if (offset.isNull()) { return this->getAltitude(); }
756  const CAltitude alt = this->getAltitude().withOffset(offset);
757  this->setAltitude(alt);
758  return alt;
759  }
760 
762  {
763  if (offset.isNull()) { return *this; }
764  CAircraftSituation copy(*this);
765  copy.addAltitudeOffset(offset);
766  return copy;
767  }
768 
770  {
771  Q_ASSERT(altitude.getAltitudeType() == CAltitude::PressureAltitude);
772  m_pressureAltitude = altitude;
773  }
774 
775  void CAircraftSituation::setPitch(const CAngle &pitch) { m_pitch = pitch.normalizedToPlusMinus180Degrees(); }
776 
778 
780  {
781  static const CAngle za(0, CAngleUnit::deg());
782  static const CHeading zh(za, CHeading::True);
783  this->setPitch(za);
784  this->setBank(za);
785  this->setHeading(zh);
786  }
787 
789  {
790  this->setZeroPBH();
791  this->setGroundSpeed(CSpeed(0, CSpeedUnit::defaultUnit()));
792  }
793 
795  {
796  return QStringLiteral("P: %1 %2 B: %3 %4 H: %5 %6")
797  .arg(this->getPitch().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
798  this->getPitch().valueRoundedWithUnit(CAngleUnit::rad(), 5, true),
799  this->getBank().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
800  this->getBank().valueRoundedWithUnit(CAngleUnit::rad(), 5, true),
801  this->getHeading().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
802  this->getHeading().valueRoundedWithUnit(CAngleUnit::rad(), 5, true));
803  }
804 
806  {
807  const double gsKmh = this->getGroundSpeed().value(CSpeedUnit::km_h());
808  return gsKmh >= 2.5;
809  }
810 
812  {
813  if (this->isNull()) { return true; }
814 
815  // those we can exclude, we are ON GROUND not guessed
816  if (this->isOnGround() && this->hasInboundGroundDetails()) { return false; }
817 
818  // cases where we can skip
819  // Concorde had a take-off speed of 220 knots (250 mph) and
820  // landing speed was 187 mph
821  if (this->getGroundSpeed().value(CSpeedUnit::kts()) > 225.0) { return true; }
822 
823  if (this->hasGroundElevation())
824  {
825  static const CLength threshold(400, CLengthUnit::m());
826  const CLength aboveGround = this->getHeightAboveGround();
827  if (!aboveGround.isNull() && aboveGround >= threshold) { return true; } // too high for ground
828  }
829  return false;
830  }
831 
832  CLength CAircraftSituation::getDistancePerTime(std::chrono::milliseconds ms, const CLength &min) const
833  {
834  if (this->getGroundSpeed().isNull())
835  {
836  if (!min.isNull()) { return min; }
837  return { 0, CLengthUnit::nullUnit() };
838  }
839  const double seconds = ms.count() / 1000.0;
840  const double gsMeterSecond = this->getGroundSpeed().value(CSpeedUnit::m_s());
841  const CLength d(seconds * gsMeterSecond, CLengthUnit::m());
842  if (!min.isNull() && d < min) { return min; }
843  return d;
844  }
845 
847  {
848  using namespace std::chrono_literals;
849  return this->getDistancePerTime(250ms, min);
850  }
851 
853  {
854  m_correspondingCallsign = callsign;
855  m_correspondingCallsign.setTypeHint(CCallsign::Aircraft);
856  }
857 
859 
860  bool CAircraftSituation::adjustGroundFlag(const CAircraftParts &parts, bool alwaysSetDetails,
861  double timeDeviationFactor, qint64 *differenceMs)
862  {
863  Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1");
864  static const qint64 Max = std::numeric_limits<qint64>::max();
865  if (differenceMs) { *differenceMs = Max; }
866 
867  if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
868  if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
869  const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch());
870  const bool adjust = (d >= 0) || qAbs(d) < (timeDeviationFactor *
871  parts.getTimeOffsetMs()); // future or past within deviation range
872  if (!adjust) { return false; }
873 
874  if (differenceMs) { *differenceMs = d; }
875  m_onGroundInfo = COnGroundInfo(parts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround,
877  return true;
878  }
879 
880  bool CAircraftSituation::adjustGroundFlag(const CAircraftPartsList &partsList, bool alwaysSetDetails,
881  double timeDeviationFactor, qint64 *differenceMs)
882  {
883  Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1");
884  static const qint64 Max = std::numeric_limits<qint64>::max();
885  if (differenceMs) { *differenceMs = Max; }
886 
887  if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
888  if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
889  if (partsList.isEmpty()) { return false; }
890 
891  CAircraftParts bestParts;
892  bool adjust = false;
893  qint64 bestDistance = Max;
894  for (const CAircraftParts &parts : partsList)
895  {
896  const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch());
897  const qint64 posD = qAbs(d);
898  const bool candidate =
899  (d >= 0) ||
900  posD < (timeDeviationFactor * parts.getTimeOffsetMs()); // future or past within deviation range
901  if (!candidate || bestDistance <= posD) { continue; }
902  bestDistance = posD;
903  if (differenceMs) { *differenceMs = d; }
904  adjust = true;
905  bestParts = parts;
906  if (bestDistance == 0) { break; }
907  }
908  if (!adjust) { return false; }
909 
910  const COnGroundInfo::IsOnGround og =
911  bestParts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround;
912  m_onGroundInfo = COnGroundInfo(og, COnGroundInfo::InFromParts);
913  return true;
914  }
915 } // 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.
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.
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
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.
qint64 getAdjustedTimeDifferenceMs(qint64 compareTime) const
Time difference in ms (this -> compare)
QString getFormattedTimestampAndOffset(bool includeRawTimestamp) const
Timestamp and offset.
Value object encapsulating information about aircraft's lights.
void setBeaconOn(bool on)
Set beacon lights.
void setTaxiOn(bool on)
Set taxi lights.
void setCabinOn(bool on)
Set cabin lights.
void setNavOn(bool on)
Set nav lights.
void setRecognitionOn(bool on)
Set recognition lights.
void setLandingOn(bool on)
Set landing lights.
Value object encapsulating information of aircraft's parts.
Definition: aircraftparts.h:26
bool isOnGround() const
Is aircraft on ground?
Value object encapsulating a list of aircraft parts.
Value object encapsulating information of an aircraft's situation.
QString getGroundElevationAndInfo() const
Ground elevation plus info.
AltitudeCorrection correctAltitude(bool enableDragToGround=true)
Set the corrected altitude from CAircraftSituation::getCorrectedAltitude.
void setCallsign(const CCallsign &callsign)
Corresponding callsign.
void setPressureAltitude(const CAltitude &altitude)
Set pressure altitude.
const CAltitude & getGroundElevation() const
Elevation of the ground directly beneath.
void resetGroundElevation()
Reset ground elevation.
bool hasGroundElevation() const
Is ground elevation value available.
bool equalPbhVectorAltitudeElevation(const CAircraftSituation &other) const
Equal PBH and vecto, plus altitude/elevation.
void setCG(const physical_quantities::CLength &cg)
Set CG.
void setGroundSpeed(const physical_quantities::CSpeed &groundspeed)
Set ground speed.
physical_quantities::CLength getDistancePerTime250ms(const physical_quantities::CLength &min=physical_quantities::CLength::null()) const
Distance per milliseconds (250ms)
bool setGroundElevation(const aviation::CAltitude &altitude, GndElevationInfo info, bool transferred=false)
Elevation of the ground directly beneath at the given situation.
const CHeading & getHeading() const
Get heading.
std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
static constexpr double MaxDeltaElevationFt
Threshold until we interpolate elevations.
CAltitude addAltitudeOffset(const physical_quantities::CLength &offset)
Add offset to altitude.
bool transferGroundElevationFromMe(CAircraftSituation &transferToSituation, const physical_quantities::CLength &radius=geo::CElevationPlane::singlePointRadius()) const
Transfer from "this" situation to otherSituation.
CAircraftSituation()=default
Default constructor.
physical_quantities::CLengthUnit getAltitudeOrDefaultUnit() const
Get altitude unit.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle)
bool canTransferGroundElevation(const CAircraftSituation &transferToSituation, const physical_quantities::CLength &radius=geo::CElevationPlane::singlePointRadius()) const
Can the elevation be transferred to another situation?
QString getGroundElevationInfoAsString() const
How did we get gnd.elevation?
void setHeading(const CHeading &heading)
Set heading.
QString convertToQString(bool i18n=false) const
Cast as QString.
aviation::COnGroundInfo getOnGroundInfo() const
On ground info.
QString getPBHInfo() const
Get PBH info (all together)
geo::CLongitude longitude() const
Longitude.
static const QString & altitudeCorrectionToString(AltitudeCorrection correction)
Enum to string.
GndElevationInfo getGroundElevationInfo() const
How did we get gnd.elevation?
AltitudeCorrection
How was altitude corrected?
@ NoElevation
no correction as there is no elevation
@ DraggedToGround
other scenery too high, but on ground
bool shouldGuessOnGround() const
Should we guess on ground?
bool transferGroundElevationToMe(const CAircraftSituation &fromSituation, const physical_quantities::CLength &radius, bool transferred)
Transfer ground elevation from given situation (to me)
CAircraftSituation withAltitudeOffset(const physical_quantities::CLength &offset) const
Situation with altitude offset.
bool hasGroundDetailsForGndInterpolation() const
Do the ground details permit ground interpolation?
GndElevationInfo
Where did we get elevation from?
@ SituationChange
from swift::misc::aviation::CAircraftSituationChange
@ FromProvider
from swift::misc::simulation::ISimulationEnvironmentProvider
@ Average
average value of "nearby" situation CAircraftSituationList::averageElevationOfNonMovingAircraft
@ Interpolated
interpolated between 2 elevations
geo::CLatitude latitude() const
Latitude.
bool isOnGroundInfoAvailable() const
On ground info available?
static const physical_quantities::CLength & defaultCG()
A default CG if not other value is available.
bool setGroundElevationChecked(const geo::CElevationPlane &elevationPlane, GndElevationInfo info, bool transferred=false)
Set elevation of the ground directly beneath, but checked.
void setAltitude(const CAltitude &altitude)
Set altitude.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
static const CAircraftSituation & null()
Null situation.
bool isOtherElevationInfoBetter(GndElevationInfo otherInfo, bool transferred) const
Is given info better (more accurate)?
physical_quantities::CLength getGroundDistance(const physical_quantities::CLength &centerOfGravity) const
Distance to ground, null if impossible to calculate.
void setGroundElevationInfo(GndElevationInfo details)
How we did get gnd.elevation.
static bool isCorrectedAltitude(AltitudeCorrection correction)
Means corrected altitude?
CAltitude getCorrectedAltitude(bool enableDragToGround=true, AltitudeCorrection *correction=nullptr) const
Get altitude under consideration of ground elevation and ground flag.
bool canLikelySkipNearGroundInterpolation() const
Situation looks like an aircraft not near ground.
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 CAltitude & getAltitude() const
Get altitude.
const CAircraftVelocity & getVelocity() const
Get 6DOF velocity.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
bool equalPbhAndVector(const CAircraftSituation &other) const
Equal PBH and vector.
physical_quantities::CLength getDistancePerTime(std::chrono::milliseconds, const physical_quantities::CLength &min=physical_quantities::CLength::null()) const
Distance per milliseconds.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
bool equalPbh(const CAircraftSituation &other) const
Equal pitch, bank heading.
int comparePropertyByIndex(CPropertyIndexRef index, const CAircraftSituation &compareValue) const
Compare for index.
bool isGroundElevationInfoTransferred() const
Is the elv.info transferred?
void setZeroPBHandGs()
Set PBH and GS values to 0 (zero)
static const QString & gndElevationInfoToString(GndElevationInfo details)
Enum to string.
const physical_quantities::CAngle & getPitch() const
Get pitch.
static const physical_quantities::CLength & deltaNearGround()
Delta distance, near to ground.
bool interpolateElevation(const aviation::CAircraftSituation &oldSituation, const aviation::CAircraftSituation &newSituation)
Interpolate "this" elevation from the two adjacent positions.
bool isMoving() const
Is moving? Means ground speed > epsilon.
const physical_quantities::CLength & getCG() const
Get CG if any.
const geo::CCoordinateGeodetic & getPosition() const
Get position.
bool isOnGroundFromNetwork() const
On ground by network flag?
const geo::CElevationPlane & getGroundElevationPlane() const
Elevation of the ground directly beneath.
static geo::CElevationPlane interpolatedElevation(const CAircraftSituation &situation, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const physical_quantities::CLength &distance=physical_quantities::CLength::null())
Interpolate between the 2 situations for situation.
void setOnGroundDetails(COnGroundInfo::OnGroundDetails details)
On ground details.
bool equalPbhVectorAltitude(const CAircraftSituation &other) const
Equal PBH and vecto, plus altitude.
bool isOnGroundFromParts() const
On ground by parts?
bool hasInboundGroundDetails() const
Has inbound ground details.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
physical_quantities::CLength getHeightAboveGround() const
Height above ground.
void setZeroPBH()
Set PBH values to 0 (zero)
bool adjustGroundFlag(const CAircraftParts &parts, bool alwaysSetDetails, double timeDeviationFactor=0.1, qint64 *differenceMs=nullptr)
Transfer ground flag from parts.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const CAircraftVelocity &compareValue) const
Compare for index.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
CAltitude switchedUnit(const physical_quantities::CLengthUnit &newUnit) const
Value in switched unit.
Definition: altitude.cpp:78
static physical_quantities::CLengthUnit defaultUnit()
Default unit for calculations.
Definition: altitude.cpp:445
int comparePropertyByIndex(CPropertyIndexRef index, const CAltitude &compareValue) const
Set property by index.
Definition: altitude.cpp:99
CAltitude withOffset(const CLength &offset) const
Altitude with offset.
Definition: altitude.cpp:61
int compare(const CAltitude &otherAltitude) const
Return negative, zero, or positive if a is less than, equal to, or greater than b.
Definition: altitude.cpp:399
@ PressureAltitude
Altitude above the standard datum plane.
Definition: altitude.h:82
AltitudeType getAltitudeType() const
Current altitude type.
Definition: altitude.h:157
CAltitude toPressureAltitude(const physical_quantities::CPressure &seaLevelPressure) const
Returns the altitude converted to pressure altitude. Requires the current barometric pressure at MSL.
Definition: altitude.cpp:131
Value object encapsulating information of a callsign.
Definition: callsign.h:30
int comparePropertyByIndex(CPropertyIndexRef index, const CCallsign &compareValue) const
Compare for index.
Definition: callsign.cpp:341
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: callsign.cpp:310
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: callsign.cpp:324
void setTypeHint(TypeHint hint)
Type hint.
Definition: callsign.h:114
Heading as used in aviation, can be true or magnetic heading.
Definition: heading.h:41
CHeading normalizedToPlusMinus180Degrees() const
As [-179.99, 180.0] normalized heading.
Definition: heading.cpp:39
Information about the ground status.
Definition: ongroundinfo.h:19
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
OnGroundDetails
Reliability of on ground information.
Definition: ongroundinfo.h:31
@ InFromParts
set from aircraft parts
Definition: ongroundinfo.h:39
@ InFromNetwork
received from network
Definition: ongroundinfo.h:38
@ NotSetGroundDetails
not set or unknown if correct (e.g.
Definition: ongroundinfo.h:32
void setOnGroundDetails(OnGroundDetails details)
When source of knowledge changes.
Definition: ongroundinfo.h:69
IsOnGround getOnGround() const
Is on ground?
OnGroundDetails getGroundDetails() const
Get ground details.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const CCoordinateGeodetic &compareValue) const
Set property by index.
const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
CCoordinateGeodetic & switchUnit(const physical_quantities::CLengthUnit &unit)
Switch unit of height.
void setGeodeticHeight(const aviation::CAltitude &height)
Set height (ellipsoidal or geodetic height)
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Plane of same elevation, can be a single point or larger area (e.g. airport)
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
const aviation::CAltitude & getAltitude() const
Altitude (synonym for geodetic height)
bool isNull() const
Existing value?
const physical_quantities::CLength & getRadius() const
Radius.
void setRadiusOrMinimumRadius(const physical_quantities::CLength &radius)
Radius or minimum CElevationPlane::singlePointRadius.
void fixRadius()
Set minimum radius if not having radius.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
const physical_quantities::CLength & getRadiusOrMinimumRadius() const
Radius or minimum radius.
int comparePropertyByIndex(CPropertyIndexRef index, const CElevationPlane &elevationPlane) const
Compare for index.
void setSinglePointRadius()
Treat as single point as obtained from simulator.
physical_quantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
Great circle distance.
bool isValidVectorRange() const
Check values.
bool equalNormalVectorDouble(const std::array< double, 3 > &otherVector) const
Is equal? Epsilon considered.
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
static void registerMetadata()
Register metadata.
Definition: mixinmetatype.h:54
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:74
Physical unit angle (radians, degrees)
Definition: angle.h:23
CAngle normalizedToPlusMinus180Degrees() const
As [-179.99, 180.0] normalized angle.
Definition: angle.cpp:95
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.
PQ switchedUnit(const MU &newUnit) const
Return copy with switched unit.
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".
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
QString arg(Args &&... args) const const
QVariant fromValue(T &&value)
bool toBool() const const
int toInt(bool *ok) const const
T value() 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