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() {}
91 
92  CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign)
93  : m_correspondingCallsign(correspondingCallsign)
94  {}
95 
97  const CAngle &pitch, const CAngle &bank, const CSpeed &gs,
98  const CElevationPlane &groundElevation)
99  : m_position(position), m_groundElevationPlane(groundElevation),
100  m_heading(heading.normalizedToPlusMinus180Degrees()), m_pitch(pitch.normalizedToPlusMinus180Degrees()),
101  m_bank(bank.normalizedToPlusMinus180Degrees()), m_groundSpeed(gs)
102  {
103  m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar()));
104  }
105 
106  CAircraftSituation::CAircraftSituation(const CCallsign &correspondingCallsign, const CCoordinateGeodetic &position,
107  const CHeading &heading, const CAngle &pitch, const CAngle &bank,
108  const CSpeed &gs, const CElevationPlane &groundElevation)
109  : m_correspondingCallsign(correspondingCallsign), m_position(position), m_groundElevationPlane(groundElevation),
110  m_heading(heading.normalizedToPlusMinus180Degrees()), m_pitch(pitch.normalizedToPlusMinus180Degrees()),
111  m_bank(bank.normalizedToPlusMinus180Degrees()), m_groundSpeed(gs)
112  {
113  m_correspondingCallsign.setTypeHint(CCallsign::Aircraft);
114  m_pressureAltitude = position.geodeticHeight().toPressureAltitude(CPressure(1013.25, CPressureUnit::mbar()));
115  }
116 
117  QString CAircraftSituation::convertToQString(bool i18n) const
118  {
119  return u"ts: " % this->getFormattedTimestampAndOffset(true) % u" | " % m_position.toQString(i18n) %
120  u" | alt: " % this->getAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) % u' ' %
121  this->getCorrectedAltitude().valueRoundedWithUnit(CLengthUnit::ft(), 1) % u"[cor] | og: " %
122  this->getOnGroundInfo().toQString(i18n) % u" | CG: " %
123  (m_cg.isNull() ? QStringLiteral("null") :
124  m_cg.valueRoundedWithUnit(CLengthUnit::m(), 1) % u' ' %
125  m_cg.valueRoundedWithUnit(CLengthUnit::ft(), 1)) %
126  u" | skip ng: " % boolToYesNo(this->canLikelySkipNearGroundInterpolation()) % u" | bank: " %
127  m_bank.toQString(i18n) % u" | pitch: " % m_pitch.toQString(i18n) % u" | heading: " %
128  m_heading.toQString(i18n) % u" | GS: " % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::kts(), 1, true) %
129  u' ' % m_groundSpeed.valueRoundedWithUnit(CSpeedUnit::m_s(), 1, true) % u" | elevation [" %
130  this->getGroundElevationInfoAsString() % u"]: " % (m_groundElevationPlane.toQString(i18n));
131  }
132 
134  {
135  static const QString under("underflow");
136  static const QString dragged("dragged to gnd");
137  static const QString no("no correction");
138  static const QString noElv("no elv.");
139  static const QString unknown("unknown");
140  static const QString agl("AGL");
141  switch (correction)
142  {
143  case Underflow: return under;
144  case DraggedToGround: return dragged;
145  case NoElevation: return noElv;
146  case NoCorrection: return no;
147  case AGL: return agl;
148  default: break;
149  }
150  return unknown;
151  }
152 
154  {
155  switch (correction)
156  {
157  case Underflow:
158  case DraggedToGround: return true;
159  case NoElevation:
160  case NoCorrection:
161  case AGL:
162  default: break;
163  }
164  return false;
165  }
166 
168  {
169  static const QString noDetails("no details");
170  static const QString unknown("unknown");
171  static const QString provider("provider");
172  static const QString change("situation change");
173  static const QString cache("cached");
174  static const QString test("test");
175  static const QString interpolated("interpolated");
176  static const QString extrapolated("extrapolated");
177  static const QString avg("average");
178 
179  switch (details)
180  {
181  case NoElevationInfo: return noDetails;
182  case FromProvider: return provider;
183  case SituationChange: return change;
184  case FromCache: return cache;
185  case Test: return test;
186  case Interpolated: return interpolated;
187  case Extrapolated: return extrapolated;
188  case Average: return avg;
189  default: break;
190  }
191  return unknown;
192  }
193 
195  {
196  static const CLength small(0.5, CLengthUnit::m());
197  return small;
198  }
199 
201  {
202  static const CAircraftSituation n;
203  return n;
204  }
205 
207  {
208  static const CLength cg(2.5, CLengthUnit::m());
209  return cg;
210  }
211 
213  const CAircraftSituation &oldSituation,
214  const CAircraftSituation &newSituation,
215  const CLength &distance)
216  {
217  if (oldSituation.isNull() || newSituation.isNull()) { return CElevationPlane::null(); }
218  if (!oldSituation.hasGroundElevation() || !newSituation.hasGroundElevation())
219  {
220  return CElevationPlane::null();
221  }
222  if (oldSituation.equalNormalVectorDouble(newSituation)) { return newSituation.getGroundElevationPlane(); }
223 
224  const double newElvFt = newSituation.getGroundElevation().value(CLengthUnit::ft());
225  const double oldElvFt = oldSituation.getGroundElevation().value(CLengthUnit::ft());
226  const double deltaElvFt = newElvFt - oldElvFt;
227  if (deltaElvFt > MaxDeltaElevationFt)
228  {
229  return CElevationPlane::null();
230  } // threshold, interpolation not possible
231 
232  if (!situation.isNull())
233  {
234  if (CBuildConfig::isLocalDeveloperDebugBuild())
235  {
236  Q_ASSERT_X(situation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
237  Q_ASSERT_X(oldSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
238  Q_ASSERT_X(newSituation.isValidVectorRange(), Q_FUNC_INFO, "Invalid range");
239  }
240 
241  const double distanceSituationNewM =
242  situation.calculateGreatCircleDistance(newSituation).value(CLengthUnit::m());
243  if (distanceSituationNewM < 5.0) { return newSituation.getGroundElevationPlane(); }
244 
245  const double distanceOldNewM =
246  (distance.isNull() ? oldSituation.calculateGreatCircleDistance(newSituation) : distance)
247  .value(CLengthUnit::m());
248  if (distanceOldNewM < 5.0) { return oldSituation.getGroundElevationPlane(); }
249 
250  const double distRatio = distanceSituationNewM / distanceOldNewM;
251 
252  // very close to the situations we return their elevation
253  if (distRatio < 0.05) { return newSituation.getGroundElevationPlane(); }
254  if (distRatio > 0.95) { return oldSituation.getGroundElevationPlane(); }
255 
256  const double situationElvFt = newElvFt - distRatio * deltaElvFt;
257  return CElevationPlane(situation, situationElvFt, CElevationPlane::singlePointRadius());
258  }
259  else
260  {
261  const double elvSumFt = oldElvFt + newElvFt;
262  const double elvFt = 0.5 * elvSumFt;
263  return CElevationPlane(newSituation, elvFt, CElevationPlane::singlePointRadius());
264  }
265  }
266 
268  {
269  if (index.isMyself()) { return QVariant::fromValue(*this); }
271  {
273  }
274  if (ICoordinateGeodetic::canHandleIndex(index)) { return ICoordinateGeodetic::propertyByIndex(index); }
275 
276  const ColumnIndex i = index.frontCasted<ColumnIndex>();
277  switch (i)
278  {
279  case IndexPosition: return m_position.propertyByIndex(index.copyFrontRemoved());
280  case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
281  case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
282  case IndexAltitude: return this->getAltitude().propertyByIndex(index.copyFrontRemoved());
283  case IndexHeading: return m_heading.propertyByIndex(index.copyFrontRemoved());
284  case IndexPitch: return m_pitch.propertyByIndex(index.copyFrontRemoved());
285  case IndexPBHInfo: return QVariant::fromValue(this->getPBHInfo());
286  case IndexVelocity: return QVariant::fromValue(this->getVelocity());
287  case IndexBank: return m_bank.propertyByIndex(index.copyFrontRemoved());
288  case IndexCG: return m_cg.propertyByIndex(index.copyFrontRemoved());
289  case IndexGroundSpeed: return m_groundSpeed.propertyByIndex(index.copyFrontRemoved());
290  case IndexGroundElevationPlane: return m_groundElevationPlane.propertyByIndex(index.copyFrontRemoved());
291  case IndexCallsign: return m_correspondingCallsign.propertyByIndex(index.copyFrontRemoved());
292  case IndexIsOnGroundInfo: return m_onGroundInfo.propertyByIndex(index.copyFrontRemoved());
293  case IndexGroundElevationInfo: return QVariant::fromValue(this->getGroundElevationInfo());
294  case IndexGroundElevationInfoTransferred: return QVariant::fromValue(this->isGroundElevationInfoTransferred());
295  case IndexGroundElevationInfoString: return QVariant::fromValue(this->getGroundElevationInfoAsString());
296  case IndexGroundElevationPlusInfo: return QVariant::fromValue(this->getGroundElevationAndInfo());
297  case IndexCanLikelySkipNearGroundInterpolation:
298  return QVariant::fromValue(this->canLikelySkipNearGroundInterpolation());
299  default: return CValueObject::propertyByIndex(index);
300  }
301  }
302 
303  void CAircraftSituation::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
304  {
305  if (index.isMyself())
306  {
307  (*this) = variant.value<CAircraftSituation>();
308  return;
309  }
311  {
313  return;
314  }
315 
316  const ColumnIndex i = index.frontCasted<ColumnIndex>();
317  switch (i)
318  {
319  case IndexPosition: m_position.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
320  case IndexPitch: m_pitch.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
321  case IndexBank: m_bank.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
322  case IndexVelocity: m_velocity.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
323  case IndexCG: m_cg.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
324  case IndexGroundSpeed: m_groundSpeed.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
325  case IndexGroundElevationPlane:
326  m_groundElevationPlane.setPropertyByIndex(index.copyFrontRemoved(), variant);
327  break;
328  case IndexCallsign: m_correspondingCallsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
329  case IndexIsOnGroundInfo: m_onGroundInfo.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
330  case IndexGroundElevationInfo: m_elvInfo = variant.toInt(); break;
331  case IndexGroundElevationInfoTransferred: m_isElvInfoTransferred = variant.toBool(); break;
332  case IndexGroundElevationPlusInfo: break;
333  case IndexCanLikelySkipNearGroundInterpolation: break;
334  default: CValueObject::setPropertyByIndex(index, variant); break;
335  }
336  }
337 
339  const CAircraftSituation &compareValue) const
340  {
342  {
343  return ITimestampWithOffsetBased::comparePropertyByIndex(index, compareValue);
344  }
345  if (ICoordinateGeodetic::canHandleIndex(index))
346  {
347  return ICoordinateGeodetic::comparePropertyByIndex(index, compareValue);
348  }
349  const ColumnIndex i = index.frontCasted<ColumnIndex>();
350  switch (i)
351  {
352  case IndexPosition:
353  return m_position.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPosition());
354  case IndexAltitude:
355  return this->getAltitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getAltitude());
356  case IndexVelocity:
357  return m_velocity.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getVelocity());
358  case IndexPBHInfo: // fall through
359  case IndexPitch: return m_pitch.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPitch());
360  case IndexBank: return m_bank.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getBank());
361  case IndexCG: return m_cg.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCG());
362  case IndexGroundSpeed:
363  return m_groundSpeed.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getGroundSpeed());
364  case IndexGroundElevationPlane:
365  case IndexGroundElevationPlusInfo:
366  {
367  const int c = m_groundElevationPlane.comparePropertyByIndex(index.copyFrontRemoved(),
368  compareValue.getGroundElevationPlane());
369  if (c != 0 || i == IndexGroundElevationPlane) { return c; }
370  return Compare::compare(this->getGroundElevationInfo(), compareValue.getGroundElevationInfo());
371  }
372  case IndexCallsign:
373  return m_correspondingCallsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
374  case IndexIsOnGroundInfo:
375  return m_onGroundInfo.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getOnGroundInfo());
376  case IndexGroundElevationInfo:
377  case IndexGroundElevationInfoString:
378  {
379  const int c = Compare::compare(this->getGroundElevationInfo(), compareValue.getGroundElevationInfo());
380  if (c != 0) { return c; }
381  }
382  [[fallthrough]];
383  case IndexGroundElevationInfoTransferred:
384  return Compare::compare(m_isElvInfoTransferred, compareValue.m_isElvInfoTransferred);
385  case IndexCanLikelySkipNearGroundInterpolation:
386  return Compare::compare(this->canLikelySkipNearGroundInterpolation(),
387  compareValue.canLikelySkipNearGroundInterpolation());
388  default: break;
389  }
390  const QString assertMsg("No comparison for index " + index.toQString());
391  SWIFT_VERIFY_X(false, Q_FUNC_INFO, qUtf8Printable(assertMsg));
392  return 0;
393  }
394 
395  bool CAircraftSituation::isNull() const { return this->isPositionNull(); }
396 
398  bool transferred) const
399  {
400  if (otherInfo == NoElevationInfo || otherInfo == Test) { return false; }
401  const int otherInfoInt = static_cast<int>(otherInfo);
402  if (otherInfoInt > m_elvInfo) { return true; }
403  if (otherInfoInt == m_elvInfo)
404  {
405  if (m_isElvInfoTransferred == transferred) { return false; } // not better (equal)
406  return !transferred; // if not transferred it is better
407  }
408  return false;
409  }
410 
412  {
413  return this->getPitch() == other.getPitch() && this->getBank() == other.getBank() &&
414  this->getHeading() == other.getHeading();
415  }
416 
418  {
419  return this->equalNormalVectorDouble(other.normalVectorDouble()) && this->equalPbh(other);
420  }
421 
423  {
424  if (!this->equalPbhAndVector(other)) { return false; }
425  const int c = this->getAltitude().compare(other.getAltitude());
426  return c == 0;
427  }
428 
430  {
431  if (!this->equalPbhVectorAltitude(other)) { return false; }
432  const int c = this->getGroundElevation().compare(other.getGroundElevation());
433  return c == 0;
434  }
435 
437  {
438  m_position.setNull();
439  m_pressureAltitude.setNull();
440  m_heading.setNull();
441  m_pitch.setNull();
442  m_bank.setNull();
443  m_velocity = {};
444  m_groundElevationPlane.setNull();
445  m_groundSpeed.setNull();
446  m_onGroundInfo = {};
447  m_elvInfo = NoElevationInfo;
448  m_isElvInfoTransferred = false;
449  m_cg.setNull();
450  }
451 
453  {
454  return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts;
455  }
456 
458  {
459  return this->isOnGround() && m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork;
460  }
461 
463  {
464  if (this->hasInboundGroundDetails()) { return true; }
465  return m_onGroundInfo.getOnGround() != COnGroundInfo::OnGroundSituationUnknown &&
467  }
468 
470 
472  {
473  if (centerOfGravity.isNull() || !this->hasGroundElevation()) { return CLength::null(); }
474  const CAltitude groundPlusCG = this->getGroundElevation().withOffset(centerOfGravity);
475  const CLength groundDistance = (this->getAltitude() - groundPlusCG);
476  return groundDistance;
477  }
478 
480  {
481  return m_onGroundInfo.getGroundDetails() != COnGroundInfo::NotSetGroundDetails;
482  }
483 
484  COnGroundInfo CAircraftSituation::getOnGroundInfo() const { return m_onGroundInfo; }
485 
487  {
488  m_onGroundInfo.setOnGroundDetails(details);
489  }
490 
491  void CAircraftSituation::setOnGroundInfo(const aviation::COnGroundInfo &info) { m_onGroundInfo = info; }
492 
494  {
495  if (!this->hasGroundElevation()) { return NoElevationInfo; }
496  return static_cast<GndElevationInfo>(m_elvInfo);
497  }
498 
500  {
501  return m_isElvInfoTransferred ? u"tx: " % gndElevationInfoToString(this->getGroundElevationInfo()) :
503  }
504 
506  {
507  static const QString n("null");
508  if (m_groundElevationPlane.isNull()) { return n; }
509 
510  return m_groundElevationPlane.getAltitude().toQString(true) % u" [" % this->getGroundElevationInfoAsString() %
511  u']';
512  }
513 
515  const CLength &radius) const
516  {
517  if (!this->hasGroundElevation()) { return false; }
518 
519  // decide if transfer makes sense
520  // always transfer from provider, but do not override provider
521  if (transferToSituation.getGroundElevationInfo() == CAircraftSituation::FromProvider) { return false; }
523  transferToSituation.getGroundElevationInfo() == CAircraftSituation::FromCache)
524  {
525  return false;
526  }
527 
528  // distance
529  const CLength distance = this->getGroundElevationPlane().calculateGreatCircleDistance(transferToSituation);
530  const bool transferable = (distance <= radius);
531  return transferable;
532  }
533 
535  const CLength &radius) const
536  {
537  return transferToSituation.transferGroundElevationToMe(*this, radius, true);
538  }
539 
541  bool transferred)
542  {
543  if (!fromSituation.canTransferGroundElevation(*this, radius)) { return false; }
544  return this->setGroundElevation(fromSituation.getGroundElevationPlane(), fromSituation.getGroundElevationInfo(),
545  transferred);
546  }
547 
548  bool CAircraftSituation::transferGroundElevationToMe(const CAircraftSituation &fromSituation, bool transferred)
549  {
550  return this->setGroundElevation(fromSituation.getGroundElevationPlane(), fromSituation.getGroundElevationInfo(),
551  transferred);
552  }
553 
555  const CAircraftSituation &newSituation)
556  {
557  const CElevationPlane ep = CAircraftSituation::interpolatedElevation(*this, oldSituation, newSituation);
558  if (ep.isNull()) { return false; }
559  this->setGroundElevation(ep, Interpolated);
560  return true;
561  }
562 
564 
566  {
567  return m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromParts ||
569  }
570 
571  bool CAircraftSituation::setGroundElevation(const CAltitude &altitude, GndElevationInfo info, bool transferred)
572  {
573  bool set = false;
574  if (altitude.isNull())
575  {
576  m_groundElevationPlane = CElevationPlane::null();
577  m_isElvInfoTransferred = false;
578  this->setGroundElevationInfo(NoElevationInfo);
579  }
580  else
581  {
582  m_groundElevationPlane = CElevationPlane(*this);
583  m_groundElevationPlane.setSinglePointRadius();
584  m_isElvInfoTransferred = transferred;
585  m_groundElevationPlane.setGeodeticHeight(altitude.switchedUnit(this->getAltitudeUnit()));
586  this->setGroundElevationInfo(info);
587  set = true;
588  }
589  return set;
590  }
591 
593  bool transferred)
594  {
595  bool set = false;
596  if (elevationPlane.isNull())
597  {
598  m_groundElevationPlane = CElevationPlane::null();
599  m_isElvInfoTransferred = false;
600  this->setGroundElevationInfo(NoElevationInfo);
601  }
602  else
603  {
604  m_groundElevationPlane = elevationPlane;
605  m_groundElevationPlane.fixRadius();
606  m_isElvInfoTransferred = transferred;
607  this->setGroundElevationInfo(info);
608  Q_ASSERT_X(!m_groundElevationPlane.getRadius().isNull(), Q_FUNC_INFO, "Null radius");
609  m_groundElevationPlane.switchUnit(
610  this->getAltitudeOrDefaultUnit()); // we use ft as internal unit, no "must" but simplification
611  set = true;
612  }
613  return set;
614  }
615 
617  bool transferred)
618  {
619  if (elevationPlane.isNull()) { return false; }
620  const CLength distance = this->calculateGreatCircleDistance(elevationPlane);
621  if (distance > elevationPlane.getRadiusOrMinimumRadius()) { return false; }
622  if (m_groundElevationPlane.isNull() || this->isOtherElevationInfoBetter(info, transferred))
623  {
624  // better values
625  this->setGroundElevation(elevationPlane, info, transferred);
626  m_groundElevationPlane.setRadiusOrMinimumRadius(distance);
627  return true;
628  }
629  return false;
630  }
631 
633  {
634  m_groundElevationPlane = CElevationPlane::null();
635  this->setGroundElevationInfo(NoElevationInfo);
636  }
637 
639  {
640  if (this->getAltitude().isNull()) { return CLength::null(); }
641  if (this->getAltitude().getReferenceDatum() == CAltitude::AboveGround)
642  {
643  // we have a sure value explicitly set
644  return this->getAltitude();
645  }
646 
647  const CLength gh(this->getGroundElevation());
648  if (gh.isNull()) { return CLength::null(); }
649 
650  // sanity checks
651  if (std::isnan(gh.value()))
652  {
653  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "nan ground");
654  return CLength::null();
655  }
656  if (std::isnan(this->getAltitude().value()))
657  {
658  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "nan altitude");
659  return CLength::null();
660  }
661 
662  const CLength ag = this->getAltitude() - gh;
663  return ag;
664  }
665 
667  {
668  m_heading = heading.normalizedToPlusMinus180Degrees();
669  }
670 
672  {
673  if (this->getAltitude().isNull()) { return CAltitude::defaultUnit(); }
674  return m_position.geodeticHeight().getUnit();
675  }
676 
678  CAircraftSituation::AltitudeCorrection *correction) const
679  {
680  return this->getCorrectedAltitude(m_cg, enableDragToGround, correction);
681  }
682 
683  CAltitude CAircraftSituation::getCorrectedAltitude(const CLength &centerOfGravity, bool enableDragToGround,
684  AltitudeCorrection *correction) const
685  {
686  if (correction) { *correction = UnknownCorrection; }
687  if (!this->hasGroundElevation())
688  {
689  if (correction) { *correction = NoElevation; }
690  return this->getAltitude();
691  }
692 
693  // above ground
694  if (this->getAltitude().getReferenceDatum() == CAltitude::AboveGround)
695  {
696  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Unsupported");
697  if (correction) { *correction = AGL; }
698  return this->getAltitude();
699  }
700  else
701  {
702  const CAltitude groundPlusCG =
703  this->getGroundElevation().withOffset(centerOfGravity).switchedUnit(this->getAltitudeOrDefaultUnit());
704  if (groundPlusCG.isNull())
705  {
706  if (correction) { *correction = NoElevation; }
707  return this->getAltitude();
708  }
709  const CLength groundDistance = this->getAltitude() - groundPlusCG;
710  const bool underflow = groundDistance.isNegativeWithEpsilonConsidered();
711  if (underflow)
712  {
713  if (correction) { *correction = Underflow; }
714  return groundPlusCG;
715  }
716  const bool nearGround = groundDistance.abs() < deltaNearGround();
717  if (nearGround)
718  {
719  if (correction) { *correction = NoCorrection; }
720  return groundPlusCG;
721  }
722  const bool forceDragToGround = (enableDragToGround && isOnGround()) &&
723  (this->hasInboundGroundDetails() ||
725  if (forceDragToGround)
726  {
727  if (correction) { *correction = DraggedToGround; }
728  return groundPlusCG;
729  }
730 
731  if (correction) { *correction = NoCorrection; }
732  return this->getAltitude();
733  }
734  }
735 
737  {
738  return this->correctAltitude(m_cg, enableDragToGround);
739  }
740 
742  bool enableDragToGround)
743  {
744  CAircraftSituation::AltitudeCorrection altitudeCorrection = CAircraftSituation::UnknownCorrection;
745  this->setAltitude(this->getCorrectedAltitude(centerOfGravity, enableDragToGround, &altitudeCorrection));
746  this->setCG(centerOfGravity);
747  return altitudeCorrection;
748  }
749 
751  {
752  m_position.setGeodeticHeight(altitude.switchedUnit(CAltitude::defaultUnit()));
753  }
754 
756  {
757  if (offset.isNull()) { return this->getAltitude(); }
758  const CAltitude alt = this->getAltitude().withOffset(offset);
759  this->setAltitude(alt);
760  return alt;
761  }
762 
764  {
765  if (offset.isNull()) { return *this; }
766  CAircraftSituation copy(*this);
767  copy.addAltitudeOffset(offset);
768  return copy;
769  }
770 
772  {
773  Q_ASSERT(altitude.getAltitudeType() == CAltitude::PressureAltitude);
774  m_pressureAltitude = altitude;
775  }
776 
777  void CAircraftSituation::setPitch(const CAngle &pitch) { m_pitch = pitch.normalizedToPlusMinus180Degrees(); }
778 
780 
782  {
783  static const CAngle za(0, CAngleUnit::deg());
784  static const CHeading zh(za, CHeading::True);
785  this->setPitch(za);
786  this->setBank(za);
787  this->setHeading(zh);
788  }
789 
791  {
792  this->setZeroPBH();
793  this->setGroundSpeed(CSpeed(0, CSpeedUnit::defaultUnit()));
794  }
795 
797  {
798  return QStringLiteral("P: %1 %2 B: %3 %4 H: %5 %6")
799  .arg(this->getPitch().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
800  this->getPitch().valueRoundedWithUnit(CAngleUnit::rad(), 5, true),
801  this->getBank().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
802  this->getBank().valueRoundedWithUnit(CAngleUnit::rad(), 5, true),
803  this->getHeading().valueRoundedWithUnit(CAngleUnit::deg(), 1, true),
804  this->getHeading().valueRoundedWithUnit(CAngleUnit::rad(), 5, true));
805  }
806 
808  {
809  const double gsKmh = this->getGroundSpeed().value(CSpeedUnit::km_h());
810  return gsKmh >= 2.5;
811  }
812 
814  {
815  if (this->isNull()) { return true; }
816 
817  // those we can exclude, we are ON GROUND not guessed
818  if (this->isOnGround() && this->hasInboundGroundDetails()) { return false; }
819 
820  // cases where we can skip
821  // Concorde had a take-off speed of 220 knots (250 mph) and
822  // landing speed was 187 mph
823  if (this->getGroundSpeed().value(CSpeedUnit::kts()) > 225.0) { return true; }
824 
825  if (this->hasGroundElevation())
826  {
827  static const CLength threshold(400, CLengthUnit::m());
828  const CLength aboveGround = this->getHeightAboveGround();
829  if (!aboveGround.isNull() && aboveGround >= threshold) { return true; } // too high for ground
830  }
831  return false;
832  }
833 
834  CLength CAircraftSituation::getDistancePerTime(std::chrono::milliseconds ms, const CLength &min) const
835  {
836  if (this->getGroundSpeed().isNull())
837  {
838  if (!min.isNull()) { return min; }
839  return CLength(0, CLengthUnit::nullUnit());
840  }
841  const double seconds = ms.count() / 1000.0;
842  const double gsMeterSecond = this->getGroundSpeed().value(CSpeedUnit::m_s());
843  const CLength d(seconds * gsMeterSecond, CLengthUnit::m());
844  if (!min.isNull() && d < min) { return min; }
845  return d;
846  }
847 
849  {
850  using namespace std::chrono_literals;
851  return this->getDistancePerTime(250ms, min);
852  }
853 
855  {
856  m_correspondingCallsign = callsign;
857  m_correspondingCallsign.setTypeHint(CCallsign::Aircraft);
858  }
859 
861 
862  bool CAircraftSituation::adjustGroundFlag(const CAircraftParts &parts, bool alwaysSetDetails,
863  double timeDeviationFactor, qint64 *differenceMs)
864  {
865  Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1");
866  static const qint64 Max = std::numeric_limits<qint64>::max();
867  if (differenceMs) { *differenceMs = Max; }
868 
869  if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
870  if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
871  const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch());
872  const bool adjust = (d >= 0) || qAbs(d) < (timeDeviationFactor *
873  parts.getTimeOffsetMs()); // future or past within deviation range
874  if (!adjust) { return false; }
875 
876  if (differenceMs) { *differenceMs = d; }
877  m_onGroundInfo = COnGroundInfo(parts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround,
879  return true;
880  }
881 
882  bool CAircraftSituation::adjustGroundFlag(const CAircraftPartsList &partsList, bool alwaysSetDetails,
883  double timeDeviationFactor, qint64 *differenceMs)
884  {
885  Q_ASSERT_X(timeDeviationFactor >= 0 && timeDeviationFactor <= 1.0, Q_FUNC_INFO, "Expect 0..1");
886  static const qint64 Max = std::numeric_limits<qint64>::max();
887  if (differenceMs) { *differenceMs = Max; }
888 
889  if (m_onGroundInfo.getGroundDetails() == COnGroundInfo::InFromNetwork) { return false; }
890  if (alwaysSetDetails) { m_onGroundInfo.setOnGroundDetails(COnGroundInfo::InFromParts); }
891  if (partsList.isEmpty()) { return false; }
892 
893  CAircraftParts bestParts;
894  bool adjust = false;
895  qint64 bestDistance = Max;
896  for (const CAircraftParts &parts : partsList)
897  {
898  const qint64 d = this->getAdjustedTimeDifferenceMs(parts.getAdjustedMSecsSinceEpoch());
899  const qint64 posD = qAbs(d);
900  const bool candidate =
901  (d >= 0) ||
902  posD < (timeDeviationFactor * parts.getTimeOffsetMs()); // future or past within deviation range
903  if (!candidate || bestDistance <= posD) { continue; }
904  bestDistance = posD;
905  if (differenceMs) { *differenceMs = d; }
906  adjust = true;
907  bestParts = parts;
908  if (bestDistance == 0) { break; }
909  }
910  if (!adjust) { return false; }
911 
912  const COnGroundInfo::IsOnGround og =
913  bestParts.isOnGround() ? COnGroundInfo::OnGround : COnGroundInfo::NotOnGround;
914  m_onGroundInfo = COnGroundInfo(og, COnGroundInfo::InFromParts);
915  return true;
916  }
917 } // 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.
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.
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)
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
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.
virtual geo::CLatitude latitude() const
Latitude.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
virtual std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
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.
virtual bool isNull() const
Null situation.
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.
virtual geo::CLongitude longitude() const
Longitude.
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.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
CCoordinateGeodetic & switchUnit(const physical_quantities::CLengthUnit &unit)
Switch unit of height.
virtual const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
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)
virtual 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: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
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
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.
#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