swift
remoteaircraftprovider.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include "config/buildconfig.h"
7 #include "misc/json.h"
8 #include "misc/logmessage.h"
10 #include "misc/stringutils.h"
11 #include "misc/verify.h"
12 
13 using namespace swift::misc::aviation;
14 using namespace swift::misc::physical_quantities;
15 using namespace swift::misc::geo;
16 using namespace swift::misc::json;
17 using namespace swift::config;
18 
19 namespace swift::misc::simulation
20 {
21  IRemoteAircraftProvider::IRemoteAircraftProvider() {}
22 
23  IRemoteAircraftProvider::~IRemoteAircraftProvider() {}
24 
25  const QStringList &CRemoteAircraftProvider::getLogCategories()
26  {
27  static const QStringList cats { CLogCategories::matching(), CLogCategories::network() };
28  return cats;
29  }
30 
31  CRemoteAircraftProvider::CRemoteAircraftProvider(QObject *parent)
32  : QObject(parent), IRemoteAircraftProvider(), CIdentifiable(this)
33  {}
34 
36  {
37  QReadLocker l(&m_lockAircraft);
38  const QList<CSimulatedAircraft> aircraftInRange = m_aircraftInRange.values();
39  l.unlock();
40  return CSimulatedAircraftList(aircraftInRange);
41  }
42 
44  {
45  QReadLocker l(&m_lockAircraft);
46  const QList<CCallsign> callsigns = m_aircraftInRange.keys();
47  l.unlock();
48  return CCallsignSet(callsigns);
49  }
50 
52  {
53  const CSimulatedAircraft aircraft = this->getAircraftInRange().findFirstByCallsign(callsign);
54  return aircraft;
55  }
56 
58  {
59  const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign)); // threadsafe
60  return aircraft.getModel();
61  }
62 
64  {
65  static const CAircraftSituationList empty;
66  QReadLocker l(&m_lockSituations);
67  if (!m_situationsByCallsign.contains(callsign)) { return empty; }
68  return m_situationsByCallsign[callsign];
69  }
70 
72  {
73  const CAircraftSituationList situations = this->remoteAircraftSituations(callsign);
74  if (index < 0 || index >= situations.size()) { return CAircraftSituation::null(); }
75  return situations[index];
76  }
77 
80  {
81  const CAircraftSituationList situations = this->remoteAircraftSituations(callsign);
82  return situations.getOffsetMinMaxMean();
83  }
84 
86  {
87  QReadLocker l(&m_lockSituations);
88  const QList<CAircraftSituation> situations(m_latestSituationByCallsign.values());
89  l.unlock();
90  return CAircraftSituationList(situations);
91  }
92 
94  {
95  QReadLocker l(&m_lockSituations);
96  const QList<CAircraftSituation> situations(m_latestOnGroundProviderElevation.values());
97  l.unlock();
98  return CAircraftSituationList(situations);
99  }
100 
102  {
103  QReadLocker l(&m_lockSituations);
104  if (!m_situationsByCallsign.contains(callsign)) { return -1; }
105  return m_situationsByCallsign[callsign].size();
106  }
107 
109  {
110  static const CAircraftPartsList empty;
111  QReadLocker l(&m_lockParts);
112  if (!m_partsByCallsign.contains(callsign)) { return empty; }
113  return m_partsByCallsign[callsign];
114  }
115 
117  {
118  QReadLocker l(&m_lockParts);
119  if (!m_partsByCallsign.contains(callsign)) { return -1; }
120  return m_partsByCallsign[callsign].size();
121  }
122 
124  {
125  QReadLocker l(&m_lockParts);
126  return m_aircraftWithParts.contains(callsign);
127  }
128 
130  {
131  QReadLocker l(&m_lockParts);
132  return m_aircraftWithParts.size();
133  }
134 
136  {
137  QReadLocker l(&m_lockParts);
138  return m_aircraftWithParts;
139  }
140 
143  {
144  QReadLocker l(&m_lockChanges);
145  return m_changesByCallsign[callsign];
146  }
147 
149  {
150  QReadLocker l(&m_lockChanges);
151  return m_changesByCallsign[callsign].size();
152  }
153 
155  {
156  QReadLocker l(&m_lockAircraft);
157  return m_aircraftInRange.size();
158  }
159 
161  {
162  const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
163 
164  // locked members
165  {
166  QWriteLocker l(&m_lockParts);
167  m_partsByCallsign.clear();
168  m_aircraftWithParts.clear();
169  m_partsAdded = 0;
170  m_partsLastModified.clear();
171  }
172  {
173  QWriteLocker l(&m_lockSituations);
174  m_situationsByCallsign.clear();
175  m_latestSituationByCallsign.clear();
176  m_latestOnGroundProviderElevation.clear();
177  m_situationsAdded = 0;
178  m_situationsLastModified.clear();
179  m_testOffset.clear();
180  }
181  {
182  QWriteLocker l(&m_lockChanges);
183  m_changesByCallsign.clear();
184  }
185 
186  {
187  QWriteLocker l(&m_lockPartsHistory);
188  m_aircraftPartsMessages.clear();
189  }
190  {
191  QWriteLocker l(&m_lockMessages);
192  m_reverseLookupMessages.clear();
193  }
194  {
195  QWriteLocker l(&m_lockAircraft);
196  m_aircraftInRange.clear();
197  m_dbCGPerCallsign.clear();
198  }
199 
200  for (const CCallsign &cs : callsigns) { emit this->removedAircraft(cs); }
201  }
202 
204  {
205  QWriteLocker l(&m_lockMessages);
206  m_reverseLookupMessages.remove(callsign);
207  }
208 
210  {
211  if (this->isAircraftInRange(aircraft.getCallsign())) { return false; }
212 
213  // store
214  {
215  QWriteLocker l(&m_lockAircraft);
216  m_aircraftInRange.insert(aircraft.getCallsign(), aircraft);
217  }
218  emit this->addedAircraft(aircraft);
219  emit this->changedAircraftInRange();
220  return true;
221  }
222 
224  bool skipEqualValues)
225  {
226  Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
227  int c = 0;
228  {
229  QWriteLocker l(&m_lockAircraft);
230  if (!m_aircraftInRange.contains(callsign)) { return 0; }
231  c = m_aircraftInRange[callsign].apply(vm, skipEqualValues).size();
232  }
233  if (c > 0) { emit this->changedAircraftInRange(); }
234  return c;
235  }
236 
238  const CAircraftSituation &situation,
239  const CLength &distance, const CAngle &bearing)
240  {
241  Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
242  {
243  QWriteLocker l(&m_lockAircraft);
244  if (!m_aircraftInRange.contains(callsign)) { return false; }
245  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
246  aircraft.setSituation(situation);
247  if (!bearing.isNull()) { aircraft.setRelativeBearing(bearing); }
248  if (!distance.isNull()) { aircraft.setRelativeDistance(distance); }
249  }
250  return true;
251  }
252 
254  bool allowTestAltitudeOffset)
255  {
256  const CCallsign cs = situation.getCallsign();
257  if (cs.isEmpty()) { return situation; }
258 
259  // testing
260  if (CBuildConfig::isLocalDeveloperDebugBuild())
261  {
262  SWIFT_VERIFY_X(situation.getTimeOffsetMs() > 0, Q_FUNC_INFO, "Missing offset");
263  SWIFT_VERIFY_X(situation.isValidVectorRange(), Q_FUNC_INFO, "Invalid vector");
264  }
265 
266  // add altitude offset (for testing only)
267  CAircraftSituation situationCorrected(
268  allowTestAltitudeOffset ? this->addTestAltitudeOffsetToSituation(situation) : situation);
269 
270  // CG, model
271  const CAircraftModel aircraftModel = this->getAircraftInRangeModelForCallsign(cs);
272  if (situation.hasCG() && aircraftModel.getCG() != situation.getCG()) { this->updateCG(cs, situation.getCG()); }
273 
274  // list from new to old
275  CAircraftSituationList updatedSituations; // copy of updated situations
276  {
277  const qint64 now = QDateTime::currentMSecsSinceEpoch();
278  QWriteLocker lock(&m_lockSituations);
279  m_situationsAdded++;
280  m_situationsLastModified[cs] = now;
281  CAircraftSituationList &newSituationsList = m_situationsByCallsign[cs];
282  newSituationsList.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
283  const int situations = newSituationsList.size();
284  if (situations < 1)
285  {
286  newSituationsList.prefillLatestAdjustedFirst(situationCorrected,
288  }
289  else if (!situationCorrected.hasVelocity() && newSituationsList.front().hasVelocity())
290  {
291  return situationCorrected;
292  }
293  else
294  {
295  // newSituationsList.push_frontKeepLatestFirstIgnoreOverlapping(situationCorrected, true,
296  // IRemoteAircraftProvider::MaxSituationsPerCallsign);
297  newSituationsList.push_frontKeepLatestFirstAdjustOffset(
298  situationCorrected, true, IRemoteAircraftProvider::MaxSituationsPerCallsign);
299  newSituationsList.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
300  newSituationsList
301  .transferElevationForward(); // transfer elevations, will do nothing if elevations already exist
302 
303  // unify all inbound ground information
304  if (situation.hasInboundGroundDetails())
305  {
306  newSituationsList.setOnGroundDetails(situation.getOnGroundInfo().getGroundDetails());
307  }
308  }
309  m_latestSituationByCallsign[cs] = situationCorrected;
310 
311  // check sort order
312  if (CBuildConfig::isLocalDeveloperDebugBuild())
313  {
314  SWIFT_VERIFY_X(newSituationsList.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO,
315  "wrong adjusted sort order");
316  SWIFT_VERIFY_X(newSituationsList.isSortedLatestFirst(), Q_FUNC_INFO, "wrong sort order");
318  Q_FUNC_INFO, "Wrong size");
319  }
320 
321  if (!situation.hasInboundGroundDetails())
322  {
323  // first use a version without standard deviations to guess "on ground
324  const CAircraftSituationChange simpleChange(updatedSituations, situationCorrected.getCG(),
325  aircraftModel.isVtol(), true, false);
326 
327  // guess GND
328  simpleChange.guessOnGround(newSituationsList.front(), aircraftModel);
329  }
330  updatedSituations = m_situationsByCallsign[cs];
331 
332  } // lock
333 
334  // calculate change AFTER gnd. was guessed
335  Q_ASSERT_X(!updatedSituations.isEmpty(), Q_FUNC_INFO, "Missing situations");
336  const CAircraftSituationChange change(updatedSituations, situationCorrected.getCG(), aircraftModel.isVtol(),
337  true, true);
338  this->storeChange(change);
339 
340  // situation has been added
341  emit this->addedAircraftSituation(situationCorrected);
342 
343  // bye
344  return situationCorrected;
345  }
346 
348  bool removeOutdated)
349  {
350  SWIFT_VERIFY_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
351  if (callsign.isEmpty()) { return; }
352 
353  // list sorted from new to old
354  const qint64 ts = QDateTime::currentMSecsSinceEpoch();
355  CAircraftPartsList correctiveParts;
356  {
357  QWriteLocker lock(&m_lockParts);
358  m_partsAdded++;
359  m_partsLastModified[callsign] = ts;
360  CAircraftPartsList &partsList = m_partsByCallsign[callsign];
362  partsList.setAdjustedSortHint(CAircraftPartsList::AdjustedTimestampLatestFirst);
363 
364  // remove outdated parts (but never remove the most recent one)
365  if (removeOutdated) { IRemoteAircraftProvider::removeOutdatedParts(partsList); }
366  correctiveParts = partsList;
367 
368  // check sort order
369  Q_ASSERT_X(partsList.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "wrong sort order");
370  Q_ASSERT_X(partsList.size() <= IRemoteAircraftProvider::MaxPartsPerCallsign, Q_FUNC_INFO, "Wrong size");
371  } // lock
372 
373  // adjust gnd.flag from parts
374  if (!correctiveParts.isEmpty())
375  {
376  QWriteLocker lock(&m_lockSituations);
377  CAircraftSituationList &situationList = m_situationsByCallsign[callsign];
378  const int c = situationList.adjustGroundFlag(parts);
379  if (c > 0) { m_situationsLastModified[callsign] = ts; }
380  }
381 
382  // update aircraft
383  {
384  QWriteLocker l(&m_lockAircraft);
385  if (m_aircraftInRange.contains(callsign))
386  {
387  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
388  aircraft.setParts(parts);
389  aircraft.setPartsSynchronized(true);
390  }
391  }
392 
393  // update parts
394  {
395  // aircraft supporting parts
396  QWriteLocker l(&m_lockParts);
397  m_aircraftWithParts.insert(callsign); // mark as callsign which supports parts
398  }
399 
400  emit this->addedAircraftParts(callsign, parts);
401  }
402 
403  void CRemoteAircraftProvider::storeAircraftParts(const CCallsign &callsign, const QJsonObject &jsonObject,
404  qint64 currentOffsetMs)
405  {
406  const CSimulatedAircraft remoteAircraft(this->getAircraftInRangeForCallsign(callsign));
407  const bool isFull = jsonObject.value(CAircraftParts::attributeNameIsFullJson()).toBool();
408  const bool validCs = remoteAircraft.hasValidCallsign();
409  if (!validCs)
410  {
411  if (!isFull) { return; } // incremental parts broadcasting
412  return; // suspicious
413  }
414 
415  // If we are not yet synchronized, we throw away any incremental packet
416  if (!remoteAircraft.isPartsSynchronized() && !isFull) { return; }
417 
418  CAircraftParts parts;
419  try
420  {
421  if (isFull)
422  {
423  if (CBuildConfig::isLocalDeveloperDebugBuild())
424  {
425  // validation in dev.env.
426  const int attributes = jsonObject.size();
427  const bool correctCount = (attributes == CAircraftParts::attributesCountFullJson);
428  SWIFT_VERIFY_X(correctCount || !CBuildConfig::isLocalDeveloperDebugBuild(), Q_FUNC_INFO,
429  "Wrong full aircraft parts");
430  if (!correctCount)
431  {
432  CLogMessage(this).warning(u"Wrong full parts attributes, %1 (expected %2)")
433  << attributes << CAircraftParts::attributesCountFullJson;
435  if (attributes < 3)
436  {
437  // EXPERIMENTAL
438  if (attributes < 1) { return; }
439 
440  // treat as incremental
441  CLogMessage(this).warning(u"Treating %1 attributes as incremental") << attributes;
442  parts = this->remoteAircraftParts(callsign).frontOrDefault(); // latest
443  const QJsonObject config = applyIncrementalObject(parts.toJson(), jsonObject);
444  parts.convertFromJson(config);
445  }
446  }
447  }
448  parts.convertFromJson(jsonObject);
449  }
450  else
451  {
452  // incremental update
453  parts = this->remoteAircraftParts(callsign).frontOrDefault(); // latest
454  const QJsonObject config = applyIncrementalObject(parts.toJson(), jsonObject);
455  parts.convertFromJson(config);
456  }
457  }
458  catch (const CJsonException &ex)
459  {
460  CStatusMessage message = CStatusMessage::fromJsonException(ex, this, "Invalid parts packet");
462  CLogMessage::preformatted(message);
463  }
464 
465  // make sure in any case right time and correct details
466  parts.setCurrentUtcTime();
467  parts.setTimeOffsetMs(currentOffsetMs);
468  parts.setPartsDetails(CAircraftParts::FSDAircraftParts);
469 
470  // store part history (parts always absolute)
471  this->storeAircraftParts(callsign, parts, false);
472 
473  // history
474  if (this->isAircraftPartsHistoryEnabled())
475  {
476  const QJsonDocument doc(jsonObject);
477  const QString partsAsString = doc.toJson(QJsonDocument::Compact);
478  const CStatusMessage message(this, CStatusMessage::SeverityInfo,
479  callsign.isEmpty() ? callsign.toQString() + ": " + partsAsString.trimmed() :
480  partsAsString.trimmed());
481 
482  QReadLocker l(&m_lockPartsHistory);
483  if (m_aircraftPartsMessages.contains(callsign))
484  {
485  CStatusMessageList &msgs = m_aircraftPartsMessages[callsign];
486  msgs.push_back(message);
487  }
488  else { m_aircraftPartsMessages.insert(callsign, message); }
489  }
490  }
491 
492  void CRemoteAircraftProvider::storeChange(const CAircraftSituationChange &change)
493  {
494  // a change with the same timestamp will be replaced
495  const CCallsign cs(change.getCallsign());
496  QWriteLocker lock(&m_lockChanges);
497  CAircraftSituationChangeList &changeList = m_changesByCallsign[cs];
499  }
500 
502  const CAircraftSituationChange &change,
503  const CAircraftModel &aircraftModel)
504  {
505  if (aircraftModel.hasCG() && !situation.hasCG()) { situation.setCG(aircraftModel.getCG()); }
506  if (!situation.shouldGuessOnGround()) { return false; }
507  return change.guessOnGround(situation, aircraftModel);
508  }
509 
510  bool CRemoteAircraftProvider::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering)
511  {
512  // here just synonym
513  return this->setAircraftEnabledFlag(callsign, enabledForRendering);
514  }
515 
516  bool CRemoteAircraftProvider::setAircraftEnabledFlag(const CCallsign &callsign, bool enabledForRendering)
517  {
518  QWriteLocker l(&m_lockAircraft);
519  if (!m_aircraftInRange.contains(callsign)) { return false; }
520  return m_aircraftInRange[callsign].setEnabled(enabledForRendering);
521  }
522 
523  int CRemoteAircraftProvider::updateMultipleAircraftEnabled(const CCallsignSet &callsigns, bool enabledForRendering)
524  {
525  if (callsigns.isEmpty()) { return 0; }
526  QWriteLocker l(&m_lockAircraft);
527  int c = 0;
528  for (const CCallsign &cs : callsigns)
529  {
530  if (!m_aircraftInRange.contains(cs)) { continue; }
531  if (m_aircraftInRange[cs].setEnabled(enabledForRendering)) { c++; }
532  }
533  return c;
534  }
535 
537  const CIdentifier &originator)
538  {
539  if (CIdentifiable::isMyIdentifier(originator)) { return false; }
540  const CPropertyIndexVariantMap vm(CSimulatedAircraft::IndexModel, CVariant::from(model));
541  const int c = this->updateAircraftInRange(callsign, vm);
542  return c > 0;
543  }
544 
546  const CIdentifier &originator)
547  {
548  if (CIdentifiable::isMyIdentifier(originator)) { return false; }
549  const CPropertyIndexVariantMap vm(CSimulatedAircraft::IndexNetworkModel, CVariant::from(model));
550  const int c = this->updateAircraftInRange(callsign, vm);
551  return c > 0;
552  }
553 
554  bool CRemoteAircraftProvider::updateFastPositionEnabled(const CCallsign &callsign, bool enableFastPositonUpdates)
555  {
556  QWriteLocker l(&m_lockAircraft);
557  if (!m_aircraftInRange.contains(callsign)) { return false; }
558  return m_aircraftInRange[callsign].setFastPositionUpdates(enableFastPositonUpdates);
559  }
560 
561  bool CRemoteAircraftProvider::updateAircraftRendered(const CCallsign &callsign, bool rendered)
562  {
563  QWriteLocker l(&m_lockAircraft);
564  if (!m_aircraftInRange.contains(callsign)) { return false; }
565  return m_aircraftInRange[callsign].setRendered(rendered);
566  }
567 
569  {
570  if (callsigns.isEmpty()) { return 0; }
571  int c = 0;
572  for (const CCallsign &cs : callsigns)
573  {
574  if (!m_aircraftInRange.contains(cs)) { continue; }
575  if (m_aircraftInRange[cs].setRendered(rendered)) { c++; }
576  }
577  return c;
578  }
579 
581  const CElevationPlane &elevation,
583  bool *setForOnGroundPosition)
584  {
585  if (!this->isAircraftInRange(callsign)) { return 0; }
586 
587  // update aircraft situation
588  const qint64 now = QDateTime::currentMSecsSinceEpoch();
589  const CAircraftModel model = this->getAircraftInRangeModelForCallsign(callsign);
591  bool setForOnGndPosition = false;
592 
593  int updated = 0;
594  {
595  QWriteLocker l(&m_lockSituations);
596  CAircraftSituationList &situations = m_situationsByCallsign[callsign];
597  if (situations.isEmpty()) { return 0; }
598  updated = setGroundElevationCheckedAndGuessGround(situations, elevation, info, model, &change,
599  &setForOnGndPosition);
600  if (updated < 1) { return 0; }
601  m_situationsLastModified[callsign] = now;
602  const CAircraftSituation latestSituation = situations.front();
603  if (info == CAircraftSituation::FromProvider && latestSituation.isOnGround())
604  {
605  m_latestOnGroundProviderElevation[callsign] = latestSituation;
606  }
607  }
608 
609  // update change
610  if (!change.isNull()) { this->storeChange(change); }
611 
612  // aircraft updates
613  QWriteLocker l(&m_lockAircraft);
614  if (m_aircraftInRange.contains(callsign))
615  {
616  m_aircraftInRange[callsign].setGroundElevationChecked(elevation, info);
617  }
618 
619  if (setForOnGroundPosition) { *setForOnGroundPosition = setForOnGndPosition; }
620  return updated; // updated situations
621  }
622 
623  bool CRemoteAircraftProvider::updateCG(const CCallsign &callsign, const CLength &cg)
624  {
625  QWriteLocker l(&m_lockAircraft);
626  if (!m_aircraftInRange.contains(callsign)) { return false; }
627  m_aircraftInRange[callsign].setCG(cg);
628  return true;
629  }
630 
632  const QString &modelString)
633  {
634  QWriteLocker l(&m_lockAircraft);
635  if (!m_aircraftInRange.contains(callsign)) { return false; }
636  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
637  if (!cg.isNull()) { aircraft.setCG(cg); }
638  if (!modelString.isEmpty()) { aircraft.setModelString(modelString); }
639  return true;
640  }
641 
642  CCallsignSet CRemoteAircraftProvider::updateCGForModel(const QString &modelString, const CLength &cg)
643  {
644  CCallsignSet callsigns;
645  if (modelString.isEmpty()) { return callsigns; }
646 
647  QWriteLocker l(&m_lockAircraft);
648  for (CSimulatedAircraft &aircraft : m_aircraftInRange)
649  {
650  if (caseInsensitiveStringCompare(aircraft.getModelString(), modelString))
651  {
652  aircraft.setCG(cg);
653  callsigns.push_back(aircraft.getCallsign());
654  }
655  }
656  return callsigns;
657  }
658 
660  {
661  QReadLocker l(&m_lockAircraft);
662  return m_dbCGPerCallsign.contains(callsign) ? m_dbCGPerCallsign[callsign] : CLength::null();
663  }
664 
665  CLength CRemoteAircraftProvider::getCGFromDB(const QString &modelString) const
666  {
667  QReadLocker l(&m_lockAircraft);
668  return m_dbCGPerCallsign.contains(modelString) ? m_dbCGPerCallsign[modelString] : CLength::null();
669  }
670 
671  void CRemoteAircraftProvider::rememberCGFromDB(const CLength &cgFromDB, const CCallsign &callsign)
672  {
673  QWriteLocker l(&m_lockAircraft);
674  m_dbCGPerCallsign[callsign] = cgFromDB;
675  }
676 
677  void CRemoteAircraftProvider::rememberCGFromDB(const CLength &cgFromDB, const QString &modelString)
678  {
679  QWriteLocker l(&m_lockAircraft);
680  m_dbCGPerModelString[modelString] = cgFromDB;
681  }
682 
684  {
685  const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
686  QWriteLocker l(&m_lockAircraft);
687  for (const CCallsign &cs : callsigns) { m_aircraftInRange[cs].setRendered(false); }
688  }
689 
691  {
692  QWriteLocker l(&m_lockMessages);
693  m_enableReverseLookupMsgs = enable;
694  }
695 
697  {
698  QReadLocker l(&m_lockMessages);
699  return m_enableReverseLookupMsgs;
700  }
701 
703  {
704  QReadLocker l(&m_lockMessages);
705  return m_reverseLookupMessages.value(callsign);
706  }
707 
709  const CStatusMessageList &messages)
710  {
711  if (callsign.isEmpty()) { return; }
712  if (messages.isEmpty()) { return; }
713  QWriteLocker l(&m_lockMessages);
714  if (!m_enableReverseLookupMsgs) { return; }
715  if (m_reverseLookupMessages.contains(callsign))
716  {
717  CStatusMessageList &msgs = m_reverseLookupMessages[callsign];
718  msgs.push_back(messages);
719  }
720  else { m_reverseLookupMessages.insert(callsign, messages); }
721  }
722 
724  {
725  if (callsign.isEmpty()) { return; }
726  if (message.isEmpty()) { return; }
727  this->addReverseLookupMessages(callsign, CStatusMessageList({ message }));
728  }
729 
730  void CRemoteAircraftProvider::addReverseLookupMessage(const CCallsign &callsign, const QString &message,
732  {
733  if (callsign.isEmpty()) { return; }
734  if (message.isEmpty()) { return; }
735  const CStatusMessage m = CCallsign::logMessage(callsign, message, getLogCategories(), severity);
736  this->addReverseLookupMessage(callsign, m);
737  }
738 
740 
742  {
743  if (callsign.isEmpty()) { return false; }
744  QReadLocker l(&m_lockSituations);
745  return m_testOffset.contains(callsign);
746  }
747 
749  {
750  QReadLocker l(&m_lockSituations);
751  return m_testOffset.contains(testAltitudeOffsetCallsign());
752  }
753 
756  {
757  const CCallsign cs(situation.getCallsign());
758  const bool globalOffset = this->hasTestAltitudeOffsetGlobalValue();
759  if (!globalOffset && !this->hasTestAltitudeOffset(cs)) { return situation; }
760 
761  QReadLocker l(&m_lockSituations);
762  const CLength os =
763  m_testOffset.contains(cs) ? m_testOffset.value(cs) : m_testOffset.value(testAltitudeOffsetCallsign());
764  if (os.isNull() || os.isZeroEpsilonConsidered()) { return situation; }
765  return situation.withAltitudeOffset(os);
766  }
767 
768  ReverseLookupLogging CRemoteAircraftProvider::whatToReverseLog() const
769  {
770  QReadLocker l(&m_lockMessages);
771  return m_enableReverseLookupMsgs;
772  }
773 
775  const CElevationPlane &elevationPlane,
777  const CAircraftModel &model,
778  CAircraftSituationChange *changeOut,
779  bool *setForOnGroundPosition)
780  {
781  if (setForOnGroundPosition) { *setForOnGroundPosition = false; } // set a default
782  if (elevationPlane.isNull()) { return 0; }
783  if (situations.isEmpty()) { return 0; }
784 
785  // the change has the timestamps of the latest situation
786  // Q_ASSERT_X(situations.m_tsAdjustedSortHint == CAircraftSituationList::AdjustedTimestampLatestFirst ||
787  // situations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Need sorted situations without
788  // NULL positions");
789  const CAircraftSituationChange simpleChange(situations, model.getCG(), model.isVtol(), true, false);
790  int c = 0; // changed elevations
791  bool latest = true;
792  bool setForOnGndPosition = false;
793 
794  for (CAircraftSituation &s : situations)
795  {
796  const bool set = s.setGroundElevationChecked(elevationPlane, info);
797  if (set)
798  {
799  // simpleChange is only valid for the latest situation
800  // this will do nothing if not appropriate!
801  const bool guessed = (latest ? simpleChange : CAircraftSituationChange::null()).guessOnGround(s, model);
802  Q_UNUSED(guessed)
803  c++;
804 
805  // if not guessed and "on ground" we mark the "elevation"
806  // as an elevation for a ground position
807  if (!setForOnGndPosition && s.hasInboundGroundDetails() && s.isOnGround())
808  {
809  setForOnGndPosition = true;
810  }
811  }
812  latest = false; // only first pos. is "the latest" one
813  }
814 
815  if (setForOnGroundPosition) { *setForOnGroundPosition = setForOnGndPosition; }
816  if (changeOut)
817  {
818  const CAircraftSituationChange change(situations, model.getCG(), model.isVtol(), true, true);
819  *changeOut = change;
820  }
821 
822  return c;
823  }
824 
826  {
827  QReadLocker l(&m_lockPartsHistory);
828  return m_aircraftPartsMessages.value(callsign);
829  }
830 
832  {
833  QReadLocker l(&m_lockPartsHistory);
834  return m_enableAircraftPartsHistory;
835  }
836 
838  {
839  QWriteLocker l(&m_lockPartsHistory);
840  m_enableAircraftPartsHistory = enabled;
841  }
842 
844  {
845  QReadLocker l(&m_lockSituations);
846  return m_situationsAdded;
847  }
848 
850  {
851  QReadLocker l(&m_lockSituations);
852  return m_situationsLastModified.value(callsign, -1);
853  }
854 
856  {
857  QReadLocker l(&m_lockParts);
858  return m_partsLastModified.value(callsign, -1);
859  }
860 
862  const CLength &range, int minValues,
863  int sufficientValues) const
864  {
865  const CAircraftSituationList situations = this->latestOnGroundProviderElevations();
866  return situations.averageElevationOfTaxiingOnGroundAircraft(reference, range, minValues, sufficientValues);
867  }
868 
870  {
871  const bool remove = offset.isNull() || offset.isZeroEpsilonConsidered();
872  QWriteLocker l(&m_lockSituations);
873  if (remove)
874  {
875  m_testOffset.remove(callsign);
876  return false;
877  }
878 
879  m_testOffset[callsign] = offset;
880  return true;
881  }
882 
884  {
885  QReadLocker l(&m_lockParts);
886  return m_partsAdded;
887  }
888 
890  {
891  if (callsign.isEmpty()) { return false; }
892  QReadLocker l(&m_lockAircraft);
893  return m_aircraftInRange.contains(callsign);
894  }
895 
897  {
898  if (callsign.isEmpty()) { return false; }
899  const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign);
900  return aircraft.isVtol();
901  }
902 
904  QObject *receiver, std::function<void(const CAircraftSituation &)> addedSituationFunction,
905  std::function<void(const CCallsign &, const CAircraftParts &)> addedPartsFunction,
906  std::function<void(const CCallsign &)> removedAircraftFunction,
907  std::function<void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot)
908  {
909  Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver");
910 
911  // bind does not allow to define connection type, so we use receiver as workaround
912  const QMetaObject::Connection uc; // unconnected
913  const QMetaObject::Connection c1 = addedSituationFunction ?
914  connect(this, &CRemoteAircraftProvider::addedAircraftSituation, receiver,
915  addedSituationFunction, Qt::QueuedConnection) :
916  uc;
917  Q_ASSERT_X(c1 || !addedSituationFunction, Q_FUNC_INFO, "connect failed");
918  const QMetaObject::Connection c2 = addedPartsFunction ?
919  connect(this, &CRemoteAircraftProvider::addedAircraftParts, receiver,
920  addedPartsFunction, Qt::QueuedConnection) :
921  uc;
922  Q_ASSERT_X(c2 || !addedPartsFunction, Q_FUNC_INFO, "connect failed");
923  const QMetaObject::Connection c3 = removedAircraftFunction ?
924  connect(this, &CRemoteAircraftProvider::removedAircraft, receiver,
925  removedAircraftFunction, Qt::QueuedConnection) :
926  uc;
927  Q_ASSERT_X(c3 || !removedAircraftFunction, Q_FUNC_INFO, "connect failed");
928  const QMetaObject::Connection c4 = aircraftSnapshotSlot ?
930  receiver, aircraftSnapshotSlot, Qt::QueuedConnection) :
931  uc;
932  Q_ASSERT_X(c4 || !aircraftSnapshotSlot, Q_FUNC_INFO, "connect failed");
933  return QList<QMetaObject::Connection>({ c1, c2, c3, c4 });
934  }
935 
937  {
938  {
939  QWriteLocker l1(&m_lockParts);
940  m_partsByCallsign.remove(callsign);
941  m_aircraftWithParts.remove(callsign);
942  m_partsLastModified.remove(callsign);
943  }
944  {
945  QWriteLocker l2(&m_lockSituations);
946  m_situationsByCallsign.remove(callsign);
947  m_latestSituationByCallsign.remove(callsign);
948  m_latestOnGroundProviderElevation.remove(callsign);
949  m_situationsLastModified.remove(callsign);
950  }
951  {
952  QWriteLocker l4(&m_lockPartsHistory);
953  m_aircraftPartsMessages.remove(callsign);
954  }
955  bool removedCallsign = false;
956  {
957  QWriteLocker l(&m_lockAircraft);
958  m_dbCGPerCallsign.remove(callsign);
959  const int c = m_aircraftInRange.remove(callsign);
960  removedCallsign = c > 0;
961  }
962  return removedCallsign;
963  }
964 
966 
968  {
969  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
970  return this->provider()->getAircraftInRange();
971  }
972 
974  {
975  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
976  return this->provider()->isAircraftInRange(callsign);
977  }
978 
980  {
981  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
982  return this->provider()->isVtolAircraft(callsign);
983  }
984 
986  {
987  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
988  return this->provider()->getAircraftInRangeCount();
989  }
990 
992  {
993  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
994  return this->provider()->getAircraftInRangeCallsigns();
995  }
996 
998  {
999  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1000  return this->provider()->getAircraftInRangeForCallsign(callsign);
1001  }
1002 
1004  {
1005  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1006  return this->provider()->getAircraftInRangeModelForCallsign(callsign);
1007  }
1008 
1010  {
1011  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1012  return this->provider()->getLatestAirspaceAircraftSnapshot();
1013  }
1014 
1017  {
1018  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1019  return this->provider()->remoteAircraftSituations(callsign);
1020  }
1021 
1023  {
1024  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1025  return this->provider()->remoteAircraftSituation(callsign, index);
1026  }
1027 
1029  {
1030  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1031  return this->provider()->latestRemoteAircraftSituations();
1032  }
1033 
1035  {
1036  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1037  return this->provider()->latestOnGroundProviderElevations();
1038  }
1039 
1041  {
1042  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1043  return this->provider()->remoteAircraftSituationChanges(callsign);
1044  }
1045 
1047  {
1048  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1049  return this->provider()->remoteAircraftParts(callsign);
1050  }
1051 
1053  {
1054  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1055  return this->provider()->remoteAircraftPartsCount(callsign);
1056  }
1057 
1059  {
1060  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1061  return this->provider()->remoteAircraftSupportingParts();
1062  }
1063 
1065  {
1066  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1067  return this->provider()->remoteAircraftSituationsCount(callsign);
1068  }
1069 
1071  const CIdentifier &originator)
1072  {
1073  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1074  return this->provider()->updateAircraftModel(callsign, model, originator);
1075  }
1076 
1078  const CIdentifier &originator)
1079  {
1080  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1081  return this->provider()->updateAircraftNetworkModel(callsign, model, originator);
1082  }
1083 
1084  bool CRemoteAircraftAware::updateAircraftRendered(const CCallsign &callsign, bool rendered)
1085  {
1086  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1087  return this->provider()->updateAircraftRendered(callsign, rendered);
1088  }
1089 
1091  {
1092  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1093  return this->provider()->updateMultipleAircraftRendered(callsigns, rendered);
1094  }
1095 
1098  bool *updatedAircraftGroundElevation)
1099  {
1100  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1101  return this->provider()->updateAircraftGroundElevation(callsign, elevation, info,
1102  updatedAircraftGroundElevation);
1103  }
1104 
1105  bool CRemoteAircraftAware::updateCG(const CCallsign &callsign, const CLength &cg)
1106  {
1107  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1108  return this->provider()->updateCG(callsign, cg);
1109  }
1110 
1111  CCallsignSet CRemoteAircraftAware::updateCGForModel(const QString &modelString, const CLength &cg)
1112  {
1113  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1114  return this->provider()->updateCGForModel(modelString, cg);
1115  }
1116 
1118  const QString &modelString)
1119  {
1120  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1121  return this->provider()->updateCGAndModelString(callsign, cg, modelString);
1122  }
1123 
1125  {
1126  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1127  this->provider()->updateMarkAllAsNotRendered();
1128  }
1129 
1131  {
1132  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1133  return this->provider()->aircraftSituationsAdded();
1134  }
1135 
1137  {
1138  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1139  return this->provider()->aircraftPartsAdded();
1140  }
1141 
1143  {
1144  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1145  return this->provider()->situationsLastModified(callsign);
1146  }
1147 
1149  {
1150  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1151  return this->provider()->partsLastModified(callsign);
1152  }
1153 
1155  const CLength &range, int minValues) const
1156  {
1157  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1158  return this->provider()->averageElevationOfNonMovingAircraft(reference, range, minValues);
1159  }
1160 
1162  {
1163  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1164  return this->provider()->isRemoteAircraftSupportingParts(callsign);
1165  }
1166 
1168  {
1169  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1170  return this->provider()->getRemoteAircraftSupportingPartsCount();
1171  }
1172 
1173  bool CRemoteAircraftAware::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering)
1174  {
1175  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1176  return this->provider()->updateAircraftEnabled(callsign, enabledForRendering);
1177  }
1178 
1179  bool CRemoteAircraftAware::setAircraftEnabledFlag(const CCallsign &callsign, bool enabledForRendering)
1180  {
1181  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1182  return this->provider()->setAircraftEnabledFlag(callsign, enabledForRendering);
1183  }
1184 
1185  bool CRemoteAircraftAware::updateMultipleAircraftEnabled(const CCallsignSet &callsigns, bool enabledForRendering)
1186  {
1187  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1188  return this->provider()->updateMultipleAircraftEnabled(callsigns, enabledForRendering);
1189  }
1190 
1192  {
1193  static const CAircraftParts empty;
1194  const CAircraftPartsList parts = this->remoteAircraftParts(callsign);
1195  return parts.isEmpty() ? empty : parts.latestObject();
1196  }
1197 
1199  {
1200  // remove all outdated parts, but keep at least one
1201  if (partsList.isEmpty()) { return; }
1202 
1203  // we expect the latest value at front
1204  // but to make sure we do the search
1205  const qint64 ts = partsList.latestTimestampMsecsSinceEpoch() - MaxPartsAgePerCallsignSecs * 1000;
1206  partsList.removeBefore(ts);
1207  Q_ASSERT_X(!partsList.isEmpty(), Q_FUNC_INFO, "Need at least 1 value");
1208  }
1209 
1211  {
1212  static const CCallsign wildcard("ZZZZ");
1213  return wildcard;
1214  }
1215 } // namespace swift::misc::simulation
size_type size() const
Returns number of elements in the collection.
Definition: collection.h:185
void remove(const T &object)
Efficient remove using the find and erase of the implementation container. Typically O(log n).
Definition: collection.h:307
iterator insert(const_iterator hint, const T &value)
For compatibility with std::inserter.
Definition: collection.h:199
bool isEmpty() const
Synonym for empty.
Definition: collection.h:191
iterator push_back(const T &value)
Synonym for insert.
Definition: collection.h:238
void clear()
Removes all elements in the collection.
Definition: collection.h:194
Base class with a member CIdentifier to be inherited by a class which has an identity in the environm...
Definition: identifiable.h:24
bool isMyIdentifier(const CIdentifier &otherIdentifier) const
My identifier?
Definition: identifiable.h:33
Value object encapsulating information identifying a component of a modular distributed swift process...
Definition: identifier.h:29
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
static const QString & matching()
Matching.
static const QString & network()
Network specific, but not necessarily one specific flight network.
Class for emitting a log message.
Definition: logmessage.h:27
static void preformatted(const CStatusMessage &statusMessage)
Sends a verbatim, preformatted message to the log.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
bool isEmpty() const
Message empty.
Specialized value object compliant map for variants, based on indexes.
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
Definition: range.h:109
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
const_reference frontOrDefault() const
Access the first element, or a default-initialized value if the sequence is empty.
Definition: sequence.h:239
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
reference front()
Access the first element.
Definition: sequence.h:225
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
static CStatusMessage fromJsonException(const CJsonException &ex, const CLogCategoryList &categories, const QString &prefix)
Object from JSON exception message.
constexpr static auto SeverityDebug
Status severities.
void setSeverity(StatusSeverity severity)
Severity.
constexpr static auto SeverityInfo
Status severities.
Status messages, e.g. from Core -> GUI.
static CVariant from(T &&value)
Synonym for fromValue().
Definition: variant.h:147
IRemoteAircraftProvider * provider()
Provider.
Definition: provider.h:72
void setCurrentUtcTime()
Set the current time as timestamp.
qint64 latestTimestampMsecsSinceEpoch() const
Latest timestamp.
OBJ latestObject() const
Latest object.
int removeBefore(const QDateTime &dateTime)
Remove objects with timestamp before dateTime.
bool isSortedLatestFirst() const
Is completely sorted: latest last.
qint64 getTimeOffsetMs() const
Milliseconds to add to timestamp for interpolation.
void setTimeOffsetMs(qint64 offset)
Milliseconds to add to timestamp for interpolation.
bool isSortedAdjustedLatestFirst() const
Is completely sorted: latest last.
void setAdjustedSortHint(HintAdjustedTimestampSort hint)
Set the hint.
MillisecondsMinMaxMean getOffsetMinMaxMean() const
Difference of timestamp values.
void push_frontKeepLatestAdjustedFirst(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
void prefillLatestAdjustedFirst(const OBJ &value, int elements, qint64 deltaTimeMs=-1)
Prefill with elements.
void push_frontKeepLatestFirstAdjustOffset(const OBJ &value, bool replaceSameTimestamp=true, int maxElements=-1)
Insert as first element by keeping maxElements and the latest first.
Value object encapsulating information of aircraft's parts.
Definition: aircraftparts.h:26
void setPartsDetails(PartsDetails details)
Set parts details.
Value object encapsulating a list of aircraft parts.
Value object about changes in situations.
const CCallsign & getCallsign() const
Get callsign.
bool guessOnGround(CAircraftSituation &situation, const simulation::CAircraftModel &model) const
Guess on ground flag.
Value object encapsulating a list of aircraft parts.
Value object encapsulating information of an aircraft's situation.
void setCG(const physical_quantities::CLength &cg)
Set CG.
aviation::COnGroundInfo getOnGroundInfo() const
On ground info.
bool shouldGuessOnGround() const
Should we guess on ground?
CAircraftSituation withAltitudeOffset(const physical_quantities::CLength &offset) const
Situation with altitude offset.
GndElevationInfo
Where did we get elevation from?
bool hasVelocity() const
Is velocity non-zero?
const CCallsign & getCallsign() const
Corresponding callsign.
const physical_quantities::CLength & getCG() const
Get CG if any.
bool hasInboundGroundDetails() const
Has inbound ground details.
geo::CElevationPlane averageElevationOfTaxiingOnGroundAircraft(const CAircraftSituation &reference, const physical_quantities::CLength &range, int minValues=1, int sufficientValues=2) const
Average elevation for "nearby" aircraft "not/slowly moving" and having an elevation.
int adjustGroundFlag(const CAircraftParts &parts, double timeDeviationFactor=0.1)
Adjust flag from parts by using CAircraftSituation::adjustGroundFlag.
int transferElevationForward(const physical_quantities::CLength &radius=geo::CElevationPlane::singlePointRadius())
Transfer elevations forward from older to newer.
void setOnGroundDetails(COnGroundInfo::OnGroundDetails details)
Set on ground details for all situations.
bool isSortedAdjustedLatestFirstWithoutNullPositions() const
Latest first and no null positions?
Value object encapsulating information of a callsign.
Definition: callsign.h:30
bool isEmpty() const
Is empty?
Definition: callsign.h:63
Value object for a set of callsigns.
Definition: callsignset.h:26
OnGroundDetails getGroundDetails() const
Get ground details.
OBJ findFirstByCallsign(const CCallsign &callsign, const OBJ &ifNotFound={}) const
Find the first aircraft by callsign, if none return given one.
Plane of same elevation, can be a single point or larger area (e.g. airport)
virtual bool isNull() const
Existing value?
bool isValidVectorRange() const
Check values.
void setRelativeDistance(const physical_quantities::CLength &distance)
Set relative distance.
void setRelativeBearing(const physical_quantities::CAngle &angle)
Set bearing to own plane.
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
Definition: mixinjson.h:153
QJsonObject toJson() const
Cast to JSON object.
Definition: mixinjson.h:132
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:74
Physical unit angle (radians, degrees)
Definition: angle.h:23
Physical unit length (length)
Definition: length.h:18
bool isZeroEpsilonConsidered() const
Quantity value <= epsilon.
Aircraft model (used by another pilot, my models on disk)
Definition: aircraftmodel.h:71
const physical_quantities::CLength & getCG() const
Get center of gravity.
bool hasCG() const
CG value available?
geo::CElevationPlane averageElevationOfNonMovingAircraft(const aviation::CAircraftSituation &reference, const physical_quantities::CLength &range, int minValues=1) const
Average elevation of aircraft in given range, which are NOT moving.
int aircraftSituationsAdded() const
Number of situations added.
CAirspaceAircraftSnapshot getLatestAirspaceAircraftSnapshot() const
Current snapshot.
aviation::CCallsignSet getAircraftInRangeCallsigns() const
Unique callsigns for aircraft in range.
bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
aviation::CAircraftSituationList latestRemoteAircraftSituations() const
Latest aircraft situation for all callsigns.
aviation::CAircraftSituation remoteAircraftSituation(const aviation::CCallsign &callsign, int index) const
Rendered aircraft situations (per callsign and index)
bool updateMultipleAircraftEnabled(const aviation::CCallsignSet &callsigns, bool enabledForRendering)
Enable/disable aircraft.
qint64 partsLastModified(const aviation::CCallsign &callsign) const
When last modified.
aviation::CAircraftSituationList remoteAircraftSituations(const aviation::CCallsign &callsign) const
Rendered aircraft situations (per callsign, time history)
qint64 situationsLastModified(const aviation::CCallsign &callsign) const
When last modified.
bool updateMultipleAircraftRendered(const aviation::CCallsignSet &callsigns, bool rendered)
Set aircraft rendered.
CSimulatedAircraftList getAircraftInRange() const
All remote aircraft.
int updateAircraftGroundElevation(const aviation::CCallsign &callsign, const geo::CElevationPlane &elevation, aviation::CAircraftSituation::GndElevationInfo info, bool *updateAircraftGroundElevation)
Update the ground elevation.
int getAircraftInRangeCount() const
Count remote aircraft.
aviation::CAircraftSituationList latestOnGroundProviderElevations() const
Latest aircraft situation "on ground" having a provider elevation.
aviation::CCallsignSet remoteAircraftSupportingParts() const
Remote aircraft supporting parts.
void updateMarkAllAsNotRendered()
Mark all as not rendered.
bool updateAircraftEnabled(const aviation::CCallsign &callsign, bool enabledForRendering)
Enable/disable aircraft and follow up logic like sending signals.
bool updateAircraftNetworkModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change network model.
CSimulatedAircraft getAircraftInRangeForCallsign(const aviation::CCallsign &callsign) const
Aircraft for callsign.
aviation::CAircraftPartsList remoteAircraftParts(const aviation::CCallsign &callsign) const
All parts (per callsign, time history)
aviation::CAircraftSituationChangeList remoteAircraftSituationChanges(const aviation::CCallsign &callsign) const
Aircraft changes.
bool isVtolAircraft(const aviation::CCallsign &callsign) const
Is VTOL aircraft?
bool updateCG(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg)
Update the CG.
bool updateCGAndModelString(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg, const QString &modelString)
Update the CG and model string.
bool isRemoteAircraftSupportingParts(const aviation::CCallsign &callsign) const
Is remote aircraft supporting parts?
int remoteAircraftSituationsCount(const aviation::CCallsign &callsign) const
Number of remote aircraft situations for callsign.
CAircraftModel getAircraftInRangeModelForCallsign(const aviation::CCallsign &callsign) const
Aircraft model for callsign.
bool updateAircraftRendered(const aviation::CCallsign &callsign, bool rendered)
Set aircraft rendered.
bool setAircraftEnabledFlag(const aviation::CCallsign &callsign, bool enabledForRendering)
Just set enable/disable aircraft flag, no further logic.
aviation::CCallsignSet updateCGForModel(const QString &modelString, const physical_quantities::CLength &cg)
Update the CG for this model string.
int aircraftPartsAdded() const
Number of parts added.
bool updateAircraftModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change model.
int getRemoteAircraftSupportingPartsCount() const
Number of aircraft supporting parts.
int remoteAircraftPartsCount(const aviation::CCallsign &callsign) const
All parts (per callsign, time history)
virtual swift::misc::CStatusMessageList getReverseLookupMessages(const swift::misc::aviation::CCallsign &callsign) const
Get reverse lookup meesages.
virtual bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
virtual int remoteAircraftSituationChangesCount(const aviation::CCallsign &callsign) const
Aircraft changes count.
virtual void updateMarkAllAsNotRendered()
Mark all as not rendered.
virtual int updateMultipleAircraftRendered(const aviation::CCallsignSet &callsigns, bool rendered)
Set aircraft rendered.
virtual CSimulatedAircraftList getAircraftInRange() const
All remote aircraft.
virtual aviation::CAircraftSituation storeAircraftSituation(const aviation::CAircraftSituation &situation, bool allowTestAltitudeOffset=true)
Store an aircraft situation.
static const QStringList & getLogCategories()
Log categories.
virtual bool updateCGAndModelString(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg, const QString &modelString)
Update the CG and model string.
virtual bool setAircraftEnabledFlag(const swift::misc::aviation::CCallsign &callsign, bool enabledForRendering)
Just set enable/disable aircraft flag, no further logic.
virtual aviation::CCallsignSet remoteAircraftSupportingParts() const
Remote aircraft supporting parts.
bool hasTestAltitudeOffset(const aviation::CCallsign &callsign) const
Has test offset value?
bool addNewAircraftInRange(const CSimulatedAircraft &aircraft)
Add new aircraft, ignored if aircraft already exists.
aviation::CAircraftSituation addTestAltitudeOffsetToSituation(const aviation::CAircraftSituation &situation) const
Add an offset for testing.
virtual int getRemoteAircraftSupportingPartsCount() const
Number of aircraft supporting parts.
bool removeAircraft(const aviation::CCallsign &callsign)
Remove all aircraft in range.
virtual qint64 situationsLastModified(const aviation::CCallsign &callsign) const
When last modified.
void changedAircraftInRange()
Aircraft were changed.
virtual bool isAircraftPartsHistoryEnabled() const
Is storing aircraft parts history enabled?
virtual int remoteAircraftSituationsCount(const aviation::CCallsign &callsign) const
Number of remote aircraft situations for callsign.
virtual aviation::CAircraftSituation remoteAircraftSituation(const aviation::CCallsign &callsign, int index) const
Rendered aircraft situations (per callsign and index)
virtual geo::CElevationPlane averageElevationOfNonMovingAircraft(const aviation::CAircraftSituation &reference, const physical_quantities::CLength &range, int minValues=1, int sufficientValues=2) const
Average elevation of aircraft in given range, which are NOT moving.
virtual aviation::CAircraftSituationList remoteAircraftSituations(const aviation::CCallsign &callsign) const
Rendered aircraft situations (per callsign, time history)
virtual bool isVtolAircraft(const aviation::CCallsign &callsign) const
Is VTOL aircraft?
virtual aviation::CAircraftSituationChangeList remoteAircraftSituationChanges(const aviation::CCallsign &callsign) const
Aircraft changes.
void addedAircraftParts(const swift::misc::aviation::CCallsign &callsign, const swift::misc::aviation::CAircraftParts &parts)
Parts added.
virtual MillisecondsMinMaxMean remoteAircraftSituationsTimestampDifferenceMinMaxMean(const aviation::CCallsign &callsign) const
Average update time.
int updateAircraftInRange(const aviation::CCallsign &callsign, const CPropertyIndexVariantMap &vm, bool skipEqualValues=true)
Update aircraft.
virtual aviation::CCallsignSet updateCGForModel(const QString &modelString, const physical_quantities::CLength &cg)
Update the CG for this model string.
virtual void enableAircraftPartsHistory(bool enabled)
Enable storing of aircraft parts history.
virtual CStatusMessageList getAircraftPartsHistory(const aviation::CCallsign &callsign) const
Get aircraft parts history.
void addedAircraft(const swift::misc::simulation::CSimulatedAircraft &remoteAircraft)
A new aircraft appeared.
void storeAircraftParts(const aviation::CCallsign &callsign, const aviation::CAircraftParts &parts, bool removeOutdated)
Store an aircraft part.
bool updateAircraftInRangeDistanceBearing(const aviation::CCallsign &callsign, const aviation::CAircraftSituation &situation, const physical_quantities::CLength &distance, const physical_quantities::CAngle &bearing)
Update aircraft bearing, distance and situation.
virtual int remoteAircraftPartsCount(const aviation::CCallsign &callsign) const
All parts (per callsign, time history)
virtual bool updateAircraftEnabled(const aviation::CCallsign &callsign, bool enabledForRendering)
Enable/disable aircraft and follow up logic like sending signals.
virtual void rememberCGFromDB(const physical_quantities::CLength &cgFromDB, const aviation::CCallsign &callsign)
CG values from DB.
void removeReverseLookupMessages(const aviation::CCallsign &callsign)
Remove the lookup messages.
void addReverseLookupMessages(const aviation::CCallsign &callsign, const CStatusMessageList &messages)
Reverse lookup messages.
virtual int aircraftPartsAdded() const
Number of parts added.
bool guessOnGroundAndUpdateModelCG(aviation::CAircraftSituation &situation, const aviation::CAircraftSituationChange &change, const CAircraftModel &aircraftModel)
Guess situation "on ground" and update model's CG if applicable.
virtual aviation::CAircraftSituationList latestRemoteAircraftSituations() const
Latest aircraft situation for all callsigns.
void airspaceAircraftSnapshot(const swift::misc::simulation::CAirspaceAircraftSnapshot &snapshot)
New aircraft snapshot.
virtual bool updateAircraftNetworkModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change network model.
virtual bool updateAircraftModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change model.
void addedAircraftSituation(const swift::misc::aviation::CAircraftSituation &situation)
Situation added.
virtual physical_quantities::CLength getCGFromDB(const aviation::CCallsign &callsign) const
CG values from DB.
virtual qint64 partsLastModified(const aviation::CCallsign &callsign) const
When last modified.
virtual bool updateFastPositionEnabled(const aviation::CCallsign &callsign, bool enableFastPositonUpdates)
Change fast position updates.
virtual QList< QMetaObject::Connection > connectRemoteAircraftProviderSignals(QObject *receiver, std::function< void(const aviation::CAircraftSituation &)> addedSituationSlot, std::function< void(const aviation::CCallsign &, const aviation::CAircraftParts &)> addedPartsSlot, std::function< void(const aviation::CCallsign &)> removedAircraftSlot, std::function< void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot)
Connect signals to slot receiver. As the interface is no QObject, slots can not be connected directly...
virtual bool updateAircraftRendered(const aviation::CCallsign &callsign, bool rendered)
Set aircraft rendered.
virtual aviation::CAircraftSituationList latestOnGroundProviderElevations() const
Latest aircraft situation "on ground" having a provider elevation.
ReverseLookupLogging whatToReverseLog() const
What to log?
virtual aviation::CCallsignSet getAircraftInRangeCallsigns() const
Unique callsigns for aircraft in range.
virtual ReverseLookupLogging isReverseLookupMessagesEnabled() const
Enabled reverse lookup logging?
virtual CAircraftModel getAircraftInRangeModelForCallsign(const aviation::CCallsign &callsign) const
Aircraft model for callsign.
virtual CSimulatedAircraft getAircraftInRangeForCallsign(const aviation::CCallsign &callsign) const
Aircraft for callsign.
virtual int aircraftSituationsAdded() const
Number of situations added.
virtual aviation::CAircraftPartsList remoteAircraftParts(const aviation::CCallsign &callsign) const
All parts (per callsign, time history)
static int setGroundElevationCheckedAndGuessGround(aviation::CAircraftSituationList &situations, const geo::CElevationPlane &elevationPlane, aviation::CAircraftSituation::GndElevationInfo info, const simulation::CAircraftModel &model, aviation::CAircraftSituationChange *changeOut, bool *setForOnGroundPosition)
Set ground elevation from elevation plane and guess ground.
virtual void enableReverseLookupMessages(ReverseLookupLogging enable)
Enable reverse lookup logging.
void removeAllAircraft()
Remove all aircraft in range.
void addReverseLookupMessage(const aviation::CCallsign &callsign, const CStatusMessage &message)
Reverse lookup messages.
virtual int updateMultipleAircraftEnabled(const aviation::CCallsignSet &callsigns, bool enabledForRendering)
Enable/disable aircraft.
virtual bool updateCG(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg)
Update the CG.
virtual bool isRemoteAircraftSupportingParts(const aviation::CCallsign &callsign) const
Is remote aircraft supporting parts?
virtual int getAircraftInRangeCount() const
Count remote aircraft.
bool hasTestAltitudeOffsetGlobalValue() const
Has test offset value?
bool testAddAltitudeOffset(const aviation::CCallsign &callsign, const physical_quantities::CLength &offset)
Offset for callsign.
void removedAircraft(const swift::misc::aviation::CCallsign &callsign)
An aircraft disappeared.
virtual int updateAircraftGroundElevation(const aviation::CCallsign &callsign, const geo::CElevationPlane &elevation, aviation::CAircraftSituation::GndElevationInfo info, bool *setForOnGroundPosition)
Update the ground elevation.
Comprehensive information of an aircraft.
void setPartsSynchronized(bool synchronized)
Set the synchronisation flag.
bool isPartsSynchronized() const
Have parts been synchronized with a remote client?
bool setCG(const physical_quantities::CLength &cg)
Set the center of gravity.
void setModelString(const QString &modelString)
Set model string.
void setSituation(const aviation::CAircraftSituation &situation)
Set situation. Won't overwrite the velocity unless it held the default value.
const aviation::CCallsign & getCallsign() const
Get callsign.
bool hasValidCallsign() const
Valid callsign?
const simulation::CAircraftModel & getModel() const
Get model (model used for mapping)
void setParts(const aviation::CAircraftParts &parts)
Set aircraft parts.
Value object encapsulating a list of aircraft.
Direct thread safe in memory access to remote aircraft.
static constexpr int MaxPartsAgePerCallsignSecs
How many seconds to keep parts for interpolation.
static const aviation::CCallsign & testAltitudeOffsetCallsign()
Wildcard callsign.
aviation::CAircraftParts getLatestAircraftParts(const aviation::CCallsign &callsign) const
Get the latest aircraft parts (if any, otherwise default)
static constexpr int MaxPartsPerCallsign
How many parts we keep per callsign.
static constexpr int MaxSituationsPerCallsign
How many situations we keep per callsign.
static void removeOutdatedParts(aviation::CAircraftPartsList &partsList)
Remove outdated aircraft parts, but never the most recent one.
virtual aviation::CAircraftPartsList remoteAircraftParts(const aviation::CCallsign &callsign) const =0
All parts (per callsign, time history)
SWIFT_MISC_EXPORT bool caseInsensitiveStringCompare(const QString &c1, const QString &c2)
Case insensitive string compare.
StatusSeverity
Status severities.
Definition: statusmessage.h:35
Milliseconds minimum/maximum/mean.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26