mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-23 22:15:37 +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
|
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);
|
bool s2 = connect(this, &CAirspaceMonitor::addedRemoteAircraftParts, partsSlot);
|
||||||
|
Q_ASSERT(s2);
|
||||||
bool s3 = connect(this, &CAirspaceMonitor::removedRemoteAircraft, removedAircraftSlot);
|
bool s3 = connect(this, &CAirspaceMonitor::removedRemoteAircraft, removedAircraftSlot);
|
||||||
|
Q_ASSERT(s3);
|
||||||
return s1 && s2 && s3;
|
return s1 && s2 && s3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,16 +751,18 @@ namespace BlackCore
|
|||||||
if (c > 0) { ps_sendReadyForModelMatching(callsign, 1); }
|
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));
|
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
|
||||||
if (!this->m_connected) { return; }
|
if (!this->m_connected) { return; }
|
||||||
|
|
||||||
|
CCallsign callsign(situation.getCallsign());
|
||||||
|
Q_ASSERT(!callsign.isEmpty());
|
||||||
|
|
||||||
// store situation history
|
// store situation history
|
||||||
CAircraftSituation situationWithCallsign(situation);
|
// this->m_aircraftSituations.insert_front(situation);
|
||||||
situationWithCallsign.setCallsign(callsign);
|
|
||||||
// this->m_aircraftSituations.insert_front(situationWithCallsign);
|
|
||||||
// this->m_aircraftSituations.removeOlderThanNowMinusOffset(AircraftSituationsRemovedOffsetMs);
|
// this->m_aircraftSituations.removeOlderThanNowMinusOffset(AircraftSituationsRemovedOffsetMs);
|
||||||
|
emit this->addedRemoteAircraftSituation(situation);
|
||||||
|
|
||||||
bool exists = this->m_aircraftInRange.containsCallsign(callsign);
|
bool exists = this->m_aircraftInRange.containsCallsign(callsign);
|
||||||
if (!exists)
|
if (!exists)
|
||||||
@@ -829,7 +835,6 @@ namespace BlackCore
|
|||||||
this->m_aircraftWatchdog.resetCallsign(callsign);
|
this->m_aircraftWatchdog.resetCallsign(callsign);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit this->addedRemoteAircraftSituation(situationWithCallsign);
|
|
||||||
emit this->changedAircraftInRange();
|
emit this->changedAircraftInRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ namespace BlackCore
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
//! Create aircraft in range, this is the only place where a new aircraft should be added
|
//! 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_realNameReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, const QString &realname);
|
||||||
void ps_capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, quint32 flags);
|
void ps_capabilitiesReplyReceived(const BlackMisc::Aviation::CCallsign &callsign, quint32 flags);
|
||||||
|
|||||||
@@ -35,48 +35,19 @@ namespace BlackCore
|
|||||||
Q_UNUSED(c);
|
Q_UNUSED(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<CAircraftSituationList> IInterpolator::getSituationsTimeSplit(const CCallsign &callsign, qint64 splitTimeMsSinceEpoch) const
|
CAircraftSituationList IInterpolator::getInterpolatedSituations(qint64 currentTimeMsSinceEpoch)
|
||||||
{
|
{
|
||||||
QReadLocker l(&m_situationsLock);
|
QReadLocker l(&m_lockSituations);
|
||||||
static const QList<CAircraftSituationList> empty({ CAircraftSituationList(), CAircraftSituationList() });
|
const CSituationsPerCallsign situationsCopy(m_situationsByCallsign);
|
||||||
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);
|
|
||||||
l.unlock();
|
l.unlock();
|
||||||
|
|
||||||
CAircraftSituationList latestInterpolations;
|
CAircraftSituationList latestInterpolations;
|
||||||
if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); }
|
if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); }
|
||||||
for (const CCallsign &cs : situationsCopy.keys())
|
for (const CCallsign &cs : situationsCopy.keys())
|
||||||
{
|
{
|
||||||
bool ok = false;
|
InterpolationStatus status;
|
||||||
CAircraftSituation situation = getCurrentInterpolatedSituation(situationsCopy, cs, currentTimeMsSinceEpoch, &ok);
|
CAircraftSituation situation = getInterpolatedSituation(cs, currentTimeMsSinceEpoch, status, &situationsCopy);
|
||||||
if (ok)
|
if (status.allTrue())
|
||||||
{
|
{
|
||||||
latestInterpolations.push_back(situation);
|
latestInterpolations.push_back(situation);
|
||||||
}
|
}
|
||||||
@@ -86,71 +57,51 @@ namespace BlackCore
|
|||||||
// further logging could go here
|
// further logging could go here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return latestInterpolations;
|
||||||
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)";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IInterpolator::asyncRequestSituationsCalculationsForAllCallsigns(int requestId, qint64 currentTimeMsSinceEpoch)
|
IInterpolator::CSituationsPerCallsign IInterpolator::getSituationsByCallsign() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(requestId >= 0);
|
QReadLocker l(&m_lockSituations);
|
||||||
QMetaObject::invokeMethod(this, "syncRequestSituationsCalculationsForAllCallsigns",
|
|
||||||
Qt::QueuedConnection, Q_ARG(int, requestId), Q_ARG(qint64, currentTimeMsSinceEpoch));
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<CCallsign, CAircraftSituationList> IInterpolator::getSituationsByCallsign() const
|
|
||||||
{
|
|
||||||
QReadLocker l(&m_situationsLock);
|
|
||||||
return m_situationsByCallsign;
|
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
|
CAircraftSituationList IInterpolator::getSituationsForCallsign(const CCallsign &callsign) const
|
||||||
{
|
{
|
||||||
QReadLocker l(&m_situationsLock);
|
QReadLocker l(&m_lockSituations);
|
||||||
static const CAircraftSituationList empty;
|
static const CAircraftSituationList empty;
|
||||||
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
|
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
|
||||||
return m_situationsByCallsign[callsign];
|
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)
|
void IInterpolator::ps_onAddedAircraftSituation(const CAircraftSituation &situation)
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&m_situationsLock);
|
QWriteLocker lock(&m_lockSituations);
|
||||||
const CCallsign callsign(situation.getCallsign());
|
const CCallsign callsign(situation.getCallsign());
|
||||||
Q_ASSERT(!callsign.isEmpty());
|
Q_ASSERT(!callsign.isEmpty());
|
||||||
if (callsign.isEmpty()) { return; }
|
if (callsign.isEmpty()) { return; }
|
||||||
@@ -158,32 +109,57 @@ namespace BlackCore
|
|||||||
|
|
||||||
// list from new to old
|
// list from new to old
|
||||||
CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
|
CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
|
||||||
l.insertTimestampObject(situation, MaxSituationsPerCallsign);
|
l.push_frontMaxElements(situation, MaxSituationsPerCallsign);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts)
|
void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts)
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&m_partsLock);
|
QWriteLocker lock(&m_lockParts);
|
||||||
const CCallsign callsign(parts.getCallsign());
|
const CCallsign callsign(parts.getCallsign());
|
||||||
Q_ASSERT(!callsign.isEmpty());
|
Q_ASSERT(!callsign.isEmpty());
|
||||||
if (callsign.isEmpty()) { return; }
|
if (callsign.isEmpty()) { return; }
|
||||||
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << parts.getCallsign() << parts.getMSecsSinceEpoch(); }
|
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];
|
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)
|
void IInterpolator::ps_onRemovedAircraft(const CCallsign &callsign)
|
||||||
{
|
{
|
||||||
QWriteLocker ls(&m_situationsLock);
|
QWriteLocker ls(&m_lockSituations);
|
||||||
QWriteLocker lp(&m_partsLock);
|
QWriteLocker lp(&m_lockParts);
|
||||||
Q_ASSERT(!callsign.isEmpty());
|
Q_ASSERT(!callsign.isEmpty());
|
||||||
if (callsign.isEmpty()) { return; }
|
if (callsign.isEmpty()) { return; }
|
||||||
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << callsign; }
|
if (this->m_withDebugMsg) { CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO << callsign; }
|
||||||
|
|
||||||
this->m_partsByCallsign.remove(callsign);
|
this->m_partsByCallsign.remove(callsign);
|
||||||
this->m_situationsByCallsign.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
|
} // namespace
|
||||||
|
|||||||
@@ -29,45 +29,72 @@ namespace BlackCore
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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 destructor
|
||||||
virtual ~IInterpolator() {}
|
virtual ~IInterpolator() {}
|
||||||
|
|
||||||
//! Log category
|
//! Log category
|
||||||
static QString getMessageCategory() { return "swift.iinterpolator"; }
|
static QString getMessageCategory() { return "swift.iinterpolator"; }
|
||||||
|
|
||||||
//! Has situations?
|
//! Status of interpolation
|
||||||
//! \deprecated Try not to use, it would be more efficient to directly getting the values and decide then
|
struct InterpolationStatus
|
||||||
//! \threadsafe
|
{
|
||||||
virtual bool hasEnoughAircraftSituations(const BlackMisc::Aviation::CCallsign &callsign) const;
|
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
|
//! Current interpolated situation
|
||||||
//! \threadsafe
|
//! \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
|
//! \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
|
//! The situations per callsign
|
||||||
//! \threadsafe
|
//! \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
|
//! Situations for given callsign
|
||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const;
|
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
|
//! Enable debug messages
|
||||||
void enableDebugMessages(bool enabled);
|
void enableDebugMessages(bool enabled);
|
||||||
|
|
||||||
@@ -76,20 +103,6 @@ namespace BlackCore
|
|||||||
static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign
|
static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign
|
||||||
static const int MaxKeptInterpolationRequests = 3; //!< How many requests are stored
|
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:
|
private slots:
|
||||||
//! New situation got added
|
//! New situation got added
|
||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
@@ -107,23 +120,17 @@ namespace BlackCore
|
|||||||
//! Constructor
|
//! Constructor
|
||||||
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProviderReadOnly *provider, const QString &workerName, QObject *parent = nullptr);
|
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
|
bool m_withDebugMsg = false; //!< allows to disable debug messages
|
||||||
|
BlackMisc::Aviation::CCallsignList m_aircraftSupportingParts; //!< aircraft supporting parts
|
||||||
private:
|
|
||||||
mutable QReadWriteLock m_situationsLock;
|
|
||||||
mutable QReadWriteLock m_partsLock;
|
|
||||||
mutable QReadWriteLock m_requestedInterpolationsLock;
|
|
||||||
|
|
||||||
// hashs, because not sorted by key but keeping order
|
// hashs, because not sorted by key but keeping order
|
||||||
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftSituationList> m_situationsByCallsign;
|
CSituationsPerCallsign m_situationsByCallsign; //!< situations
|
||||||
QHash<BlackMisc::Aviation::CCallsign, BlackMisc::Aviation::CAircraftPartsList> m_partsByCallsign;
|
CPartsPerCallsign m_partsByCallsign; //!< parts
|
||||||
QHash<int, BlackMisc::Aviation::CAircraftSituationList> m_requestedInterpolations;
|
|
||||||
|
// locks
|
||||||
|
mutable QReadWriteLock m_lockSituations; //!< lock for situations
|
||||||
|
mutable QReadWriteLock m_lockParts; //!< lock for parts
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -20,18 +20,31 @@ using namespace BlackMisc::Aviation;
|
|||||||
|
|
||||||
namespace BlackCore
|
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;
|
const static CAircraftSituation empty;
|
||||||
if (ok) { *ok = false; }
|
status.reset();
|
||||||
if (!allSituations.contains(callsign)) { return empty; }
|
QList<CAircraftSituationList> splitSituations;
|
||||||
if (allSituations[callsign].isEmpty()) { return empty; }
|
|
||||||
|
|
||||||
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
|
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
|
||||||
qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs;
|
qint64 splitTimeMsSinceEpoch = currentTimeMsSinceEpoc - TimeOffsetMs;
|
||||||
QList<CAircraftSituationList> splitSituations = allSituations[callsign].splitByTime(splitTimeMsSinceEpoch);
|
|
||||||
CAircraftSituationList &situationsNewer = splitSituations[0]; // latest first
|
if (situationsPerCallsign)
|
||||||
CAircraftSituationList &situationsOlder = splitSituations[1]; // latest first
|
{
|
||||||
|
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
|
// interpolation situations
|
||||||
CAircraftSituation oldSituation;
|
CAircraftSituation oldSituation;
|
||||||
@@ -52,7 +65,6 @@ namespace BlackCore
|
|||||||
// We just place at he last position until we get before / after situations
|
// We just place at he last position until we get before / after situations
|
||||||
if (situationsOlderNo < 1 || situationsNewerNo < 1)
|
if (situationsOlderNo < 1 || situationsNewerNo < 1)
|
||||||
{
|
{
|
||||||
if (ok) { *ok = true; }
|
|
||||||
// no after situations
|
// no after situations
|
||||||
if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest
|
if (situationsOlderNo < 1) { return situationsNewer.back(); } // oldest newest
|
||||||
|
|
||||||
@@ -73,6 +85,7 @@ namespace BlackCore
|
|||||||
|
|
||||||
CAircraftSituation currentSituation(oldSituation);
|
CAircraftSituation currentSituation(oldSituation);
|
||||||
CCoordinateGeodetic currentPosition;
|
CCoordinateGeodetic currentPosition;
|
||||||
|
status.interpolationSucceeded = true;
|
||||||
|
|
||||||
// Time between start and end packet
|
// Time between start and end packet
|
||||||
double deltaTime = oldSituation.absMsecsTo(newSituation);
|
double deltaTime = oldSituation.absMsecsTo(newSituation);
|
||||||
@@ -82,7 +95,7 @@ namespace BlackCore
|
|||||||
// 1) values > 1 mean extrapolation
|
// 1) values > 1 mean extrapolation
|
||||||
// 2) values > 2 mean no new situations coming in
|
// 2) values > 2 mean no new situations coming in
|
||||||
double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime);
|
double simulationTimeFraction = 1 - ((newSituation.getMSecsSinceEpoch() - splitTimeMsSinceEpoch) / deltaTime);
|
||||||
if (simulationTimeFraction > 1.5)
|
if (simulationTimeFraction > 2.0)
|
||||||
{
|
{
|
||||||
if (this->m_withDebugMsg)
|
if (this->m_withDebugMsg)
|
||||||
{
|
{
|
||||||
@@ -91,21 +104,34 @@ namespace BlackCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
|
// 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
|
* simulationTimeFraction
|
||||||
+ oldSituation.getPosition().latitude());
|
+ oldLat);
|
||||||
|
|
||||||
// Interpolate latitude: Lon = (LonB - LonA) * t + LonA
|
// Interpolate latitude: Lon = (LonB - LonA) * t + LonA
|
||||||
currentPosition.setLongitude((newSituation.getPosition().longitude() - oldSituation.getPosition().longitude())
|
currentPosition.setLongitude((newLng - oldLng)
|
||||||
* simulationTimeFraction
|
* simulationTimeFraction
|
||||||
+ oldSituation.getPosition().longitude());
|
+ oldLng);
|
||||||
currentSituation.setPosition(currentPosition);
|
currentSituation.setPosition(currentPosition);
|
||||||
|
|
||||||
// Interpolate altitude: Alt = (AltB - AltA) * t + AltA
|
// 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
|
* simulationTimeFraction
|
||||||
+ oldSituation.getAltitude(),
|
+ oldAlt,
|
||||||
oldSituation.getAltitude().getReferenceDatum()));
|
oldAlt.getReferenceDatum()));
|
||||||
|
|
||||||
|
if (newLat == oldLat && newLng == oldLng && oldAlt == newAlt)
|
||||||
|
{
|
||||||
|
return currentSituation;
|
||||||
|
}
|
||||||
|
|
||||||
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
|
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
|
||||||
CHeading headingBegin = oldSituation.getHeading();
|
CHeading headingBegin = oldSituation.getHeading();
|
||||||
@@ -143,13 +169,13 @@ namespace BlackCore
|
|||||||
|
|
||||||
// TODO: According to the specification, banks to the right should be negative.
|
// TODO: According to the specification, banks to the right should be negative.
|
||||||
// But somehow we get positive banks from the network.
|
// But somehow we get positive banks from the network.
|
||||||
bank *= -1;
|
bank *= -1.0;
|
||||||
currentSituation.setBank(bank);
|
currentSituation.setBank(bank);
|
||||||
|
|
||||||
currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
|
currentSituation.setGroundspeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
|
||||||
* simulationTimeFraction
|
* simulationTimeFraction
|
||||||
+ oldSituation.getGroundSpeed());
|
+ oldSituation.getGroundSpeed());
|
||||||
if (ok) { *ok = true; }
|
status.changedPosition = true;
|
||||||
Q_ASSERT(currentSituation.getCallsign() == callsign);
|
Q_ASSERT(currentSituation.getCallsign() == callsign);
|
||||||
return currentSituation;
|
return currentSituation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace BlackCore
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
//! \copydoc IInterpolator::getCurrentInterpolatedSituation
|
//! \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
|
//! Log category
|
||||||
static QString getMessageCategory() { return "swift.interpolatorlinear"; }
|
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.
|
* 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);
|
const BlackMisc::Aviation::CTransponder &transponder);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -648,16 +648,17 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
const CCallsign callsign(callsignChar);
|
const CCallsign callsign(callsignChar);
|
||||||
const CAircraftSituation situation(
|
const CAircraftSituation situation(
|
||||||
|
callsign,
|
||||||
CCoordinateGeodetic(position->latitude, position->longitude, 0.0),
|
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()),
|
CHeading(position->heading, CHeading::True, CAngleUnit::deg()),
|
||||||
CAngle(position->pitch, CAngleUnit::deg()),
|
CAngle(position->pitch, CAngleUnit::deg()),
|
||||||
CAngle(position->bank, CAngleUnit::deg()),
|
CAngle(position->bank, CAngleUnit::deg()),
|
||||||
CSpeed(position->groundSpeed, CSpeedUnit::kts())
|
CSpeed(position->groundSpeed, CSpeedUnit::kts())
|
||||||
);
|
);
|
||||||
|
|
||||||
QString tn("transponder ");
|
QString transponderName("transponder ");
|
||||||
tn.append(callsign.asString());
|
transponderName.append(callsign.asString());
|
||||||
CTransponder::TransponderMode mode = CTransponder::StateStandby;
|
CTransponder::TransponderMode mode = CTransponder::StateStandby;
|
||||||
switch (position->transponderMode)
|
switch (position->transponderMode)
|
||||||
{
|
{
|
||||||
@@ -675,19 +676,21 @@ namespace BlackCore
|
|||||||
break;
|
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
|
// 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))
|
if (CTransponder::isValidTransponderCode(position->transponderCode))
|
||||||
{
|
{
|
||||||
transponder = CTransponder(tn, position->transponderCode, mode);
|
transponder = CTransponder(transponderName, position->transponderCode, mode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: how do with log this
|
CLogMessage(static_cast<CNetworkVatlib *>(nullptr)).warning("Wrong transponder code %1 for %2") << position->transponderCode << callsign;
|
||||||
qDebug() << "Wrong transponder code" << position->transponderMode << 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)
|
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
|
* 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
|
Q_OBJECT
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ namespace BlackMisc
|
|||||||
CLength heightAboveGround(this->getHeightAboveGround());
|
CLength heightAboveGround(this->getHeightAboveGround());
|
||||||
if (!heightAboveGround.isNull())
|
if (!heightAboveGround.isNull())
|
||||||
{
|
{
|
||||||
return heightAboveGround.value(CLengthUnit::m()) < 2.0;
|
return heightAboveGround.value(CLengthUnit::m()) < 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we guess on pitch an bank
|
// we guess on pitch an bank
|
||||||
@@ -120,7 +120,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
if (this->getGroundSpeed().value(CSpeedUnit::km_h()) > 80) { return false; }
|
if (this->getGroundSpeed().value(CSpeedUnit::km_h()) > 80) { return false; }
|
||||||
|
|
||||||
// not sure, but his is a guess
|
// not sure, but this is a guess
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ namespace BlackMisc
|
|||||||
BLACK_ENABLE_TUPLE_CONVERSION(CCoordinateGeodetic)
|
BLACK_ENABLE_TUPLE_CONVERSION(CCoordinateGeodetic)
|
||||||
BlackMisc::Geo::CLatitude m_latitude; //!< Latitude
|
BlackMisc::Geo::CLatitude m_latitude; //!< Latitude
|
||||||
BlackMisc::Geo::CLongitude m_longitude; //!< Longitude
|
BlackMisc::Geo::CLongitude m_longitude; //!< Longitude
|
||||||
BlackMisc::PhysicalQuantities::CLength m_geodeticHeight; //!< height, ellipsoidal or geodetic height
|
BlackMisc::PhysicalQuantities::CLength m_geodeticHeight { 0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit() }; //!< height, ellipsoidal or geodetic height
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -234,6 +234,12 @@ namespace BlackMisc
|
|||||||
*/
|
*/
|
||||||
void push_back(const T &value) { Q_ASSERT(pimpl()); pimpl()->push_back(value); }
|
void push_back(const T &value) { Q_ASSERT(pimpl()); pimpl()->push_back(value); }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Insert as first element.
|
||||||
|
* \pre The sequence must be initialized.
|
||||||
|
*/
|
||||||
|
void push_front(const T &value) { insert(begin(), value); }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Move-appends an element at the end of the sequence.
|
* \brief Move-appends an element at the end of the sequence.
|
||||||
* \pre The sequence must be initialized.
|
* \pre The sequence must be initialized.
|
||||||
@@ -272,12 +278,6 @@ namespace BlackMisc
|
|||||||
*/
|
*/
|
||||||
void insert(T &&value) { push_back(std::move(value)); }
|
void insert(T &&value) { push_back(std::move(value)); }
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Insert as first element.
|
|
||||||
* \pre The sequence must be initialized.
|
|
||||||
*/
|
|
||||||
void insert_front(const T &value) { insert(begin(), value); }
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Synonym for push_back.
|
* \brief Synonym for push_back.
|
||||||
* \pre The sequence must be initialized.
|
* \pre The sequence must be initialized.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
void CRemoteAircraftProviderDummy::insertNewSituation(const CAircraftSituation &situation)
|
void CRemoteAircraftProviderDummy::insertNewSituation(const CAircraftSituation &situation)
|
||||||
{
|
{
|
||||||
this->m_situations.insertTimestampObject(situation, 20);
|
this->m_situations.push_frontMaxElements(situation, 20);
|
||||||
emit addedRemoteAircraftSituation(situation);
|
emit addedRemoteAircraftSituation(situation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,17 @@ namespace BlackMisc
|
|||||||
return this->findBy(Predicates::MemberValid(&CSimulatedAircraft::getPilot)).transform(Predicates::MemberTransform(&CSimulatedAircraft::getPilot));
|
return this->findBy(Predicates::MemberValid(&CSimulatedAircraft::getPilot)).transform(Predicates::MemberTransform(&CSimulatedAircraft::getPilot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCallsignList CSimulatedAircraftList::getCallsignsWithSyncronizedParts() const
|
||||||
|
{
|
||||||
|
CCallsignList csl;
|
||||||
|
for (const CSimulatedAircraft &aircraft : (*this))
|
||||||
|
{
|
||||||
|
if (!aircraft.isPartsSynchronized()) { continue; }
|
||||||
|
csl.push_back(aircraft.getCallsign());
|
||||||
|
}
|
||||||
|
return csl;
|
||||||
|
}
|
||||||
|
|
||||||
CAircraftList CSimulatedAircraftList::toAircraftList() const
|
CAircraftList CSimulatedAircraftList::toAircraftList() const
|
||||||
{
|
{
|
||||||
CAircraftList al;
|
CAircraftList al;
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ namespace BlackMisc
|
|||||||
//! All pilots (with valid data)
|
//! All pilots (with valid data)
|
||||||
BlackMisc::Network::CUserList getPilots() const;
|
BlackMisc::Network::CUserList getPilots() const;
|
||||||
|
|
||||||
|
//! Callsigns of aircraft with synchronized parts
|
||||||
|
BlackMisc::Aviation::CCallsignList getCallsignsWithSyncronizedParts() const;
|
||||||
|
|
||||||
//! \copydoc CValueObject::toQVariant
|
//! \copydoc CValueObject::toQVariant
|
||||||
virtual QVariant toQVariant() const override { return QVariant::fromValue(*this); }
|
virtual QVariant toQVariant() const override { return QVariant::fromValue(*this); }
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ namespace BlackMisc
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class OBJ, class CONTAINER>
|
||||||
|
CONTAINER ITimestampObjectList<OBJ, CONTAINER>::findBeforeAndRemove(qint64 msSinceEpoch)
|
||||||
|
{
|
||||||
|
CONTAINER result(findBefore(msSinceEpoch));
|
||||||
|
this->removeBefore(msSinceEpoch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <class OBJ, class CONTAINER>
|
template <class OBJ, class CONTAINER>
|
||||||
CONTAINER ITimestampObjectList<OBJ, CONTAINER>::findBeforeNowMinusOffset(qint64 msOffset) const
|
CONTAINER ITimestampObjectList<OBJ, CONTAINER>::findBeforeNowMinusOffset(qint64 msOffset) const
|
||||||
{
|
{
|
||||||
@@ -75,18 +83,18 @@ namespace BlackMisc
|
|||||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::latestValue() const
|
OBJ ITimestampObjectList<OBJ, CONTAINER>::latestValue() const
|
||||||
{
|
{
|
||||||
if (this->container().isEmpty()) { return OBJ(); }
|
if (this->container().isEmpty()) { return OBJ(); }
|
||||||
CONTAINER container(container()); // copy
|
CONTAINER copy(container()); // copy
|
||||||
container.sortLatestFirst();
|
copy.sortLatestFirst();
|
||||||
return container.front();
|
return copy.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class OBJ, class CONTAINER>
|
template <class OBJ, class CONTAINER>
|
||||||
OBJ ITimestampObjectList<OBJ, CONTAINER>::oldestValue() const
|
OBJ ITimestampObjectList<OBJ, CONTAINER>::oldestValue() const
|
||||||
{
|
{
|
||||||
if (this->container().isEmpty()) { return OBJ(); }
|
if (this->container().isEmpty()) { return OBJ(); }
|
||||||
CONTAINER container(container()); // copy
|
CONTAINER copy(container()); // copy
|
||||||
container.sortLatestFirst();
|
copy.sortLatestFirst();
|
||||||
return container.back();
|
return copy.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class OBJ, class CONTAINER>
|
template <class OBJ, class CONTAINER>
|
||||||
@@ -134,14 +142,14 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class OBJ, class CONTAINER>
|
template <class OBJ, class CONTAINER>
|
||||||
void ITimestampObjectList<OBJ, CONTAINER>::insertTimestampObject(const OBJ &object, int maxElements)
|
void ITimestampObjectList<OBJ, CONTAINER>::push_frontMaxElements(const OBJ &object, int maxElements)
|
||||||
{
|
{
|
||||||
Q_ASSERT(maxElements > 1);
|
Q_ASSERT(maxElements > 1);
|
||||||
if (this->container().size() >= (maxElements - 1))
|
if (this->container().size() >= (maxElements - 1))
|
||||||
{
|
{
|
||||||
this->container().truncate(maxElements - 1);
|
this->container().truncate(maxElements - 1);
|
||||||
}
|
}
|
||||||
this->container().insert_front(object);
|
this->container().push_front(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// see here for the reason of thess forward instantiations
|
// see here for the reason of thess forward instantiations
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ namespace BlackMisc
|
|||||||
//! List of objects before msSinceEpoch
|
//! List of objects before msSinceEpoch
|
||||||
CONTAINER findBefore(qint64 msSinceEpoch) const;
|
CONTAINER findBefore(qint64 msSinceEpoch) const;
|
||||||
|
|
||||||
|
//! Get objects before msSinceEpoch and remove those
|
||||||
|
CONTAINER findBeforeAndRemove(qint64 msSinceEpoch);
|
||||||
|
|
||||||
//! List of objects before now - offset
|
//! List of objects before now - offset
|
||||||
CONTAINER findBeforeNowMinusOffset(qint64 msOffset) const;
|
CONTAINER findBeforeNowMinusOffset(qint64 msOffset) const;
|
||||||
|
|
||||||
@@ -67,7 +70,7 @@ namespace BlackMisc
|
|||||||
void sortOldestFirst();
|
void sortOldestFirst();
|
||||||
|
|
||||||
//! Inserts as first object by keeping max. elements
|
//! Inserts as first object by keeping max. elements
|
||||||
void insertTimestampObject(const OBJ &object, int maxElements);
|
void push_frontMaxElements(const OBJ &object, int maxElements);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Constructor
|
//! Constructor
|
||||||
|
|||||||
@@ -81,31 +81,14 @@ namespace BlackSimPlugin
|
|||||||
if (m_clientStatus == Disconnected) { return; }
|
if (m_clientStatus == Disconnected) { return; }
|
||||||
|
|
||||||
|
|
||||||
bool ok;
|
IInterpolator::InterpolationStatus status;
|
||||||
CAircraftSituation situation = this->m_interpolator->getCurrentInterpolatedSituation(this->m_interpolator->getSituationsByCallsign(), m_callsign, -1, &ok);
|
CAircraftSituation situation = this->m_interpolator->getInterpolatedSituation(m_callsign, -1, status);
|
||||||
if (!ok) { return; }
|
|
||||||
MPPositionSlewMode positionSlewMode = aircraftSituationToFS9(situation);
|
|
||||||
|
|
||||||
QByteArray positionMessage;
|
// Test only for successful interpolation. FS9 requires constant positions
|
||||||
MultiPlayerPacketParser::writeType(positionMessage, CFs9Sdk::MULTIPLAYER_PACKET_ID_POSITION_SLEWMODE);
|
if (!status.interpolationSucceeded) return;
|
||||||
MultiPlayerPacketParser::writeSize(positionMessage, positionSlewMode.size());
|
|
||||||
positionSlewMode.packet_index = m_packetIndex;
|
|
||||||
++m_packetIndex;
|
|
||||||
positionMessage = MultiPlayerPacketParser::writeMessage(positionMessage, positionSlewMode);
|
|
||||||
|
|
||||||
sendMessage(positionMessage);
|
|
||||||
|
|
||||||
QByteArray paramMessage;
|
|
||||||
MPParam param;
|
|
||||||
MultiPlayerPacketParser::writeType(paramMessage, CFs9Sdk::MULTIPLAYER_PACKET_ID_PARAMS);
|
|
||||||
MultiPlayerPacketParser::writeSize(paramMessage, param.size());
|
|
||||||
param.packet_index = m_packetIndex;
|
|
||||||
++m_packetIndex;
|
|
||||||
paramMessage = MultiPlayerPacketParser::writeMessage(paramMessage, param);
|
|
||||||
sendMessage(paramMessage);
|
|
||||||
|
|
||||||
m_lastAircraftSituation = situation;
|
|
||||||
|
|
||||||
|
sendMultiplayerPosition(situation);
|
||||||
|
sendMultiplayerParamaters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFs9Client::initialize()
|
void CFs9Client::initialize()
|
||||||
|
|||||||
@@ -71,31 +71,32 @@ namespace BlackSimPlugin
|
|||||||
HRESULT CSimConnectDefinitions::initRemoteAircraft(const HANDLE hSimConnect)
|
HRESULT CSimConnectDefinitions::initRemoteAircraft(const HANDLE hSimConnect)
|
||||||
{
|
{
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "Initial Position", NULL, SIMCONNECT_DATATYPE_INITPOSITION);
|
// Position
|
||||||
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition, "Initial Position", NULL, SIMCONNECT_DATATYPE_INITPOSITION);
|
||||||
|
|
||||||
// Lights
|
// Lights
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT STROBE", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT STROBE", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT LANDING", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT LANDING", "Bool");
|
||||||
// hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT TAXI", "Bool");
|
// hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT TAXI", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT BEACON", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT BEACON", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT NAV", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT NAV", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LIGHT LOGO", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LIGHT LOGO", "Bool");
|
||||||
|
|
||||||
// Flaps
|
// Flaps
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LEADING EDGE FLAPS LEFT PERCENT", "Percent Over 100");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LEADING EDGE FLAPS LEFT PERCENT", "Percent Over 100");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "LEADING EDGE FLAPS RIGHT PERCENT", "Percent Over 100");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "LEADING EDGE FLAPS RIGHT PERCENT", "Percent Over 100");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "TRAILING EDGE FLAPS LEFT PERCENT", "Percent Over 100");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "TRAILING EDGE FLAPS LEFT PERCENT", "Percent Over 100");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "TRAILING EDGE FLAPS RIGHT PERCENT", "Percent Over 100");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "TRAILING EDGE FLAPS RIGHT PERCENT", "Percent Over 100");
|
||||||
|
|
||||||
// Gear & Spoiler
|
// Gear & Spoiler
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "GEAR HANDLE POSITION", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "GEAR HANDLE POSITION", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "SPOILERS HANDLE POSITION", "Percent Over 100");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "SPOILERS HANDLE POSITION", "Percent Over 100");
|
||||||
|
|
||||||
// Engines
|
// Engines
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "GENERAL ENG COMBUSTION:1", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "GENERAL ENG COMBUSTION:1", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "GENERAL ENG COMBUSTION:2", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "GENERAL ENG COMBUSTION:2", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "GENERAL ENG COMBUSTION:3", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "GENERAL ENG COMBUSTION:3", "Bool");
|
||||||
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraft, "GENERAL ENG COMBUSTION:4", "Bool");
|
hr += SimConnect_AddToDataDefinition(hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts, "GENERAL ENG COMBUSTION:4", "Bool");
|
||||||
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,10 +70,9 @@ namespace BlackSimPlugin
|
|||||||
char title[256]; //!< Aircraft model string
|
char title[256]; //!< Aircraft model string
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Data struct of remote aircraft
|
//! Data struct of remote aircraft parts
|
||||||
struct DataDefinitionRemoteAircraft
|
struct DataDefinitionRemoteAircraftParts
|
||||||
{
|
{
|
||||||
SIMCONNECT_DATA_INITPOSITION position; //!< Aircrafts position
|
|
||||||
double lightStrobe; //!< Is strobe light on?
|
double lightStrobe; //!< Is strobe light on?
|
||||||
double lightLanding; //!< Is landing light on?
|
double lightLanding; //!< Is landing light on?
|
||||||
// double lightTaxi; //!< Is taxi light on?
|
// double lightTaxi; //!< Is taxi light on?
|
||||||
@@ -141,7 +140,8 @@ namespace BlackSimPlugin
|
|||||||
{
|
{
|
||||||
DataOwnAircraft,
|
DataOwnAircraft,
|
||||||
DataOwnAircraftTitle,
|
DataOwnAircraftTitle,
|
||||||
DataRemoteAircraft,
|
DataRemoteAircraftParts,
|
||||||
|
DataRemoteAircraftPosition,
|
||||||
DataSimEnvironment,
|
DataSimEnvironment,
|
||||||
DataClientAreaSb, //!< whole SB area
|
DataClientAreaSb, //!< whole SB area
|
||||||
DataClientAreaSbIdent, //!< ident single value
|
DataClientAreaSbIdent, //!< ident single value
|
||||||
|
|||||||
@@ -597,111 +597,138 @@ namespace BlackSimPlugin
|
|||||||
|
|
||||||
void CSimulatorFsx::updateRemoteAircraft()
|
void CSimulatorFsx::updateRemoteAircraft()
|
||||||
{
|
{
|
||||||
static_assert(sizeof(DataDefinitionRemoteAircraft) == 176, "DataDefinitionRemoteAircraft has an incorrect size.");
|
static_assert(sizeof(DataDefinitionRemoteAircraftParts) == 120, "DataDefinitionRemoteAircraftParts has an incorrect size.");
|
||||||
Q_ASSERT(this->m_interpolator);
|
Q_ASSERT(this->m_interpolator);
|
||||||
Q_ASSERT_X(this->m_interpolator->thread() != this->thread(), "updateOtherAircraft", "interpolator should run in its own thread");
|
Q_ASSERT_X(this->m_interpolator->thread() != this->thread(), "updateOtherAircraft", "interpolator should run in its own thread");
|
||||||
|
|
||||||
// nothing to do, reset request id and exit
|
// nothing to do, reset request id and exit
|
||||||
|
if (this->isPaused()) { return; } // no interpolation while paused
|
||||||
int remoteAircraftNo = this->remoteAircraft().size();
|
int remoteAircraftNo = this->remoteAircraft().size();
|
||||||
if (remoteAircraftNo < 1) { m_interpolationRequest = 0; return; }
|
if (remoteAircraftNo < 1) { m_interpolationRequest = 0; return; }
|
||||||
|
|
||||||
// initial request, and bye. First time we have aircraft
|
// interpolate and send to SIM
|
||||||
if (m_interpolationRequest == 0)
|
m_interpolationRequest++;
|
||||||
{
|
|
||||||
m_interpolator->syncRequestSituationsCalculationsForAllCallsigns(++m_interpolationRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to get old request
|
// values used for position and parts
|
||||||
bool lastRequestAvailable = false;
|
bool isOnGround = false;
|
||||||
CAircraftSituationList interpolations = m_interpolator->getRequest(m_interpolationRequest, &lastRequestAvailable);
|
|
||||||
if (!lastRequestAvailable)
|
|
||||||
{
|
|
||||||
// warning the 1st and every 10th time
|
|
||||||
bool warning = m_interpolationsSkipped % 10;
|
|
||||||
m_interpolationsSkipped++;
|
|
||||||
if (warning)
|
|
||||||
{
|
|
||||||
CLogMessage(this).warning("Skipped interpolation %1 time(s)") << m_interpolationsSkipped;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// non blocking calculations in background
|
qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||||
m_interpolator->syncRequestSituationsCalculationsForAllCallsigns(++m_interpolationRequest);
|
for (const CSimConnectObject &simObj : m_simConnectObjects)
|
||||||
|
|
||||||
// now send to sim
|
|
||||||
for (const CAircraftSituation ¤tSituation : interpolations)
|
|
||||||
{
|
{
|
||||||
const CCallsign callsign(currentSituation.getCallsign());
|
const CCallsign callsign(simObj.getCallsign());
|
||||||
if (!m_simConnectObjects.contains(callsign)) { continue; } // only if aircraft is already available
|
IInterpolator::InterpolationStatus interpolatorStatus;
|
||||||
bool hasParts;
|
IInterpolator::PartsStatus partsStatus;
|
||||||
const CSimConnectObject &simObj = m_simConnectObjects[callsign];
|
|
||||||
if (simObj.getObjectId() == 0) { continue; }
|
if (simObj.getObjectId() == 0) { continue; }
|
||||||
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxInitPosition(currentSituation);
|
CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, interpolatorStatus);
|
||||||
CAircraftParts parts = m_interpolator->getLatestPartsBeforeOffset(callsign, IInterpolator::TimeOffsetMs, &hasParts);
|
|
||||||
|
|
||||||
DataDefinitionRemoteAircraft ddRemoteAircraft;
|
// having the on gground flag in parts forces me to obtain parts here
|
||||||
if (hasParts)
|
// which is not hte smartest thing regarding performance
|
||||||
|
CAircraftPartsList parts = this->m_interpolator->getAndRemovePartsBeforeOffset(callsign, currentTimestamp - IInterpolator::TimeOffsetMs, partsStatus);
|
||||||
|
if (interpolatorStatus.allTrue())
|
||||||
{
|
{
|
||||||
// we have parts
|
// update situation
|
||||||
position.OnGround = parts.isOnGround() ? 1 : 0;
|
SIMCONNECT_DATA_INITPOSITION position = aircraftSituationToFsxInitPosition(interpolatedSituation);
|
||||||
ddRemoteAircraft.position = position;
|
|
||||||
ddRemoteAircraft.lightStrobe = parts.getLights().isStrobeOn() ? 1.0 : 0.0;
|
//! \todo The onGround in parts is nuts, as already mentioned in the discussion
|
||||||
ddRemoteAircraft.lightLanding = parts.getLights().isLandingOn() ? 1.0 : 0.0;
|
// a) I am forced to read parts even if i just want to update position
|
||||||
// ddRemoteAircraft.lightTaxi = parts.getLights().isTaxiOn() ? 1.0 : 0.0;
|
// b) Unlike the other values it is not a fire aforget value, as I need it again in the next cycle
|
||||||
ddRemoteAircraft.lightBeacon = parts.getLights().isBeaconOn() ? 1.0 : 0.0;
|
if (partsStatus.supportsParts && !parts.isEmpty())
|
||||||
ddRemoteAircraft.lightNav = parts.getLights().isNavOn() ? 1.0 : 0.0;
|
{
|
||||||
ddRemoteAircraft.lightLogo = parts.getLights().isLogoOn() ? 1.0 : 0.0;
|
// we have parts, and use the closest ground
|
||||||
ddRemoteAircraft.flapsLeadingEdgeLeftPercent = parts.getFlapsPercent() / 100.0;
|
isOnGround = parts.front().isOnGround();
|
||||||
ddRemoteAircraft.flapsLeadingEdgeRightPercent = parts.getFlapsPercent() / 100.0;
|
|
||||||
ddRemoteAircraft.flapsTrailingEdgeLeftPercent = parts.getFlapsPercent() / 100.0;
|
|
||||||
ddRemoteAircraft.flapsTrailingEdgeRightPercent = parts.getFlapsPercent() / 100.0;
|
|
||||||
ddRemoteAircraft.spoilersHandlePosition = parts.isSpoilersOut() ? 1.0 : 0.0;
|
|
||||||
ddRemoteAircraft.gearHandlePosition = parts.isGearDown() ? 1 : 0;
|
|
||||||
ddRemoteAircraft.engine1Combustion = parts.isEngineOn(1) ? 1 : 0;
|
|
||||||
ddRemoteAircraft.engine2Combustion = parts.isEngineOn(2) ? 1 : 0;;
|
|
||||||
ddRemoteAircraft.engine3Combustion = parts.isEngineOn(3) ? 1 : 0;
|
|
||||||
ddRemoteAircraft.engine4Combustion = parts.isEngineOn(4) ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//! \todo interpolator, set data without parts by educated guessing whatsoever
|
isOnGround = interpolatedSituation.isOnGroundGuessed();
|
||||||
bool onGround = currentSituation.isOnGroundGuessed();
|
}
|
||||||
position.OnGround = onGround ? 1 : 0;
|
|
||||||
ddRemoteAircraft.position = position;
|
position.OnGround = isOnGround ? 1 : 0;
|
||||||
ddRemoteAircraft.gearHandlePosition = onGround ? 1 : 0;
|
HRESULT hr = S_OK;
|
||||||
|
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftPosition,
|
||||||
|
simObj.getObjectId(), 0, 0,
|
||||||
|
sizeof(SIMCONNECT_DATA_INITPOSITION), &position);
|
||||||
|
if (hr != S_OK) { CLogMessage(this).warning("Failed so set position on SimObject %1 callsign: %2") << simObj.getObjectId() << callsign; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set parts
|
||||||
|
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
|
||||||
|
if (partsStatus.supportsParts)
|
||||||
|
{
|
||||||
|
// parts is supported, but do we need to update?
|
||||||
|
if (parts.isEmpty()) { continue; }
|
||||||
|
|
||||||
|
// we have parts
|
||||||
|
CAircraftParts newestParts = parts.front();
|
||||||
|
ddRemoteAircraftParts.lightStrobe = newestParts.getLights().isStrobeOn() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.lightLanding = newestParts.getLights().isLandingOn() ? 1.0 : 0.0;
|
||||||
|
// ddRemoteAircraftParts.lightTaxi = newestParts.getLights().isTaxiOn() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.lightBeacon = newestParts.getLights().isBeaconOn() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.lightNav = newestParts.getLights().isNavOn() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.lightLogo = newestParts.getLights().isLogoOn() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.flapsLeadingEdgeLeftPercent = newestParts.getFlapsPercent() / 100.0;
|
||||||
|
ddRemoteAircraftParts.flapsLeadingEdgeRightPercent = newestParts.getFlapsPercent() / 100.0;
|
||||||
|
ddRemoteAircraftParts.flapsTrailingEdgeLeftPercent = newestParts.getFlapsPercent() / 100.0;
|
||||||
|
ddRemoteAircraftParts.flapsTrailingEdgeRightPercent = newestParts.getFlapsPercent() / 100.0;
|
||||||
|
ddRemoteAircraftParts.spoilersHandlePosition = newestParts.isSpoilersOut() ? 1.0 : 0.0;
|
||||||
|
ddRemoteAircraftParts.gearHandlePosition = newestParts.isGearDown() ? 1 : 0;
|
||||||
|
ddRemoteAircraftParts.engine1Combustion = newestParts.isEngineOn(1) ? 1 : 0;
|
||||||
|
ddRemoteAircraftParts.engine2Combustion = newestParts.isEngineOn(2) ? 1 : 0;;
|
||||||
|
ddRemoteAircraftParts.engine3Combustion = newestParts.isEngineOn(3) ? 1 : 0;
|
||||||
|
ddRemoteAircraftParts.engine4Combustion = newestParts.isEngineOn(4) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mode is guessing parts
|
||||||
|
if (this->m_interpolationRequest % 20 != 0) { continue; } // only update every 20th cycle
|
||||||
|
if (!interpolatorStatus.allTrue()) { continue; } // no position, no really guess possible
|
||||||
|
|
||||||
|
ddRemoteAircraftParts.gearHandlePosition = isOnGround ? 1 : 0;
|
||||||
|
|
||||||
// when first detected moving, lights on
|
// when first detected moving, lights on
|
||||||
if (onGround && currentSituation.getGroundSpeed().value(CSpeedUnit::km_h()) > 15)
|
if (isOnGround)
|
||||||
{
|
{
|
||||||
// ddRemoteAircraft.light = 1.0;
|
// ddRemoteAircraftParts.lightTaxi = 1.0;
|
||||||
ddRemoteAircraft.lightBeacon = 1.0;
|
ddRemoteAircraftParts.lightBeacon = 1.0;
|
||||||
ddRemoteAircraft.lightNav = 1.0;
|
ddRemoteAircraftParts.lightNav = 1.0;
|
||||||
ddRemoteAircraft.lightLanding = 0.0;
|
|
||||||
|
double gskmh = interpolatedSituation.getGroundSpeed().value(CSpeedUnit::km_h());
|
||||||
|
if (gskmh > 7.5)
|
||||||
|
{
|
||||||
|
// mode taxi
|
||||||
|
// ddRemoteAircraftParts.lightTaxi = 1.0;
|
||||||
|
ddRemoteAircraftParts.lightLanding = 0.0;
|
||||||
}
|
}
|
||||||
else if (onGround)
|
else if (gskmh > 25)
|
||||||
{
|
{
|
||||||
// ddRemoteAircraft.lightTaxi = 0.0;
|
// mode accelaration for takeoff
|
||||||
ddRemoteAircraft.lightBeacon = 1.0;
|
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||||
ddRemoteAircraft.lightNav = 1.0;
|
ddRemoteAircraftParts.lightLanding = 1.0;
|
||||||
ddRemoteAircraft.lightLanding = 0.0;
|
|
||||||
}
|
}
|
||||||
else if (!onGround)
|
else
|
||||||
{
|
{
|
||||||
// ddRemoteAircraft.lightTaxi = 0.0;
|
// slow movements or parking
|
||||||
ddRemoteAircraft.lightBeacon = 1.0;
|
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||||
ddRemoteAircraft.lightNav = 1.0;
|
ddRemoteAircraftParts.lightLanding = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||||
|
ddRemoteAircraftParts.lightBeacon = 1.0;
|
||||||
|
ddRemoteAircraftParts.lightNav = 1.0;
|
||||||
|
// landing lights for < 10000ft (normally MSL, here ignored)
|
||||||
|
ddRemoteAircraftParts.lightLanding = (interpolatedSituation.getAltitude().value(CLengthUnit::ft()) < 10000) ? 1.0 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraft,
|
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts,
|
||||||
simObj.getObjectId(), 0, 0,
|
simObj.getObjectId(), 0, 0,
|
||||||
sizeof(DataDefinitionRemoteAircraft), &ddRemoteAircraft);
|
sizeof(DataDefinitionRemoteAircraftParts), &ddRemoteAircraftParts);
|
||||||
|
if (hr != S_OK) { CLogMessage(this).warning("Failed so set parts on SimObject %1 callsign: %2") << simObj.getObjectId() << callsign; }
|
||||||
|
|
||||||
if (hr != S_OK) { CLogMessage(this).warning("Failed so set data on SimObject"); }
|
} // all callsigns
|
||||||
} // all situations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxInitPosition(const CAircraftSituation &situation)
|
SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxInitPosition(const CAircraftSituation &situation)
|
||||||
|
|||||||
Reference in New Issue
Block a user