mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 17:35:34 +08:00
Reflecting discussed changes for interpolation performance refs #386
(based on FSX testing) * Only send changed situation to SIM * Split sending of parts / situations * Only send parts with a reduced frequency (means slower as positions) * Mark geodetic height as null for default values (the value is usually unavailable) * Fixed altitude to MSL for network data * Trace which aircrafts support aircraft parts via network * Renamed insert_fron push_front (as proposed by Roland) Status quo / lessons learnt * On slower PCs jitter is still noticed for interpolated aircraft. * Running interpolation in an independent process (aka core, not in GUI) reduced load dependencies => it seems to make sense to run driver in own thread * The onGround flag in parts seems clumsy as it required to retrieve parts for position updates * In interpolation performance really matters
This commit is contained in:
@@ -120,9 +120,13 @@ namespace BlackCore
|
||||
std::function<void(const CCallsign &)> removedAircraftSlot
|
||||
)
|
||||
{
|
||||
bool s1 = connect(this, &CAirspaceMonitor::addedRemoteAircraftSituation, situationSlot);
|
||||
// bool s1 = connect(this, &CAirspaceMonitor::addedRemoteAircraftSituation, situationSlot);
|
||||
bool s1 = connect(this->m_network, &INetwork::aircraftPositionUpdate, situationSlot);
|
||||
Q_ASSERT(s1);
|
||||
bool s2 = connect(this, &CAirspaceMonitor::addedRemoteAircraftParts, partsSlot);
|
||||
Q_ASSERT(s2);
|
||||
bool s3 = connect(this, &CAirspaceMonitor::removedRemoteAircraft, removedAircraftSlot);
|
||||
Q_ASSERT(s3);
|
||||
return s1 && s2 && s3;
|
||||
}
|
||||
|
||||
@@ -747,16 +751,18 @@ namespace BlackCore
|
||||
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
|
||||
}
|
||||
|
||||
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CCallsign &callsign, const CAircraftSituation &situation, const CTransponder &transponder)
|
||||
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder)
|
||||
{
|
||||
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
|
||||
if (!this->m_connected) { return; }
|
||||
|
||||
CCallsign callsign(situation.getCallsign());
|
||||
Q_ASSERT(!callsign.isEmpty());
|
||||
|
||||
// store situation history
|
||||
CAircraftSituation situationWithCallsign(situation);
|
||||
situationWithCallsign.setCallsign(callsign);
|
||||
// this->m_aircraftSituations.insert_front(situationWithCallsign);
|
||||
// this->m_aircraftSituations.insert_front(situation);
|
||||
// this->m_aircraftSituations.removeOlderThanNowMinusOffset(AircraftSituationsRemovedOffsetMs);
|
||||
emit this->addedRemoteAircraftSituation(situation);
|
||||
|
||||
bool exists = this->m_aircraftInRange.containsCallsign(callsign);
|
||||
if (!exists)
|
||||
@@ -829,7 +835,6 @@ namespace BlackCore
|
||||
this->m_aircraftWatchdog.resetCallsign(callsign);
|
||||
}
|
||||
|
||||
emit this->addedRemoteAircraftSituation(situationWithCallsign);
|
||||
emit this->changedAircraftInRange();
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace BlackCore
|
||||
|
||||
private slots:
|
||||
//! Create aircraft in range, this is the only place where a new aircraft should be added
|
||||
void ps_aircraftUpdateReceived(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
|
||||
void ps_aircraftUpdateReceived(const BlackMisc::Aviation::CAircraftSituation &situation, const BlackMisc::Aviation::CTransponder &transponder);
|
||||
|
||||
void ps_realNameReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname);
|
||||
void ps_capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, quint32 flags);
|
||||
|
||||
@@ -35,48 +35,19 @@ namespace BlackCore
|
||||
Q_UNUSED(c);
|
||||
}
|
||||
|
||||
QList<CAircraftSituationList> IInterpolator::getSituationsTimeSplit(const CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const
|
||||
CAircraftSituationList IInterpolator::getInterpolatedSituations(qint64 currentTimeMsSinceEpoch)
|
||||
{
|
||||
QReadLocker l(&m_situationsLock);
|
||||
static const QList<CAircraftSituationList> empty({ CAircraftSituationList(), CAircraftSituationList() });
|
||||
if (!this->m_situationsByCallsign.contains(callsign)) { return empty; }
|
||||
return this->m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
}
|
||||
|
||||
bool IInterpolator::hasEnoughAircraftSituations(const CCallsign &callsign) const
|
||||
{
|
||||
QReadLocker l(&m_situationsLock);
|
||||
if (!this->m_situationsByCallsign.contains(callsign)) { return false; }
|
||||
return this->m_situationsByCallsign[callsign].findBeforeNowMinusOffset(TimeOffsetMs).size() > 0;
|
||||
}
|
||||
|
||||
CAircraftParts IInterpolator::getLatestPartsBeforeOffset(const CCallsign &callsign, qint64 timeOffset, bool *ok) const
|
||||
{
|
||||
QReadLocker l(&m_partsLock);
|
||||
static const CAircraftParts empty;
|
||||
if (ok) { *ok = false; }
|
||||
if (this->m_partsByCallsign.contains(callsign)) { return empty; }
|
||||
CAircraftPartsList partsList = this->m_partsByCallsign[callsign].findBeforeNowMinusOffset(timeOffset);
|
||||
l.unlock();
|
||||
if (partsList.isEmpty()) { return empty; }
|
||||
if (ok) { *ok = true; }
|
||||
return partsList.latestValue();
|
||||
}
|
||||
|
||||
void IInterpolator::syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch)
|
||||
{
|
||||
QReadLocker l(&m_situationsLock);
|
||||
Q_ASSERT(requestId >= 0);
|
||||
const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> situationsCopy(m_situationsByCallsign);
|
||||
QReadLocker l(&m_lockSituations);
|
||||
const CSituationsPerCallsign situationsCopy(m_situationsByCallsign);
|
||||
l.unlock();
|
||||
|
||||
CAircraftSituationList latestInterpolations;
|
||||
if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); }
|
||||
for (const CCallsign &cs : situationsCopy.keys())
|
||||
{
|
||||
bool ok = false;
|
||||
CAircraftSituation situation = getCurrentInterpolatedSituation(situationsCopy, cs, currentTimeMsSinceEpoch, &ok);
|
||||
if (ok)
|
||||
InterpolationStatus status;
|
||||
CAircraftSituation situation = getInterpolatedSituation(cs, currentTimeMsSinceEpoch, status, &situationsCopy);
|
||||
if (status.allTrue())
|
||||
{
|
||||
latestInterpolations.push_back(situation);
|
||||
}
|
||||
@@ -86,71 +57,51 @@ namespace BlackCore
|
||||
// further logging could go here
|
||||
}
|
||||
}
|
||||
|
||||
QWriteLocker wl(&m_requestedInterpolationsLock);
|
||||
while (m_requestedInterpolations.size() >= MaxKeptInterpolationRequests - 1)
|
||||
{
|
||||
m_requestedInterpolations.erase(--m_requestedInterpolations.end());
|
||||
}
|
||||
m_requestedInterpolations.insert(requestId, latestInterpolations); // new to old
|
||||
if (m_withDebugMsg)
|
||||
{
|
||||
CLogMessage(this).debug() << "Added request" << requestId << "with" << latestInterpolations.size() << "interpolation(s)";
|
||||
}
|
||||
return latestInterpolations;
|
||||
}
|
||||
|
||||
void IInterpolator::asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch)
|
||||
IInterpolator::CSituationsPerCallsign IInterpolator::getSituationsByCallsign() const
|
||||
{
|
||||
Q_ASSERT(requestId >= 0);
|
||||
QMetaObject::invokeMethod(this, "syncRequestSituationsCalculationsForAllCallsigns",
|
||||
Qt::QueuedConnection, Q_ARG(int, requestId), Q_ARG(qint64, currentTimeMsSinceEpoch));
|
||||
}
|
||||
|
||||
QHash<CCallsign, CAircraftSituationList> IInterpolator::getSituationsByCallsign() const
|
||||
{
|
||||
QReadLocker l(&m_situationsLock);
|
||||
QReadLocker l(&m_lockSituations);
|
||||
return m_situationsByCallsign;
|
||||
}
|
||||
|
||||
CAircraftPartsList IInterpolator::getAndRemovePartsBeforeOffset(const CCallsign &callsign, qint64 cutoffTime, BlackCore::IInterpolator::PartsStatus &partsStatus)
|
||||
{
|
||||
static const CAircraftPartsList empty;
|
||||
partsStatus.reset();
|
||||
QWriteLocker l(&m_lockParts);
|
||||
if (this->m_partsByCallsign.contains(callsign))
|
||||
{
|
||||
partsStatus.supportsParts = true;
|
||||
return this->m_partsByCallsign[callsign].findBeforeAndRemove(cutoffTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
partsStatus.supportsParts = m_aircraftSupportingParts.contains(callsign);
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void IInterpolator::clear()
|
||||
{
|
||||
QWriteLocker s(&m_lockSituations);
|
||||
QWriteLocker p(&m_lockParts);
|
||||
m_situationsByCallsign.clear();
|
||||
m_partsByCallsign.clear();
|
||||
}
|
||||
|
||||
CAircraftSituationList IInterpolator::getSituationsForCallsign(const CCallsign &callsign) const
|
||||
{
|
||||
QReadLocker l(&m_situationsLock);
|
||||
QReadLocker l(&m_lockSituations);
|
||||
static const CAircraftSituationList empty;
|
||||
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
|
||||
return m_situationsByCallsign[callsign];
|
||||
}
|
||||
|
||||
int IInterpolator::latestFinishedRequestId() const
|
||||
{
|
||||
QReadLocker l(&m_requestedInterpolationsLock);
|
||||
if (m_requestedInterpolations.isEmpty()) { return -1; }
|
||||
return m_requestedInterpolations.keys().first();
|
||||
}
|
||||
|
||||
CAircraftSituationList IInterpolator::latestFinishedRequest() const
|
||||
{
|
||||
QReadLocker l(&m_requestedInterpolationsLock);
|
||||
static const CAircraftSituationList empty;
|
||||
if (m_requestedInterpolations.isEmpty()) { return empty; }
|
||||
return m_requestedInterpolations.values().first();
|
||||
}
|
||||
|
||||
CAircraftSituationList IInterpolator::getRequest(int requestId, bool *ok) const
|
||||
{
|
||||
QReadLocker l(&m_requestedInterpolationsLock);
|
||||
static const CAircraftSituationList empty;
|
||||
if (!m_requestedInterpolations.contains(requestId))
|
||||
{
|
||||
if (ok) { *ok = false; }
|
||||
return empty;
|
||||
}
|
||||
if (ok) { *ok = true; }
|
||||
return m_requestedInterpolations[requestId];
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onAddedAircraftSituation(const CAircraftSituation &situation)
|
||||
{
|
||||
QWriteLocker lock(&m_situationsLock);
|
||||
QWriteLocker lock(&m_lockSituations);
|
||||
const CCallsign callsign(situation.getCallsign());
|
||||
Q_ASSERT(!callsign.isEmpty());
|
||||
if (callsign.isEmpty()) { return; }
|
||||
@@ -158,32 +109,57 @@ namespace BlackCore
|
||||
|
||||
// list from new to old
|
||||
CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
|
||||
l.insertTimestampObject(situation, MaxSituationsPerCallsign);
|
||||
l.push_frontMaxElements(situation, MaxSituationsPerCallsign);
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts)
|
||||
{
|
||||
QWriteLocker lock(&m_partsLock);
|
||||
QWriteLocker lock(&m_lockParts);
|
||||
const CCallsign callsign(parts.getCallsign());
|
||||
Q_ASSERT(!callsign.isEmpty());
|
||||
if (callsign.isEmpty()) { return; }
|
||||
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << parts.getCallsign() << parts.getMSecsSinceEpoch(); }
|
||||
|
||||
// list from new to old
|
||||
// list sorted from new to old
|
||||
CAircraftPartsList &l = this->m_partsByCallsign[callsign];
|
||||
l.insertTimestampObject(parts, MaxPartsPerCallsign);
|
||||
l.push_frontMaxElements(parts, MaxPartsPerCallsign);
|
||||
|
||||
if (m_aircraftSupportingParts.contains(callsign)) { return; }
|
||||
m_aircraftSupportingParts.push_back(callsign);
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onRemovedAircraft(const CCallsign &callsign)
|
||||
{
|
||||
QWriteLocker ls(&m_situationsLock);
|
||||
QWriteLocker lp(&m_partsLock);
|
||||
QWriteLocker ls(&m_lockSituations);
|
||||
QWriteLocker lp(&m_lockParts);
|
||||
Q_ASSERT(!callsign.isEmpty());
|
||||
if (callsign.isEmpty()) { return; }
|
||||
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << callsign; }
|
||||
|
||||
this->m_partsByCallsign.remove(callsign);
|
||||
this->m_situationsByCallsign.remove(callsign);
|
||||
this->m_aircraftSupportingParts.remove(callsign);
|
||||
}
|
||||
|
||||
bool IInterpolator::InterpolationStatus::allTrue() const
|
||||
{
|
||||
return interpolationSucceeded && changedPosition;
|
||||
}
|
||||
|
||||
void IInterpolator::InterpolationStatus::reset()
|
||||
{
|
||||
changedPosition = false;
|
||||
interpolationSucceeded = false;
|
||||
}
|
||||
|
||||
bool IInterpolator::PartsStatus::allTrue() const
|
||||
{
|
||||
return supportsParts;
|
||||
}
|
||||
|
||||
void IInterpolator::PartsStatus::reset()
|
||||
{
|
||||
supportsParts = false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -29,45 +29,72 @@ namespace BlackCore
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
//! Situations per callsign
|
||||
typedef QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> CSituationsPerCallsign;
|
||||
|
||||
//! Parts per callsign
|
||||
typedef QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftPartsList> CPartsPerCallsign;
|
||||
|
||||
//! Virtual destructor
|
||||
virtual ~IInterpolator() {}
|
||||
|
||||
//! Log category
|
||||
static QString getMessageCategory() { return "swift.iinterpolator"; }
|
||||
|
||||
//! Has situations?
|
||||
//! \deprecated Try not to use, it would be more efficient to directly getting the values and decide then
|
||||
//! \threadsafe
|
||||
virtual bool hasEnoughAircraftSituations(const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
//! Status of interpolation
|
||||
struct InterpolationStatus
|
||||
{
|
||||
public:
|
||||
bool changedPosition = false; //!< position was changed
|
||||
bool interpolationSucceeded = false; //!< interpolation succeeded (means enough values, etc.)
|
||||
|
||||
//! all OK
|
||||
bool allTrue() const;
|
||||
|
||||
//! Reset to default values
|
||||
void reset();
|
||||
};
|
||||
|
||||
//! Status regarding parts
|
||||
struct PartsStatus
|
||||
{
|
||||
bool supportsParts = false; //!< supports parts for given callsign
|
||||
|
||||
//! all OK
|
||||
bool allTrue() const;
|
||||
|
||||
//! Reset to default values
|
||||
void reset();
|
||||
};
|
||||
|
||||
//! Current interpolated situation
|
||||
//! \threadsafe
|
||||
virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const = 0;
|
||||
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
|
||||
const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc,
|
||||
InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign = nullptr) const = 0;
|
||||
|
||||
//! Latest parts before time - offset
|
||||
//! Do a complete calculation for all know callsigns.
|
||||
//! \param currentTimeMsSinceEpoch if no value is passed current time is used
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftParts getLatestPartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset = TimeOffsetMs, bool *ok = nullptr) const;
|
||||
//!
|
||||
virtual BlackMisc::Aviation::CAircraftSituationList getInterpolatedSituations(qint64 currentTimeMsSinceEpoch = -1);
|
||||
|
||||
//! The situations per callsign
|
||||
//! \threadsafe
|
||||
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> getSituationsByCallsign() const;
|
||||
CSituationsPerCallsign getSituationsByCallsign() const;
|
||||
|
||||
//! Parts before given offset time (aka pending parts)
|
||||
//! \threadsafe
|
||||
virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset, PartsStatus &partsStatus);
|
||||
|
||||
//! Clear all data
|
||||
//! \threadsafe
|
||||
virtual void clear();
|
||||
|
||||
//! Situations for given callsign
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
|
||||
//! Last finished request id, -1 means none
|
||||
//! \threadsafe
|
||||
int latestFinishedRequestId() const;
|
||||
|
||||
//! Latest calculation
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftSituationList latestFinishedRequest() const;
|
||||
|
||||
//! Calculation by id
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftSituationList getRequest(int requestId, bool *ok = nullptr) const;
|
||||
|
||||
//! Enable debug messages
|
||||
void enableDebugMessages(bool enabled);
|
||||
|
||||
@@ -76,20 +103,6 @@ namespace BlackCore
|
||||
static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign
|
||||
static const int MaxKeptInterpolationRequests = 3; //!< How many requests are stored
|
||||
|
||||
public slots:
|
||||
//! Do a complete calculation for all know callsigns in background.
|
||||
//! Only use positive numbers.
|
||||
//! \param requestId
|
||||
//! \param currentTimeMsSinceEpoch if no value is passed current time is used
|
||||
//! \threadsafe
|
||||
//!
|
||||
void syncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1);
|
||||
|
||||
//! Do a complete calculation for all know callsigns in background.
|
||||
//! Non blocking call of \sa syncRequestSituationsCalculationsForAllCallsigns
|
||||
//! \threadsafe
|
||||
void asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch = -1);
|
||||
|
||||
private slots:
|
||||
//! New situation got added
|
||||
//! \threadsafe
|
||||
@@ -107,23 +120,17 @@ namespace BlackCore
|
||||
//! Constructor
|
||||
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProviderReadOnly *provider, const QString &workerName, QObject *parent = nullptr);
|
||||
|
||||
//! Situations for times before / after
|
||||
//! \sa ITimestampObjectList::splitByTime
|
||||
//! \threadsafe
|
||||
//! \deprecated For first version
|
||||
QList<BlackMisc::Aviation::CAircraftSituationList> getSituationsTimeSplit(const BlackMisc::Aviation::CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const;
|
||||
|
||||
bool m_withDebugMsg = false; //!< allows to disable debug messages
|
||||
|
||||
private:
|
||||
mutable QReadWriteLock m_situationsLock;
|
||||
mutable QReadWriteLock m_partsLock;
|
||||
mutable QReadWriteLock m_requestedInterpolationsLock;
|
||||
BlackMisc::Aviation::CCallsignList m_aircraftSupportingParts; //!< aircraft supporting parts
|
||||
|
||||
// hashs, because not sorted by key but keeping order
|
||||
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> m_situationsByCallsign;
|
||||
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftPartsList> m_partsByCallsign;
|
||||
QHash<int, BlackMisc::Aviation::CAircraftSituationList> m_requestedInterpolations;
|
||||
CSituationsPerCallsign m_situationsByCallsign; //!< situations
|
||||
CPartsPerCallsign m_partsByCallsign; //!< parts
|
||||
|
||||
// locks
|
||||
mutable QReadWriteLock m_lockSituations; //!< lock for situations
|
||||
mutable QReadWriteLock m_lockParts; //!< lock for parts
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -20,18 +20,31 @@ using namespace BlackMisc::Aviation;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
CAircraftSituation CInterpolatorLinear::getCurrentInterpolatedSituation(const QHash<CCallsign, CAircraftSituationList> &allSituations, const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, bool *ok) const
|
||||
CAircraftSituation CInterpolatorLinear::getInterpolatedSituation(const CCallsign &callsign, qint64 currentTimeMsSinceEpoc, InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign) const
|
||||
{
|
||||
const static CAircraftSituation empty;
|
||||
if (ok) { *ok = false; }
|
||||
if (!allSituations.contains(callsign)) { return empty; }
|
||||
if (allSituations[callsign].isEmpty()) { return empty; }
|
||||
|
||||
status.reset();
|
||||
QList<CAircraftSituationList> splitSituations;
|
||||
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
|
||||
qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs;
|
||||
QList<CAircraftSituationList> splitSituations = allSituations[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
CAircraftSituationList &situationsNewer = splitSituations[0]; // latest first
|
||||
CAircraftSituationList &situationsOlder = splitSituations[1]; // latest first
|
||||
|
||||
if (situationsPerCallsign)
|
||||
{
|
||||
if (!situationsPerCallsign->contains(callsign)) { return empty; }
|
||||
if ((*situationsPerCallsign)[callsign].isEmpty()) { return empty; }
|
||||
splitSituations = (*situationsPerCallsign)[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
}
|
||||
else
|
||||
{
|
||||
// only part where it is locked
|
||||
QReadLocker lock(&m_lockSituations);
|
||||
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
|
||||
if (m_situationsByCallsign[callsign].isEmpty()) { return empty; }
|
||||
splitSituations = m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
}
|
||||
|
||||
CAircraftSituationList &situationsNewer = splitSituations[0]; // newer part
|
||||
CAircraftSituationList &situationsOlder = splitSituations[1]; // older part
|
||||
|
||||
// interpolation situations
|
||||
CAircraftSituation oldSituation;
|
||||
@@ -52,7 +65,6 @@ namespace BlackCore
|
||||
// We just place at he last position until we get before / after situations
|
||||
if (situationsOlderNo < 1 || situationsNewerNo < 1)
|
||||
{
|
||||
if (ok) { *ok = true; }
|
||||
// no after situations
|
||||
if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest
|
||||
|
||||
@@ -73,6 +85,7 @@ namespace BlackCore
|
||||
|
||||
CAircraftSituation currentSituation(oldSituation);
|
||||
CCoordinateGeodetic currentPosition;
|
||||
status.interpolationSucceeded = true;
|
||||
|
||||
// Time between start and end packet
|
||||
double deltaTime = oldSituation.absMsecsTo(newSituation);
|
||||
@@ -82,7 +95,7 @@ namespace BlackCore
|
||||
// 1) values > 1 mean extrapolation
|
||||
// 2) values > 2 mean no new situations coming in
|
||||
double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime);
|
||||
if (simulationTimeFraction > 1.5)
|
||||
if (simulationTimeFraction > 2.0)
|
||||
{
|
||||
if (this->m_withDebugMsg)
|
||||
{
|
||||
@@ -91,21 +104,34 @@ namespace BlackCore
|
||||
}
|
||||
|
||||
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
|
||||
currentPosition.setLatitude((newSituation.getPosition().latitude() - oldSituation.getPosition().latitude())
|
||||
const CLatitude oldLat(oldSituation.latitude());
|
||||
const CLatitude newLat(newSituation.latitude());
|
||||
const CLongitude oldLng(oldSituation.longitude());
|
||||
const CLongitude newLng(newSituation.longitude());
|
||||
|
||||
currentPosition.setLatitude((newLat - oldLat)
|
||||
* simulationTimeFraction
|
||||
+ oldSituation.getPosition().latitude());
|
||||
+ oldLat);
|
||||
|
||||
// Interpolate latitude: Lon = (LonB - LonA) * t + LonA
|
||||
currentPosition.setLongitude((newSituation.getPosition().longitude() - oldSituation.getPosition().longitude())
|
||||
currentPosition.setLongitude((newLng - oldLng)
|
||||
* simulationTimeFraction
|
||||
+ oldSituation.getPosition().longitude());
|
||||
+ oldLng);
|
||||
currentSituation.setPosition(currentPosition);
|
||||
|
||||
// Interpolate altitude: Alt = (AltB - AltA) * t + AltA
|
||||
currentSituation.setAltitude(CAltitude((newSituation.getAltitude() - oldSituation.getAltitude())
|
||||
const CAltitude oldAlt(oldSituation.getAltitude());
|
||||
const CAltitude newAlt(newSituation.getAltitude());
|
||||
Q_ASSERT(oldAlt.getReferenceDatum() == newAlt.getReferenceDatum()); // otherwise no calculation is possible
|
||||
currentSituation.setAltitude(CAltitude((newAlt - oldAlt)
|
||||
* simulationTimeFraction
|
||||
+ oldSituation.getAltitude(),
|
||||
oldSituation.getAltitude().getReferenceDatum()));
|
||||
+ oldAlt,
|
||||
oldAlt.getReferenceDatum()));
|
||||
|
||||
if (newLat == oldLat && newLng == oldLng && oldAlt == newAlt)
|
||||
{
|
||||
return currentSituation;
|
||||
}
|
||||
|
||||
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
|
||||
CHeading headingBegin = oldSituation.getHeading();
|
||||
@@ -143,13 +169,13 @@ namespace BlackCore
|
||||
|
||||
// TODO: According to the specification, banks to the right should be negative.
|
||||
// But somehow we get positive banks from the network.
|
||||
bank *= -1;
|
||||
bank *= -1.0;
|
||||
currentSituation.setBank(bank);
|
||||
|
||||
currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
|
||||
* simulationTimeFraction
|
||||
+ oldSituation.getGroundSpeed());
|
||||
if (ok) { *ok = true; }
|
||||
status.changedPosition = true;
|
||||
Q_ASSERT(currentSituation.getCallsign() == callsign);
|
||||
return currentSituation;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace BlackCore
|
||||
{}
|
||||
|
||||
//! \copydoc IInterpolator::getCurrentInterpolatedSituation
|
||||
virtual BlackMisc::Aviation::CAircraftSituation getCurrentInterpolatedSituation(const QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> &allSituations, const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc = -1, bool *ok = nullptr) const override;
|
||||
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc, InterpolationStatus &status, const CSituationsPerCallsign *situationsPerCallsign = nullptr) const override;
|
||||
|
||||
//! Log category
|
||||
static QString getMessageCategory() { return "swift.interpolatorlinear"; }
|
||||
|
||||
@@ -430,8 +430,9 @@ namespace BlackCore
|
||||
|
||||
/*!
|
||||
* We received a notification of the state of another aircraft on the network.
|
||||
* Corresponding callsign in \sa CAircraftSituation::getCallsign .
|
||||
*/
|
||||
void aircraftPositionUpdate(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftSituation &situation,
|
||||
void aircraftPositionUpdate(const BlackMisc::Aviation::CAircraftSituation &situation,
|
||||
const BlackMisc::Aviation::CTransponder &transponder);
|
||||
|
||||
/*!
|
||||
|
||||
@@ -648,16 +648,17 @@ namespace BlackCore
|
||||
{
|
||||
const CCallsign callsign(callsignChar);
|
||||
const CAircraftSituation situation(
|
||||
callsign,
|
||||
CCoordinateGeodetic(position->latitude, position->longitude, 0.0),
|
||||
CAltitude(position->altitudeTrue, CAltitude::AboveGround, CLengthUnit::ft()),
|
||||
CAltitude(position->altitudeTrue, CAltitude::MeanSeaLevel, CLengthUnit::ft()),
|
||||
CHeading(position->heading, CHeading::True, CAngleUnit::deg()),
|
||||
CAngle(position->pitch, CAngleUnit::deg()),
|
||||
CAngle(position->bank, CAngleUnit::deg()),
|
||||
CSpeed(position->groundSpeed, CSpeedUnit::kts())
|
||||
);
|
||||
|
||||
QString tn("transponder ");
|
||||
tn.append(callsign.asString());
|
||||
QString transponderName("transponder ");
|
||||
transponderName.append(callsign.asString());
|
||||
CTransponder::TransponderMode mode = CTransponder::StateStandby;
|
||||
switch (position->transponderMode)
|
||||
{
|
||||
@@ -675,19 +676,21 @@ namespace BlackCore
|
||||
break;
|
||||
}
|
||||
|
||||
// I did have a situation where I got wrong transponger codes (KB)
|
||||
// I did have a situation where I got wrong transponder codes (KB)
|
||||
// So I now check for a valid code in order to detect such codes
|
||||
CTransponder transponder(tn, 0, mode);
|
||||
CTransponder transponder;
|
||||
if (CTransponder::isValidTransponderCode(position->transponderCode))
|
||||
{
|
||||
transponder = CTransponder(tn, position->transponderCode, mode);
|
||||
transponder = CTransponder(transponderName, position->transponderCode, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: how do with log this
|
||||
qDebug() << "Wrong transponder code" << position->transponderMode << callsign;
|
||||
CLogMessage(static_cast<CNetworkVatlib *>(nullptr)).warning("Wrong transponder code %1 for %2") << position->transponderCode << callsign;
|
||||
|
||||
// default
|
||||
transponder = CTransponder(transponderName, 7000, mode);
|
||||
}
|
||||
emit cbvar_cast(cbvar)->aircraftPositionUpdate(callsign, situation, transponder);
|
||||
emit cbvar_cast(cbvar)->aircraftPositionUpdate(situation, transponder);
|
||||
}
|
||||
|
||||
void CNetworkVatlib::onAircraftConfigReceived(VatSessionID, const char *callsign, const char *aircraftConfig, void *cbvar)
|
||||
|
||||
@@ -27,7 +27,9 @@ namespace BlackCore
|
||||
/*!
|
||||
* Implementation of INetwork using the vatlib shim
|
||||
*/
|
||||
class CNetworkVatlib : public INetwork, public BlackMisc::Simulation::COwnAircraftProviderSupport
|
||||
class CNetworkVatlib :
|
||||
public INetwork,
|
||||
public BlackMisc::Simulation::COwnAircraftProviderSupport // network vatlib consumes own aircraft data and sets ICAO/callsign data
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user