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  const QStringList &CRemoteAircraftProvider::getLogCategories()
22  {
24  return cats;
25  }
26 
27  CRemoteAircraftProvider::CRemoteAircraftProvider(QObject *parent) : QObject(parent), CIdentifiable(this) {}
28 
30  {
31  QReadLocker l(&m_lockAircraft);
32  const QList<CSimulatedAircraft> aircraftInRange = m_aircraftInRange.values();
33  l.unlock();
34  return { aircraftInRange };
35  }
36 
38  {
39  QReadLocker l(&m_lockAircraft);
40  const QList<CCallsign> callsigns = m_aircraftInRange.keys();
41  l.unlock();
42  return { callsigns };
43  }
44 
46  {
47  const CSimulatedAircraft aircraft = this->getAircraftInRange().findFirstByCallsign(callsign);
48  return aircraft;
49  }
50 
52  {
53  const CSimulatedAircraft aircraft(this->getAircraftInRangeForCallsign(callsign)); // threadsafe
54  return aircraft.getModel();
55  }
56 
58  {
59  static const CAircraftSituationList empty;
60  QReadLocker l(&m_lockSituations);
61  if (!m_situationsByCallsign.contains(callsign)) { return empty; }
62  return m_situationsByCallsign[callsign];
63  }
64 
66  {
67  const CAircraftSituationList situations = this->remoteAircraftSituations(callsign);
68  if (index < 0 || index >= situations.size()) { return CAircraftSituation::null(); }
69  return situations[index];
70  }
71 
74  {
75  const CAircraftSituationList situations = this->remoteAircraftSituations(callsign);
76  return situations.getOffsetMinMaxMean();
77  }
78 
80  {
81  QReadLocker l(&m_lockSituations);
82  const QList<CAircraftSituation> situations(m_latestSituationByCallsign.values());
83  l.unlock();
84  return { situations };
85  }
86 
88  {
89  QReadLocker l(&m_lockSituations);
90  const QList<CAircraftSituation> situations(m_latestOnGroundProviderElevation.values());
91  l.unlock();
92  return { situations };
93  }
94 
96  {
97  QReadLocker l(&m_lockSituations);
98  if (!m_situationsByCallsign.contains(callsign)) { return -1; }
99  return m_situationsByCallsign[callsign].size();
100  }
101 
103  {
104  static const CAircraftPartsList empty;
105  QReadLocker l(&m_lockParts);
106  if (!m_partsByCallsign.contains(callsign)) { return empty; }
107  return m_partsByCallsign[callsign];
108  }
109 
111  {
112  QReadLocker l(&m_lockParts);
113  if (!m_partsByCallsign.contains(callsign)) { return -1; }
114  return m_partsByCallsign[callsign].size();
115  }
116 
118  {
119  QReadLocker l(&m_lockParts);
120  return m_aircraftWithParts.contains(callsign);
121  }
122 
124  {
125  QReadLocker l(&m_lockParts);
126  return m_aircraftWithParts.size();
127  }
128 
130  {
131  QReadLocker l(&m_lockParts);
132  return m_aircraftWithParts;
133  }
134 
137  {
138  QReadLocker l(&m_lockChanges);
139  return m_changesByCallsign[callsign];
140  }
141 
143  {
144  QReadLocker l(&m_lockChanges);
145  return m_changesByCallsign[callsign].size();
146  }
147 
149  {
150  QReadLocker l(&m_lockAircraft);
151  return m_aircraftInRange.size();
152  }
153 
155  {
156  const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
157 
158  // locked members
159  {
160  QWriteLocker l(&m_lockParts);
161  m_partsByCallsign.clear();
162  m_aircraftWithParts.clear();
163  m_partsAdded = 0;
164  m_partsLastModified.clear();
165  }
166  {
167  QWriteLocker l(&m_lockSituations);
168  m_situationsByCallsign.clear();
169  m_latestSituationByCallsign.clear();
170  m_latestOnGroundProviderElevation.clear();
171  m_situationsAdded = 0;
172  m_situationsLastModified.clear();
173  m_testOffset.clear();
174  }
175  {
176  QWriteLocker l(&m_lockChanges);
177  m_changesByCallsign.clear();
178  }
179 
180  {
181  QWriteLocker l(&m_lockPartsHistory);
182  m_aircraftPartsMessages.clear();
183  }
184  {
185  QWriteLocker l(&m_lockMessages);
186  m_reverseLookupMessages.clear();
187  }
188  {
189  QWriteLocker l(&m_lockAircraft);
190  m_aircraftInRange.clear();
191  m_dbCGPerCallsign.clear();
192  }
193 
194  for (const CCallsign &cs : callsigns) { emit this->removedAircraft(cs); }
195  }
196 
198  {
199  QWriteLocker l(&m_lockMessages);
200  m_reverseLookupMessages.remove(callsign);
201  }
202 
204  {
205  if (this->isAircraftInRange(aircraft.getCallsign())) { return false; }
206 
207  // store
208  {
209  QWriteLocker l(&m_lockAircraft);
210  m_aircraftInRange.insert(aircraft.getCallsign(), aircraft);
211  }
212  emit this->addedAircraft(aircraft);
213  emit this->changedAircraftInRange();
214  return true;
215  }
216 
218  bool skipEqualValues)
219  {
220  Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
221  int c = 0;
222  {
223  QWriteLocker l(&m_lockAircraft);
224  if (!m_aircraftInRange.contains(callsign)) { return 0; }
225  c = m_aircraftInRange[callsign].apply(vm, skipEqualValues).size();
226  }
227  if (c > 0) { emit this->changedAircraftInRange(); }
228  return c;
229  }
230 
232  const CAircraftSituation &situation,
233  const CLength &distance, const CAngle &bearing)
234  {
235  Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
236  {
237  QWriteLocker l(&m_lockAircraft);
238  if (!m_aircraftInRange.contains(callsign)) { return false; }
239  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
240  aircraft.setSituation(situation);
241  if (!bearing.isNull()) { aircraft.setRelativeBearing(bearing); }
242  if (!distance.isNull()) { aircraft.setRelativeDistance(distance); }
243  }
244  return true;
245  }
246 
248  bool allowTestAltitudeOffset)
249  {
250  const CCallsign cs = situation.getCallsign();
251  if (cs.isEmpty()) { return situation; }
252 
253  // testing
254  if (CBuildConfig::isLocalDeveloperDebugBuild())
255  {
256  SWIFT_VERIFY_X(situation.getTimeOffsetMs() > 0, Q_FUNC_INFO, "Missing offset");
257  SWIFT_VERIFY_X(situation.isValidVectorRange(), Q_FUNC_INFO, "Invalid vector");
258  }
259 
260  // add altitude offset (for testing only)
261  CAircraftSituation situationCorrected(
262  allowTestAltitudeOffset ? this->addTestAltitudeOffsetToSituation(situation) : situation);
263 
264  // CG, model
265  const CAircraftModel aircraftModel = this->getAircraftInRangeModelForCallsign(cs);
266  if (situation.hasCG() && aircraftModel.getCG() != situation.getCG()) { this->updateCG(cs, situation.getCG()); }
267 
268  // list from new to old
269  CAircraftSituationList updatedSituations; // copy of updated situations
270  {
271  const qint64 now = QDateTime::currentMSecsSinceEpoch();
272  QWriteLocker lock(&m_lockSituations);
273  m_situationsAdded++;
274  m_situationsLastModified[cs] = now;
275  CAircraftSituationList &newSituationsList = m_situationsByCallsign[cs];
276  newSituationsList.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
277  const int situations = newSituationsList.size();
278  if (situations < 1)
279  {
280  newSituationsList.prefillLatestAdjustedFirst(situationCorrected,
282  }
283  else if (!situationCorrected.hasVelocity() && newSituationsList.front().hasVelocity())
284  {
285  return situationCorrected;
286  }
287  else
288  {
289  // newSituationsList.push_frontKeepLatestFirstIgnoreOverlapping(situationCorrected, true,
290  // IRemoteAircraftProvider::MaxSituationsPerCallsign);
291  newSituationsList.push_frontKeepLatestFirstAdjustOffset(
292  situationCorrected, true, IRemoteAircraftProvider::MaxSituationsPerCallsign);
293  newSituationsList.setAdjustedSortHint(CAircraftSituationList::AdjustedTimestampLatestFirst);
294  newSituationsList
295  .transferElevationForward(); // transfer elevations, will do nothing if elevations already exist
296 
297  // unify all inbound ground information
298  if (situation.hasInboundGroundDetails())
299  {
300  newSituationsList.setOnGroundDetails(situation.getOnGroundInfo().getGroundDetails());
301  }
302  }
303  m_latestSituationByCallsign[cs] = situationCorrected;
304 
305  // check sort order
306  if (CBuildConfig::isLocalDeveloperDebugBuild())
307  {
308  SWIFT_VERIFY_X(newSituationsList.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO,
309  "wrong adjusted sort order");
310  SWIFT_VERIFY_X(newSituationsList.isSortedLatestFirst(), Q_FUNC_INFO, "wrong sort order");
312  Q_FUNC_INFO, "Wrong size");
313  }
314 
315  if (!situation.hasInboundGroundDetails())
316  {
317  // first use a version without standard deviations to guess "on ground
318  const CAircraftSituationChange simpleChange(updatedSituations, situationCorrected.getCG(),
319  aircraftModel.isVtol(), true, false);
320 
321  // guess GND
322  simpleChange.guessOnGround(newSituationsList.front(), aircraftModel);
323  }
324  updatedSituations = m_situationsByCallsign[cs];
325 
326  } // lock
327 
328  // calculate change AFTER gnd. was guessed
329  Q_ASSERT_X(!updatedSituations.isEmpty(), Q_FUNC_INFO, "Missing situations");
330  const CAircraftSituationChange change(updatedSituations, situationCorrected.getCG(), aircraftModel.isVtol(),
331  true, true);
332  this->storeChange(change);
333 
334  // situation has been added
335  emit this->addedAircraftSituation(situationCorrected);
336 
337  // bye
338  return situationCorrected;
339  }
340 
342  bool removeOutdated)
343  {
344  SWIFT_VERIFY_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
345  if (callsign.isEmpty()) { return; }
346 
347  // list sorted from new to old
348  const qint64 ts = QDateTime::currentMSecsSinceEpoch();
349  CAircraftPartsList correctiveParts;
350  {
351  QWriteLocker lock(&m_lockParts);
352  m_partsAdded++;
353  m_partsLastModified[callsign] = ts;
354  CAircraftPartsList &partsList = m_partsByCallsign[callsign];
356  partsList.setAdjustedSortHint(CAircraftPartsList::AdjustedTimestampLatestFirst);
357 
358  // remove outdated parts (but never remove the most recent one)
359  if (removeOutdated) { IRemoteAircraftProvider::removeOutdatedParts(partsList); }
360  correctiveParts = partsList;
361 
362  // check sort order
363  Q_ASSERT_X(partsList.isSortedAdjustedLatestFirst(), Q_FUNC_INFO, "wrong sort order");
364  Q_ASSERT_X(partsList.size() <= IRemoteAircraftProvider::MaxPartsPerCallsign, Q_FUNC_INFO, "Wrong size");
365  } // lock
366 
367  // adjust gnd.flag from parts
368  if (!correctiveParts.isEmpty())
369  {
370  QWriteLocker lock(&m_lockSituations);
371  CAircraftSituationList &situationList = m_situationsByCallsign[callsign];
372  const int c = situationList.adjustGroundFlag(parts);
373  if (c > 0) { m_situationsLastModified[callsign] = ts; }
374  }
375 
376  // update aircraft
377  {
378  QWriteLocker l(&m_lockAircraft);
379  if (m_aircraftInRange.contains(callsign))
380  {
381  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
382  aircraft.setParts(parts);
383  aircraft.setPartsSynchronized(true);
384  }
385  }
386 
387  // update parts
388  {
389  // aircraft supporting parts
390  QWriteLocker l(&m_lockParts);
391  m_aircraftWithParts.insert(callsign); // mark as callsign which supports parts
392  }
393 
394  emit this->addedAircraftParts(callsign, parts);
395  }
396 
397  void CRemoteAircraftProvider::storeAircraftParts(const CCallsign &callsign, const QJsonObject &jsonObject,
398  qint64 currentOffsetMs)
399  {
400  const CSimulatedAircraft remoteAircraft(this->getAircraftInRangeForCallsign(callsign));
401  const bool isFull = jsonObject.value(CAircraftParts::attributeNameIsFullJson()).toBool();
402  const bool validCs = remoteAircraft.hasValidCallsign();
403  if (!validCs)
404  {
405  if (!isFull) { return; } // incremental parts broadcasting
406  return; // suspicious
407  }
408 
409  // If we are not yet synchronized, we throw away any incremental packet
410  if (!remoteAircraft.isPartsSynchronized() && !isFull) { return; }
411 
412  CAircraftParts parts;
413  try
414  {
415  if (isFull)
416  {
417  if (CBuildConfig::isLocalDeveloperDebugBuild())
418  {
419  // validation in dev.env.
420  const int attributes = jsonObject.size();
421  const bool correctCount = (attributes == CAircraftParts::attributesCountFullJson);
422  SWIFT_VERIFY_X(correctCount || !CBuildConfig::isLocalDeveloperDebugBuild(), Q_FUNC_INFO,
423  "Wrong full aircraft parts");
424  if (!correctCount)
425  {
426  CLogMessage(this).warning(u"Wrong full parts attributes, %1 (expected %2)")
427  << attributes << CAircraftParts::attributesCountFullJson;
429  if (attributes < 3)
430  {
431  // EXPERIMENTAL
432  if (attributes < 1) { return; }
433 
434  // treat as incremental
435  CLogMessage(this).warning(u"Treating %1 attributes as incremental") << attributes;
436  parts = this->remoteAircraftParts(callsign).frontOrDefault(); // latest
437  const QJsonObject config = applyIncrementalObject(parts.toJson(), jsonObject);
438  parts.convertFromJson(config);
439  }
440  }
441  }
442  parts.convertFromJson(jsonObject);
443  }
444  else
445  {
446  // incremental update
447  parts = this->remoteAircraftParts(callsign).frontOrDefault(); // latest
448  const QJsonObject config = applyIncrementalObject(parts.toJson(), jsonObject);
449  parts.convertFromJson(config);
450  }
451  }
452  catch (const CJsonException &ex)
453  {
454  CStatusMessage message = CStatusMessage::fromJsonException(ex, this, "Invalid parts packet");
456  CLogMessage::preformatted(message);
457  }
458 
459  // make sure in any case right time and correct details
460  parts.setCurrentUtcTime();
461  parts.setTimeOffsetMs(currentOffsetMs);
462  parts.setPartsDetails(CAircraftParts::FSDAircraftParts);
463 
464  // store part history (parts always absolute)
465  this->storeAircraftParts(callsign, parts, false);
466 
467  // history
468  if (this->isAircraftPartsHistoryEnabled())
469  {
470  const QJsonDocument doc(jsonObject);
471  const QString partsAsString = doc.toJson(QJsonDocument::Compact);
472  const CStatusMessage message(this, CStatusMessage::SeverityInfo,
473  callsign.isEmpty() ? callsign.toQString() + ": " + partsAsString.trimmed() :
474  partsAsString.trimmed());
475 
476  QReadLocker l(&m_lockPartsHistory);
477  if (m_aircraftPartsMessages.contains(callsign))
478  {
479  CStatusMessageList &msgs = m_aircraftPartsMessages[callsign];
480  msgs.push_back(message);
481  }
482  else { m_aircraftPartsMessages.insert(callsign, message); }
483  }
484  }
485 
486  void CRemoteAircraftProvider::storeChange(const CAircraftSituationChange &change)
487  {
488  // a change with the same timestamp will be replaced
489  const CCallsign cs(change.getCallsign());
490  QWriteLocker lock(&m_lockChanges);
491  CAircraftSituationChangeList &changeList = m_changesByCallsign[cs];
493  }
494 
496  const CAircraftSituationChange &change,
497  const CAircraftModel &aircraftModel)
498  {
499  if (aircraftModel.hasCG() && !situation.hasCG()) { situation.setCG(aircraftModel.getCG()); }
500  if (!situation.shouldGuessOnGround()) { return false; }
501  return change.guessOnGround(situation, aircraftModel);
502  }
503 
504  bool CRemoteAircraftProvider::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering)
505  {
506  // here just synonym
507  return this->setAircraftEnabledFlag(callsign, enabledForRendering);
508  }
509 
510  bool CRemoteAircraftProvider::setAircraftEnabledFlag(const CCallsign &callsign, bool enabledForRendering)
511  {
512  QWriteLocker l(&m_lockAircraft);
513  if (!m_aircraftInRange.contains(callsign)) { return false; }
514  return m_aircraftInRange[callsign].setEnabled(enabledForRendering);
515  }
516 
517  int CRemoteAircraftProvider::updateMultipleAircraftEnabled(const CCallsignSet &callsigns, bool enabledForRendering)
518  {
519  if (callsigns.isEmpty()) { return 0; }
520  QWriteLocker l(&m_lockAircraft);
521  int c = 0;
522  for (const CCallsign &cs : callsigns)
523  {
524  if (!m_aircraftInRange.contains(cs)) { continue; }
525  if (m_aircraftInRange[cs].setEnabled(enabledForRendering)) { c++; }
526  }
527  return c;
528  }
529 
531  const CIdentifier &originator)
532  {
533  if (CIdentifiable::isMyIdentifier(originator)) { return false; }
534  const CPropertyIndexVariantMap vm(CSimulatedAircraft::IndexModel, CVariant::from(model));
535  const int c = this->updateAircraftInRange(callsign, vm);
536  return c > 0;
537  }
538 
540  const CIdentifier &originator)
541  {
542  if (CIdentifiable::isMyIdentifier(originator)) { return false; }
543  const CPropertyIndexVariantMap vm(CSimulatedAircraft::IndexNetworkModel, CVariant::from(model));
544  const int c = this->updateAircraftInRange(callsign, vm);
545  return c > 0;
546  }
547 
548  bool CRemoteAircraftProvider::updateFastPositionEnabled(const CCallsign &callsign, bool enableFastPositonUpdates)
549  {
550  QWriteLocker l(&m_lockAircraft);
551  if (!m_aircraftInRange.contains(callsign)) { return false; }
552  return m_aircraftInRange[callsign].setFastPositionUpdates(enableFastPositonUpdates);
553  }
554 
555  bool CRemoteAircraftProvider::updateAircraftRendered(const CCallsign &callsign, bool rendered)
556  {
557  QWriteLocker l(&m_lockAircraft);
558  if (!m_aircraftInRange.contains(callsign)) { return false; }
559  return m_aircraftInRange[callsign].setRendered(rendered);
560  }
561 
563  {
564  if (callsigns.isEmpty()) { return 0; }
565  int c = 0;
566  for (const CCallsign &cs : callsigns)
567  {
568  if (!m_aircraftInRange.contains(cs)) { continue; }
569  if (m_aircraftInRange[cs].setRendered(rendered)) { c++; }
570  }
571  return c;
572  }
573 
575  const CElevationPlane &elevation,
577  bool *setForOnGroundPosition)
578  {
579  if (!this->isAircraftInRange(callsign)) { return 0; }
580 
581  // update aircraft situation
582  const qint64 now = QDateTime::currentMSecsSinceEpoch();
583  const CAircraftModel model = this->getAircraftInRangeModelForCallsign(callsign);
585  bool setForOnGndPosition = false;
586 
587  int updated = 0;
588  {
589  QWriteLocker l(&m_lockSituations);
590  CAircraftSituationList &situations = m_situationsByCallsign[callsign];
591  if (situations.isEmpty()) { return 0; }
592  updated = setGroundElevationCheckedAndGuessGround(situations, elevation, info, model, &change,
593  &setForOnGndPosition);
594  if (updated < 1) { return 0; }
595  m_situationsLastModified[callsign] = now;
596  const CAircraftSituation latestSituation = situations.front();
597  if (info == CAircraftSituation::FromProvider && latestSituation.isOnGround())
598  {
599  m_latestOnGroundProviderElevation[callsign] = latestSituation;
600  }
601  }
602 
603  // update change
604  if (!change.isNull()) { this->storeChange(change); }
605 
606  // aircraft updates
607  QWriteLocker l(&m_lockAircraft);
608  if (m_aircraftInRange.contains(callsign))
609  {
610  m_aircraftInRange[callsign].setGroundElevationChecked(elevation, info);
611  }
612 
613  if (setForOnGroundPosition) { *setForOnGroundPosition = setForOnGndPosition; }
614  return updated; // updated situations
615  }
616 
617  bool CRemoteAircraftProvider::updateCG(const CCallsign &callsign, const CLength &cg)
618  {
619  QWriteLocker l(&m_lockAircraft);
620  if (!m_aircraftInRange.contains(callsign)) { return false; }
621  m_aircraftInRange[callsign].setCG(cg);
622  return true;
623  }
624 
626  const QString &modelString)
627  {
628  QWriteLocker l(&m_lockAircraft);
629  if (!m_aircraftInRange.contains(callsign)) { return false; }
630  CSimulatedAircraft &aircraft = m_aircraftInRange[callsign];
631  if (!cg.isNull()) { aircraft.setCG(cg); }
632  if (!modelString.isEmpty()) { aircraft.setModelString(modelString); }
633  return true;
634  }
635 
637  {
638  CCallsignSet callsigns;
639  if (modelString.isEmpty()) { return callsigns; }
640 
641  QWriteLocker l(&m_lockAircraft);
642  for (CSimulatedAircraft &aircraft : m_aircraftInRange)
643  {
644  if (caseInsensitiveStringCompare(aircraft.getModelString(), modelString))
645  {
646  aircraft.setCG(cg);
647  callsigns.push_back(aircraft.getCallsign());
648  }
649  }
650  return callsigns;
651  }
652 
654  {
655  QReadLocker l(&m_lockAircraft);
656  return m_dbCGPerCallsign.contains(callsign) ? m_dbCGPerCallsign[callsign] : CLength::null();
657  }
658 
660  {
661  QReadLocker l(&m_lockAircraft);
662  return m_dbCGPerCallsign.contains(modelString) ? m_dbCGPerCallsign[modelString] : CLength::null();
663  }
664 
665  void CRemoteAircraftProvider::rememberCGFromDB(const CLength &cgFromDB, const CCallsign &callsign)
666  {
667  QWriteLocker l(&m_lockAircraft);
668  m_dbCGPerCallsign[callsign] = cgFromDB;
669  }
670 
671  void CRemoteAircraftProvider::rememberCGFromDB(const CLength &cgFromDB, const QString &modelString)
672  {
673  QWriteLocker l(&m_lockAircraft);
674  m_dbCGPerModelString[modelString] = cgFromDB;
675  }
676 
678  {
679  const CCallsignSet callsigns = this->getAircraftInRangeCallsigns();
680  QWriteLocker l(&m_lockAircraft);
681  for (const CCallsign &cs : callsigns) { m_aircraftInRange[cs].setRendered(false); }
682  }
683 
685  {
686  QWriteLocker l(&m_lockMessages);
687  m_enableReverseLookupMsgs = enable;
688  }
689 
691  {
692  QReadLocker l(&m_lockMessages);
693  return m_enableReverseLookupMsgs;
694  }
695 
697  {
698  QReadLocker l(&m_lockMessages);
699  return m_reverseLookupMessages.value(callsign);
700  }
701 
703  const CStatusMessageList &messages)
704  {
705  if (callsign.isEmpty()) { return; }
706  if (messages.isEmpty()) { return; }
707  QWriteLocker l(&m_lockMessages);
708  if (!m_enableReverseLookupMsgs) { return; }
709  if (m_reverseLookupMessages.contains(callsign))
710  {
711  CStatusMessageList &msgs = m_reverseLookupMessages[callsign];
712  msgs.push_back(messages);
713  }
714  else { m_reverseLookupMessages.insert(callsign, messages); }
715  }
716 
718  {
719  if (callsign.isEmpty()) { return; }
720  if (message.isEmpty()) { return; }
721  this->addReverseLookupMessages(callsign, CStatusMessageList({ message }));
722  }
723 
726  {
727  if (callsign.isEmpty()) { return; }
728  if (message.isEmpty()) { return; }
729  const CStatusMessage m = CCallsign::logMessage(callsign, message, getLogCategories(), severity);
730  this->addReverseLookupMessage(callsign, m);
731  }
732 
734 
736  {
737  if (callsign.isEmpty()) { return false; }
738  QReadLocker l(&m_lockSituations);
739  return m_testOffset.contains(callsign);
740  }
741 
743  {
744  QReadLocker l(&m_lockSituations);
745  return m_testOffset.contains(testAltitudeOffsetCallsign());
746  }
747 
750  {
751  const CCallsign cs(situation.getCallsign());
752  const bool globalOffset = this->hasTestAltitudeOffsetGlobalValue();
753  if (!globalOffset && !this->hasTestAltitudeOffset(cs)) { return situation; }
754 
755  QReadLocker l(&m_lockSituations);
756  const CLength os =
757  m_testOffset.contains(cs) ? m_testOffset.value(cs) : m_testOffset.value(testAltitudeOffsetCallsign());
758  if (os.isNull() || os.isZeroEpsilonConsidered()) { return situation; }
759  return situation.withAltitudeOffset(os);
760  }
761 
762  ReverseLookupLogging CRemoteAircraftProvider::whatToReverseLog() const
763  {
764  QReadLocker l(&m_lockMessages);
765  return m_enableReverseLookupMsgs;
766  }
767 
769  const CElevationPlane &elevationPlane,
771  const CAircraftModel &model,
772  CAircraftSituationChange *changeOut,
773  bool *setForOnGroundPosition)
774  {
775  if (setForOnGroundPosition) { *setForOnGroundPosition = false; } // set a default
776  if (elevationPlane.isNull()) { return 0; }
777  if (situations.isEmpty()) { return 0; }
778 
779  // the change has the timestamps of the latest situation
780  // Q_ASSERT_X(situations.m_tsAdjustedSortHint == CAircraftSituationList::AdjustedTimestampLatestFirst ||
781  // situations.isSortedAdjustedLatestFirstWithoutNullPositions(), Q_FUNC_INFO, "Need sorted situations without
782  // NULL positions");
783  const CAircraftSituationChange simpleChange(situations, model.getCG(), model.isVtol(), true, false);
784  int c = 0; // changed elevations
785  bool latest = true;
786  bool setForOnGndPosition = false;
787 
788  for (CAircraftSituation &s : situations)
789  {
790  const bool set = s.setGroundElevationChecked(elevationPlane, info);
791  if (set)
792  {
793  // simpleChange is only valid for the latest situation
794  // this will do nothing if not appropriate!
795  const bool guessed = (latest ? simpleChange : CAircraftSituationChange::null()).guessOnGround(s, model);
796  Q_UNUSED(guessed)
797  c++;
798 
799  // if not guessed and "on ground" we mark the "elevation"
800  // as an elevation for a ground position
801  if (!setForOnGndPosition && s.hasInboundGroundDetails() && s.isOnGround())
802  {
803  setForOnGndPosition = true;
804  }
805  }
806  latest = false; // only first pos. is "the latest" one
807  }
808 
809  if (setForOnGroundPosition) { *setForOnGroundPosition = setForOnGndPosition; }
810  if (changeOut)
811  {
812  const CAircraftSituationChange change(situations, model.getCG(), model.isVtol(), true, true);
813  *changeOut = change;
814  }
815 
816  return c;
817  }
818 
820  {
821  QReadLocker l(&m_lockPartsHistory);
822  return m_aircraftPartsMessages.value(callsign);
823  }
824 
826  {
827  QReadLocker l(&m_lockPartsHistory);
828  return m_enableAircraftPartsHistory;
829  }
830 
832  {
833  QWriteLocker l(&m_lockPartsHistory);
834  m_enableAircraftPartsHistory = enabled;
835  }
836 
838  {
839  QReadLocker l(&m_lockSituations);
840  return m_situationsAdded;
841  }
842 
844  {
845  QReadLocker l(&m_lockSituations);
846  return m_situationsLastModified.value(callsign, -1);
847  }
848 
850  {
851  QReadLocker l(&m_lockParts);
852  return m_partsLastModified.value(callsign, -1);
853  }
854 
856  const CLength &range, int minValues,
857  int sufficientValues) const
858  {
859  const CAircraftSituationList situations = this->latestOnGroundProviderElevations();
860  return situations.averageElevationOfTaxiingOnGroundAircraft(reference, range, minValues, sufficientValues);
861  }
862 
864  {
865  const bool remove = offset.isNull() || offset.isZeroEpsilonConsidered();
866  QWriteLocker l(&m_lockSituations);
867  if (remove)
868  {
869  m_testOffset.remove(callsign);
870  return false;
871  }
872 
873  m_testOffset[callsign] = offset;
874  return true;
875  }
876 
878  {
879  QReadLocker l(&m_lockParts);
880  return m_partsAdded;
881  }
882 
884  {
885  if (callsign.isEmpty()) { return false; }
886  QReadLocker l(&m_lockAircraft);
887  return m_aircraftInRange.contains(callsign);
888  }
889 
891  {
892  if (callsign.isEmpty()) { return false; }
893  const CSimulatedAircraft aircraft = this->getAircraftInRangeForCallsign(callsign);
894  return aircraft.isVtol();
895  }
896 
898  QObject *receiver, std::function<void(const CAircraftSituation &)> addedSituationFunction,
899  std::function<void(const CCallsign &, const CAircraftParts &)> addedPartsFunction,
900  std::function<void(const CCallsign &)> removedAircraftFunction,
901  std::function<void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot)
902  {
903  Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver");
904 
905  // bind does not allow to define connection type, so we use receiver as workaround
906  const QMetaObject::Connection uc; // unconnected
907  const QMetaObject::Connection c1 = addedSituationFunction ?
909  addedSituationFunction, Qt::QueuedConnection) :
910  uc;
911  Q_ASSERT_X(c1 || !addedSituationFunction, Q_FUNC_INFO, "connect failed");
912  const QMetaObject::Connection c2 = addedPartsFunction ?
914  addedPartsFunction, Qt::QueuedConnection) :
915  uc;
916  Q_ASSERT_X(c2 || !addedPartsFunction, Q_FUNC_INFO, "connect failed");
917  const QMetaObject::Connection c3 = removedAircraftFunction ?
919  removedAircraftFunction, Qt::QueuedConnection) :
920  uc;
921  Q_ASSERT_X(c3 || !removedAircraftFunction, Q_FUNC_INFO, "connect failed");
922  const QMetaObject::Connection c4 = aircraftSnapshotSlot ?
924  receiver, aircraftSnapshotSlot, Qt::QueuedConnection) :
925  uc;
926  Q_ASSERT_X(c4 || !aircraftSnapshotSlot, Q_FUNC_INFO, "connect failed");
927  return QList<QMetaObject::Connection>({ c1, c2, c3, c4 });
928  }
929 
931  {
932  {
933  QWriteLocker l1(&m_lockParts);
934  m_partsByCallsign.remove(callsign);
935  m_aircraftWithParts.remove(callsign);
936  m_partsLastModified.remove(callsign);
937  }
938  {
939  QWriteLocker l2(&m_lockSituations);
940  m_situationsByCallsign.remove(callsign);
941  m_latestSituationByCallsign.remove(callsign);
942  m_latestOnGroundProviderElevation.remove(callsign);
943  m_situationsLastModified.remove(callsign);
944  }
945  {
946  QWriteLocker l4(&m_lockPartsHistory);
947  m_aircraftPartsMessages.remove(callsign);
948  }
949  bool removedCallsign = false;
950  {
951  QWriteLocker l(&m_lockAircraft);
952  m_dbCGPerCallsign.remove(callsign);
953  const int c = m_aircraftInRange.remove(callsign);
954  removedCallsign = c > 0;
955  }
956  return removedCallsign;
957  }
958 
960  {
961  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
962  return this->provider()->getAircraftInRange();
963  }
964 
966  {
967  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
968  return this->provider()->isAircraftInRange(callsign);
969  }
970 
972  {
973  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
974  return this->provider()->isVtolAircraft(callsign);
975  }
976 
978  {
979  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
980  return this->provider()->getAircraftInRangeCount();
981  }
982 
984  {
985  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
986  return this->provider()->getAircraftInRangeCallsigns();
987  }
988 
990  {
991  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
992  return this->provider()->getAircraftInRangeForCallsign(callsign);
993  }
994 
996  {
997  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
998  return this->provider()->getAircraftInRangeModelForCallsign(callsign);
999  }
1000 
1002  {
1003  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1004  return this->provider()->getLatestAirspaceAircraftSnapshot();
1005  }
1006 
1009  {
1010  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1011  return this->provider()->remoteAircraftSituations(callsign);
1012  }
1013 
1015  {
1016  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1017  return this->provider()->remoteAircraftSituation(callsign, index);
1018  }
1019 
1021  {
1022  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1023  return this->provider()->latestRemoteAircraftSituations();
1024  }
1025 
1027  {
1028  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1029  return this->provider()->latestOnGroundProviderElevations();
1030  }
1031 
1033  {
1034  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1035  return this->provider()->remoteAircraftSituationChanges(callsign);
1036  }
1037 
1039  {
1040  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1041  return this->provider()->remoteAircraftParts(callsign);
1042  }
1043 
1045  {
1046  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1047  return this->provider()->remoteAircraftPartsCount(callsign);
1048  }
1049 
1051  {
1052  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1053  return this->provider()->remoteAircraftSupportingParts();
1054  }
1055 
1057  {
1058  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1059  return this->provider()->remoteAircraftSituationsCount(callsign);
1060  }
1061 
1063  const CIdentifier &originator)
1064  {
1065  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1066  return this->provider()->updateAircraftModel(callsign, model, originator);
1067  }
1068 
1070  const CIdentifier &originator)
1071  {
1072  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1073  return this->provider()->updateAircraftNetworkModel(callsign, model, originator);
1074  }
1075 
1076  bool CRemoteAircraftAware::updateAircraftRendered(const CCallsign &callsign, bool rendered)
1077  {
1078  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1079  return this->provider()->updateAircraftRendered(callsign, rendered);
1080  }
1081 
1083  {
1084  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1085  return this->provider()->updateMultipleAircraftRendered(callsigns, rendered);
1086  }
1087 
1090  bool *updatedAircraftGroundElevation)
1091  {
1092  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1093  return this->provider()->updateAircraftGroundElevation(callsign, elevation, info,
1094  updatedAircraftGroundElevation);
1095  }
1096 
1097  bool CRemoteAircraftAware::updateCG(const CCallsign &callsign, const CLength &cg)
1098  {
1099  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1100  return this->provider()->updateCG(callsign, cg);
1101  }
1102 
1104  {
1105  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1106  return this->provider()->updateCGForModel(modelString, cg);
1107  }
1108 
1110  const QString &modelString)
1111  {
1112  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1113  return this->provider()->updateCGAndModelString(callsign, cg, modelString);
1114  }
1115 
1117  {
1118  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1119  this->provider()->updateMarkAllAsNotRendered();
1120  }
1121 
1123  {
1124  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1125  return this->provider()->aircraftSituationsAdded();
1126  }
1127 
1129  {
1130  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1131  return this->provider()->aircraftPartsAdded();
1132  }
1133 
1135  {
1136  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1137  return this->provider()->situationsLastModified(callsign);
1138  }
1139 
1141  {
1142  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1143  return this->provider()->partsLastModified(callsign);
1144  }
1145 
1147  const CLength &range, int minValues) const
1148  {
1149  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1150  return this->provider()->averageElevationOfNonMovingAircraft(reference, range, minValues);
1151  }
1152 
1154  {
1155  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1156  return this->provider()->isRemoteAircraftSupportingParts(callsign);
1157  }
1158 
1160  {
1161  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1162  return this->provider()->getRemoteAircraftSupportingPartsCount();
1163  }
1164 
1165  bool CRemoteAircraftAware::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering)
1166  {
1167  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1168  return this->provider()->updateAircraftEnabled(callsign, enabledForRendering);
1169  }
1170 
1171  bool CRemoteAircraftAware::setAircraftEnabledFlag(const CCallsign &callsign, bool enabledForRendering)
1172  {
1173  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1174  return this->provider()->setAircraftEnabledFlag(callsign, enabledForRendering);
1175  }
1176 
1177  bool CRemoteAircraftAware::updateMultipleAircraftEnabled(const CCallsignSet &callsigns, bool enabledForRendering)
1178  {
1179  Q_ASSERT_X(this->provider(), Q_FUNC_INFO, "No object available");
1180  return this->provider()->updateMultipleAircraftEnabled(callsigns, enabledForRendering);
1181  }
1182 
1184  {
1185  static const CAircraftParts empty;
1186  const CAircraftPartsList parts = this->remoteAircraftParts(callsign);
1187  return parts.isEmpty() ? empty : parts.latestObject();
1188  }
1189 
1191  {
1192  // remove all outdated parts, but keep at least one
1193  if (partsList.isEmpty()) { return; }
1194 
1195  // we expect the latest value at front
1196  // but to make sure we do the search
1197  const qint64 ts = partsList.latestTimestampMsecsSinceEpoch() - MaxPartsAgePerCallsignSecs * 1000;
1198  partsList.removeBefore(ts);
1199  Q_ASSERT_X(!partsList.isEmpty(), Q_FUNC_INFO, "Need at least 1 value");
1200  }
1201 
1203  {
1204  static const CCallsign wildcard("ZZZZ");
1205  return wildcard;
1206  }
1207 } // 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:144
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)
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)
swift::misc::CStatusMessageList getReverseLookupMessages(const swift::misc::aviation::CCallsign &callsign) const
Get reverse lookup meesages.
bool isAircraftInRange(const aviation::CCallsign &callsign) const
Is aircraft in range?
int remoteAircraftSituationChangesCount(const aviation::CCallsign &callsign) const
Aircraft changes count.
int updateMultipleAircraftRendered(const aviation::CCallsignSet &callsigns, bool rendered)
Set aircraft rendered.
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.
bool updateCGAndModelString(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg, const QString &modelString)
Update the CG and model string.
bool setAircraftEnabledFlag(const swift::misc::aviation::CCallsign &callsign, bool enabledForRendering)
Just set enable/disable aircraft flag, no further logic.
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.
int getRemoteAircraftSupportingPartsCount() const
Number of aircraft supporting parts.
bool removeAircraft(const aviation::CCallsign &callsign)
Remove all aircraft in range.
qint64 situationsLastModified(const aviation::CCallsign &callsign) const
When last modified.
void changedAircraftInRange()
Aircraft were changed.
bool isAircraftPartsHistoryEnabled() const
Is storing aircraft parts history enabled?
int remoteAircraftSituationsCount(const aviation::CCallsign &callsign) const
Number of remote aircraft situations for callsign.
aviation::CAircraftSituation remoteAircraftSituation(const aviation::CCallsign &callsign, int index) const
Rendered aircraft situations (per callsign and index)
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.
aviation::CAircraftSituationList remoteAircraftSituations(const aviation::CCallsign &callsign) const
Rendered aircraft situations (per callsign, time history)
bool isVtolAircraft(const aviation::CCallsign &callsign) const
Is VTOL aircraft?
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.
MillisecondsMinMaxMean remoteAircraftSituationsTimestampDifferenceMinMaxMean(const aviation::CCallsign &callsign) const
Average update time.
int updateAircraftInRange(const aviation::CCallsign &callsign, const CPropertyIndexVariantMap &vm, bool skipEqualValues=true)
Update aircraft.
aviation::CCallsignSet updateCGForModel(const QString &modelString, const physical_quantities::CLength &cg)
Update the CG for this model string.
void enableAircraftPartsHistory(bool enabled)
Enable storing of aircraft parts history.
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.
int remoteAircraftPartsCount(const aviation::CCallsign &callsign) const
All parts (per callsign, time history)
bool updateAircraftEnabled(const aviation::CCallsign &callsign, bool enabledForRendering)
Enable/disable aircraft and follow up logic like sending signals.
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.
bool guessOnGroundAndUpdateModelCG(aviation::CAircraftSituation &situation, const aviation::CAircraftSituationChange &change, const CAircraftModel &aircraftModel)
Guess situation "on ground" and update model's CG if applicable.
aviation::CAircraftSituationList latestRemoteAircraftSituations() const
Latest aircraft situation for all callsigns.
void airspaceAircraftSnapshot(const swift::misc::simulation::CAirspaceAircraftSnapshot &snapshot)
New aircraft snapshot.
bool updateAircraftNetworkModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change network model.
bool updateAircraftModel(const aviation::CCallsign &callsign, const CAircraftModel &model, const CIdentifier &originator)
Change model.
void addedAircraftSituation(const swift::misc::aviation::CAircraftSituation &situation)
Situation added.
physical_quantities::CLength getCGFromDB(const aviation::CCallsign &callsign) const
CG values from DB.
qint64 partsLastModified(const aviation::CCallsign &callsign) const
When last modified.
bool updateFastPositionEnabled(const aviation::CCallsign &callsign, bool enableFastPositonUpdates)
Change fast position updates.
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...
bool updateAircraftRendered(const aviation::CCallsign &callsign, bool rendered)
Set aircraft rendered.
aviation::CAircraftSituationList latestOnGroundProviderElevations() const
Latest aircraft situation "on ground" having a provider elevation.
ReverseLookupLogging whatToReverseLog() const
What to log?
aviation::CCallsignSet getAircraftInRangeCallsigns() const
Unique callsigns for aircraft in range.
ReverseLookupLogging isReverseLookupMessagesEnabled() const
Enabled reverse lookup logging?
CAircraftModel getAircraftInRangeModelForCallsign(const aviation::CCallsign &callsign) const
Aircraft model for callsign.
CSimulatedAircraft getAircraftInRangeForCallsign(const aviation::CCallsign &callsign) const
Aircraft for callsign.
int aircraftSituationsAdded() const
Number of situations added.
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.
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.
int updateMultipleAircraftEnabled(const aviation::CCallsignSet &callsigns, bool enabledForRendering)
Enable/disable aircraft.
bool updateCG(const aviation::CCallsign &callsign, const physical_quantities::CLength &cg)
Update the CG.
bool isRemoteAircraftSupportingParts(const aviation::CCallsign &callsign) const
Is remote aircraft supporting parts?
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.
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.
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
qint64 currentMSecsSinceEpoch()
void clear()
bool contains(const Key &key) const const
QHash< Key, T >::iterator insert(const Key &key, const T &value)
QList< Key > keys() const const
bool remove(const Key &key)
qsizetype size() const const
T value(const Key &key) const const
QList< T > values() const const
QByteArray toJson(QJsonDocument::JsonFormat format) const const
qsizetype size() const const
QJsonValue value(QLatin1StringView key) const const
bool toBool(bool defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void unlock()
bool isEmpty() const const
QString trimmed() const const
QueuedConnection
Milliseconds minimum/maximum/mean.
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26