refactor: Use dynamic lookup with pure virtual methods

This makes it clearer what an IInterpolant and Interpolator must
implemented.
But it should be checked if using virtual here is okay performance-wise.
This commit is contained in:
Lars Toenning
2024-01-09 22:59:23 +01:00
parent be2c756c8c
commit cb7e6c43e2
7 changed files with 77 additions and 97 deletions

View File

@@ -14,6 +14,27 @@ namespace BlackMisc::Simulation
class IInterpolant class IInterpolant
{ {
public: public:
//! Default ctor
IInterpolant() = default;
//! Constructor
explicit IInterpolant(int situationsAvailable) : m_situationsAvailable(situationsAvailable) {}
//! Constructor
IInterpolant(qint64 interpolatedTime, int situationsAvailable) : m_interpolatedTime(interpolatedTime), m_situationsAvailable(situationsAvailable) {}
virtual ~IInterpolant() = default;
//! Perform the interpolation
//! \return interpolated position and altitude
virtual std::tuple<Geo::CCoordinateGeodetic, Aviation::CAltitude> interpolatePositionAndAltitude() const = 0;
//! Interpolate the ground information/factor
virtual Aviation::COnGroundInfo interpolateGroundFactor() const = 0;
//! Get the PBH interpolator
virtual const IInterpolatorPbh &pbh() const = 0;
//! "Real time" representing the interpolated situation //! "Real time" representing the interpolated situation
qint64 getInterpolatedTime() const { return m_interpolatedTime; } qint64 getInterpolatedTime() const { return m_interpolatedTime; }
@@ -33,15 +54,6 @@ namespace BlackMisc::Simulation
void setRecalculated(bool reCalculated) { m_recalculated = reCalculated; } void setRecalculated(bool reCalculated) { m_recalculated = reCalculated; }
protected: protected:
//! Default ctor
IInterpolant() = default;
//! Constructor
explicit IInterpolant(int situationsAvailable) : m_situationsAvailable(situationsAvailable) {}
//! Constructor
IInterpolant(qint64 interpolatedTime, int situationsAvailable) : m_interpolatedTime(interpolatedTime), m_situationsAvailable(situationsAvailable) {}
qint64 m_interpolatedTime = -1; //!< "Real time "of interpolated situation qint64 m_interpolatedTime = -1; //!< "Real time "of interpolated situation
int m_situationsAvailable = 0; //!< used situations int m_situationsAvailable = 0; //!< used situations
bool m_valid = true; //!< valid? bool m_valid = true; //!< valid?

View File

@@ -31,12 +31,11 @@ using namespace BlackMisc::PhysicalQuantities;
namespace BlackMisc::Simulation namespace BlackMisc::Simulation
{ {
template <typename Derived> CInterpolator::CInterpolator(const CCallsign &callsign,
CInterpolator<Derived>::CInterpolator(const CCallsign &callsign, ISimulationEnvironmentProvider *simEnvProvider,
ISimulationEnvironmentProvider *simEnvProvider, IInterpolationSetupProvider *setupProvider,
IInterpolationSetupProvider *setupProvider, IRemoteAircraftProvider *remoteProvider,
IRemoteAircraftProvider *remoteProvider, CInterpolationLogger *logger) : m_callsign(callsign)
CInterpolationLogger *logger) : m_callsign(callsign)
{ {
// normally when created m_cg is still null since there is no CG in the provider yet // normally when created m_cg is still null since there is no CG in the provider yet
@@ -52,8 +51,7 @@ namespace BlackMisc::Simulation
this->attachLogger(logger); this->attachLogger(logger);
} }
template <typename Derived> CLength CInterpolator::getAndFetchModelCG(const CLength &dbCG)
CLength CInterpolator<Derived>::getAndFetchModelCG(const CLength &dbCG)
{ {
CLength cgDb = dbCG; CLength cgDb = dbCG;
if (cgDb.isNull()) if (cgDb.isNull())
@@ -74,8 +72,7 @@ namespace BlackMisc::Simulation
return cg; return cg;
} }
template <typename Derived> CAircraftSituationList CInterpolator::remoteAircraftSituationsAndChange(const CInterpolationAndRenderingSetupPerCallsign &setup)
CAircraftSituationList CInterpolator<Derived>::remoteAircraftSituationsAndChange(const CInterpolationAndRenderingSetupPerCallsign &setup)
{ {
CAircraftSituationList validSituations = this->remoteAircraftSituations(m_callsign); CAircraftSituationList validSituations = this->remoteAircraftSituations(m_callsign);
@@ -103,8 +100,7 @@ namespace BlackMisc::Simulation
return validSituations; return validSituations;
} }
template <typename Derived> bool CInterpolator::presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change)
bool CInterpolator<Derived>::presetGroundElevation(CAircraftSituation &situationToPreset, const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation, const CAircraftSituationChange &change)
{ {
// IMPORTANT: we do not know what the situation will be (interpolated to), so we cannot transfer // IMPORTANT: we do not know what the situation will be (interpolated to), so we cannot transfer
situationToPreset.resetGroundElevation(); situationToPreset.resetGroundElevation();
@@ -151,15 +147,13 @@ namespace BlackMisc::Simulation
return situationToPreset.hasGroundElevation(); return situationToPreset.hasGroundElevation();
} }
template <typename Derived> void CInterpolator::deferredInit()
void CInterpolator<Derived>::deferredInit()
{ {
if (m_model.hasModelString()) { return; } // set in-between if (m_model.hasModelString()) { return; } // set in-between
this->initCorrespondingModel(); this->initCorrespondingModel();
} }
template <typename Derived> bool CInterpolator::verifyInterpolationSituations(const CAircraftSituation &oldest, const CAircraftSituation &newer, const CAircraftSituation &latest, const CInterpolationAndRenderingSetupPerCallsign &setup)
bool CInterpolator<Derived>::verifyInterpolationSituations(const CAircraftSituation &oldest, const CAircraftSituation &newer, const CAircraftSituation &latest, const CInterpolationAndRenderingSetupPerCallsign &setup)
{ {
if (!CBuildConfig::isLocalDeveloperDebugBuild()) { return true; } if (!CBuildConfig::isLocalDeveloperDebugBuild()) { return true; }
CAircraftSituationList situations; CAircraftSituationList situations;
@@ -196,15 +190,13 @@ namespace BlackMisc::Simulation
return sorted && details; return sorted && details;
} }
template <typename Derived> const QStringList &CInterpolator::getLogCategories()
const QStringList &CInterpolator<Derived>::getLogCategories()
{ {
static const QStringList cats { CLogCategories::interpolator() }; static const QStringList cats { CLogCategories::interpolator() };
return cats; return cats;
} }
template <typename Derived> CInterpolationResult CInterpolator::getInterpolation(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, uint32_t aircraftNumber)
CInterpolationResult CInterpolator<Derived>::getInterpolation(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, uint32_t aircraftNumber)
{ {
CInterpolationResult result; CInterpolationResult result;
@@ -222,8 +214,7 @@ namespace BlackMisc::Simulation
return result; return result;
} }
template <typename Derived> CAircraftSituation CInterpolator::getInterpolatedSituation()
CAircraftSituation CInterpolator<Derived>::getInterpolatedSituation()
{ {
Q_ASSERT_X(!m_currentInterpolationStatus.isInterpolated(), Q_FUNC_INFO, "Expect reset status"); Q_ASSERT_X(!m_currentInterpolationStatus.isInterpolated(), Q_FUNC_INFO, "Expect reset status");
if (m_currentSituations.isEmpty()) if (m_currentSituations.isEmpty())
@@ -235,7 +226,7 @@ namespace BlackMisc::Simulation
// interpolant as function of derived class // interpolant as function of derived class
// CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant // CInterpolatorLinear::Interpolant or CInterpolatorSpline::Interpolant
SituationLog log; SituationLog log;
const auto interpolant = derived()->getInterpolant(log); const IInterpolant &interpolant = getInterpolant(log);
const bool isValidInterpolant = interpolant.isValid(); const bool isValidInterpolant = interpolant.isValid();
CAircraftSituation currentSituation = m_lastSituation; CAircraftSituation currentSituation = m_lastSituation;
@@ -400,8 +391,7 @@ namespace BlackMisc::Simulation
return currentSituation; return currentSituation;
} }
template <typename Derived> CAircraftParts CInterpolator::getInterpolatedParts()
CAircraftParts CInterpolator<Derived>::getInterpolatedParts()
{ {
// Parts are supposed to be in correct order, latest first // Parts are supposed to be in correct order, latest first
const CAircraftPartsList validParts = this->remoteAircraftParts(m_callsign); const CAircraftPartsList validParts = this->remoteAircraftParts(m_callsign);
@@ -435,8 +425,7 @@ namespace BlackMisc::Simulation
return currentParts; return currentParts;
} }
template <typename Derived> CAircraftParts CInterpolator::getInterpolatedOrGuessedParts(int aircraftNumber)
CAircraftParts CInterpolator<Derived>::getInterpolatedOrGuessedParts(int aircraftNumber)
{ {
Q_ASSERT_X(m_partsToSituationInterpolationRatio >= 1 && m_partsToSituationInterpolationRatio < 11, Q_FUNC_INFO, "Wrong ratio"); Q_ASSERT_X(m_partsToSituationInterpolationRatio >= 1 && m_partsToSituationInterpolationRatio < 11, Q_FUNC_INFO, "Wrong ratio");
const bool needParts = m_unitTest || m_lastParts.isNull(); const bool needParts = m_unitTest || m_lastParts.isNull();
@@ -482,8 +471,7 @@ namespace BlackMisc::Simulation
return parts; return parts;
} }
template <typename Derived> const CAircraftParts &CInterpolator::logAndReturnNullParts(const QString &info, bool log)
const CAircraftParts &CInterpolator<Derived>::logAndReturnNullParts(const QString &info, bool log)
{ {
if (!m_lastParts.isNull()) if (!m_lastParts.isNull())
{ {
@@ -502,14 +490,12 @@ namespace BlackMisc::Simulation
return CAircraftParts::null(); return CAircraftParts::null();
} }
template <typename Derived> bool CInterpolator::doLogging() const
bool CInterpolator<Derived>::doLogging() const
{ {
return this->hasAttachedLogger() && m_currentSetup.logInterpolation(); return this->hasAttachedLogger() && m_currentSetup.logInterpolation();
} }
template <typename Derived> CAircraftParts CInterpolator::guessParts(const CAircraftSituation &situation, const CAircraftSituationChange &change, const CAircraftModel &model)
CAircraftParts CInterpolator<Derived>::guessParts(const CAircraftSituation &situation, const CAircraftSituationChange &change, const CAircraftModel &model)
{ {
CAircraftParts parts; CAircraftParts parts;
parts.setMSecsSinceEpoch(situation.getMSecsSinceEpoch()); parts.setMSecsSinceEpoch(situation.getMSecsSinceEpoch());
@@ -638,8 +624,7 @@ namespace BlackMisc::Simulation
return parts; return parts;
} }
template <typename Derived> void CInterpolator::logParts(const CAircraftParts &parts, int partsNo, bool empty) const
void CInterpolator<Derived>::logParts(const CAircraftParts &parts, int partsNo, bool empty) const
{ {
if (!this->doLogging()) { return; } if (!this->doLogging()) { return; }
PartsLog logInfo; PartsLog logInfo;
@@ -651,8 +636,7 @@ namespace BlackMisc::Simulation
m_logger->logParts(logInfo); m_logger->logParts(logInfo);
} }
template <typename Derived> QString CInterpolator::getInterpolatorInfo() const
QString CInterpolator<Derived>::getInterpolatorInfo() const
{ {
return QStringLiteral("Callsign: ") % return QStringLiteral("Callsign: ") %
m_callsign.asString() % m_callsign.asString() %
@@ -664,14 +648,12 @@ namespace BlackMisc::Simulation
boolToYesNo(m_lastSituation.isNull()); boolToYesNo(m_lastSituation.isNull());
} }
template <typename Derived> void CInterpolator::resetLastInterpolation()
void CInterpolator<Derived>::resetLastInterpolation()
{ {
m_lastSituation.setNull(); m_lastSituation.setNull();
} }
template <typename Derived> bool CInterpolator::initIniterpolationStepData(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, int aircraftNumber)
bool CInterpolator<Derived>::initIniterpolationStepData(qint64 currentTimeSinceEpoch, const CInterpolationAndRenderingSetupPerCallsign &setup, int aircraftNumber)
{ {
Q_ASSERT_X(!m_callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign"); Q_ASSERT_X(!m_callsign.isEmpty(), Q_FUNC_INFO, "Missing callsign");
@@ -723,8 +705,7 @@ namespace BlackMisc::Simulation
return success; return success;
} }
template <typename Derived> CAircraftSituation CInterpolator::initInterpolatedSituation(const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation) const
CAircraftSituation CInterpolator<Derived>::initInterpolatedSituation(const CAircraftSituation &oldSituation, const CAircraftSituation &newSituation) const
{ {
if (m_currentSituations.isEmpty()) { return CAircraftSituation::null(); } if (m_currentSituations.isEmpty()) { return CAircraftSituation::null(); }
@@ -750,8 +731,7 @@ namespace BlackMisc::Simulation
return currentSituation; return currentSituation;
} }
template <typename Derived> void CInterpolator::initCorrespondingModel(const CAircraftModel &model)
void CInterpolator<Derived>::initCorrespondingModel(const CAircraftModel &model)
{ {
if (model.hasModelString()) if (model.hasModelString())
{ {
@@ -768,16 +748,8 @@ namespace BlackMisc::Simulation
this->getAndFetchModelCG(model.getCG()); this->getAndFetchModelCG(model.getCG());
} }
template <typename Derived> void CInterpolator::markAsUnitTest()
void CInterpolator<Derived>::markAsUnitTest()
{ {
m_unitTest = true; m_unitTest = true;
} }
// see here for the reason of thess forward instantiations
// https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
//! \cond PRIVATE
template class CInterpolator<CInterpolatorLinear>;
template class CInterpolator<CInterpolatorSpline>;
//! \endcond
} // namespace } // namespace

View File

@@ -13,6 +13,8 @@
#include "blackmisc/simulation/remoteaircraftprovider.h" #include "blackmisc/simulation/remoteaircraftprovider.h"
#include "blackmisc/simulation/interpolationsetupprovider.h" #include "blackmisc/simulation/interpolationsetupprovider.h"
#include "blackmisc/simulation/simulationenvironmentprovider.h" #include "blackmisc/simulation/simulationenvironmentprovider.h"
#include "blackmisc/simulation/interpolationlogger.h"
#include "blackmisc/simulation/interpolant.h"
#include "blackmisc/simulation/aircraftmodel.h" #include "blackmisc/simulation/aircraftmodel.h"
#include "blackmisc/aviation/aircraftsituationchange.h" #include "blackmisc/aviation/aircraftsituationchange.h"
#include "blackmisc/aviation/aircraftsituation.h" #include "blackmisc/aviation/aircraftsituation.h"
@@ -20,6 +22,7 @@
#include "blackmisc/aviation/callsign.h" #include "blackmisc/aviation/callsign.h"
#include "blackmisc/logcategories.h" #include "blackmisc/logcategories.h"
#include "blackmisc/statusmessagelist.h" #include "blackmisc/statusmessagelist.h"
#include "blackmisc/blackmiscexport.h"
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
@@ -32,9 +35,11 @@ namespace BlackMisc::Simulation
class CInterpolatorLinear; class CInterpolatorLinear;
class CInterpolatorSpline; class CInterpolatorSpline;
//! Interpolator, calculation inbetween positions //! Base class for interpolating (calculate positions inbetween updates).
template <typename Derived> //! One instance is responsible for one aircraft
class CInterpolator : //! This class provides the high level functions for interpolation (called from the simulator plugin), logging functionality, as well as the logic to interpolate aircraft parts.
//! Information for the position interpolation (basically aircraft updates from FSD) are provided from this class.
class BLACKMISC_EXPORT CInterpolator :
protected CSimulationEnvironmentAware, protected CSimulationEnvironmentAware,
protected CInterpolationSetupAware, protected CInterpolationSetupAware,
protected CRemoteAircraftAware protected CRemoteAircraftAware
@@ -174,17 +179,9 @@ namespace BlackMisc::Simulation
//! Return NULL parts and log //! Return NULL parts and log
const BlackMisc::Aviation::CAircraftParts &logAndReturnNullParts(const QString &info, bool log); const BlackMisc::Aviation::CAircraftParts &logAndReturnNullParts(const QString &info, bool log);
//! @{ //! Get the interpolant for the given time point
//! Derived class virtual const IInterpolant &getInterpolant(SituationLog &log) = 0;
Derived *derived() { return static_cast<Derived *>(this); }
const Derived *derived() const { return static_cast<const Derived *>(this); }
//! @}
}; };
//! \cond PRIVATE
extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator<CInterpolatorLinear>;
extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator<CInterpolatorSpline>;
//! \endcond
} // namespace } // namespace
// namespace // namespace
#endif // guard #endif // guard

View File

@@ -100,7 +100,7 @@ namespace BlackMisc::Simulation
} }
} }
CInterpolatorLinear::CInterpolant CInterpolatorLinear::getInterpolant(SituationLog &log) const IInterpolant &CInterpolatorLinear::getInterpolant(SituationLog &log)
{ {
// set default situations // set default situations
CAircraftSituation startSituation = m_interpolant.getStartSituation(); CAircraftSituation startSituation = m_interpolant.getStartSituation();

View File

@@ -25,7 +25,7 @@ namespace BlackMisc
namespace Simulation namespace Simulation
{ {
//! Linear interpolator, calculation inbetween positions //! Linear interpolator, calculation inbetween positions
class BLACKMISC_EXPORT CInterpolatorLinear : public CInterpolator<CInterpolatorLinear> class BLACKMISC_EXPORT CInterpolatorLinear : public CInterpolator
{ {
virtual void anchor() override; virtual void anchor() override;
@@ -47,12 +47,11 @@ namespace BlackMisc
CInterpolant(const Aviation::CAircraftSituation &startSituation, const Aviation::CAircraftSituation &endSituation, double timeFraction, qint64 interpolatedTime); CInterpolant(const Aviation::CAircraftSituation &startSituation, const Aviation::CAircraftSituation &endSituation, double timeFraction, qint64 interpolatedTime);
//! @} //! @}
//! Perform the interpolation //! \copydoc BlackMisc::Simulation::IInterpolant::interpolatePositionAndAltitude
//! \return interpolated position and altitude std::tuple<Geo::CCoordinateGeodetic, Aviation::CAltitude> interpolatePositionAndAltitude() const override;
std::tuple<Geo::CCoordinateGeodetic, Aviation::CAltitude> interpolatePositionAndAltitude() const;
//! Interpolate the ground information/factor //! \copydoc BlackMisc::Simulation::IInterpolant::interpolateGroundFactor
Aviation::COnGroundInfo interpolateGroundFactor() const; Aviation::COnGroundInfo interpolateGroundFactor() const override;
//! Start situation //! Start situation
const Aviation::CAircraftSituation &getStartSituation() const { return m_startSituation; } const Aviation::CAircraftSituation &getStartSituation() const { return m_startSituation; }
@@ -60,7 +59,8 @@ namespace BlackMisc
//! End situation //! End situation
const Aviation::CAircraftSituation &getEndSituation() const { return m_endSituation; } const Aviation::CAircraftSituation &getEndSituation() const { return m_endSituation; }
const IInterpolatorPbh &pbh() const { return m_pbh; } //! \copydoc BlackMisc::Simulation::IInterpolant::pbh
const IInterpolatorPbh &pbh() const override { return m_pbh; }
private: private:
Aviation::CAircraftSituation m_startSituation; Aviation::CAircraftSituation m_startSituation;
@@ -69,8 +69,8 @@ namespace BlackMisc
CInterpolatorLinearPbh m_pbh; CInterpolatorLinearPbh m_pbh;
}; };
//! Get the interpolant for the given time point //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolant
CInterpolant getInterpolant(SituationLog &log); const IInterpolant &getInterpolant(SituationLog &log) override;
private: private:
CInterpolant m_interpolant; //!< current interpolant CInterpolant m_interpolant; //!< current interpolant

View File

@@ -175,7 +175,7 @@ namespace BlackMisc::Simulation
void CInterpolatorSpline::anchor() void CInterpolatorSpline::anchor()
{} {}
CInterpolatorSpline::CInterpolant CInterpolatorSpline::getInterpolant(SituationLog &log) const IInterpolant &CInterpolatorSpline::getInterpolant(SituationLog &log)
{ {
// recalculate derivatives only if they changed // recalculate derivatives only if they changed
// m_situationsLastModified updated in initIniterpolationStepData // m_situationsLastModified updated in initIniterpolationStepData

View File

@@ -15,7 +15,7 @@
namespace BlackMisc::Simulation namespace BlackMisc::Simulation
{ {
//! Cubic spline interpolator //! Cubic spline interpolator
class BLACKMISC_EXPORT CInterpolatorSpline : public CInterpolator<CInterpolatorSpline> class BLACKMISC_EXPORT CInterpolatorSpline : public CInterpolator
{ {
virtual void anchor() override; virtual void anchor() override;
@@ -63,13 +63,11 @@ namespace BlackMisc::Simulation
//! Constructor //! Constructor
CInterpolant(const PosArray &pa, const PhysicalQuantities::CLengthUnit &altitudeUnit, const CInterpolatorLinearPbh &pbh); CInterpolant(const PosArray &pa, const PhysicalQuantities::CLengthUnit &altitudeUnit, const CInterpolatorLinearPbh &pbh);
//! Perform the interpolation //! \copydoc BlackMisc::Simulation::IInterpolant::interpolatePositionAndAltitude
//! \param situation situation used as a base for interpolation. Contains for example the already interpolated PBH. std::tuple<Geo::CCoordinateGeodetic, Aviation::CAltitude> interpolatePositionAndAltitude() const override;
//! \return \p situation with interpolated position and altitude and updated timestamp
std::tuple<Geo::CCoordinateGeodetic, Aviation::CAltitude> interpolatePositionAndAltitude() const;
//! Interpolate the ground information/factor //! \copydoc BlackMisc::Simulation::IInterpolant::interpolateGroundFactor
Aviation::COnGroundInfo interpolateGroundFactor() const; Aviation::COnGroundInfo interpolateGroundFactor() const override;
//! Set the time values //! Set the time values
void setTimes(qint64 currentTimeMs, double timeFraction, qint64 interpolatedTimeMs); void setTimes(qint64 currentTimeMs, double timeFraction, qint64 interpolatedTimeMs);
@@ -77,7 +75,8 @@ namespace BlackMisc::Simulation
//! \private UNIT tests/ASSERT only //! \private UNIT tests/ASSERT only
const PosArray &getPa() const { return m_pa; } const PosArray &getPa() const { return m_pa; }
const IInterpolatorPbh &pbh() const { return m_pbh; } //! \copydoc BlackMisc::Simulation::IInterpolant::pbh
const IInterpolatorPbh &pbh() const override { return m_pbh; }
private: private:
PosArray m_pa; //!< current positions array, latest values last PosArray m_pa; //!< current positions array, latest values last
@@ -86,8 +85,8 @@ namespace BlackMisc::Simulation
CInterpolatorLinearPbh m_pbh; //!< the used PBH interpolator CInterpolatorLinearPbh m_pbh; //!< the used PBH interpolator
}; };
//! Strategy used by CInterpolator::getInterpolatedSituation //! \copydoc BlackMisc::Simulation::CInterpolator::getInterpolant
CInterpolant getInterpolant(SituationLog &log); const IInterpolant &getInterpolant(SituationLog &log) override;
private: private:
//! Update the elevations used in CInterpolatorSpline::m_s //! Update the elevations used in CInterpolatorSpline::m_s