refs #395, improvements for snapshot / restricted aircraft handling

* fixed isCurrentThreadCreatingThread and renamed to isCurrentThreadObjectThread (this check was never working), added 2 more thread checks
* changed remove aircraft function to return number of returned aircraft (like with the containers this allows to avoid unnecessary signals)
* removed unused function ps_recalculateRenderedAircraft() / SimulatorCommon
* using Queued airspaceAircraftSnapshot signal for binding (functor connect does not provide connection type)
* extened ASSERTs to check threads
* simulator: initial situation function with return value (success?)
* simulator: avoid unneccessary copy and provide correct rendered flag in add aircraft function
This commit is contained in:
Klaus Basan
2015-05-19 16:13:10 +02:00
parent beef0a5ec9
commit 880a954db9
19 changed files with 194 additions and 118 deletions

View File

@@ -7,7 +7,8 @@
* contained in the LICENSE file.
*/
#include "airspace_analyzer.h"
#include "blackcore/airspace_analyzer.h"
#include "blackcore/blackcorefreefunctions.h"
#include "blackmisc/logmessage.h"
#include <QDateTime>
@@ -30,7 +31,7 @@ namespace BlackCore
// all in new thread from here on
m_timer.setObjectName(this->objectName().append(":m_timer"));
m_timer.start(5000);
m_timer.start(7500);
bool c = connect(&m_timer, &QTimer::timeout, this, &CAirspaceAnalyzer::ps_timeout);
Q_ASSERT(c);
@@ -53,7 +54,8 @@ namespace BlackCore
Q_ASSERT(c);
Q_UNUSED(c);
this->start();
// start in own thread
this->start(QThread::LowestPriority);
}
CAirspaceAircraftSnapshot CAirspaceAnalyzer::getLatestAirspaceAircraftSnapshot() const
@@ -172,6 +174,9 @@ namespace BlackCore
void CAirspaceAnalyzer::analyzeAirspace()
{
Q_ASSERT_X(!isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Expect to run in background thread");
Q_ASSERT_X(!isApplicationThreadObjectThread(this), Q_FUNC_INFO, "Expect to run in background thread affinity");
bool restricted;
int maxAircraft;
CLength maxRenderedDistance, maxRenderedBoundary;
@@ -183,17 +188,24 @@ namespace BlackCore
maxRenderedBoundary = this->m_simulatorMaxRenderedBoundary;
}
//! \todo Analyzer: generate only when restricted?
CSimulatedAircraftList aircraftInRange(getAircraftInRange()); // thread safe copy from provider
CAirspaceAircraftSnapshot snapshot(
getAircraftInRange(), // thread safe copy
aircraftInRange,
restricted, maxAircraft, maxRenderedDistance, maxRenderedBoundary
);
// lock block
{
QWriteLocker l(&m_lockSnapshot);
snapshot.setRestrictionChanged(m_latestAircraftSnapshot);
bool wasValid = m_latestAircraftSnapshot.isValidSnapshot();
m_latestAircraftSnapshot = snapshot;
if (!wasValid) { return; } // ignore the 1st snapshot
snapshot.setRestrictionChanged(m_latestAircraftSnapshot);
}
emit airspaceAircraftSnapshot(snapshot);
}

View File

@@ -58,9 +58,12 @@ namespace BlackCore
this->connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CAirspaceMonitor::ps_receivedBookings);
this->connect(this->m_vatsimDataFileReader, &CVatsimDataFileReader::dataRead, this, &CAirspaceMonitor::ps_receivedDataFile);
// Force snapshot in the main event loop
this->connect(this->m_analyzer, &CAirspaceAnalyzer::airspaceAircraftSnapshot, this, &CAirspaceMonitor::airspaceAircraftSnapshot, Qt::QueuedConnection);
// Analyzer
this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAircraft, this, &CAirspaceMonitor::ps_pilotDisconnected);
this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAtc, this, &CAirspaceMonitor::ps_atcControllerDisconnected);
this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAircraft, this, &CAirspaceMonitor::ps_pilotDisconnected, Qt::QueuedConnection);
this->connect(this->m_analyzer, &CAirspaceAnalyzer::timeoutAtc, this, &CAirspaceMonitor::ps_atcControllerDisconnected, Qt::QueuedConnection);
}
CSimulatedAircraftList CAirspaceMonitor::getAircraftInRange() const
@@ -136,14 +139,18 @@ namespace BlackCore
std::function<void(const CAirspaceAircraftSnapshot &)> aircraftSnapshotSlot
)
{
// bind does not allow to define connection type
// so anything in its own thread will be sent with this thread affinity
QMetaObject::Connection c1 = connect(this, &CAirspaceMonitor::addedAircraftSituation, situationSlot);
Q_ASSERT(c1);
Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed");
QMetaObject::Connection c2 = connect(this, &CAirspaceMonitor::addedAircraftParts, partsSlot);
Q_ASSERT(c2);
Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed");
QMetaObject::Connection c3 = connect(this, &CAirspaceMonitor::removedAircraft, removedAircraftSlot);
Q_ASSERT(c3);
QMetaObject::Connection c4 = this->connect(this->m_analyzer, &CAirspaceAnalyzer::airspaceAircraftSnapshot, aircraftSnapshotSlot);
Q_ASSERT(c4);
Q_ASSERT_X(c3, Q_FUNC_INFO, "connect failed");
// trick is to use the Queued signal here
// analyzer (own thread) -> airspaceAircraftSnapshot -> AirspaceMonitor -> airspaceAircraftSnapshot queued in main thread
QMetaObject::Connection c4 = this->connect(this, &CAirspaceMonitor::airspaceAircraftSnapshot, aircraftSnapshotSlot);
Q_ASSERT_X(c4, Q_FUNC_INFO, "connect failed");
return QList<QMetaObject::Connection>({ c1, c2, c3, c4});
}
@@ -600,7 +607,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_receivedBookings(const CAtcStationList &bookedStations)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (bookedStations.isEmpty())
{
this->m_atcStationsBooked.clear();
@@ -620,7 +627,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_receivedDataFile()
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
for (auto client = this->m_otherClients.begin(); client != this->m_otherClients.end(); ++client)
{
if (client->hasSpecifiedVoiceCapabilities()) { continue; } // we already have voice caps
@@ -667,7 +674,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_atcPositionUpdate(const CCallsign &callsign, const BlackMisc::PhysicalQuantities::CFrequency &frequency, const CCoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &range)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
Q_ASSERT(CComSystem::isValidCivilAviationFrequency(frequency));
if (!this->m_connected) { return; }
CAtcStationList stationsWithCallsign = this->m_atcStationsOnline.findByCallsign(callsign);
@@ -718,7 +725,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_atcControllerDisconnected(const CCallsign &callsign)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
this->m_otherClients.removeByCallsign(callsign);
if (this->m_atcStationsOnline.containsCallsign(callsign))
@@ -735,7 +742,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_atisReceived(const CCallsign &callsign, const CInformationMessage &atisMessage)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (!this->m_connected || callsign.isEmpty()) return;
CPropertyIndexVariantMap vm(CAtcStation::IndexAtis, atisMessage.toCVariant());
int changedOnline = this->m_atcStationsOnline.applyIf(&CAtcStation::getCallsign, callsign, vm);
@@ -749,7 +756,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_atisVoiceRoomReceived(const CCallsign &callsign, const QString &url)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (!this->m_connected) { return; }
QString trimmedUrl = url.trimmed();
CPropertyIndexVariantMap vm({ CAtcStation::IndexVoiceRoom, CVoiceRoom::IndexUrl }, trimmedUrl);
@@ -776,7 +783,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_atisLogoffTimeReceived(const CCallsign &callsign, const QString &zuluTime)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (!this->m_connected) { return; }
if (zuluTime.length() == 4)
{
@@ -800,7 +807,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_icaoCodesReceived(const CCallsign &callsign, const CAircraftIcaoData &icaoData)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
Q_ASSERT(!callsign.isEmpty());
if (!this->m_connected) { return; }
@@ -833,7 +840,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_aircraftUpdateReceived(const CAircraftSituation &situation, const CTransponder &transponder)
{
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread");
Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Called in different thread");
if (!this->m_connected) { return; }
CCallsign callsign(situation.getCallsign());
@@ -923,7 +930,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_aircraftInterimUpdateReceived(const CAircraftSituation &situation)
{
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "Called in different thread");
Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Called in different thread");
if (!this->m_connected) { return; }
CCallsign callsign(situation.getCallsign());
@@ -955,14 +962,16 @@ namespace BlackCore
vm.addValue(CAircraft::IndexDistanceToOwnAircraft, distance);
// here I expect always a changed value
{
QWriteLocker l(&m_lockAircraft);
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
}
emit this->changedAircraftInRange();
QWriteLocker l(&m_lockAircraft);
this->m_aircraftInRange.applyIfCallsign(callsign, vm);
}
void CAirspaceMonitor::ps_pilotDisconnected(const CCallsign &callsign)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
// in case of inconsistencies I always remove here
this->m_otherClients.removeByCallsign(callsign);
@@ -989,7 +998,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_frequencyReceived(const CCallsign &callsign, const CFrequency &frequency)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
// update
int changed;
@@ -1003,7 +1012,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_aircraftConfigReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &jsonObject, bool isFull)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
CSimulatedAircraft simAircraft(getAircraftInRangeForCallsign(callsign));
@@ -1039,7 +1048,7 @@ namespace BlackCore
void CAirspaceMonitor::ps_sendInterimPositions()
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (!this->m_connected || !m_sendInterimPositions) { return; }
CSimulatedAircraftList aircrafts = m_aircraftInRange.findBy(&CSimulatedAircraft::fastPositionUpdates, true);
m_network->sendInterimPositions(aircrafts.getCallsigns());

View File

@@ -197,6 +197,9 @@ namespace BlackCore
//! An aircraft disappeared
void removedAircraft(const BlackMisc::Aviation::CCallsign &callsign);
//! \copydoc CAirspaceAnalyzer::airspaceAircraftSnapshot
void airspaceAircraftSnapshot(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
private:
BlackMisc::Aviation::CAtcStationList m_atcStationsOnline;
BlackMisc::Aviation::CAtcStationList m_atcStationsBooked;

View File

@@ -17,11 +17,25 @@ namespace BlackCore
qRegisterMetaType<BlackCore::INetwork::ConnectionStatus>();
}
bool isCurrentThreadCreatingThread(QObject *toBeTested)
bool isCurrentThreadObjectThread(QObject *toBeTested)
{
Q_ASSERT_X(toBeTested, Q_FUNC_INFO, "missing QObject");
if (!toBeTested) { return false; }
if (!toBeTested->thread()) { return false; }
return (QThread::currentThreadId() == toBeTested->thread()->currentThreadId());
return (QThread::currentThread() == toBeTested->thread());
}
bool isApplicationThreadObjectThread(QObject *toBeTested)
{
Q_ASSERT_X(toBeTested, Q_FUNC_INFO, "missing QObject");
if (!toBeTested) { return false; }
if (!toBeTested->thread()) { return false; }
return (QCoreApplication::instance()->thread() == toBeTested->thread());
}
bool isCurrentThreadApplicationThread()
{
return (QCoreApplication::instance()->thread() == QThread::currentThread());
}
} // namespace

View File

@@ -14,9 +14,17 @@ namespace BlackCore
//! Register all relevant metadata in BlackCore
BLACKCORE_EXPORT void registerMetadata();
//! Is the current thread the one created the object
//! Is the current thread the QObject's thread?
//! \remarks can be used as ASSERT check for threaded objects
BLACKCORE_EXPORT bool isCurrentThreadCreatingThread(QObject *toBeTested);
BLACKCORE_EXPORT bool isCurrentThreadObjectThread(QObject *toBeTested);
//! Is the application thread the QObject's thread?
//! \remarks can be used as ASSERT check for threaded objects
BLACKCORE_EXPORT bool isApplicationThreadObjectThread(QObject *toBeTested);
//! Is the current thread the Application thread?
//! \remarks can be used as ASSERT check for threaded objects
BLACKCORE_EXPORT bool isCurrentThreadApplicationThread();
} // BlackCore

View File

@@ -214,10 +214,10 @@ namespace BlackCore
virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) = 0;
//! Remove remote aircraft from simulator
virtual bool physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) = 0;
virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) = 0;
//! Remove all remote aircraft
virtual void physicallyRemoveAllRemoteAircraft() = 0;
virtual int physicallyRemoveAllRemoteAircraft() = 0;
//! Emit the combined status
//! \sa simulatorStatusChanged;

View File

@@ -38,7 +38,7 @@ namespace BlackCore
std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftSituation, this, std::placeholders::_1),
std::bind(&CSimulatorCommon::ps_remoteProviderAddAircraftParts, this, std::placeholders::_1),
std::bind(&CSimulatorCommon::ps_remoteProviderRemovedAircraft, this, std::placeholders::_1),
std::bind(static_cast<void(CSimulatorCommon::*)(const CAirspaceAircraftSnapshot &)>(&CSimulatorCommon::ps_recalculateRenderedAircraft), this, std::placeholders::_1));
std::bind(&CSimulatorCommon::ps_recalculateRenderedAircraft, this, std::placeholders::_1));
// timer
this->m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer"));
@@ -97,7 +97,7 @@ namespace BlackCore
for (const CSimulatedAircraft &aircraft : m_highlightedAircraft)
{
// get the current state for this aircraft
// it might has been removed in the mean time
// it might has been removed in the meantime
const CCallsign cs(aircraft.getCallsign());
resetAircraftFromBacked(cs);
}
@@ -124,19 +124,26 @@ namespace BlackCore
}
}
void CSimulatorCommon::setInitialAircraftSituationAndParts(CSimulatedAircraft &aircraft) const
bool CSimulatorCommon::setInitialAircraftSituation(CSimulatedAircraft &aircraft) const
{
if (!this->m_interpolator) { return; }
if (!this->m_interpolator) { return false; }
const CCallsign callsign(aircraft.getCallsign());
if (this->remoteAircraftSituationsCount(callsign) < 1) { return; }
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
// with an interpolator the interpolated situation is used
// to avoid position jittering
// to avoid position jittering when displayed
qint64 time = QDateTime::currentMSecsSinceEpoch();
IInterpolator::InterpolationStatus interpolationStatus;
CAircraftSituation as(m_interpolator->getInterpolatedSituation(callsign, time, aircraft.isVtol(), interpolationStatus));
if (interpolationStatus.interpolationSucceeded) { aircraft.setSituation(as); }
if (interpolationStatus.interpolationSucceeded)
{
aircraft.setSituation(as);
return true;
}
else
{
return false;
}
}
int CSimulatorCommon::getMaxRenderedAircraft() const
@@ -268,14 +275,14 @@ namespace BlackCore
emit renderRestrictionsChanged(false, getMaxRenderedAircraft(), getMaxRenderedDistance(), getRenderedDistanceBoundary());
}
bool CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns)
int CSimulatorCommon::physicallyRemoveMultipleRemoteAircraft(const CCallsignSet &callsigns)
{
int removed = 0;
for (const CCallsign &callsign : callsigns)
{
if (physicallyRemoveRemoteAircraft(callsign)) { removed++; }
}
return removed > 0;
return removed;
}
void CSimulatorCommon::ps_oneSecondTimer()
@@ -283,28 +290,29 @@ namespace BlackCore
blinkHighlightedAircraft();
}
void CSimulatorCommon::ps_recalculateRenderedAircraft()
{
this->ps_recalculateRenderedAircraft(getLatestAirspaceAircraftSnapshot());
}
void CSimulatorCommon::ps_recalculateRenderedAircraft(const CAirspaceAircraftSnapshot &snapshot)
{
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
if (!snapshot.isValidSnapshot()) { return;}
// for unrestricted values all add/remove actions are directly linked
// when changing back from restricted->unrestricted an one time update is required
if (!snapshot.isRestricted() && !snapshot.isRestrictionChanged()) { return; }
Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "Needs to run in object thread");
Q_ASSERT_X(snapshot.generatingThreadName() != QThread::currentThread(), Q_FUNC_INFO, "Expect snapshot from background thread");
// restricted snapshot values?
bool changed = false;
if (snapshot.isRenderingEnabled())
{
CCallsignSet callsignsInSimulator(physicallyRenderedAircraft());
CCallsignSet callsignsInSimulator(physicallyRenderedAircraft()); // state in simulator
CCallsignSet callsignsToBeRemoved(callsignsInSimulator.difference(snapshot.getEnabledAircraftCallsignsByDistance()));
CCallsignSet callsignsToBeAdded(snapshot.getEnabledAircraftCallsignsByDistance().difference(callsignsInSimulator));
this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved);
if (!callsignsToBeRemoved.isEmpty())
{
int r = this->physicallyRemoveMultipleRemoteAircraft(callsignsToBeRemoved);
changed = r > 0;
}
if (!callsignsToBeAdded.isEmpty())
{
@@ -312,18 +320,23 @@ namespace BlackCore
for (const CSimulatedAircraft &aircraft : aircraftToBeAdded)
{
Q_ASSERT_X(aircraft.isEnabled(), Q_FUNC_INFO, "Disabled aircraft detected as to be added");
this->physicallyAddRemoteAircraft(aircraft);
bool a = this->physicallyAddRemoteAircraft(aircraft);
changed = changed || a;
}
}
}
else
{
this->physicallyRemoveAllRemoteAircraft();
// no rendering at all, we remove everything
int r = this->physicallyRemoveAllRemoteAircraft();
changed = r > 0;
}
// we handled snapshot
emit airspaceSnapshotHandled();
if (changed)
{
emit airspaceSnapshotHandled();
}
}
void CSimulatorCommon::ps_remoteProviderAddAircraftSituation(const CAircraftSituation &situation)

View File

@@ -93,15 +93,12 @@ namespace BlackCore
virtual void deleteAllRenderingRestrictions() override;
//! \copydoc IContextSimulator::physicallyRemoveRemoteAircraft
virtual bool physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) override;
virtual int physicallyRemoveMultipleRemoteAircraft(const BlackMisc::Aviation::CCallsignSet &callsigns) override;
protected slots:
//! Slow timer used to highlight aircraft, can be used for other things too
virtual void ps_oneSecondTimer();
//! Recalculate the rendered aircraft
virtual void ps_recalculateRenderedAircraft();
//! Recalculate the rendered aircraft
virtual void ps_recalculateRenderedAircraft(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &snapshot);
@@ -130,11 +127,11 @@ namespace BlackCore
//! Blink the highlighted aircraft
void blinkHighlightedAircraft();
//! Restore aircraft from backedn data
//! Restore aircraft from backend data
void resetAircraftFromBacked(const BlackMisc::Aviation::CCallsign &callsign);
//! Override parts and situation from current interpolator values, if any!
void setInitialAircraftSituationAndParts(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const;
//! Override situation from current interpolator values, if any!
bool setInitialAircraftSituation(BlackMisc::Simulation::CSimulatedAircraft &aircraft) const;
bool m_debugMessages = false; //!< Display debug messages
bool m_blinkCycle = false; //!< use for highlighting

View File

@@ -23,7 +23,8 @@ namespace BlackMisc
const CSimulatedAircraftList &allAircraft,
bool restricted, int maxAircraft, const CLength &maxRenderedDistance, const CLength &maxRenderedBoundary) :
m_timestampMsSinceEpoch(QDateTime::currentMSecsSinceEpoch()),
m_restricted(restricted)
m_restricted(restricted),
m_threadName(QThread::currentThread()->objectName())
{
m_renderingEnabled = !restricted || (
maxAircraft > 0 &&
@@ -38,45 +39,46 @@ namespace BlackMisc
m_aircraftCallsignsByDistance = aircraft.getCallsigns();
m_vtolAircraftCallsignsByDistance = vtolAircraft.getCallsigns();
// no restrictions, just find by attributes
if (!restricted)
{
m_enabledAircraftCallsignsByDistance = aircraft.findByEnabled(true).getCallsigns();
m_disabledAircraftCallsignsByDistance = aircraft.findByEnabled(false).getCallsigns();
m_enabledVtolAircraftCallsignsByDistance = vtolAircraft.findByEnabled(true).getCallsigns();
return;
}
else
{
// if no rendering all aircraft are disabled
if (!m_renderingEnabled)
{
m_disabledAircraftCallsignsByDistance = aircraft.getCallsigns();
return;
}
int count = 0;
for (const CSimulatedAircraft &currentAircraft : aircraft)
// no rendering, this means all aircraft are disabled
if (!m_renderingEnabled)
{
m_disabledAircraftCallsignsByDistance = aircraft.getCallsigns();
return;
}
// restricted
int count = 0; // when max. aircraft reached?
for (const CSimulatedAircraft &currentAircraft : aircraft)
{
CCallsign cs(currentAircraft.getCallsign());
if (currentAircraft.isEnabled())
{
CCallsign cs(currentAircraft.getCallsign());
if (currentAircraft.isEnabled())
{
CLength distance(currentAircraft.getDistanceToOwnAircraft());
if (count >= maxAircraft ||
(!maxRenderedDistance.isNull() && distance >= maxRenderedBoundary) ||
(!maxRenderedBoundary.isNull() && distance >= maxRenderedBoundary))
{
m_disabledAircraftCallsignsByDistance.push_back(cs);
}
else
{
count++;
m_enabledAircraftCallsignsByDistance.push_back(cs);
if (currentAircraft.isVtol()) { m_enabledVtolAircraftCallsignsByDistance.push_back(cs); }
}
}
else
CLength distance(currentAircraft.getDistanceToOwnAircraft());
if (count >= maxAircraft ||
(!maxRenderedDistance.isNull() && distance >= maxRenderedBoundary) ||
(!maxRenderedBoundary.isNull() && distance >= maxRenderedBoundary))
{
m_disabledAircraftCallsignsByDistance.push_back(cs);
}
else
{
count++;
m_enabledAircraftCallsignsByDistance.push_back(cs);
if (currentAircraft.isVtol()) { m_enabledVtolAircraftCallsignsByDistance.push_back(cs); }
}
}
else
{
m_disabledAircraftCallsignsByDistance.push_back(cs);
}
}
}

View File

@@ -83,12 +83,16 @@ namespace BlackMisc
//! \copydoc CValueObject::convertToQString
QString convertToQString(bool i18n = false) const;
//! Generating thread name
const QString &generatingThreadName() const { return m_threadName; }
private:
BLACK_ENABLE_TUPLE_CONVERSION(CAirspaceAircraftSnapshot)
qint64 m_timestampMsSinceEpoch = -1;
bool m_restricted = false;
bool m_restrictionChanged = false;
bool m_renderingEnabled = true;
QString m_threadName; //!< generating thread name for debugging purposes
// remark closest aircraft always first
BlackMisc::Aviation::CCallsignSet m_aircraftCallsignsByDistance;

View File

@@ -108,6 +108,7 @@ namespace BlackMisc
std::function<void(const BlackMisc::Aviation::CCallsign &)> removedAircraftSlot,
std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> aircraftSnapshot
) = 0;
};
//! Class which can be directly used to access an \sa IRemoteAircraftProvider object
@@ -165,6 +166,6 @@ namespace BlackMisc
} // namespace
} // namespace
Q_DECLARE_INTERFACE(BlackMisc::Simulation::IRemoteAircraftProvider, "IRemoteAircraftProvider")
Q_DECLARE_INTERFACE(BlackMisc::Simulation::IRemoteAircraftProvider, "BlackMisc::Simulation::IRemoteAircraftProvider:IRemoteAircraftProvider")
#endif // guard

View File

@@ -75,6 +75,7 @@ namespace BlackMisc
template <class OBJ, class CONTAINER>
QList<CONTAINER> ITimestampObjectList<OBJ, CONTAINER>::splitByTime(qint64 msSinceEpoch, bool alreadySortedLatestFirst) const
{
// fixme: Split by time is one of the most frequently called functions in interpolator, so any performance improvement here counts
CONTAINER newer(this->container());
if (!alreadySortedLatestFirst) { newer.sortLatestFirst(); }
CONTAINER older;
@@ -82,7 +83,6 @@ namespace BlackMisc
{
if (it->isOlderThan(msSinceEpoch))
{
// better "move", ?? std::make_move_iterator
older.insert(CRange<typename CONTAINER::iterator>(it, newer.end()));
newer.erase(it, newer.end());
break;

View File

@@ -133,13 +133,17 @@ namespace BlackSimPlugin
return true;
}
void CSimulatorFs9::physicallyRemoveAllRemoteAircraft()
int CSimulatorFs9::physicallyRemoveAllRemoteAircraft()
{
if (this->m_hashFs9Clients.isEmpty()) { return 0; }
QList<CCallsign> callsigns(this->m_hashFs9Clients.keys());
int r = 0;
for (const CCallsign &cs : callsigns)
{
physicallyRemoveRemoteAircraft(cs);
if (physicallyRemoveRemoteAircraft(cs)) { r++; }
}
return r;
}
CCallsignSet CSimulatorFs9::physicallyRenderedAircraft() const

View File

@@ -64,7 +64,7 @@ namespace BlackSimPlugin
virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
//! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft
virtual void physicallyRemoveAllRemoteAircraft() override;
virtual int physicallyRemoveAllRemoteAircraft() override;
//! \copydoc ISimulator::physicallyRenderedAircraft
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;

View File

@@ -31,7 +31,7 @@ namespace BlackSimPlugin
IRemoteAircraftProvider *renderedAircraftProvider,
QObject *parent) :
CSimulatorCommon(info, ownAircraftProvider, renderedAircraftProvider, parent),
m_fsuipc(new FsCommon::CFsuipc())
m_fsuipc(new CFsuipc())
{
// hack to init mapper
CAircraftMapper *mapper = mapperInstance();

View File

@@ -139,7 +139,7 @@ namespace BlackSimPlugin
bool CSimulatorFsx::physicallyAddRemoteAircraft(const Simulation::CSimulatedAircraft &newRemoteAircraft)
{
CCallsign callsign(newRemoteAircraft.getCallsign());
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "thread");
Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
if (callsign.isEmpty()) { return false; }
@@ -151,38 +151,41 @@ namespace BlackSimPlugin
CLogMessage(this).warning("Have to remove aircraft %1 before I can add it") << callsign;
}
CSimulatedAircraft newRemoteAircraftCopy(newRemoteAircraft); // copy which can be modified
this->setInitialAircraftSituationAndParts(newRemoteAircraftCopy); // set interpolated data/parts if available
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(newRemoteAircraftCopy.getSituation());
CSimConnectObject simObj(callsign, m_nextObjID, 0, newRemoteAircraft.isVtol());
++m_nextObjID;
// matched models
CAircraftModel aircraftModel = modelMatching(newRemoteAircraftCopy);
CAircraftModel aircraftModel = modelMatching(newRemoteAircraft);
Q_ASSERT_X(newRemoteAircraft.getCallsign() == aircraftModel.getCallsign(), Q_FUNC_INFO, "mismatching callsigns");
this->updateAircraftModel(callsign, aircraftModel, simulatorOriginator());
this->updateAircraftRendered(callsign, true, simulatorOriginator());
CSimulatedAircraft aircraftAfterModelApplied(getAircraftInRangeForCallsign(newRemoteAircraft.getCallsign()));
aircraftAfterModelApplied.setRendered(true);
emit modelMatchingCompleted(aircraftAfterModelApplied);
// create AI
bool rendered = false;
if (isConnected())
{
//! \todo FSX driver if exists, recreate (new model?, new ICAO code)
// initial position
this->setInitialAircraftSituation(aircraftAfterModelApplied); // set interpolated data/parts if available
SIMCONNECT_DATA_INITPOSITION initialPosition = aircraftSituationToFsxInitPosition(aircraftAfterModelApplied.getSituation());
QByteArray m = aircraftModel.getModelString().toLocal8Bit();
HRESULT hr = SimConnect_AICreateNonATCAircraft(m_hSimConnect, m.constData(), qPrintable(callsign.toQString().left(12)), initialPosition, static_cast<SIMCONNECT_DATA_REQUEST_ID>(simObj.getRequestId()));
if (hr != S_OK) { CLogMessage(this).error("SimConnect, can not create AI traffic"); }
m_simConnectObjects.insert(callsign, simObj);
CLogMessage(this).info("FSX: Added aircraft %1") << callsign.toQString();
return true;
rendered = true;
}
else
{
CLogMessage(this).warning("FSX: Not connected, not added aircraft %1") << callsign.toQString();
return false;
}
aircraftAfterModelApplied.setRendered(rendered);
this->updateAircraftRendered(callsign, rendered, simulatorOriginator());
emit modelMatchingCompleted(aircraftAfterModelApplied);
return rendered;
}
bool CSimulatorFsx::updateOwnSimulatorCockpit(const CAircraft &ownAircraft, const QString &originator)
@@ -531,18 +534,21 @@ namespace BlackSimPlugin
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CCallsign &callsign)
{
// only remove from sim
Q_ASSERT(BlackCore::isCurrentThreadCreatingThread(this));
Q_ASSERT(BlackCore::isCurrentThreadObjectThread(this));
if (!m_simConnectObjects.contains(callsign)) { return false; }
return physicallyRemoveRemoteAircraft(m_simConnectObjects.value(callsign));
}
void CSimulatorFsx::physicallyRemoveAllRemoteAircraft()
int CSimulatorFsx::physicallyRemoveAllRemoteAircraft()
{
if (m_simConnectObjects.isEmpty()) { return 0; }
QList<CCallsign> callsigns(m_simConnectObjects.keys());
int r = 0;
for (const CCallsign &cs : callsigns)
{
physicallyRemoveRemoteAircraft(cs);
if (physicallyRemoveRemoteAircraft(cs)) { r++; }
}
return r;
}
bool CSimulatorFsx::physicallyRemoveRemoteAircraft(const CSimConnectObject &simObject)
@@ -637,7 +643,7 @@ namespace BlackSimPlugin
{
static_assert(sizeof(DataDefinitionRemoteAircraftParts) == 120, "DataDefinitionRemoteAircraftParts has an incorrect size.");
Q_ASSERT_X(this->m_interpolator, Q_FUNC_INFO, "missing interpolator");
Q_ASSERT_X(BlackCore::isCurrentThreadCreatingThread(this), Q_FUNC_INFO, "thread");
Q_ASSERT_X(BlackCore::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
// nothing to do, reset request id and exit
if (this->isPaused() && this->m_pausedSimFreezesInterpolation) { return; } // no interpolation while paused

View File

@@ -102,7 +102,7 @@ namespace BlackSimPlugin
virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
//! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft
virtual void physicallyRemoveAllRemoteAircraft() override;
virtual int physicallyRemoveAllRemoteAircraft() override;
//! \copydoc ISimulator::updateOwnCockpit
virtual bool updateOwnSimulatorCockpit(const BlackMisc::Aviation::CAircraft &ownAircraft, const QString &originator) override;

View File

@@ -393,11 +393,14 @@ namespace BlackSimPlugin
return true;
}
void CSimulatorXPlane::physicallyRemoveAllRemoteAircraft()
int CSimulatorXPlane::physicallyRemoveAllRemoteAircraft()
{
//! \todo XP driver obtain number of removed aircraft
int r = getAircraftInRangeCount();
m_traffic->removeAllPlanes();
updateMarkAllAsNotRendered(simulatorOriginator());
CLogMessage(this).info("XP: Removed all aircraft");
return r;
}
CCallsignSet CSimulatorXPlane::physicallyRenderedAircraft() const

View File

@@ -60,7 +60,7 @@ namespace BlackSimPlugin
virtual bool physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign) override;
//! \copydoc BlackCore::ISimulator::physicallyRemoveAllRemoteAircraft
virtual void physicallyRemoveAllRemoteAircraft() override;
virtual int physicallyRemoveAllRemoteAircraft() override;
//! \copydoc ISimulator::physicallyRenderedAircraft
virtual BlackMisc::Aviation::CCallsignSet physicallyRenderedAircraft() const override;