9 #include "QStringBuilder"
24 using namespace swift::misc::physical_quantities;
25 using namespace swift::misc::math;
26 using namespace swift::config;
30 namespace swift::misc::aviation
32 void CAircraftSituationChange::registerMetadata()
35 qRegisterMetaType<CAircraftSituationChange::GuessedSceneryDeviation>();
40 bool alreadySortedLatestFirst,
bool calcStdDeviations)
42 if (situations.
size() < 2) {
return; }
46 if (CBuildConfig::isLocalDeveloperDebugBuild())
49 "Wrong sort order or NULL position");
56 m_situationsCount = situations.
size();
57 m_correspondingCallsign = cs;
73 if (sorted.
size() >= 3)
80 if (calcStdDeviations)
82 this->calculateStdDeviations(situations, cg);
83 m_rotateUp = sorted.
front().
getPitch() > (m_pitchMean + m_pitchStdDev);
94 QString *details =
nullptr;
97 const bool vtol = model.
isVtol();
102 situation.
setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
103 if (details) { *details = QStringLiteral(
"No VTOL, push back"); }
109 situation.
setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
110 if (details) { *details = QStringLiteral(
"No VTOL, not moving => on ground"); }
116 situation.
setOnGroundInfo({ COnGroundInfo::NotOnGround, COnGroundInfo::OnGroundByGuessing });
122 if (!guessedRotateSpeed.
isNull())
126 SWIFT_VERIFY_X(validGuessedSpeed, Q_FUNC_INFO,
"Wrong guessed value for lift off");
128 sureRotateSpeed = guessedRotateSpeed * 1.25;
134 if (details) { *details = QStringLiteral(
"max.pitch"); }
139 if (details) { *details = QStringLiteral(
"max.bank"); }
157 if (details) { *details = QStringLiteral(
"elevation on ground"); }
165 if (!vtol && wasConstOnGround())
170 if (details) { *details = QStringLiteral(
"rotating up detected"); }
175 situation.
setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
176 if (details) { *details = QStringLiteral(
"waiting for rotating up"); }
180 if (isConstAscending())
183 if (details) { *details = QStringLiteral(
"const ascending"); }
192 situation.
setOnGroundInfo({ COnGroundInfo::OnGroundSituationUnknown, COnGroundInfo::NotSetGroundDetails });
197 if (!guessedRotateSpeed.
isNull())
202 situation.
setOnGroundInfo({ COnGroundInfo::OnGround, COnGroundInfo::OnGroundByGuessing });
205 *details = QStringLiteral(
"Guessing, max.guessed gs.") +
213 if (details) { *details = QStringLiteral(
"Fall through"); }
217 bool CAircraftSituationChange::hasSceneryDeviation()
const {
return !m_guessedSceneryDeviation.isNull(); }
219 bool CAircraftSituationChange::hasElevationDevWithinAllowedRange()
const
221 if (m_elvStdDev.isNull()) {
return false; }
222 return m_elvStdDev < CAircraftSituation::allowedAltitudeDeviation();
225 bool CAircraftSituationChange::hasAltitudeDevWithinAllowedRange()
const
227 if (m_altStdDev.isNull()) {
return false; }
228 return m_altStdDev < CAircraftSituation::allowedAltitudeDeviation();
231 QString CAircraftSituationChange::convertToQString(
bool i18n)
const
234 static const QString
null(
"null");
235 if (this->isNull()) {
return null; }
236 return u
"CS: '" % this->getCallsign().asString() % u
" ' ts: " % this->getTimestampAndOffset(
true) %
237 u
" | situations:" % QString::number(m_situationsCount) % u
" | ts adj.: " %
238 QString::number(m_oldestAdjustedTimestampMSecsSinceEpoch) % u
'-' %
239 QString::number(m_latestAdjustedTimestampMSecsSinceEpoch) % u
" | just takeoff: " %
242 u
" | all not gnd: " %
boolToYesNo(this->isConstNotOnGround()) % u
'/' %
244 u
" descending: " %
boolToYesNo(this->isConstDescending()) % u
" | accelerating.: " %
245 boolToYesNo(this->isConstAccelerating()) % u
" decelarating: " %
247 u
" | push back: " %
boolToYesNo(this->containsPushBack()) % u
" | scenery delta: " %
248 m_guessedSceneryDeviation.valueRoundedWithUnit(1) % u
" [" % this->getSceneryDeviationHintAsString() %
249 u
"] | AGL delta: " % m_gndDistMean.valueRoundedWithUnit(1) % u
'/' %
250 m_gndDistStdDev.valueRoundedWithUnit(1) % u
" | std.dev/mean: pitch " %
251 m_pitchMean.valueRoundedWithUnit(1) % u
'/' % m_pitchStdDev.valueRoundedWithUnit(1) % u
" gs " %
252 m_gsMean.valueRoundedWithUnit(1) % u
'/' % m_gsStdDev.valueRoundedWithUnit(1) % u
" alt. " %
253 m_altMean.valueRoundedWithUnit(1) % u
'/' % m_altStdDev.valueRoundedWithUnit(1) % u
" elv. " %
254 m_elvMean.valueRoundedWithUnit(1) % u
'/' % m_elvStdDev.valueRoundedWithUnit(1);
259 if (index.
isMyself()) {
return QVariant::fromValue(*
this); }
268 case IndexCallsign:
return m_correspondingCallsign.propertyByIndex(index.
copyFrontRemoved());
269 case IndexSituationsCount:
return QVariant::fromValue(m_situationsCount);
270 case IndexConstAscending:
return QVariant::fromValue(m_constAscending);
271 case IndexConstDescending:
return QVariant::fromValue(m_constDescending);
272 case IndexConstNotOnGround:
return QVariant::fromValue(m_constNotOnGround);
273 case IndexConstOnGround:
return QVariant::fromValue(m_constOnGround);
274 case IndexIsNull:
return QVariant::fromValue(this->isNull());
275 case IndexJustTakingOff:
return QVariant::fromValue(m_justTakeoff);
276 case IndexJustTouchingDown:
return QVariant::fromValue(m_justTouchdown);
277 case IndexRotatingUp:
return QVariant::fromValue(m_rotateUp);
278 case IndexContainsPushBack:
return QVariant::fromValue(m_containsPushBack);
279 case IndexAltitudeMean:
return QVariant::fromValue(m_altMean);
280 case IndexAltitudeStdDev:
return QVariant::fromValue(m_altStdDev);
281 case IndexElevationMean:
return QVariant::fromValue(m_elvMean);
282 case IndexElevationStdDev:
return QVariant::fromValue(m_elvStdDev);
287 void CAircraftSituationChange::setPropertyByIndex(
CPropertyIndexRef index,
const QVariant &variant)
303 case IndexCallsign: m_correspondingCallsign.setPropertyByIndex(index.
copyFrontRemoved(), variant);
break;
304 case IndexSituationsCount: m_situationsCount = variant.toInt();
break;
305 case IndexConstAscending: m_constAscending = variant.toBool();
break;
306 case IndexConstDescending: m_constDescending = variant.toBool();
break;
307 case IndexConstNotOnGround: m_constNotOnGround = variant.toBool();
break;
308 case IndexConstOnGround: m_constOnGround = variant.toBool();
break;
309 case IndexJustTakingOff: m_justTakeoff = variant.toBool();
break;
310 case IndexJustTouchingDown: m_justTouchdown = variant.toBool();
break;
311 case IndexRotatingUp: m_rotateUp = variant.toBool();
break;
312 case IndexContainsPushBack: m_containsPushBack = variant.toBool();
break;
314 case IndexAltitudeMean:
315 case IndexAltitudeStdDev:
316 case IndexElevationMean:
317 case IndexElevationStdDev:
break;
339 case IndexSituationsCount:
340 return Compare::compare(this->getSituationsCount(), compareValue.
getSituationsCount());
341 case IndexConstAscending:
return Compare::compare(this->isConstAscending(), compareValue.
isConstAscending());
342 case IndexConstDescending:
return Compare::compare(this->isConstDescending(), compareValue.
isConstDescending());
343 case IndexConstNotOnGround:
344 return Compare::compare(this->isConstNotOnGround(), compareValue.
isConstNotOnGround());
345 case IndexConstOnGround:
return Compare::compare(this->isConstOnGround(), compareValue.
isConstOnGround());
346 case IndexJustTakingOff:
return Compare::compare(this->isJustTakingOff(), compareValue.
isJustTakingOff());
347 case IndexJustTouchingDown:
348 return Compare::compare(this->isJustTouchingDown(), compareValue.
isJustTouchingDown());
349 case IndexRotatingUp:
return Compare::compare(this->isRotatingUp(), compareValue.
isRotatingUp());
350 case IndexContainsPushBack:
return Compare::compare(this->containsPushBack(), compareValue.
containsPushBack());
351 case IndexIsNull:
return Compare::compare(this->isNull(), compareValue.
isNull());
352 case IndexAltitudeMean:
353 return m_altMean.comparePropertyByIndex(index.
copyFrontRemoved(), compareValue.m_altMean);
354 case IndexAltitudeStdDev:
355 return m_altStdDev.comparePropertyByIndex(index.
copyFrontRemoved(), compareValue.m_altStdDev);
356 case IndexElevationMean:
357 return m_elvMean.comparePropertyByIndex(index.
copyFrontRemoved(), compareValue.m_elvMean);
358 case IndexElevationStdDev:
359 return m_elvStdDev.comparePropertyByIndex(index.
copyFrontRemoved(), compareValue.m_elvStdDev);
362 Q_ASSERT_X(
false, Q_FUNC_INFO,
"No comparison");
368 if (situations.
isEmpty()) {
return false; }
371 m_gsStdDev = gsStdDevMean.first;
372 m_gsMean = gsStdDevMean.second;
375 m_pitchStdDev = pitchStdDevMean.first;
376 m_pitchMean = pitchStdDevMean.second;
378 const QList<double> altValues = situations.
altitudeValues(CAltitude::defaultUnit());
379 if (altValues.size() == situations.
size())
382 m_altStdDev =
CAltitude(altDevMean.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
383 m_altMean =
CAltitude(altDevMean.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
386 const QList<double> elvValues = situations.
elevationValues(CAltitude::defaultUnit());
387 if (elvValues.size() == situations.
size())
390 m_elvStdDev =
CAltitude(elvDevMean.first, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
391 m_elvMean =
CAltitude(elvDevMean.second, CAltitude::MeanSeaLevel, CAltitude::defaultUnit());
393 if (altValues.size() == situations.
size())
395 QList<double> gndDistance;
396 for (
int i = 0; i < altValues.size(); i++)
398 const double delta = altValues[i] - elvValues[i];
399 gndDistance.push_back(delta);
402 m_gndDistStdDev =
CLength(gndDistanceDevMean.first, CAltitude::defaultUnit());
403 m_gndDistMean =
CLength(gndDistanceDevMean.second, CAltitude::defaultUnit());
405 const auto gndDistMinMax = std::minmax_element(gndDistance.constBegin(), gndDistance.constEnd());
406 const double gndDistMin = *gndDistMinMax.first;
407 const double gndDistMax = *gndDistMinMax.second;
408 m_minGroundDistance =
CLength(gndDistMin, CAltitude::defaultUnit());
409 m_maxGroundDistance =
CLength(gndDistMax, CAltitude::defaultUnit());
410 this->guessSceneryDeviation(cg);
424 static const QString noInfo(
"no info");
425 static const QString completeOg(
"complete og");
426 static const QString wasOg(
"was og");
427 static const QString smallAGLDev(
"small AGL dev. near gnd.");
431 case AllOnGround:
return completeOg;
432 case WasOnGround:
return wasOg;
433 case SmallAGLDeviationNearGround:
return smallAGLDev;
434 case NoDeviationInfo:
440 void CAircraftSituationChange::setSceneryDeviation(
const CLength &deviation,
const CLength &cg,
443 m_guessedSceneryDeviation = deviation;
445 this->setSceneryDeviationHint(hint);
448 void CAircraftSituationChange::guessSceneryDeviation(
const CLength &cg)
451 this->setSceneryDeviationHint(NoDeviationInfo);
452 if (m_gndDistStdDev.isNull()) {
return; }
453 if (m_gndDistMean.isNull()) {
return; }
459 if (m_gndDistStdDev <= maxDeviation)
462 if (this->isConstOnGround())
464 this->setSceneryDeviation(m_gndDistMean, cg, AllOnGround);
467 if (this->wasConstNotOnGround())
469 this->setSceneryDeviation(m_gndDistMean, cg, WasOnGround);
472 if (!m_altStdDev.isNull() && m_altStdDev <= maxDeviation)
475 if (!m_maxGroundDistance.isNull() && m_maxGroundDistance < cg)
477 if (this->isConstOnGround())
479 this->setSceneryDeviation(m_gndDistMean, cg, SmallAGLDeviationNearGround);
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
size_type size() const
Returns number of elements in the sequence.
reference front()
Access the first element.
reference back()
Access the last element.
bool isEmpty() const
Synonym for empty.
qint64 getMSecsSinceEpoch() const
Timestamp as ms value.
qint64 getAdjustedMSecsSinceEpoch() const
Timestamp with offset added for interpolation.
static bool canHandleIndex(CPropertyIndexRef index)
Can given index be handled.
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
qint64 getTimeOffsetMs() const
Milliseconds to add to timestamp for interpolation.
int comparePropertyByIndex(CPropertyIndexRef index, const ITimestampWithOffsetBased &compareValue) const
Compare for index.
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
CONTAINER getSortedAdjustedLatestFirst() const
As sorted copy.
void guessModelParameters(physical_quantities::CLength &guessedCGOut, physical_quantities::CSpeed &guessedVRotateOut) const
Guess aircraft model parameters.
Value object about changes in situations.
ColumnIndex
Properties by index.
int getSituationsCount() const
Basend on n situations.
bool containsPushBack() const
Contains any push back?
bool isConstDescending() const
Constantly descending?
bool isConstAscending() const
Constantly ascending?
bool isJustTakingOff() const
Is just taking off?
const CCallsign & getCallsign() const
Get callsign.
GuessedSceneryDeviation
Hint about the guessed scenery deviation.
bool isRotatingUp() const
Is rotating up?
bool isJustTouchingDown() const
Is just touching down?
bool isConstOnGround() const
Are all situations on ground?
bool isConstNotOnGround() const
Are all situations not on ground?
Value object encapsulating information of an aircraft's situation.
bool shouldGuessOnGround() const
Should we guess on ground?
bool hasCG() const
Has CG set?
physical_quantities::CLength getGroundDistance(const physical_quantities::CLength ¢erOfGravity) const
Distance to ground, null if impossible to calculate.
const CCallsign & getCallsign() const
Corresponding callsign.
const physical_quantities::CSpeed & getGroundSpeed() const
Get ground speed.
void setOnGroundInfo(const aviation::COnGroundInfo &info)
Set the on ground info.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
const physical_quantities::CAngle & getPitch() const
Get pitch.
bool isMoving() const
Is moving? Means ground speed > epsilon.
const physical_quantities::CLength & getCG() const
Get CG if any.
List of aircraft situations.
bool isJustTouchingDown(bool alreadySortedLatestFirst=false) const
Is just touching down?
CAircraftSituationList withoutFrontSituation() const
Remove the first situation.
bool isConstAccelerating(bool alreadySortedLatestFirst=false) const
Constantly accelerating?
bool isConstNotOnGround() const
Are all situations not on ground?
physical_quantities::CAnglePair pitchStandardDeviationAndMean() const
Pitch angles standard deviation and mean.
QList< double > elevationValues(const physical_quantities::CLengthUnit &unit) const
All elevation values.
bool isConstDecelarating(bool alreadySortedLatestFirst=false) const
Constantly decelarating?
bool isConstDescending(bool alreadySortedLatestFirst=false) const
Constantly descending?
bool isConstOnGround() const
Are all situations on ground?
bool isRotatingUp(bool alreadySortedLatestFirst=false) const
Is rotating up?
bool isJustTakingOff(bool alreadySortedLatestFirst=false) const
Is just taking off?
QList< double > altitudeValues(const physical_quantities::CLengthUnit &unit) const
All altitude values.
bool isSortedAdjustedLatestFirstWithoutNullPositions() const
Latest first and no null positions?
bool isConstAscending(bool alreadySortedLatestFirst=false) const
Constantly ascending?
bool containsPushBack() const
Contains any push back?
physical_quantities::CSpeedPair groundSpeedStandardDeviationAndMean() const
Ground speed standard deviation and mean.
Altitude as used in aviation, can be AGL or MSL altitude.
Value object encapsulating information of a callsign.
Information about the ground status.
void setOnGroundDetails(OnGroundDetails details)
When source of knowledge changes.
IsOnGround getOnGround() const
Is on ground?
static QPair< double, double > standardDeviationAndMean(const QList< double > &values)
Standard deviation (first) and mean (second)
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
static CAngleUnit deg()
Degrees.
Physical unit length (length)
static CLengthUnit ft()
Foot ft.
bool isNegativeWithEpsilonConsidered() const
Value <= 0 epsilon considered.
bool isNull() const
Is quantity null?
double value(MU unit) const
Value in given unit.
static const CSpeed & null()
NULL PQ.
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
static CSpeedUnit km_h()
Kilometer/hour km/h.
static CSpeedUnit kts()
Knots.
Aircraft model (used by another pilot, my models on disk)
bool isVtol() const
VTOL aircraft?
const physical_quantities::CLength & getCG() const
Get center of gravity.
const aviation::CAircraftIcaoCode & getAircraftIcaoCode() const
Aircraft ICAO code.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.