mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 23:05:36 +08:00
Move X-Plane interpolation into driver
ref T259
This commit is contained in:
committed by
Klaus Basan
parent
f3b48f75a1
commit
4db0b83310
@@ -79,7 +79,6 @@ namespace BlackSimPlugin
|
||||
{
|
||||
namespace XPlane
|
||||
{
|
||||
|
||||
CSimulatorXPlane::CSimulatorXPlane(const BlackMisc::Simulation::CSimulatorPluginInfo &info,
|
||||
IOwnAircraftProvider *ownAircraftProvider,
|
||||
IRemoteAircraftProvider *remoteAircraftProvider,
|
||||
@@ -247,6 +246,7 @@ namespace BlackSimPlugin
|
||||
connect(m_service, &CXSwiftBusServiceProxy::aircraftModelChanged, this, &CSimulatorXPlane::ps_emitOwnAircraftModelChanged);
|
||||
connect(m_service, &CXSwiftBusServiceProxy::airportsInRangeUpdated, this, &CSimulatorXPlane::ps_setAirportsInRange);
|
||||
m_service->updateAirportsInRange();
|
||||
connect(m_traffic, &CXSwiftBusTrafficProxy::simFrame, this, &CSimulatorXPlane::updateRemoteAircraft);
|
||||
if (m_watcher) { m_watcher->setConnection(m_conn); }
|
||||
loadCslPackages();
|
||||
emitSimulatorCombinedStatus();
|
||||
@@ -375,8 +375,25 @@ namespace BlackSimPlugin
|
||||
{
|
||||
if (!isConnected()) { return false; }
|
||||
|
||||
m_traffic->setInterpolatorMode(callsign.asString(), mode == CInterpolatorMulti::ModeSpline);
|
||||
return true;
|
||||
if(c_driverInterpolation)
|
||||
{
|
||||
if (mode == CInterpolatorMulti::ModeUnknown) { return false; }
|
||||
if (callsign.isEmpty())
|
||||
{
|
||||
const int c = m_xplaneAircrafts.setInterpolatorModes(mode);
|
||||
return c > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_xplaneAircrafts.contains(callsign)) { return false; }
|
||||
return m_xplaneAircrafts[callsign].setInterpolatorMode(mode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_traffic->setInterpolatorMode(callsign.asString(), mode == CInterpolatorMulti::ModeSpline);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QDBusConnection CSimulatorXPlane::connectionFromString(const QString &str)
|
||||
@@ -398,8 +415,15 @@ namespace BlackSimPlugin
|
||||
|
||||
bool CSimulatorXPlane::isPhysicallyRenderedAircraft(const CCallsign &callsign) const
|
||||
{
|
||||
//! \todo XP implement isRenderedAircraft correctly. This is a workaround, but not telling me if a callsign is really(!) visible in simulator
|
||||
return getAircraftInRangeForCallsign(callsign).isRendered();
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
return m_xplaneAircrafts.contains(callsign);
|
||||
}
|
||||
else
|
||||
{
|
||||
//! \todo XP implement isRenderedAircraft correctly. This is a workaround, but not telling me if a callsign is really(!) visible in simulator
|
||||
return getAircraftInRangeForCallsign(callsign).isRendered();
|
||||
}
|
||||
}
|
||||
|
||||
bool CSimulatorXPlane::updateOwnSimulatorCockpit(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, const CIdentifier &originator)
|
||||
@@ -487,90 +511,174 @@ namespace BlackSimPlugin
|
||||
bool CSimulatorXPlane::physicallyAddRemoteAircraft(const CSimulatedAircraft &newRemoteAircraft)
|
||||
{
|
||||
Q_ASSERT(isConnected());
|
||||
//! \todo XPlane driver check if already exists, how?
|
||||
//! \todo XPlane driver set correct return value
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
// entry checks
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
|
||||
Q_ASSERT_X(!newRemoteAircraft.getCallsign().isEmpty(), Q_FUNC_INFO, "empty callsign");
|
||||
Q_ASSERT_X(newRemoteAircraft.hasModelString(), Q_FUNC_INFO, "missing model string");
|
||||
|
||||
CAircraftModel aircraftModel = newRemoteAircraft.getModel();
|
||||
QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP
|
||||
m_traffic->addPlane(newRemoteAircraft.getCallsign().asString(), aircraftModel.getModelString(),
|
||||
newRemoteAircraft.getAircraftIcaoCode().getDesignator(),
|
||||
newRemoteAircraft.getAirlineIcaoCode().getDesignator(),
|
||||
livery);
|
||||
m_xplaneAircrafts.insert(newRemoteAircraft.getCallsign(), CXPlaneMPAircraft(newRemoteAircraft, &m_interpolationLogger));
|
||||
CAircraftModel aircraftModel = newRemoteAircraft.getModel();
|
||||
QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP
|
||||
m_traffic->addPlane(newRemoteAircraft.getCallsign().asString(), aircraftModel.getModelString(),
|
||||
newRemoteAircraft.getAircraftIcaoCode().getDesignator(),
|
||||
newRemoteAircraft.getAirlineIcaoCode().getDesignator(),
|
||||
livery);
|
||||
|
||||
CLogMessage(this).info("XP: Added aircraft %1") << newRemoteAircraft.getCallsign().toQString();
|
||||
CLogMessage(this).info("XP: Added aircraft %1") << newRemoteAircraft.getCallsign().toQString();
|
||||
|
||||
bool rendered = true;
|
||||
updateAircraftRendered(newRemoteAircraft.getCallsign(), rendered);
|
||||
bool rendered = true;
|
||||
updateAircraftRendered(newRemoteAircraft.getCallsign(), rendered);
|
||||
|
||||
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
|
||||
remoteAircraftCopy.setRendered(rendered);
|
||||
emit aircraftRenderingChanged(remoteAircraftCopy);
|
||||
return true;
|
||||
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
|
||||
remoteAircraftCopy.setRendered(rendered);
|
||||
emit aircraftRenderingChanged(remoteAircraftCopy);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CAircraftModel aircraftModel = newRemoteAircraft.getModel();
|
||||
QString livery = aircraftModel.getLivery().getCombinedCode(); //! \todo livery resolution for XP
|
||||
m_traffic->addPlane(newRemoteAircraft.getCallsign().asString(), aircraftModel.getModelString(),
|
||||
newRemoteAircraft.getAircraftIcaoCode().getDesignator(),
|
||||
newRemoteAircraft.getAirlineIcaoCode().getDesignator(),
|
||||
livery);
|
||||
|
||||
CLogMessage(this).info("XP: Added aircraft %1") << newRemoteAircraft.getCallsign().toQString();
|
||||
|
||||
bool rendered = true;
|
||||
updateAircraftRendered(newRemoteAircraft.getCallsign(), rendered);
|
||||
|
||||
CSimulatedAircraft remoteAircraftCopy(newRemoteAircraft);
|
||||
remoteAircraftCopy.setRendered(rendered);
|
||||
emit aircraftRenderingChanged(remoteAircraftCopy);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CSimulatorXPlane::onRemoteProviderAddedAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation)
|
||||
{
|
||||
Q_ASSERT(isConnected());
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
m_traffic->addPlanePosition(situation.getCallsign().asString(),
|
||||
situation.latitude().value(CAngleUnit::deg()),
|
||||
situation.longitude().value(CAngleUnit::deg()),
|
||||
situation.getAltitude().value(CLengthUnit::ft()),
|
||||
situation.getPitch().value(CAngleUnit::deg()),
|
||||
situation.getBank().value(CAngleUnit::deg()),
|
||||
situation.getHeading().value(CAngleUnit::deg()),
|
||||
situation.getMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(),
|
||||
situation.getTimeOffsetMs());
|
||||
|
||||
if (! isRemoteAircraftSupportingParts(situation.getCallsign()))
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
// if aircraft not supporting parts then guess the basics (onGround, gear, lights)
|
||||
//! \todo not working for vtol
|
||||
BlackMisc::Aviation::CAircraftParts parts;
|
||||
parts.setMSecsSinceEpoch(situation.getMSecsSinceEpoch());
|
||||
parts.setTimeOffsetMs(situation.getTimeOffsetMs());
|
||||
if (situation.getGroundSpeed() < CSpeed(50, CSpeedUnit::kts()))
|
||||
if (m_xplaneAircrafts.contains(situation.getCallsign()))
|
||||
{
|
||||
const auto nearestAirport = std::min_element(m_airportsInRange.cbegin(), m_airportsInRange.cend(), [&situation](auto &&a, auto &&b)
|
||||
{
|
||||
return calculateEuclideanDistanceSquared(situation, a) < calculateEuclideanDistanceSquared(situation, b);
|
||||
});
|
||||
if (nearestAirport != m_airportsInRange.cend() && situation.getAltitude() - nearestAirport->getElevation() < CLength(50, CLengthUnit::ft()))
|
||||
{
|
||||
parts.setOnGround(true);
|
||||
parts.setGearDown(true);
|
||||
}
|
||||
m_xplaneAircrafts[situation.getCallsign()].addAircraftSituation(situation);
|
||||
}
|
||||
if (situation.getAltitude() < CAltitude(10000, CLengthUnit::ft()))
|
||||
{
|
||||
parts.setLights({ true, true, true, true, true, true, true, true });
|
||||
}
|
||||
else
|
||||
{
|
||||
parts.setLights({ true, false, false, true, true, true, true, true });
|
||||
}
|
||||
onRemoteProviderAddedAircraftParts(situation.getCallsign(), parts);
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
m_traffic->addPlanePosition(situation.getCallsign().asString(),
|
||||
situation.latitude().value(CAngleUnit::deg()),
|
||||
situation.longitude().value(CAngleUnit::deg()),
|
||||
situation.getAltitude().value(CLengthUnit::ft()),
|
||||
situation.getPitch().value(CAngleUnit::deg()),
|
||||
situation.getBank().value(CAngleUnit::deg()),
|
||||
situation.getHeading().value(CAngleUnit::deg()),
|
||||
situation.getMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(),
|
||||
situation.getTimeOffsetMs());
|
||||
|
||||
if (! isRemoteAircraftSupportingParts(situation.getCallsign()))
|
||||
{
|
||||
// if aircraft not supporting parts then guess the basics (onGround, gear, lights)
|
||||
//! \todo not working for vtol
|
||||
BlackMisc::Aviation::CAircraftParts parts;
|
||||
parts.setMSecsSinceEpoch(situation.getMSecsSinceEpoch());
|
||||
parts.setTimeOffsetMs(situation.getTimeOffsetMs());
|
||||
if (situation.getGroundSpeed() < CSpeed(50, CSpeedUnit::kts()))
|
||||
{
|
||||
const auto nearestAirport = std::min_element(m_airportsInRange.cbegin(), m_airportsInRange.cend(), [&situation](auto &&a, auto &&b)
|
||||
{
|
||||
return calculateEuclideanDistanceSquared(situation, a) < calculateEuclideanDistanceSquared(situation, b);
|
||||
});
|
||||
if (nearestAirport != m_airportsInRange.cend() && situation.getAltitude() - nearestAirport->getElevation() < CLength(50, CLengthUnit::ft()))
|
||||
{
|
||||
parts.setOnGround(true);
|
||||
parts.setGearDown(true);
|
||||
}
|
||||
}
|
||||
if (situation.getAltitude() < CAltitude(10000, CLengthUnit::ft()))
|
||||
{
|
||||
parts.setLights({ true, true, true, true, true, true, true, true });
|
||||
}
|
||||
else
|
||||
{
|
||||
parts.setLights({ true, false, false, true, true, true, true, true });
|
||||
}
|
||||
onRemoteProviderAddedAircraftParts(situation.getCallsign(), parts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CSimulatorXPlane::onRemoteProviderAddedAircraftParts(const BlackMisc::Aviation::CCallsign &callsign, const BlackMisc::Aviation::CAircraftParts &parts)
|
||||
{
|
||||
Q_ASSERT(isConnected());
|
||||
m_traffic->addPlaneSurfaces(callsign.asString(), parts.isGearDown() ? 1 : 0,
|
||||
parts.getFlapsPercent() / 100.0, parts.isSpoilersOut() ? 1 : 0, parts.isSpoilersOut() ? 1 : 0, parts.getFlapsPercent() / 100.0,
|
||||
0, parts.isAnyEngineOn() ? 0 : 0.75, 0, 0, 0,
|
||||
parts.getLights().isLandingOn(), parts.getLights().isBeaconOn(), parts.getLights().isStrobeOn(), parts.getLights().isNavOn(),
|
||||
0, parts.isOnGround(), parts.getMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(), parts.getTimeOffsetMs());
|
||||
m_traffic->setPlaneTransponder(callsign.asString(), 2000, true, false);
|
||||
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
if (m_xplaneAircrafts.contains(callsign))
|
||||
{
|
||||
m_xplaneAircrafts[callsign].addAircraftParts(parts);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_traffic->addPlaneSurfaces(callsign.asString(), parts.isGearDown() ? 1 : 0,
|
||||
parts.getFlapsPercent() / 100.0, parts.isSpoilersOut() ? 1 : 0, parts.isSpoilersOut() ? 1 : 0, parts.getFlapsPercent() / 100.0,
|
||||
0, parts.isAnyEngineOn() ? 0 : 0.75, 0, 0, 0,
|
||||
parts.getLights().isLandingOn(), parts.getLights().isBeaconOn(), parts.getLights().isStrobeOn(), parts.getLights().isNavOn(),
|
||||
0, parts.isOnGround(), parts.getMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(), parts.getTimeOffsetMs());
|
||||
m_traffic->setPlaneTransponder(callsign.asString(), 2000, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool CSimulatorXPlane::physicallyRemoveRemoteAircraft(const BlackMisc::Aviation::CCallsign &callsign)
|
||||
{
|
||||
Q_ASSERT(isConnected());
|
||||
m_traffic->removePlane(callsign.asString());
|
||||
updateAircraftRendered(callsign, false);
|
||||
CLogMessage(this).info("XP: Removed aircraft %1") << callsign.toQString();
|
||||
return true;
|
||||
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
// only remove from sim
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "wrong thread");
|
||||
if (callsign.isEmpty()) { return false; } // can happen if an object is not an aircraft
|
||||
|
||||
// clean up anyway
|
||||
m_hints.remove(callsign);
|
||||
|
||||
// really remove from simulator
|
||||
if (!m_xplaneAircrafts.contains(callsign)) { return false; } // already fully removed or not yet added
|
||||
CXPlaneMPAircraft &xplaneAircraft = m_xplaneAircrafts[callsign];
|
||||
|
||||
// avoid further data from simulator
|
||||
// this->stopRequestingDataForSimObject(simObject);
|
||||
|
||||
m_traffic->removePlane(callsign.asString());
|
||||
|
||||
m_xplaneAircrafts.remove(callsign);
|
||||
|
||||
// mark in provider
|
||||
const bool updated = this->updateAircraftRendered(callsign, false);
|
||||
if (updated)
|
||||
{
|
||||
CSimulatedAircraft aircraft(xplaneAircraft.getAircraft());
|
||||
aircraft.setRendered(false);
|
||||
emit this->aircraftRenderingChanged(aircraft);
|
||||
}
|
||||
|
||||
// bye
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_traffic->removePlane(callsign.asString());
|
||||
updateAircraftRendered(callsign, false);
|
||||
CLogMessage(this).info("XP: Removed aircraft %1") << callsign.toQString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int CSimulatorXPlane::physicallyRemoveAllRemoteAircraft()
|
||||
@@ -578,11 +686,26 @@ namespace BlackSimPlugin
|
||||
Q_ASSERT(isConnected());
|
||||
//! \todo XP driver obtain number of removed aircraft
|
||||
resetHighlighting();
|
||||
int r = getAircraftInRangeCount();
|
||||
m_traffic->removeAllPlanes();
|
||||
updateMarkAllAsNotRendered();
|
||||
CLogMessage(this).info("XP: Removed all aircraft");
|
||||
return r;
|
||||
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
// remove one by one
|
||||
int r = 0;
|
||||
const CCallsignSet callsigns = m_xplaneAircrafts.getAllCallsigns();
|
||||
for (const CCallsign &cs : callsigns)
|
||||
{
|
||||
if (this->physicallyRemoveRemoteAircraft(cs)) { r++; }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = getAircraftInRangeCount();
|
||||
m_traffic->removeAllPlanes();
|
||||
updateMarkAllAsNotRendered();
|
||||
CLogMessage(this).info("XP: Removed all aircraft");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignSet CSimulatorXPlane::physicallyRenderedAircraft() const
|
||||
@@ -701,6 +824,187 @@ namespace BlackSimPlugin
|
||||
m_weather->setThunderstormRatio(0.0);
|
||||
}
|
||||
|
||||
void CSimulatorXPlane::updateRemoteAircraft()
|
||||
{
|
||||
Q_ASSERT_X(CThreadUtils::isCurrentThreadObjectThread(this), Q_FUNC_INFO, "thread");
|
||||
|
||||
const int remoteAircraftNo = this->getAircraftInRangeCount();
|
||||
if (remoteAircraftNo < 1) { m_interpolationRequest = 0; return; }
|
||||
|
||||
// interpolate and send to simulator
|
||||
m_interpolationRequest++;
|
||||
const bool enableAircraftParts = m_interpolationRenderingSetup.isAircraftPartsEnabled();
|
||||
const CCallsignSet aircraftWithParts = enableAircraftParts ? this->remoteAircraftSupportingParts() : CCallsignSet(); // optimization, fetch all parts supporting aircraft in one step (one lock)
|
||||
|
||||
// values used for position and parts
|
||||
const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
const CCallsignSet callsignsToLog(m_interpolationRenderingSetup.getLogCallsigns());
|
||||
|
||||
// interpolation for all remote aircraft
|
||||
const QList<CXPlaneMPAircraft> xplaneAircrafts(m_xplaneAircrafts.values());
|
||||
for (const CXPlaneMPAircraft &xplaneAircraft : xplaneAircrafts)
|
||||
{
|
||||
const CCallsign callsign(xplaneAircraft.getCallsign());
|
||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "missing callsign");
|
||||
|
||||
// fetch parts, as they are needed for ground interpolation
|
||||
const bool useAircraftParts = enableAircraftParts && aircraftWithParts.contains(callsign);
|
||||
const bool logInterpolationAndParts = callsignsToLog.contains(callsign);
|
||||
const CInterpolationAndRenderingSetup setup(this->getInterpolationAndRenderingSetup());
|
||||
CPartsStatus partsStatus(useAircraftParts);
|
||||
const CAircraftParts parts = useAircraftParts ? xplaneAircraft.getInterpolatedParts(currentTimestamp, setup, partsStatus, logInterpolationAndParts) : CAircraftParts();
|
||||
|
||||
// get interpolated situation
|
||||
CInterpolationStatus interpolatorStatus;
|
||||
CInterpolationHints hints(m_hints[callsign]);
|
||||
hints.setAircraftParts(useAircraftParts ? parts : CAircraftParts(), useAircraftParts);
|
||||
hints.setLoggingInterpolation(logInterpolationAndParts);
|
||||
const CAircraftSituation interpolatedSituation = xplaneAircraft.getInterpolatedSituation(currentTimestamp, setup, hints, interpolatorStatus);
|
||||
|
||||
if (interpolatorStatus.hasValidSituation())
|
||||
{
|
||||
// update situation
|
||||
if (!xplaneAircraft.isSameAsSent(interpolatedSituation))
|
||||
{
|
||||
m_xplaneAircrafts[xplaneAircraft.getCallsign()].setPositionAsSent(interpolatedSituation);
|
||||
m_traffic->setPlanePosition(interpolatedSituation.getCallsign().asString(),
|
||||
interpolatedSituation.latitude().value(CAngleUnit::deg()),
|
||||
interpolatedSituation.longitude().value(CAngleUnit::deg()),
|
||||
interpolatedSituation.getAltitude().value(CLengthUnit::ft()),
|
||||
interpolatedSituation.getPitch().value(CAngleUnit::deg()),
|
||||
interpolatedSituation.getBank().value(CAngleUnit::deg()),
|
||||
interpolatedSituation.getHeading().value(CAngleUnit::deg()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("Invalid situation for callsign: '%1' info: '%2'")
|
||||
<< callsign
|
||||
<< interpolatorStatus.toQString();
|
||||
}
|
||||
|
||||
if (useAircraftParts)
|
||||
{
|
||||
this->updateRemoteAircraftParts(xplaneAircraft, parts, partsStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// guess on position, but not every frame
|
||||
if (m_interpolationRequest % GuessRemoteAircraftPartsCycle == 0)
|
||||
{
|
||||
this->guessAndUpdateRemoteAircraftParts(xplaneAircraft, interpolatedSituation, interpolatorStatus);
|
||||
}
|
||||
}
|
||||
} // all callsigns
|
||||
|
||||
const qint64 dt = QDateTime::currentMSecsSinceEpoch() - currentTimestamp;
|
||||
m_statsUpdateAircraftTimeTotalMs += dt;
|
||||
m_statsUpdateAircraftCountMs++;
|
||||
m_statsUpdateAircraftTimeAvgMs = m_statsUpdateAircraftTimeTotalMs / m_statsUpdateAircraftCountMs;
|
||||
}
|
||||
|
||||
bool CSimulatorXPlane::updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, const CAircraftParts &parts, const CPartsStatus &partsStatus)
|
||||
{
|
||||
if (!partsStatus.isSupportingParts()) { return false; }
|
||||
return this->sendRemoteAircraftPartsToSimulator(xplaneAircraft, parts);
|
||||
}
|
||||
|
||||
bool CSimulatorXPlane::guessAndUpdateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft, const CAircraftSituation &interpolatedSituation, const CInterpolationStatus &interpolationStatus)
|
||||
{
|
||||
if (!interpolationStatus.isInterpolated()) { return false; }
|
||||
|
||||
CAircraftLights lights;
|
||||
CAircraftParts parts; // init members
|
||||
const bool isOnGround = interpolatedSituation.isOnGround() == CAircraftSituation::OnGround;
|
||||
const double gsKts = interpolatedSituation.getGroundSpeed().value(CSpeedUnit::kts());
|
||||
|
||||
parts.setEngines({ true, true, true, true });
|
||||
lights.setCabinOn(true);
|
||||
lights.setRecognitionOn(true);
|
||||
|
||||
// when first detected moving, lights on
|
||||
if (isOnGround)
|
||||
{
|
||||
parts.setGearDown(true);
|
||||
lights.setTaxiOn(true);
|
||||
lights.setBeaconOn(true);
|
||||
lights.setNavOn(true);
|
||||
|
||||
if (gsKts > 5)
|
||||
{
|
||||
// mode taxi
|
||||
lights.setTaxiOn(true);
|
||||
lights.setLandingOn(false);
|
||||
}
|
||||
else if (gsKts > 30)
|
||||
{
|
||||
// mode accelaration for takeoff
|
||||
lights.setTaxiOn(false);
|
||||
lights.setLandingOn(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// slow movements or parking
|
||||
lights.setTaxiOn(false);
|
||||
lights.setLandingOn(false);
|
||||
parts.setEngines({ false, false, false, false });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// not on ground
|
||||
parts.setGearDown(false);
|
||||
lights.setTaxiOn(false);
|
||||
lights.setBeaconOn(true);
|
||||
lights.setNavOn(true);
|
||||
// landing lights for < 10000ft (normally MSL, here ignored)
|
||||
lights.setLandingOn(interpolatedSituation.getAltitude().value(CLengthUnit::ft()) < 10000);
|
||||
|
||||
if (!xplaneAircraft.isVtol() && interpolatedSituation.hasGroundElevation())
|
||||
{
|
||||
if (interpolatedSituation.getHeightAboveGround().value(CLengthUnit::ft()) < 1000)
|
||||
{
|
||||
parts.setGearDown(true);
|
||||
parts.setFlapsPercent(25);
|
||||
}
|
||||
else if (interpolatedSituation.getHeightAboveGround().value(CLengthUnit::ft()) < 2000)
|
||||
{
|
||||
parts.setGearDown(true);
|
||||
parts.setFlapsPercent(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parts.setLights(lights);
|
||||
return this->sendRemoteAircraftPartsToSimulator(xplaneAircraft, parts);
|
||||
}
|
||||
|
||||
bool CSimulatorXPlane::sendRemoteAircraftPartsToSimulator(const CXPlaneMPAircraft &xplaneAircraft, const CAircraftParts &parts)
|
||||
{
|
||||
// same as in simulator or same as already send to simulator?
|
||||
if (xplaneAircraft.getPartsAsSent() == parts)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
m_traffic->setPlaneSurfaces(xplaneAircraft.getCallsign().asString(),
|
||||
parts.isGearDown() ? 1 : 0,
|
||||
parts.getFlapsPercent() / 100.0,
|
||||
parts.isSpoilersOut() ? 1 : 0,
|
||||
parts.isSpoilersOut() ? 1 : 0,
|
||||
parts.getFlapsPercent() / 100.0,
|
||||
0, parts.isAnyEngineOn() ? 0 : 0.75,
|
||||
0, 0, 0,
|
||||
parts.getLights().isLandingOn(), parts.getLights().isBeaconOn(), parts.getLights().isStrobeOn(), parts.getLights().isNavOn(),
|
||||
0, parts.isOnGround());
|
||||
|
||||
CAircraftLights lights = parts.getLights();
|
||||
lights.setRecognitionOn(parts.isAnyEngineOn());
|
||||
lights.setCabinOn(parts.isAnyEngineOn());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BlackCore::ISimulator *CSimulatorXPlaneFactory::create(const CSimulatorPluginInfo &info,
|
||||
IOwnAircraftProvider *ownAircraftProvider,
|
||||
IRemoteAircraftProvider *remoteAircraftProvider,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#ifndef BLACKSIMPLUGIN_SIMULATOR_XPLANE_H
|
||||
#define BLACKSIMPLUGIN_SIMULATOR_XPLANE_H
|
||||
|
||||
#include "xplanempaircraft.h"
|
||||
#include "blackcore/simulator.h"
|
||||
#include "blackcore/simulatorcommon.h"
|
||||
#include "plugins/simulator/xplaneconfig/simulatorxplaneconfig.h"
|
||||
@@ -143,6 +144,25 @@ namespace BlackSimPlugin
|
||||
void loadCslPackages();
|
||||
QString findCslPackage(const QString &modelFileName);
|
||||
|
||||
//! Update remote aircraft
|
||||
//! \remark this is where the interpolated data are set
|
||||
void updateRemoteAircraft();
|
||||
|
||||
//! Update remote aircraft parts (send to XSwiftBus)
|
||||
bool updateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft,
|
||||
const BlackMisc::Aviation::CAircraftParts &parts, const BlackMisc::Simulation::CPartsStatus &partsStatus);
|
||||
|
||||
//! Update remote aircraft parts by guessing (send to XSwiftBus)
|
||||
bool guessAndUpdateRemoteAircraftParts(const CXPlaneMPAircraft &xplaneAircraft,
|
||||
const BlackMisc::Aviation::CAircraftSituation &interpolatedSituation, const BlackMisc::Simulation::CInterpolationStatus &interpolationStatus);
|
||||
|
||||
//! Send parts to simulator
|
||||
bool sendRemoteAircraftPartsToSimulator(const CXPlaneMPAircraft &xplaneAircraft, const BlackMisc::Aviation::CAircraftParts &parts);
|
||||
|
||||
static constexpr bool c_driverInterpolation = true;
|
||||
static constexpr int GuessRemoteAircraftPartsCycle = 20; //!< guess every n-th cycle
|
||||
|
||||
// XSwiftBus interpolation
|
||||
QDBusConnection m_conn { "default" };
|
||||
QDBusServiceWatcher *m_watcher { nullptr };
|
||||
CXSwiftBusServiceProxy *m_service { nullptr };
|
||||
@@ -153,6 +173,10 @@ namespace BlackSimPlugin
|
||||
BlackMisc::Aviation::CAirportList m_airportsInRange; //!< aiports in range of own aircraft
|
||||
BlackMisc::CData<BlackMisc::Simulation::Data::TModelSetCacheXP> m_modelSet { this };
|
||||
|
||||
// Driver Interpolation
|
||||
CXPlaneMPAircrafts m_xplaneAircrafts; //!< XPlane multiplayer aircrafts
|
||||
int m_interpolationRequest = 0; //!< current interpolation request
|
||||
|
||||
//! \todo Add units to members? pitchDeg?, altitudeFt?
|
||||
struct // data is written by DBus async method callbacks
|
||||
{
|
||||
|
||||
124
src/plugins/simulator/xplane/xplanempaircraft.cpp
Normal file
124
src/plugins/simulator/xplane/xplanempaircraft.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* Copyright (C) 2018
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "xplanempaircraft.h"
|
||||
#include "blackmisc/simulation/interpolatormulti.h"
|
||||
|
||||
using namespace BlackMisc::Aviation;
|
||||
using namespace BlackMisc::Simulation;
|
||||
|
||||
namespace BlackSimPlugin
|
||||
{
|
||||
namespace XPlane
|
||||
{
|
||||
CXPlaneMPAircraft::CXPlaneMPAircraft()
|
||||
{ }
|
||||
|
||||
CXPlaneMPAircraft::CXPlaneMPAircraft(const CSimulatedAircraft &aircraft,
|
||||
CInterpolationLogger *logger) :
|
||||
m_aircraft(aircraft),
|
||||
m_interpolator(QSharedPointer<CInterpolatorMulti>::create(aircraft.getCallsign()))
|
||||
{
|
||||
m_interpolator->attachLogger(logger);
|
||||
|
||||
// if available set situation and parts
|
||||
if (aircraft.isPartsSynchronized()) { this->addAircraftParts(aircraft.getParts()); }
|
||||
if (aircraft.getSituation().hasValidTimestamp()) { this->addAircraftSituation(aircraft.getSituation()); }
|
||||
}
|
||||
|
||||
CXPlaneMPAircraft::CXPlaneMPAircraft(const CAircraftSituation &situation) :
|
||||
m_interpolator(QSharedPointer<CInterpolatorMulti>::create(situation.getCallsign()))
|
||||
{
|
||||
if (situation.hasValidTimestamp()) { this->addAircraftSituation(situation); }
|
||||
}
|
||||
|
||||
CXPlaneMPAircraft::CXPlaneMPAircraft(const CAircraftParts &parts, const CCallsign &callsign) :
|
||||
m_interpolator(QSharedPointer<CInterpolatorMulti>::create(callsign))
|
||||
{
|
||||
if (parts.hasValidTimestamp()) { this->addAircraftParts(parts); }
|
||||
}
|
||||
|
||||
void CXPlaneMPAircraft::addAircraftParts(const CAircraftParts &parts)
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
Q_ASSERT(parts.hasValidTimestamp());
|
||||
m_interpolator->addAircraftParts(parts);
|
||||
m_aircraft.setParts(parts);
|
||||
}
|
||||
|
||||
void CXPlaneMPAircraft::addAircraftSituation(const CAircraftSituation &situation)
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
Q_ASSERT(situation.hasValidTimestamp());
|
||||
m_interpolator->addAircraftSituation(situation);
|
||||
m_aircraft.setSituation(situation); // update with last situation
|
||||
}
|
||||
|
||||
bool CXPlaneMPAircraft::isSameAsSent(const CAircraftSituation &position) const
|
||||
{
|
||||
return m_positionAsSent == position;
|
||||
}
|
||||
|
||||
void CXPlaneMPAircraft::toggleInterpolatorMode()
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
m_interpolator->toggleMode();
|
||||
}
|
||||
|
||||
bool CXPlaneMPAircraft::setInterpolatorMode(CInterpolatorMulti::Mode mode)
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
return m_interpolator->setMode(mode);
|
||||
}
|
||||
|
||||
QString CXPlaneMPAircraft::getInterpolatorInfo() const
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
return m_interpolator->getInterpolatorInfo();
|
||||
}
|
||||
|
||||
void CXPlaneMPAircraft::attachInterpolatorLogger(CInterpolationLogger *logger)
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
return m_interpolator->attachLogger(logger);
|
||||
}
|
||||
|
||||
CAircraftSituation CXPlaneMPAircraft::getInterpolatedSituation(
|
||||
qint64 currentTimeSinceEpoc,
|
||||
const CInterpolationAndRenderingSetup &setup,
|
||||
const CInterpolationHints &hints, CInterpolationStatus &status) const
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
return m_interpolator->getInterpolatedSituation(currentTimeSinceEpoc, setup, hints, status);
|
||||
}
|
||||
|
||||
CAircraftParts CXPlaneMPAircraft::getInterpolatedParts(
|
||||
qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetup &setup,
|
||||
CPartsStatus &partsStatus, bool log) const
|
||||
{
|
||||
Q_ASSERT(m_interpolator);
|
||||
return m_interpolator->getInterpolatedParts(currentTimeSinceEpoc, setup, partsStatus, log);
|
||||
}
|
||||
|
||||
CCallsignSet CXPlaneMPAircrafts::getAllCallsigns() const
|
||||
{
|
||||
return CCallsignSet(this->keys());
|
||||
}
|
||||
|
||||
int CXPlaneMPAircrafts::setInterpolatorModes(CInterpolatorMulti::Mode mode)
|
||||
{
|
||||
int c = 0;
|
||||
for (const CCallsign &cs : this->keys())
|
||||
{
|
||||
if ((*this)[cs].setInterpolatorMode(mode)) c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace
|
||||
136
src/plugins/simulator/xplane/xplanempaircraft.h
Normal file
136
src/plugins/simulator/xplane/xplanempaircraft.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Copyright (C) 2018
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKSIMPLUGIN_XPLANE_XPLANEMPAIRCRAFT_H
|
||||
#define BLACKSIMPLUGIN_XPLANE_XPLANEMPAIRCRAFT_H
|
||||
|
||||
#include "blackmisc/simulation/simulatedaircraft.h"
|
||||
#include "blackmisc/simulation/interpolatormulti.h"
|
||||
#include <QSharedPointer>
|
||||
#include <QStringList>
|
||||
|
||||
namespace BlackSimPlugin
|
||||
{
|
||||
namespace XPlane
|
||||
{
|
||||
//! Class representing a X-Plane multiplayer aircraft
|
||||
class CXPlaneMPAircraft
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
CXPlaneMPAircraft();
|
||||
|
||||
//! Constructor providing initial situation/parts
|
||||
CXPlaneMPAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraft,
|
||||
BlackMisc::Simulation::CInterpolationLogger *logger);
|
||||
|
||||
//! Constructor providing initial situation
|
||||
CXPlaneMPAircraft(const BlackMisc::Aviation::CAircraftSituation &situation);
|
||||
|
||||
//! Constructor providing initial parts
|
||||
CXPlaneMPAircraft(const BlackMisc::Aviation::CAircraftParts &parts, const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Destructor
|
||||
~CXPlaneMPAircraft() {}
|
||||
|
||||
//! Get callsign
|
||||
const BlackMisc::Aviation::CCallsign &getCallsign() const { return m_aircraft.getCallsign(); }
|
||||
|
||||
//! Simulated aircraft (as added)
|
||||
const BlackMisc::Simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; }
|
||||
|
||||
//! Simulated aircraft model string
|
||||
const QString &getAircraftModelString() const { return m_aircraft.getModelString(); }
|
||||
|
||||
//! Set the aircraft
|
||||
void setAircraft(const BlackMisc::Simulation::CSimulatedAircraft &aircraft) { m_aircraft = aircraft; }
|
||||
|
||||
//! Add parts for interpolator
|
||||
void addAircraftParts(const BlackMisc::Aviation::CAircraftParts &parts);
|
||||
|
||||
//! Add situation for interpolator
|
||||
void addAircraftSituation(const BlackMisc::Aviation::CAircraftSituation &situation);
|
||||
|
||||
//! Parts as sent to simulator
|
||||
const BlackMisc::Aviation::CAircraftParts &getPartsAsSent() const { return m_partsAsSent; }
|
||||
|
||||
//! Parts as sent to simulator
|
||||
void setPartsAsSent(const BlackMisc::Aviation::CAircraftParts &parts) { m_partsAsSent = parts; }
|
||||
|
||||
//! Position as sent
|
||||
void setPositionAsSent(const BlackMisc::Aviation::CAircraftSituation &position) { m_positionAsSent = position; }
|
||||
|
||||
//! Same as sent
|
||||
bool isSameAsSent(const BlackMisc::Aviation::CAircraftSituation &position) const;
|
||||
|
||||
//! VTOL?
|
||||
bool isVtol() const { return m_aircraft.isVtol(); }
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolatorMulti::toggleMode
|
||||
void toggleInterpolatorMode();
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolatorMulti::setMode
|
||||
bool setInterpolatorMode(BlackMisc::Simulation::CInterpolatorMulti::Mode mode);
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatorInfo
|
||||
QString getInterpolatorInfo() const;
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolator::attachLogger
|
||||
void attachInterpolatorLogger(BlackMisc::Simulation::CInterpolationLogger *logger);
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedSituation
|
||||
BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
|
||||
qint64 currentTimeSinceEpoc,
|
||||
const BlackMisc::Simulation::CInterpolationAndRenderingSetup &setup,
|
||||
const BlackMisc::Simulation::CInterpolationHints &hints, BlackMisc::Simulation::CInterpolationStatus &status) const;
|
||||
|
||||
//! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolatedParts
|
||||
BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
|
||||
qint64 currentTimeSinceEpoc,
|
||||
const BlackMisc::Simulation::CInterpolationAndRenderingSetup &setup,
|
||||
BlackMisc::Simulation::CPartsStatus &partsStatus, bool log) const;
|
||||
|
||||
//! Interpolator
|
||||
BlackMisc::Simulation::CInterpolatorMulti *getInterpolator() const { return m_interpolator.data(); }
|
||||
|
||||
private:
|
||||
BlackMisc::Simulation::CSimulatedAircraft m_aircraft; //!< corresponding aircraft
|
||||
QSharedPointer<BlackMisc::Simulation::CInterpolatorMulti> m_interpolator; //!< shared pointer because CSimConnectObject can be copied
|
||||
BlackMisc::Aviation::CAircraftSituation m_positionAsSent;
|
||||
BlackMisc::Aviation::CAircraftParts m_partsAsSent;
|
||||
};
|
||||
|
||||
//! Simulator objects (aka AI aircraft)
|
||||
class CXPlaneMPAircrafts : public QHash<BlackMisc::Aviation::CCallsign, CXPlaneMPAircraft>
|
||||
{
|
||||
public:
|
||||
//! Get all callsigns
|
||||
BlackMisc::Aviation::CCallsignSet getAllCallsigns() const;
|
||||
|
||||
//! Get all callsign strings
|
||||
QStringList getAllCallsignStrings(bool sorted = false) const;
|
||||
|
||||
//! Get all callsign strings as string
|
||||
QString getAllCallsignStringsAsString(bool sorted = false, const QString &separator = ", ") const;
|
||||
|
||||
//! Toggle interpolator modes
|
||||
void toggleInterpolatorModes();
|
||||
|
||||
//! Toggle interpolator modes
|
||||
void toggleInterpolatorMode(const BlackMisc::Aviation::CCallsign &callsign);
|
||||
|
||||
//! Set interpolator modes
|
||||
int setInterpolatorModes(BlackMisc::Simulation::CInterpolatorMulti::Mode mode);
|
||||
};
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
@@ -86,6 +86,11 @@ namespace BlackSimPlugin
|
||||
m_dbusInterface->callDBus(QLatin1String("addPlanePosition"), callsign, latitude, longitude, altitude, pitch, roll, heading, relativeTime, timeOffset);
|
||||
}
|
||||
|
||||
void CXSwiftBusTrafficProxy::setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading)
|
||||
{
|
||||
m_dbusInterface->callDBus(QLatin1String("setPlanePosition"), callsign, latitude, longitude, altitude, pitch, roll, heading);
|
||||
}
|
||||
|
||||
void CXSwiftBusTrafficProxy::addPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround, qint64 relativeTime, qint64 timeOffset)
|
||||
{
|
||||
@@ -93,6 +98,13 @@ namespace BlackSimPlugin
|
||||
landLight, beaconLight, strobeLight, navLight, lightPattern, onGround, relativeTime, timeOffset);
|
||||
}
|
||||
|
||||
void CXSwiftBusTrafficProxy::setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround)
|
||||
{
|
||||
m_dbusInterface->callDBus(QLatin1String("setPlaneSurfaces"), callsign, gear, flap, spoiler, speedBrake, slat, wingSweep, thrust, elevator, rudder, aileron,
|
||||
landLight, beaconLight, strobeLight, navLight, lightPattern, onGround);
|
||||
}
|
||||
|
||||
void CXSwiftBusTrafficProxy::setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident)
|
||||
{
|
||||
m_dbusInterface->callDBus(QLatin1String("setPlaneTransponder"), callsign, code, modeC, ident);
|
||||
|
||||
@@ -61,6 +61,10 @@ namespace BlackSimPlugin
|
||||
private:
|
||||
BlackMisc::CGenericDBusInterface *m_dbusInterface = nullptr;
|
||||
|
||||
signals:
|
||||
//! \copydoc XSwiftBus::CTraffic::simFrame
|
||||
void simFrame();
|
||||
|
||||
public slots:
|
||||
//! \copydoc XSwiftBus::CTraffic::initialize
|
||||
bool initialize();
|
||||
@@ -98,10 +102,17 @@ namespace BlackSimPlugin
|
||||
//! \copydoc XSwiftBus::CTraffic::addPlanePosition
|
||||
void addPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading, qint64 relativeTime, qint64 timeOffset);
|
||||
|
||||
//! \copydoc XSwiftBus::CTraffic::setPlanePosition
|
||||
void setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading);
|
||||
|
||||
//! \copydoc XSwiftBus::CTraffic::addPlaneSurfaces
|
||||
void addPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround, qint64 relativeTime, qint64 timeOffset);
|
||||
|
||||
//! \copydoc XSwiftBus::CTraffic::setPlaneSurfaces
|
||||
void setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround);
|
||||
|
||||
//! \copydoc XSwiftBus::CTraffic::setPlaneTransponder
|
||||
void setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <XPLM/XPLMProcessing.h>
|
||||
#include <XPLM/XPLMUtilities.h>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
@@ -74,6 +75,7 @@ namespace XSwiftBus
|
||||
CTraffic::CTraffic(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
XPLMRegisterDrawCallback(CTraffic::drawCallback, xplm_Phase_Airplanes, 0, this);
|
||||
}
|
||||
|
||||
CTraffic::~CTraffic()
|
||||
@@ -124,6 +126,21 @@ namespace XSwiftBus
|
||||
m_initialized = false;
|
||||
XPMPMultiplayerCleanup();
|
||||
}
|
||||
|
||||
XPLMUnregisterDrawCallback(CTraffic::drawCallback, xplm_Phase_Airplanes, 0, this);
|
||||
}
|
||||
|
||||
void CTraffic::emitSimFrame()
|
||||
{
|
||||
qint64 currentMSecsSinceEpoch = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
// The draw callback is called twice for unknown reasons each frame. We can filter the second one by
|
||||
// requiring a minimum offset of 5 ms (equal to 200 fps).
|
||||
if (currentMSecsSinceEpoch > m_timestampLastSimFrame + 5)
|
||||
{
|
||||
emit simFrame();
|
||||
m_timestampLastSimFrame = currentMSecsSinceEpoch;
|
||||
}
|
||||
}
|
||||
|
||||
int g_maxPlanes = 100;
|
||||
@@ -258,6 +275,17 @@ namespace XSwiftBus
|
||||
}
|
||||
}
|
||||
|
||||
void CTraffic::setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading)
|
||||
{
|
||||
const auto plane = m_planesByCallsign.value(callsign, nullptr);
|
||||
plane->position.lat = latitude;
|
||||
plane->position.lon = longitude;
|
||||
plane->position.elevation = altitude;
|
||||
plane->position.pitch = static_cast<float>(pitch);
|
||||
plane->position.roll = static_cast<float>(roll);
|
||||
plane->position.heading = static_cast<float>(heading);
|
||||
}
|
||||
|
||||
void CTraffic::addPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround, qint64 relativeTime, qint64 timeOffset)
|
||||
{
|
||||
@@ -295,6 +323,32 @@ namespace XSwiftBus
|
||||
}
|
||||
}
|
||||
|
||||
void CTraffic::setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround)
|
||||
{
|
||||
Q_UNUSED(onGround);
|
||||
const auto plane = m_planesByCallsign.value(callsign, nullptr);
|
||||
if (plane)
|
||||
{
|
||||
plane->hasSurfaces = true;
|
||||
plane->targetGearPosition = gear;
|
||||
plane->surfaces.flapRatio = flap;
|
||||
plane->surfaces.spoilerRatio = spoiler;
|
||||
plane->surfaces.speedBrakeRatio = speedBrake;
|
||||
plane->surfaces.slatRatio = slat;
|
||||
plane->surfaces.wingSweep = wingSweep;
|
||||
plane->surfaces.thrust = thrust;
|
||||
plane->surfaces.yokePitch = elevator;
|
||||
plane->surfaces.yokeHeading = rudder;
|
||||
plane->surfaces.yokeRoll = aileron;
|
||||
plane->surfaces.lights.landLights = landLight;
|
||||
plane->surfaces.lights.bcnLights = beaconLight;
|
||||
plane->surfaces.lights.strbLights = strobeLight;
|
||||
plane->surfaces.lights.navLights = navLight;
|
||||
plane->surfaces.lights.flashPattern = lightPattern;
|
||||
}
|
||||
}
|
||||
|
||||
void CTraffic::setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident)
|
||||
{
|
||||
const auto plane = m_planesByCallsign.value(callsign, nullptr);
|
||||
@@ -342,6 +396,20 @@ namespace XSwiftBus
|
||||
switch (dataType)
|
||||
{
|
||||
case xpmpDataType_Position:
|
||||
{
|
||||
if (c_driverInterpolation)
|
||||
{
|
||||
const auto io_position = static_cast<XPMPPlanePosition_t *>(io_data);
|
||||
io_position->lat = plane->position.lat;
|
||||
io_position->lon = plane->position.lon;
|
||||
io_position->elevation = plane->position.elevation;
|
||||
io_position->pitch = plane->position.pitch;
|
||||
io_position->roll = plane->position.roll;
|
||||
io_position->heading = plane->position.heading;
|
||||
std::strncpy(io_position->label, plane->label, sizeof(plane->label)); // fixme don't need to copy on every frame
|
||||
return xpmpData_NewData;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlackMisc::Simulation::CInterpolationAndRenderingSetup setup;
|
||||
BlackMisc::Simulation::CInterpolationStatus status;
|
||||
@@ -364,16 +432,23 @@ namespace XSwiftBus
|
||||
return xpmpData_NewData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case xpmpDataType_Surfaces:
|
||||
if (plane->hasSurfaces)
|
||||
{
|
||||
const auto currentTime = QDateTime::currentMSecsSinceEpoch();
|
||||
while (! plane->pendingSurfaces.isEmpty() && plane->pendingSurfaces.constFirst().first <= currentTime)
|
||||
|
||||
if (! c_driverInterpolation)
|
||||
{
|
||||
//! \todo if gear is currently retracted, look ahead and pull gear position from pendingSurfaces up to 5 seconds in the future
|
||||
plane->pendingSurfaces.constFirst().second(plane);
|
||||
plane->pendingSurfaces.pop_front();
|
||||
while (! plane->pendingSurfaces.isEmpty() && plane->pendingSurfaces.constFirst().first <= currentTime)
|
||||
{
|
||||
//! \todo if gear is currently retracted, look ahead and pull gear position from pendingSurfaces up to 5 seconds in the future
|
||||
plane->pendingSurfaces.constFirst().second(plane);
|
||||
plane->pendingSurfaces.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
if (plane->surfaces.gearPosition != plane->targetGearPosition)
|
||||
{
|
||||
// interpolate gear position
|
||||
@@ -412,6 +487,15 @@ namespace XSwiftBus
|
||||
}
|
||||
}
|
||||
|
||||
int CTraffic::drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon)
|
||||
{
|
||||
Q_UNUSED(phase);
|
||||
Q_UNUSED(isBefore);
|
||||
CTraffic *traffic = static_cast<CTraffic *>(refcon);
|
||||
traffic->emitSimFrame();
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//! \endcond
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <QVector>
|
||||
#include <QStringList>
|
||||
#include "XPMPMultiplayer.h"
|
||||
#include <XPLM/XPLMDisplay.h>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
@@ -65,6 +66,10 @@ namespace XSwiftBus
|
||||
//! Called by XPluginStart
|
||||
static void initLegacyData();
|
||||
|
||||
signals:
|
||||
//! Signal emitted for each simulator rendering frame
|
||||
void simFrame();
|
||||
|
||||
public slots:
|
||||
//! Initialize the multiplayer planes rendering and return true if successful
|
||||
bool initialize();
|
||||
@@ -99,13 +104,20 @@ namespace XSwiftBus
|
||||
//! Remove all traffic aircraft
|
||||
void removeAllPlanes();
|
||||
|
||||
//! Set the position of a traffic aircraft
|
||||
//! Add the position of a traffic aircraft
|
||||
void addPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading, qint64 relativeTime, qint64 timeOffset);
|
||||
|
||||
//! Set the flight control surfaces and lights of a traffic aircraft
|
||||
//! Set the position of a traffic aircraft
|
||||
void setPlanePosition(const QString &callsign, double latitude, double longitude, double altitude, double pitch, double roll, double heading);
|
||||
|
||||
//! Add the flight control surfaces and lights of a traffic aircraft
|
||||
void addPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround, qint64 relativeTime, qint64 timeOffset);
|
||||
|
||||
//! Set the flight control surfaces and lights of a traffic aircraft
|
||||
void setPlaneSurfaces(const QString &callsign, double gear, double flap, double spoiler, double speedBrake, double slat, double wingSweep, double thrust,
|
||||
double elevator, double rudder, double aileron, bool landLight, bool beaconLight, bool strobeLight, bool navLight, int lightPattern, bool onGround);
|
||||
|
||||
//! Set the transponder of a traffic aircraft
|
||||
void setPlaneTransponder(const QString &callsign, int code, bool modeC, bool ident);
|
||||
|
||||
@@ -116,6 +128,10 @@ namespace XSwiftBus
|
||||
bool m_initialized = false;
|
||||
bool m_enabled = false;
|
||||
|
||||
static constexpr bool c_driverInterpolation = true;
|
||||
|
||||
void emitSimFrame();
|
||||
|
||||
static int preferences(const char *section, const char *name, int def);
|
||||
static float preferences(const char *section, const char *name, float def);
|
||||
|
||||
@@ -137,16 +153,20 @@ namespace XSwiftBus
|
||||
float targetGearPosition = 0;
|
||||
qint64 prevSurfacesLerpTime = 0;
|
||||
XPMPPlaneRadar_t xpdr;
|
||||
XPMPPlanePosition_t position;
|
||||
Plane(void *id_, QString callsign_, QString aircraftIcao_, QString airlineIcao_, QString livery_);
|
||||
};
|
||||
QHash<QString, Plane *> m_planesByCallsign;
|
||||
QHash<void *, Plane *> m_planesById;
|
||||
qint64 m_timestampLastSimFrame = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
int getPlaneData(void *id, int dataType, void *io_data);
|
||||
static int getPlaneData(void *id, int dataType, void *io_data, void *self)
|
||||
{
|
||||
return static_cast<CTraffic *>(self)->getPlaneData(id, dataType, io_data);
|
||||
}
|
||||
|
||||
static int drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user