diff --git a/src/blackcore/simulatorcommon.cpp b/src/blackcore/simulatorcommon.cpp index bce057287..315753d33 100644 --- a/src/blackcore/simulatorcommon.cpp +++ b/src/blackcore/simulatorcommon.cpp @@ -162,7 +162,7 @@ namespace BlackCore const qint64 time = QDateTime::currentMSecsSinceEpoch(); IInterpolator::InterpolationStatus interpolationStatus; const CAircraftSituation as(m_interpolator->getInterpolatedSituation(callsign, time, aircraft.isVtol(), interpolationStatus)); - if (interpolationStatus.interpolationSucceeded) + if (interpolationStatus.didInterpolationSucceed()) { aircraft.setSituation(as); return true; diff --git a/src/blackmisc/interpolator.cpp b/src/blackmisc/interpolator.cpp index e45b75534..38df1cfd9 100644 --- a/src/blackmisc/interpolator.cpp +++ b/src/blackmisc/interpolator.cpp @@ -40,7 +40,7 @@ namespace BlackMisc CAircraftPartsList IInterpolator::getPartsBeforeTime(const CAircraftPartsList &parts, qint64 cutoffTime, BlackMisc::IInterpolator::PartsStatus &partsStatus) const { partsStatus.reset(); - partsStatus.supportsParts = true; + partsStatus.setSupportsParts(true); if (cutoffTime < 0) { return parts; } return parts.findBefore(cutoffTime); @@ -51,8 +51,8 @@ namespace BlackMisc Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign"); partsStatus.reset(); - partsStatus.supportsParts = this->isRemoteAircraftSupportingParts(callsign); - if (!partsStatus.supportsParts) { return {}; } + partsStatus.setSupportsParts(this->isRemoteAircraftSupportingParts(callsign)); + if (!partsStatus.isSupportingParts()) { return {}; } return this->remoteAircraftParts(callsign, cutoffTime); } @@ -70,22 +70,22 @@ namespace BlackMisc bool IInterpolator::InterpolationStatus::allTrue() const { - return interpolationSucceeded && changedPosition; + return m_interpolationSucceeded && m_changedPosition; } void IInterpolator::InterpolationStatus::reset() { - changedPosition = false; - interpolationSucceeded = false; + m_changedPosition = false; + m_interpolationSucceeded = false; } bool IInterpolator::PartsStatus::allTrue() const { - return supportsParts; + return m_supportsParts; } void IInterpolator::PartsStatus::reset() { - supportsParts = false; + m_supportsParts = false; } } // namespace diff --git a/src/blackmisc/interpolator.h b/src/blackmisc/interpolator.h index f0a5686af..e2eb1cb0a 100644 --- a/src/blackmisc/interpolator.h +++ b/src/blackmisc/interpolator.h @@ -43,9 +43,22 @@ namespace BlackMisc //! Status of interpolation struct BLACKMISC_EXPORT InterpolationStatus { + private: + bool m_changedPosition = false; //!< position was changed + bool m_interpolationSucceeded = false; //!< interpolation succeeded (means enough values, etc.) + public: - bool changedPosition = false; //!< position was changed - bool interpolationSucceeded = false; //!< interpolation succeeded (means enough values, etc.) + //! Did interpolation succeed? + bool didInterpolationSucceed() const { return m_interpolationSucceeded; } + + //! Set succeeded + void setInterpolationSucceeded(bool succeeded) { m_interpolationSucceeded = succeeded; } + + //! Changed position? + bool hasChangedPosition() const { return m_changedPosition; } + + //! Set as changed + void setChangedPosition(bool changed) { m_changedPosition = changed; } //! all OK bool allTrue() const; @@ -57,11 +70,19 @@ namespace BlackMisc //! Status regarding parts struct BLACKMISC_EXPORT PartsStatus { - bool supportsParts = false; //!< supports parts for given callsign + private: + bool m_supportsParts = false; //!< supports parts for given callsign + public: //! all OK bool allTrue() const; + //! Supporting parts + bool isSupportingParts() const { return m_supportsParts; } + + //! Set support flag + void setSupportsParts(bool supports) { m_supportsParts = supports; } + //! Reset to default values void reset(); }; diff --git a/src/blackmisc/interpolatorlinear.cpp b/src/blackmisc/interpolatorlinear.cpp index 75b64029b..97d4d9b1d 100644 --- a/src/blackmisc/interpolatorlinear.cpp +++ b/src/blackmisc/interpolatorlinear.cpp @@ -60,8 +60,8 @@ namespace BlackMisc // interpolation situations CAircraftSituation oldSituation; CAircraftSituation newSituation; - status.interpolationSucceeded = true; - status.changedPosition = true; //! \todo efficiently determine whether the position has changed + status.setInterpolationSucceeded(true); + status.setChangedPosition(true); //! \todo efficiently determine whether the position has changed // latest first, now 00:20 split time // time pos diff --git a/src/blackmisc/simulation/aircraftmodellist.cpp b/src/blackmisc/simulation/aircraftmodellist.cpp index 15ee92163..7fb4688fe 100644 --- a/src/blackmisc/simulation/aircraftmodellist.cpp +++ b/src/blackmisc/simulation/aircraftmodellist.cpp @@ -54,6 +54,16 @@ namespace BlackMisc return false; } + bool CAircraftModelList::containsCallsign(const CCallsign &callsign) const + { + return this->contains(&CAircraftModel::getCallsign, callsign); + } + + bool CAircraftModelList::containsModelsWithAircraftAndAirlineDesignator(const QString &aircraftDesignator, const QString &airlineDesignator) const + { + return this->contains(&CAircraftModel::getAircraftIcaoCodeDesignator, aircraftDesignator, &CAircraftModel::getAirlineIcaoCodeDesignator, airlineDesignator); + } + CAircraftModelList CAircraftModelList::findByModelString(const QString &modelString, Qt::CaseSensitivity sensitivity) const { return this->findBy([ & ](const CAircraftModel & model) diff --git a/src/blackmisc/simulation/aircraftmodellist.h b/src/blackmisc/simulation/aircraftmodellist.h index ed70f5052..ea3f49a58 100644 --- a/src/blackmisc/simulation/aircraftmodellist.h +++ b/src/blackmisc/simulation/aircraftmodellist.h @@ -65,6 +65,12 @@ namespace BlackMisc //! Contains model with model string or id bool containsModelStringOrDbKey(const BlackMisc::Simulation::CAircraftModel &model, Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive) const; + //! Contains model for callsign + bool containsCallsign(const BlackMisc::Aviation::CCallsign &callsign) const; + + //! Contains any model with aircraft and airline designator + bool containsModelsWithAircraftAndAirlineDesignator(const QString &aircraftDesignator, const QString &airlineDesignator) const; + //! Find by model string //! \remark normally CAircraftModelList::findFirstByModelStringOrDefault would be used CAircraftModelList findByModelString(const QString &modelString, Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive) const; diff --git a/src/blackmisc/simulation/simulatedaircraftlist.cpp b/src/blackmisc/simulation/simulatedaircraftlist.cpp index 83422b534..8c2e5c925 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.cpp +++ b/src/blackmisc/simulation/simulatedaircraftlist.cpp @@ -153,5 +153,18 @@ namespace BlackMisc return false; } + bool CSimulatedAircraftList::replaceOrAddByCallsign(const CSimulatedAircraft &aircraft) + { + const CCallsign cs(aircraft.getCallsign()); + if (cs.isEmpty()) { return false; } + + if (this->containsCallsign(cs)) + { + int c = this->replaceIf(&CSimulatedAircraft::getCallsign, cs, aircraft); + return c > 0; + } + this->push_back(aircraft); + return true; + } } // namespace } // namespace diff --git a/src/blackmisc/simulation/simulatedaircraftlist.h b/src/blackmisc/simulation/simulatedaircraftlist.h index f5523ca65..fbd31c448 100644 --- a/src/blackmisc/simulation/simulatedaircraftlist.h +++ b/src/blackmisc/simulation/simulatedaircraftlist.h @@ -92,8 +92,9 @@ namespace BlackMisc //! Rendered? bool isRendered(const BlackMisc::Aviation::CCallsign &callsign) const; + //! Replace or add by callsign + bool replaceOrAddByCallsign(const CSimulatedAircraft &aircraft); }; - } //namespace } // namespace diff --git a/src/plugins/simulator/fs9/fs9client.cpp b/src/plugins/simulator/fs9/fs9client.cpp index 47c295db8..18aee1b7a 100644 --- a/src/plugins/simulator/fs9/fs9client.cpp +++ b/src/plugins/simulator/fs9/fs9client.cpp @@ -39,7 +39,7 @@ namespace BlackSimPlugin positionVelocity.lat_f = qAbs((latitude - positionVelocity.lat_i) * 65536); // Longitude - integer and decimal places - double longitude = newSituation.getPosition().longitude().value(CAngleUnit::deg()) * ( 65536.0 * 65536.0) / 360.0; + double longitude = newSituation.getPosition().longitude().value(CAngleUnit::deg()) * (65536.0 * 65536.0) / 360.0; positionVelocity.lon_hi = static_cast(longitude); positionVelocity.lon_lo = qAbs((longitude - positionVelocity.lon_hi) * 65536); @@ -96,7 +96,7 @@ namespace BlackSimPlugin positionSlewMode.lat_f = qAbs((latitude - positionSlewMode.lat_i) * 65536); // Longitude - integer and decimal places - double longitude = situation.getPosition().longitude().value(CAngleUnit::deg()) * ( 65536.0 * 65536.0) / 360.0; + double longitude = situation.getPosition().longitude().value(CAngleUnit::deg()) * (65536.0 * 65536.0) / 360.0; positionSlewMode.lon_hi = static_cast(longitude); positionSlewMode.lon_lo = qAbs((longitude - positionSlewMode.lon_hi) * 65536); @@ -119,7 +119,7 @@ namespace BlackSimPlugin } CFs9Client::CFs9Client(const CCallsign &callsign, const QString &modelName, - BlackMisc::IInterpolator *interpolator, const CTime &updateInterval, QObject *owner) : + BlackMisc::IInterpolator *interpolator, const CTime &updateInterval, QObject *owner) : CDirectPlayPeer(owner, callsign), m_updateInterval(updateInterval), m_interpolator(interpolator), m_modelName(modelName) { @@ -174,7 +174,7 @@ namespace BlackSimPlugin CAircraftSituation situation = this->m_interpolator->getInterpolatedSituation(m_callsign, -1, vtolAircraft, status); // Test only for successful interpolation. FS9 requires constant positions - if (!status.interpolationSucceeded) { return; } + if (!status.didInterpolationSucceed()) { return; } sendMultiplayerPosition(situation); sendMultiplayerParamaters(); diff --git a/src/plugins/simulator/fsx/simconnectobject.cpp b/src/plugins/simulator/fsx/simconnectobject.cpp index cae8507e6..1452ac3b2 100644 --- a/src/plugins/simulator/fsx/simconnectobject.cpp +++ b/src/plugins/simulator/fsx/simconnectobject.cpp @@ -9,6 +9,9 @@ #include "simconnectobject.h" +using namespace BlackMisc::Aviation; +using namespace BlackMisc::Simulation; + namespace BlackSimPlugin { namespace Fsx @@ -19,9 +22,83 @@ namespace BlackSimPlugin m_aircraft(aircraft), m_requestId(requestId) { } + bool CSimConnectObject::hasValidRequestId() const + { + return this->m_requestId >= 0; + } + + bool CSimConnectObject::hasValidobjectId() const + { + return this->m_objectId >= 0; + } + + bool CSimConnectObject::isPendingAdded() const + { + return !this->hasValidRequestAndObjectId() || !this->m_confirmedAdded; + } + + bool CSimConnectObject::isConfirmedAdded() const + { + Q_ASSERT_X(!m_confirmedAdded || this->hasValidRequestAndObjectId(), Q_FUNC_INFO, "confirmed but invalid ids"); + return m_confirmedAdded; + } + + void CSimConnectObject::setConfirmedAdded(bool confirm) + { + m_confirmedAdded = confirm; + m_aircraft.setRendered(true); + } + + void CSimConnectObject::setPendingRemoved(bool pending) + { + m_pendingRemoved = pending; + m_aircraft.setRendered(false); + } + bool CSimConnectObject::hasValidRequestAndObjectId() const { - return this->m_requestId >= 0 && this->m_objectId >= 0; + return this->hasValidRequestId() && this->hasValidobjectId(); + } + + bool CSimConnectObjects::setSimConnectObjectId(int requestID, int objectId) + { + // First check, if this request id belongs to us + const int requestIntId = static_cast(requestID); + auto it = std::find_if(this->begin(), this->end(), [requestIntId](const CSimConnectObject & obj) { return obj.getRequestId() == requestIntId; }); + if (it == this->end()) { return false; } + + // belongs to us + it->setObjectId(objectId); + return true; + } + + CCallsign CSimConnectObjects::getCallsignForObjectId(int objectId) const + { + return getSimObjectForObjectId(objectId).getCallsign(); + } + + CSimConnectObject CSimConnectObjects::getSimObjectForObjectId(int objectId) const + { + for (const CSimConnectObject &simObject : this->values()) + { + if (simObject.getObjectId() == objectId) { return simObject; } + } + return CSimConnectObject(); + } + + bool CSimConnectObjects::isKnownSimObjectId(int objectId) const + { + const CSimConnectObject simObject(getSimObjectForObjectId(objectId)); + return simObject.hasValidRequestAndObjectId() && objectId == simObject.getObjectId(); + } + + bool CSimConnectObjects::containsPendingAdd() const + { + for (const CSimConnectObject &simObject : this->values()) + { + if (simObject.isPendingAdded()) { return true; } + } + return false; } } // namespace } // namespace diff --git a/src/plugins/simulator/fsx/simconnectobject.h b/src/plugins/simulator/fsx/simconnectobject.h index 240800ff6..0a0358ed4 100644 --- a/src/plugins/simulator/fsx/simconnectobject.h +++ b/src/plugins/simulator/fsx/simconnectobject.h @@ -29,16 +29,16 @@ namespace BlackSimPlugin CSimConnectObject(); //! Constructor - CSimConnectObject(const BlackMisc::Simulation::CSimulatedAircraft &aircraft,int requestId); + CSimConnectObject(const BlackMisc::Simulation::CSimulatedAircraft &aircraft, int requestId); //! Destructor ~CSimConnectObject() {} //! Get Callsign - BlackMisc::Aviation::CCallsign getCallsign() const { return m_aircraft.getCallsign(); } + const BlackMisc::Aviation::CCallsign &getCallsign() const { return m_aircraft.getCallsign(); } //! Simulated aircraft (as added) - BlackMisc::Simulation::CSimulatedAircraft getAircraft() const { return m_aircraft; } + const BlackMisc::Simulation::CSimulatedAircraft &getAircraft() const { return m_aircraft; } //! Set Simconnect request id void setRequestId(int id) { m_requestId = id; } @@ -52,6 +52,27 @@ namespace BlackSimPlugin //! Set Simconnect object id int getObjectId() const { return m_objectId; } + //! Valid request id? + bool hasValidRequestId() const; + + //! Valid object id? + bool hasValidobjectId() const; + + //! Object is requested, not yet added + bool isPendingAdded() const; + + //! Adding is confirmed + bool isConfirmedAdded() const; + + //! Marked as confirmed + void setConfirmedAdded(bool confirm); + + //! Removing is pending + bool isPendingRemoved() const { return m_pendingRemoved; } + + //! Marked as confirmed + void setPendingRemoved(bool pending); + //! VTOL? bool isVtol() const { return m_aircraft.isVtol(); } @@ -62,7 +83,30 @@ namespace BlackSimPlugin BlackMisc::Simulation::CSimulatedAircraft m_aircraft; int m_requestId = -1; int m_objectId = -1; + bool m_confirmedAdded = false; + bool m_pendingRemoved = false; }; + + //! Simulator objects (aka AI aircraft + class CSimConnectObjects : public QHash + { + public: + //! Set ID of a SimConnect object, so far we only have an request id in the object + bool setSimConnectObjectId(int requestID, int objectId); + + //! Find which callsign belongs to the object id + BlackMisc::Aviation::CCallsign getCallsignForObjectId(int objectId) const; + + //! Find which callsign belongs to the object id + CSimConnectObject getSimObjectForObjectId(int objectId) const; + + //! Is the object id one of our AI objects? + bool isKnownSimObjectId(int objectId) const; + + //! Pending add condition + bool containsPendingAdd() const; + }; + } // namespace } // namespace diff --git a/src/xbus/traffic.cpp b/src/xbus/traffic.cpp index a0f59142f..6168c61d3 100644 --- a/src/xbus/traffic.cpp +++ b/src/xbus/traffic.cpp @@ -308,8 +308,8 @@ namespace XBus { BlackMisc::IInterpolator::InterpolationStatus status; auto situation = m_interpolator->getInterpolatedSituation(plane->situations, -1, false, status); - if (! status.interpolationSucceeded) { return xpmpData_Unavailable; } - if (! status.changedPosition) { return xpmpData_Unchanged; } + if (! status.didInterpolationSucceed()) { return xpmpData_Unavailable; } + if (! status.hasChangedPosition()) { return xpmpData_Unchanged; } using namespace BlackMisc::PhysicalQuantities; using namespace BlackMisc::Aviation; diff --git a/tests/blackcore/testinterpolator.cpp b/tests/blackcore/testinterpolator.cpp index ed21c131b..504567e52 100644 --- a/tests/blackcore/testinterpolator.cpp +++ b/tests/blackcore/testinterpolator.cpp @@ -99,8 +99,8 @@ namespace BlackCoreTest CAircraftSituation currentSituation(interpolator.getInterpolatedSituation (cs, currentTime, false, status) ); - QVERIFY2(status.interpolationSucceeded, "Interpolation was not succesful"); - QVERIFY2(status.changedPosition, "Interpolation did not changed"); + QVERIFY2(status.didInterpolationSucceed(), "Interpolation was not succesful"); + QVERIFY2(status.hasChangedPosition(), "Interpolation did not changed"); double latDeg = currentSituation.getPosition().latitude().valueRounded(CAngleUnit::deg(), 5); double lngDeg = currentSituation.getPosition().longitude().valueRounded(CAngleUnit::deg(), 5); QVERIFY2(latDeg < latOld && lngDeg < lngOld, "Values shall decrease"); @@ -150,7 +150,7 @@ namespace BlackCoreTest IInterpolator::PartsStatus status; CAircraftPartsList pl(interpolator.getPartsBeforeTime(cs, ts, status)); fetchedParts++; - QVERIFY2(status.supportsParts, "Parts not supported"); + QVERIFY2(status.isSupportingParts(), "Parts not supported"); QVERIFY2(!pl.isEmpty(), "Parts empty"); } timeMs = timer.elapsed();