mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 17:35:34 +08:00
refs #386, further improvements on interpolation
* extended unit tests for interpolator / parts testing * allow to skip sorting when splitting by time * update ot aircraft to FSX in own member function * Skip time sync parts (FSX) when disabled
This commit is contained in:
@@ -66,7 +66,7 @@ namespace BlackCore
|
||||
return m_situationsByCallsign;
|
||||
}
|
||||
|
||||
CAircraftPartsList IInterpolator::getAndRemovePartsBeforeOffset(const CCallsign &callsign, qint64 cutoffTime, BlackCore::IInterpolator::PartsStatus &partsStatus)
|
||||
CAircraftPartsList IInterpolator::getAndRemovePartsBeforeTime(const CCallsign &callsign, qint64 cutoffTime, BlackCore::IInterpolator::PartsStatus &partsStatus)
|
||||
{
|
||||
static const CAircraftPartsList empty;
|
||||
partsStatus.reset();
|
||||
@@ -78,6 +78,7 @@ namespace BlackCore
|
||||
}
|
||||
else
|
||||
{
|
||||
// did we ever have parts for this callsign
|
||||
partsStatus.supportsParts = m_aircraftSupportingParts.contains(callsign);
|
||||
return empty;
|
||||
}
|
||||
@@ -99,6 +100,19 @@ namespace BlackCore
|
||||
return m_situationsByCallsign[callsign];
|
||||
}
|
||||
|
||||
CAircraftPartsList IInterpolator::getPartsForCallsign(const CCallsign &callsign) const
|
||||
{
|
||||
QReadLocker l(&m_lockParts);
|
||||
static const CAircraftPartsList empty;
|
||||
if (!m_partsByCallsign.contains(callsign)) { return empty; }
|
||||
return m_partsByCallsign[callsign];
|
||||
}
|
||||
|
||||
void IInterpolator::forceSorting(bool sort)
|
||||
{
|
||||
this->m_forceSortWhenAddingValues = sort;
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onAddedAircraftSituation(const CAircraftSituation &situation)
|
||||
{
|
||||
QWriteLocker lock(&m_lockSituations);
|
||||
@@ -110,6 +124,10 @@ namespace BlackCore
|
||||
// list from new to old
|
||||
CAircraftSituationList &l = this->m_situationsByCallsign[callsign];
|
||||
l.push_frontMaxElements(situation, MaxSituationsPerCallsign);
|
||||
if (this->m_forceSortWhenAddingValues) { l.sortLatestFirst(); }
|
||||
|
||||
// check sort order
|
||||
Q_ASSERT(l.size() < 2 || l[0].getMSecsSinceEpoch() >= l[1].getMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onAddedAircraftParts(const CAircraftParts &parts)
|
||||
@@ -123,9 +141,14 @@ namespace BlackCore
|
||||
// list sorted from new to old
|
||||
CAircraftPartsList &l = this->m_partsByCallsign[callsign];
|
||||
l.push_frontMaxElements(parts, MaxPartsPerCallsign);
|
||||
if (this->m_forceSortWhenAddingValues) { l.sortLatestFirst(); }
|
||||
|
||||
if (m_aircraftSupportingParts.contains(callsign)) { return; }
|
||||
m_aircraftSupportingParts.push_back(callsign);
|
||||
m_aircraftSupportingParts.push_back(callsign); // mark as callsign which supports parts
|
||||
|
||||
// check sort order
|
||||
Q_ASSERT(l.size() < 2 || l[0].getMSecsSinceEpoch() >= l[1].getMSecsSinceEpoch());
|
||||
|
||||
}
|
||||
|
||||
void IInterpolator::ps_onRemovedAircraft(const CCallsign &callsign)
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace BlackCore
|
||||
|
||||
//! Parts before given offset time (aka pending parts)
|
||||
//! \threadsafe
|
||||
virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeOffset(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset, PartsStatus &partsStatus);
|
||||
virtual BlackMisc::Aviation::CAircraftPartsList getAndRemovePartsBeforeTime(const BlackMisc::Aviation::CCallsign &callsign, qint64 timeOffset, PartsStatus &partsStatus);
|
||||
|
||||
//! Clear all data
|
||||
//! \threadsafe
|
||||
@@ -95,9 +95,16 @@ namespace BlackCore
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftSituationList getSituationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
|
||||
//! Parts for given callsign
|
||||
//! \threadsafe
|
||||
BlackMisc::Aviation::CAircraftPartsList getPartsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const;
|
||||
|
||||
//! Enable debug messages
|
||||
void enableDebugMessages(bool enabled);
|
||||
|
||||
//! Force sorting (latest first), not required if order can be guaranteed
|
||||
void forceSorting(bool sort);
|
||||
|
||||
static const qint64 TimeOffsetMs = 6000; //!< offset for interpolation
|
||||
static const int MaxSituationsPerCallsign = 6; //!< How many situations per callsign
|
||||
static const int MaxPartsPerCallsign = 3; //!< How many parts per callsign
|
||||
@@ -120,7 +127,8 @@ namespace BlackCore
|
||||
//! Constructor
|
||||
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProviderReadOnly *provider, const QString &workerName, QObject *parent = nullptr);
|
||||
|
||||
bool m_withDebugMsg = false; //!< allows to disable debug messages
|
||||
bool m_withDebugMsg = false; //!< allows to disable debug messages
|
||||
bool m_forceSortWhenAddingValues = false; //!< force sorting (latest first) when adding values
|
||||
BlackMisc::Aviation::CCallsignList m_aircraftSupportingParts; //!< aircraft supporting parts
|
||||
|
||||
// hashs, because not sorted by key but keeping order
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace BlackCore
|
||||
|
||||
if (situationsPerCallsign)
|
||||
{
|
||||
if (!situationsPerCallsign->contains(callsign)) { return empty; }
|
||||
if ((*situationsPerCallsign)[callsign].isEmpty()) { return empty; }
|
||||
// lock free, expected that situationsPerCallsign is a copy
|
||||
if (!situationsPerCallsign->contains(callsign)) { return empty; }
|
||||
if ((*situationsPerCallsign)[callsign].isEmpty()) { return empty; }
|
||||
splitSituations = (*situationsPerCallsign)[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
}
|
||||
else
|
||||
@@ -40,7 +41,7 @@ namespace BlackCore
|
||||
QReadLocker lock(&m_lockSituations);
|
||||
if (!m_situationsByCallsign.contains(callsign)) { return empty; }
|
||||
if (m_situationsByCallsign[callsign].isEmpty()) { return empty; }
|
||||
splitSituations = m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch);
|
||||
splitSituations = m_situationsByCallsign[callsign].splitByTime(splitTimeMsSinceEpoch, true);
|
||||
}
|
||||
|
||||
CAircraftSituationList &situationsNewer = splitSituations[0]; // newer part
|
||||
@@ -78,8 +79,8 @@ namespace BlackCore
|
||||
}
|
||||
else
|
||||
{
|
||||
oldSituation = situationsOlder.front(); // first oldest
|
||||
newSituation = situationsNewer.back(); // latest newest
|
||||
oldSituation = situationsOlder.front(); // first oldest (aka newest oldest)
|
||||
newSituation = situationsNewer.back(); // latest newest (aka oldest of newer block)
|
||||
Q_ASSERT(oldSituation.getMSecsSinceEpoch() < newSituation.getMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
@@ -103,12 +104,12 @@ namespace BlackCore
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
|
||||
const CLatitude oldLat(oldSituation.latitude());
|
||||
const CLatitude newLat(newSituation.latitude());
|
||||
const CLongitude oldLng(oldSituation.longitude());
|
||||
const CLongitude newLng(newSituation.longitude());
|
||||
|
||||
// Interpolate latitude: Lat = (LatB - LatA) * t + LatA
|
||||
currentPosition.setLatitude((newLat - oldLat)
|
||||
* simulationTimeFraction
|
||||
+ oldLat);
|
||||
@@ -130,6 +131,8 @@ namespace BlackCore
|
||||
|
||||
if (newLat == oldLat && newLng == oldLng && oldAlt == newAlt)
|
||||
{
|
||||
// stop interpolation here
|
||||
//! \todo Does not work for VTOL aircraft. We need a flag for VTOL aircraft
|
||||
return currentSituation;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace BlackMisc
|
||||
CSequence(std::initializer_list<T> il) : m_pimpl(new Pimpl<QList<T>>(QList<T>(il))) {}
|
||||
|
||||
/*!
|
||||
* \brief By QList of type <T>.
|
||||
* \brief By QList of type T.
|
||||
*/
|
||||
CSequence(const QList<T> &list) : m_pimpl(new Pimpl<QList<T>>(QList<T>(list))) {}
|
||||
|
||||
|
||||
@@ -76,9 +76,17 @@ namespace BlackMisc
|
||||
void CRemoteAircraftProviderDummy::insertNewSituation(const CAircraftSituation &situation)
|
||||
{
|
||||
this->m_situations.push_frontMaxElements(situation, 20);
|
||||
this->m_situations.sortLatestFirst(); // like in real world, latest should be first
|
||||
emit addedRemoteAircraftSituation(situation);
|
||||
}
|
||||
|
||||
void CRemoteAircraftProviderDummy::insertNewAircraftParts(const CAircraftParts &parts)
|
||||
{
|
||||
this->m_parts.push_frontMaxElements(parts, 20);
|
||||
this->m_parts.sortLatestFirst(); // like in real world, latest should be first
|
||||
emit addedRemoteAircraftParts(parts);
|
||||
}
|
||||
|
||||
void CRemoteAircraftProviderDummy::clear()
|
||||
{
|
||||
m_situations.clear();
|
||||
|
||||
@@ -65,7 +65,10 @@ namespace BlackMisc
|
||||
//! For testing, add new situation and fire signals
|
||||
void insertNewSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
|
||||
|
||||
// clear all data
|
||||
//! For testing, add new parts and fire signals
|
||||
void insertNewAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts);
|
||||
|
||||
//! Clear all data
|
||||
void clear();
|
||||
|
||||
signals:
|
||||
|
||||
@@ -59,10 +59,10 @@ namespace BlackMisc
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
QList<CONTAINER> ITimestampObjectList<OBJ, CONTAINER>::splitByTime(qint64 msSinceEpoch) const
|
||||
QList<CONTAINER> ITimestampObjectList<OBJ, CONTAINER>::splitByTime(qint64 msSinceEpoch, bool alreadySortedLatestFirst) const
|
||||
{
|
||||
CONTAINER newer(this->container());
|
||||
newer.sortLatestFirst();
|
||||
if (!alreadySortedLatestFirst) { newer.sortLatestFirst(); }
|
||||
CONTAINER older;
|
||||
for (auto it = newer.begin(); it != newer.end(); ++it)
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace BlackMisc
|
||||
|
||||
//! Split into 2 containers, [0] >= msSinceEpoch ("newer") [b] < msSinceEpoch ("older")
|
||||
//! \note Sort order: latest elements first
|
||||
QList<CONTAINER> splitByTime(qint64 msSinceEpoch) const;
|
||||
QList<CONTAINER> splitByTime(qint64 msSinceEpoch, bool alreadySortedLatestFirst = false) const;
|
||||
|
||||
//! Latest value
|
||||
OBJ latestValue() const;
|
||||
|
||||
@@ -552,6 +552,9 @@ namespace BlackSimPlugin
|
||||
hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluDay, "ZULU_DAY_SET");
|
||||
hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluHours, "ZULU_HOURS_SET");
|
||||
hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventSetTimeZuluMinutes, "ZULU_MINUTES_SET");
|
||||
|
||||
hr += SimConnect_MapClientEventToSimEvent(m_hSimConnect, EventToggleTaxiLights, "TOGGLE_TAXI_LIGHTS");
|
||||
|
||||
if (hr != S_OK)
|
||||
{
|
||||
CLogMessage(this).error("FSX plugin error: %1") << "SimConnect_MapClientEventToSimEvent failed";
|
||||
@@ -617,13 +620,14 @@ namespace BlackSimPlugin
|
||||
{
|
||||
const CCallsign callsign(simObj.getCallsign());
|
||||
IInterpolator::InterpolationStatus interpolatorStatus;
|
||||
IInterpolator::PartsStatus partsStatus;
|
||||
if (simObj.getObjectId() == 0) { continue; }
|
||||
CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, interpolatorStatus);
|
||||
|
||||
// having the on gground flag in parts forces me to obtain parts here
|
||||
// which is not hte smartest thing regarding performance
|
||||
CAircraftPartsList parts = this->m_interpolator->getAndRemovePartsBeforeOffset(callsign, currentTimestamp - IInterpolator::TimeOffsetMs, partsStatus);
|
||||
// having the onGround flag in parts forces me to obtain parts here
|
||||
// which is not the smartest thing regarding performance
|
||||
IInterpolator::PartsStatus partsStatus;
|
||||
CAircraftPartsList parts = this->m_interpolator->getAndRemovePartsBeforeTime(callsign, currentTimestamp - IInterpolator::TimeOffsetMs, partsStatus);
|
||||
|
||||
if (interpolatorStatus.allTrue())
|
||||
{
|
||||
// update situation
|
||||
@@ -648,87 +652,104 @@ namespace BlackSimPlugin
|
||||
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; }
|
||||
|
||||
|
||||
|
||||
} // interpolation data
|
||||
|
||||
if (interpolatorStatus.interpolationSucceeded)
|
||||
{
|
||||
// aircraft parts
|
||||
// inside interpolator if, as no parts can be sent without position
|
||||
updateRemoteAircraftParts(simObj, parts, partsStatus, interpolatedSituation, isOnGround); // update and retrieve parts in the same step
|
||||
}
|
||||
|
||||
} // all callsigns
|
||||
qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
|
||||
m_statsUpdateAircraftTimeTotal += dt;
|
||||
m_statsUpdateAircraftCount++;
|
||||
m_statsUpdateAircraftTimeAvg = m_statsUpdateAircraftTimeTotal / m_statsUpdateAircraftCount;
|
||||
}
|
||||
|
||||
// set parts
|
||||
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
|
||||
if (partsStatus.supportsParts)
|
||||
bool CSimulatorFsx::updateRemoteAircraftParts(const CSimConnectObject &simObj, const CAircraftPartsList &parts, IInterpolator::PartsStatus partsStatus, const CAircraftSituation &interpolatedSituation, bool isOnGround) const
|
||||
{
|
||||
// set parts
|
||||
DataDefinitionRemoteAircraftParts ddRemoteAircraftParts;
|
||||
if (partsStatus.supportsParts)
|
||||
{
|
||||
// parts is supported, but do we need to update?
|
||||
if (parts.isEmpty()) { return false; }
|
||||
|
||||
// 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) { return false; } // only update every 20th cycle
|
||||
ddRemoteAircraftParts.gearHandlePosition = isOnGround ? 1 : 0;
|
||||
|
||||
// when first detected moving, lights on
|
||||
if (isOnGround)
|
||||
{
|
||||
// parts is supported, but do we need to update?
|
||||
if (parts.isEmpty()) { continue; }
|
||||
// ddRemoteAircraftParts.lightTaxi = 1.0;
|
||||
ddRemoteAircraftParts.lightBeacon = 1.0;
|
||||
ddRemoteAircraftParts.lightNav = 1.0;
|
||||
|
||||
// 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
|
||||
if (isOnGround)
|
||||
double gskmh = interpolatedSituation.getGroundSpeed().value(CSpeedUnit::km_h());
|
||||
if (gskmh > 7.5)
|
||||
{
|
||||
// mode taxi
|
||||
// ddRemoteAircraftParts.lightTaxi = 1.0;
|
||||
ddRemoteAircraftParts.lightBeacon = 1.0;
|
||||
ddRemoteAircraftParts.lightNav = 1.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 (gskmh > 25)
|
||||
{
|
||||
// mode accelaration for takeoff
|
||||
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||
ddRemoteAircraftParts.lightLanding = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// slow movements or parking
|
||||
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||
ddRemoteAircraftParts.lightLanding = 0.0;
|
||||
}
|
||||
ddRemoteAircraftParts.lightLanding = 0.0;
|
||||
}
|
||||
else if (gskmh > 25)
|
||||
{
|
||||
// mode accelaration for takeoff
|
||||
// ddRemoteAircraftParts.lightTaxi = 0.0;
|
||||
ddRemoteAircraftParts.lightLanding = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// slow movements or parking
|
||||
// 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;
|
||||
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;
|
||||
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts,
|
||||
simObj.getObjectId(), 0, 0,
|
||||
sizeof(DataDefinitionRemoteAircraftParts), &ddRemoteAircraftParts);
|
||||
if (hr != S_OK) { CLogMessage(this).warning("Failed so set parts on SimObject %1 callsign: %2") << simObj.getObjectId() << callsign; }
|
||||
Q_ASSERT(m_hSimConnect);
|
||||
HRESULT hr = S_OK;
|
||||
hr += SimConnect_SetDataOnSimObject(m_hSimConnect, CSimConnectDefinitions::DataRemoteAircraftParts,
|
||||
simObj.getObjectId(), 0, 0,
|
||||
sizeof(DataDefinitionRemoteAircraftParts), &ddRemoteAircraftParts);
|
||||
|
||||
} // all callsigns
|
||||
if (hr != S_OK) { CLogMessage(this).warning("Failed so set parts on SimObject %1 callsign: %2") << simObj.getObjectId() << simObj.getCallsign(); }
|
||||
return hr == S_OK;
|
||||
}
|
||||
|
||||
SIMCONNECT_DATA_INITPOSITION CSimulatorFsx::aircraftSituationToFsxInitPosition(const CAircraftSituation &situation)
|
||||
@@ -746,8 +767,8 @@ namespace BlackSimPlugin
|
||||
|
||||
void CSimulatorFsx::synchronizeTime(const CTime &zuluTimeSim, const CTime &localTimeSim)
|
||||
{
|
||||
if (!this->m_simTimeSynced) return;
|
||||
if (!this->isConnected()) return;
|
||||
if (!this->m_simTimeSynced) { return; }
|
||||
if (!this->isConnected()) { return; }
|
||||
if (m_syncDeferredCounter > 0)
|
||||
{
|
||||
--m_syncDeferredCounter;
|
||||
@@ -766,7 +787,7 @@ namespace BlackSimPlugin
|
||||
int targetMins = myTime.hour() * 60 + myTime.minute();
|
||||
int simMins = zuluTimeSim.valueRounded(CTimeUnit::min());
|
||||
int diffMins = qAbs(targetMins - simMins);
|
||||
if (diffMins < 2) return;
|
||||
if (diffMins < 2) { return; }
|
||||
HRESULT hr = S_OK;
|
||||
hr += SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluHours, h, SIMCONNECT_GROUP_PRIORITY_STANDARD, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
hr += SimConnect_TransmitClientEvent(m_hSimConnect, 0, EventSetTimeZuluMinutes, m, SIMCONNECT_GROUP_PRIORITY_STANDARD, SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace BlackSimPlugin
|
||||
EventSetTimeZuluYear,
|
||||
EventSetTimeZuluDay,
|
||||
EventSetTimeZuluHours,
|
||||
EventSetTimeZuluMinutes
|
||||
EventSetTimeZuluMinutes,
|
||||
EventToggleTaxiLights
|
||||
};
|
||||
|
||||
//! FSX Simulator Implementation
|
||||
@@ -165,9 +166,13 @@ namespace BlackSimPlugin
|
||||
//! Initialize SimConnect data definitions
|
||||
HRESULT initDataDefinitionsWhenConnected();
|
||||
|
||||
//! Update other aircrafts
|
||||
//! Update remote aircraft
|
||||
void updateRemoteAircraft();
|
||||
|
||||
//! Update remote airacraft parts (send to FSX)
|
||||
bool updateRemoteAircraftParts(const CSimConnectObject &simObj, const BlackMisc::Aviation::CAircraftPartsList &parts,
|
||||
BlackCore::IInterpolator::PartsStatus partsStatus, const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, bool isOnGround) const;
|
||||
|
||||
//! Format conversion
|
||||
SIMCONNECT_DATA_INITPOSITION aircraftSituationToFsxInitPosition(const BlackMisc::Aviation::CAircraftSituation &situation);
|
||||
|
||||
@@ -189,6 +194,11 @@ namespace BlackSimPlugin
|
||||
BlackCore::IInterpolator *m_interpolator = nullptr; //!< interpolator instance
|
||||
QHash<BlackMisc::Aviation::CCallsign, CSimConnectObject> m_simConnectObjects;
|
||||
QFutureWatcher<bool> m_watcherConnect;
|
||||
|
||||
// statistics
|
||||
qint64 m_statsUpdateAircraftTimeTotal = 0;
|
||||
qint64 m_statsUpdateAircraftTimeAvg = 0;
|
||||
int m_statsUpdateAircraftCount = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -146,13 +146,16 @@ namespace BlackSimPlugin
|
||||
case CSimConnectDefinitions::RequestSimEnvironment:
|
||||
{
|
||||
DataDefinitionSimEnvironment *simEnv = (DataDefinitionSimEnvironment *) &pObjData->dwData;
|
||||
qint32 zh = simEnv->zuluTimeSeconds / 3600;
|
||||
qint32 zm = (simEnv->zuluTimeSeconds - (zh * 3600)) / 60;
|
||||
CTime zulu(zh, zm);
|
||||
qint32 lh = simEnv->localTimeSeconds / 3600;
|
||||
qint32 lm = (simEnv->localTimeSeconds - (lh * 3600)) / 60;
|
||||
CTime local(lh, lm);
|
||||
simulatorFsx->synchronizeTime(zulu, local);
|
||||
if (simulatorFsx->isTimeSynchronized())
|
||||
{
|
||||
int zh = simEnv->zuluTimeSeconds / 3600;
|
||||
int zm = (simEnv->zuluTimeSeconds - (zh * 3600)) / 60;
|
||||
CTime zulu(zh, zm);
|
||||
int lh = simEnv->localTimeSeconds / 3600;
|
||||
int lm = (simEnv->localTimeSeconds - (lh * 3600)) / 60;
|
||||
CTime local(lh, lm);
|
||||
simulatorFsx->synchronizeTime(zulu, local);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -171,7 +174,7 @@ namespace BlackSimPlugin
|
||||
if (!pFacilityAirport) break;
|
||||
const QString icao(pFacilityAirport->Icao);
|
||||
if (icao.isEmpty()) { continue; } // airfield without ICAO code
|
||||
if (!CAirportIcao::isValidIcaoDesignator(icao)) continue; // tiny airfields in SIM
|
||||
if (!CAirportIcao::isValidIcaoDesignator(icao)) { continue; } // tiny airfields in SIM
|
||||
CCoordinateGeodetic pos(pFacilityAirport->Latitude, pFacilityAirport->Longitude, pFacilityAirport->Altitude);
|
||||
CAirport airport(CAirportIcao(icao), pos);
|
||||
CLength d = airport.calculcateDistanceAndBearingToOwnAircraft(posAircraft);
|
||||
|
||||
Reference in New Issue
Block a user