refs #863 Interpolator inheritance based on CRTP rather than virtual methods.

This commit is contained in:
Mathew Sutcliffe
2017-01-18 01:22:12 +00:00
parent 1c2533f5d2
commit 9c918b8799
8 changed files with 87 additions and 58 deletions

View File

@@ -49,7 +49,6 @@ namespace BlackMisc
}
namespace Simulation
{
class IInterpolator;
class CAirspaceAircraftSnapshot;
class CSimulatedAircraft;
}

View File

@@ -10,6 +10,7 @@
#include "interpolator.h"
#include "blackconfig/buildconfig.h"
#include "blackmisc/simulation/interpolationhints.h"
#include "blackmisc/simulation/interpolatorlinear.h"
#include "blackmisc/aviation/callsign.h"
#include "blackmisc/pq/length.h"
#include "blackmisc/logmessage.h"
@@ -27,24 +28,27 @@ namespace BlackMisc
{
namespace Simulation
{
IInterpolator::IInterpolator(const QString &objectName, QObject *parent) :
template <typename Derived>
CInterpolator<Derived>::CInterpolator(const QString &objectName, QObject *parent) :
QObject(parent)
{
this->setObjectName(objectName);
}
BlackMisc::Aviation::CAircraftSituation IInterpolator::getInterpolatedSituation(
template <typename Derived>
BlackMisc::Aviation::CAircraftSituation CInterpolator<Derived>::getInterpolatedSituation(
qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetup &setup,
const CInterpolationHints &hints, CInterpolationStatus &status) const
{
status.reset();
auto currentSituation = this->getInterpolatedSituation(callsign, this->m_aircraftSituations, currentTimeSinceEpoc, setup, hints, status);
auto currentSituation = derived()->getInterpolatedSituation(callsign, this->m_aircraftSituations, currentTimeSinceEpoc, setup, hints, status);
currentSituation.setCallsign(callsign); // make sure callsign is correct
return currentSituation;
}
CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch,
template <typename Derived>
CAircraftParts CInterpolator<Derived>::getInterpolatedParts(const CCallsign &callsign, const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch,
const CInterpolationAndRenderingSetup &setup, CPartsStatus &partsStatus, bool log) const
{
Q_UNUSED(setup);
@@ -102,31 +106,35 @@ namespace BlackMisc
log.callsign = callsign;
log.timestamp = currentTimeMsSinceEpoch;
log.parts = currentParts;
IInterpolator::logParts(log);
CInterpolator::logParts(log);
}
return currentParts;
}
CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, qint64 currentTimeMsSinceEpoch,
template <typename Derived>
CAircraftParts CInterpolator<Derived>::getInterpolatedParts(const CCallsign &callsign, qint64 currentTimeMsSinceEpoch,
const CInterpolationAndRenderingSetup &setup, CPartsStatus &partsStatus, bool log) const
{
partsStatus.reset();
return this->getInterpolatedParts(callsign, this->m_aircraftParts, currentTimeMsSinceEpoch, setup, partsStatus, log);
}
void IInterpolator::addAircraftSituation(const CAircraftSituation &situation)
template <typename Derived>
void CInterpolator<Derived>::addAircraftSituation(const CAircraftSituation &situation)
{
m_aircraftSituations.push_frontMaxElements(situation, IRemoteAircraftProvider::MaxSituationsPerCallsign);
}
void IInterpolator::addAircraftParts(const CAircraftParts &parts)
template <typename Derived>
void CInterpolator<Derived>::addAircraftParts(const CAircraftParts &parts)
{
m_aircraftParts.push_front(parts);
IRemoteAircraftProvider::removeOutdatedParts(m_aircraftParts);
}
CWorker *IInterpolator::writeLogInBackground()
template <typename Derived>
CWorker *CInterpolator<Derived>::writeLogInBackground()
{
QList<InterpolationLog> interpolation;
QList<PartsLog> parts;
@@ -138,7 +146,7 @@ namespace BlackMisc
CWorker *worker = CWorker::fromTask(this, "WriteInterpolationLog", [interpolation, parts]()
{
const CStatusMessageList msg = IInterpolator::writeLogFile(interpolation, parts);
const CStatusMessageList msg = CInterpolator::writeLogFile(interpolation, parts);
CLogMessage::preformatted(msg);
});
return worker;
@@ -164,57 +172,62 @@ namespace BlackMisc
return files;
}
CStatusMessageList IInterpolator::writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts)
template <typename Derived>
CStatusMessageList CInterpolator<Derived>::writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts)
{
if (parts.isEmpty() && interpolation.isEmpty()) { return CStatusMessage(static_cast<IInterpolator *>(nullptr)).warning("No data for log"); }
if (parts.isEmpty() && interpolation.isEmpty()) { return CStatusMessage(static_cast<CInterpolator *>(nullptr)).warning("No data for log"); }
static const QString html = QLatin1String("Entries: %1\n\n%2");
const QString htmlTemplate = CFileUtils::readFileToString(CBuildConfig::getHtmlTemplateFileName());
CStatusMessageList msgs;
const QString ts = QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmss");
const QString htmlInterpolation = IInterpolator::getHtmlInterpolationLog(interpolation);
const QString htmlInterpolation = CInterpolator::getHtmlInterpolationLog(interpolation);
if (!htmlInterpolation.isEmpty())
{
const QString fn = CFileUtils::appendFilePaths(CDirectoryUtils::getLogDirectory(), QString("%1 interpolation.html").arg(ts));
const bool s = CFileUtils::writeStringToFile(htmlTemplate.arg(html.arg(interpolation.size()).arg(htmlInterpolation)), fn);
msgs.push_back(IInterpolator::logStatusFileWriting(s, fn));
msgs.push_back(CInterpolator::logStatusFileWriting(s, fn));
}
const QString htmlParts = IInterpolator::getHtmlPartsLog(parts);
const QString htmlParts = CInterpolator::getHtmlPartsLog(parts);
if (!htmlParts.isEmpty())
{
const QString fn = CFileUtils::appendFilePaths(CDirectoryUtils::getLogDirectory(), QString("%1 parts.html").arg(ts));
const bool s = CFileUtils::writeStringToFile(htmlTemplate.arg(html.arg(parts.size()).arg(htmlParts)), fn);
msgs.push_back(IInterpolator::logStatusFileWriting(s, fn));
msgs.push_back(CInterpolator::logStatusFileWriting(s, fn));
}
return msgs;
}
CStatusMessage IInterpolator::logStatusFileWriting(bool success, const QString &fileName)
template <typename Derived>
CStatusMessage CInterpolator<Derived>::logStatusFileWriting(bool success, const QString &fileName)
{
if (success)
{
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).info("Written log file '%1'") << fileName;
return CStatusMessage(static_cast<CInterpolator *>(nullptr)).info("Written log file '%1'") << fileName;
}
else
{
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).error("Failed to write log file '%1'") << fileName;
return CStatusMessage(static_cast<CInterpolator *>(nullptr)).error("Failed to write log file '%1'") << fileName;
}
}
void IInterpolator::logInterpolation(const IInterpolator::InterpolationLog &log) const
template <typename Derived>
void CInterpolator<Derived>::logInterpolation(const typename CInterpolator<Derived>::InterpolationLog &log) const
{
QWriteLocker l(&m_lockLogs);
m_interpolationLogs.append(log);
}
void IInterpolator::logParts(const IInterpolator::PartsLog &parts) const
template <typename Derived>
void CInterpolator<Derived>::logParts(const typename CInterpolator<Derived>::PartsLog &parts) const
{
QWriteLocker l(&m_lockLogs);
m_partsLogs.append(parts);
}
QString IInterpolator::getHtmlInterpolationLog(const QList<InterpolationLog> &logs)
template <typename Derived>
QString CInterpolator<Derived>::getHtmlInterpolationLog(const QList<InterpolationLog> &logs)
{
if (logs.isEmpty()) { return {}; }
const QString tableHeader =
@@ -294,7 +307,8 @@ namespace BlackMisc
return QLatin1String("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1String("</table>\n");
}
QString IInterpolator::getHtmlPartsLog(const QList<PartsLog> &logs)
template <typename Derived>
QString CInterpolator<Derived>::getHtmlPartsLog(const QList<PartsLog> &logs)
{
if (logs.isEmpty()) { return {}; }
const QString tableHeader =
@@ -321,14 +335,16 @@ namespace BlackMisc
return QLatin1String("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1String("</table>\n");
}
void IInterpolator::clearLog()
template <typename Derived>
void CInterpolator<Derived>::clearLog()
{
QWriteLocker l(&m_lockLogs);
this->m_partsLogs.clear();
this->m_interpolationLogs.clear();
}
void IInterpolator::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation, bool override)
template <typename Derived>
void CInterpolator<Derived>::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation, bool override)
{
if (!override && situation.hasGroundElevation()) { return; }
const CAltitude elevation = hints.getGroundElevation(situation);
@@ -336,7 +352,8 @@ namespace BlackMisc
situation.setGroundElevation(elevation);
}
void IInterpolator::setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, CAircraftSituation &situation)
template <typename Derived>
void CInterpolator<Derived>::setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, CAircraftSituation &situation)
{
// by interpolation
if (groundFactor >= 1.0)
@@ -386,13 +403,15 @@ namespace BlackMisc
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
}
QString IInterpolator::msSinceEpochToTime(qint64 ms)
template <typename Derived>
QString CInterpolator<Derived>::msSinceEpochToTime(qint64 ms)
{
static const QString dateFormat("hh:mm:ss.zzz");
return QDateTime::fromMSecsSinceEpoch(ms).toString(dateFormat);
}
QString IInterpolator::msSinceEpochToTime(qint64 t1, qint64 t2, qint64 t3)
template <typename Derived>
QString CInterpolator<Derived>::msSinceEpochToTime(qint64 t1, qint64 t2, qint64 t3)
{
if (t3 < 0) return QString("%1 %2").arg(msSinceEpochToTime(t1), msSinceEpochToTime(t2));
return QString("%1 %2 %3").arg(msSinceEpochToTime(t1), msSinceEpochToTime(t2), msSinceEpochToTime(t3));
@@ -418,5 +437,11 @@ namespace BlackMisc
{
m_supportsParts = false;
}
// 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 BLACKMISC_EXPORT_DEFINE_TEMPLATE CInterpolator<CInterpolatorLinear>;
//! \endcond
} // namespace
} // namespace

View File

@@ -13,7 +13,6 @@
#define BLACKMISC_SIMULATION_INTERPOLATOR_H
#include "interpolationrenderingsetup.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/aviation/aircraftpartslist.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include "blackmisc/aviation/aircraftpartslist.h"
@@ -30,37 +29,41 @@ namespace BlackMisc
namespace Simulation
{
class CInterpolationHints;
class CInterpolatorLinear;
struct CInterpolationStatus;
struct CPartsStatus;
//! Interpolator, calculation inbetween positions
class BLACKMISC_EXPORT IInterpolator : public QObject
template <typename Derived>
class CInterpolator : public QObject
{
Q_OBJECT
public:
//! Log category
static QString getLogCategory() { return "swift.interpolator"; }
//! Current interpolated situation
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc,
const CInterpolationAndRenderingSetup &setup, const CInterpolationHints &hints, CInterpolationStatus &status) const;
//! Current interpolated situation, to be implemented by subclass
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CCallsign &callsign,
const BlackMisc::Aviation::CAircraftSituationList &situations, qint64 currentTimeSinceEpoc,
const CInterpolationAndRenderingSetup &setup, const CInterpolationHints &hints, CInterpolationStatus &status) const = 0;
const CInterpolationAndRenderingSetup &setup, const CInterpolationHints &hints, CInterpolationStatus &status) const
{
qFatal("Not implemented");
return {};
}
//! Parts before given offset time (aka pending parts)
virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
const Aviation::CCallsign &callsign,
const BlackMisc::Aviation::CAircraftPartsList &parts, qint64 cutoffTime,
const CInterpolationAndRenderingSetup &setup, CPartsStatus &partsStatus, bool log = false) const;
//! Parts before given offset time (aka pending parts)
virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
const BlackMisc::Aviation::CCallsign &callsign, qint64 cutoffTime,
const CInterpolationAndRenderingSetup &setup, CPartsStatus &partsStatus, bool log = false) const;
@@ -120,7 +123,7 @@ namespace BlackMisc
};
//! Constructor
IInterpolator(const QString &objectName, QObject *parent);
CInterpolator(const QString &objectName, QObject *parent);
//! Log current interpolation cycle, only stores in memory, for performance reasons
//! \remark const to allow const interpolator functions
@@ -159,6 +162,9 @@ namespace BlackMisc
//! Create readable time
static QString msSinceEpochToTime(qint64 t1, qint64 t2, qint64 t3 = -1);
Derived *derived() { return static_cast<Derived *>(this); }
const Derived *derived() const { return static_cast<const Derived *>(this); }
mutable QReadWriteLock m_lockLogs; //!< lock logging
mutable QList<PartsLog> m_partsLogs; //!< logs of parts
mutable QList<InterpolationLog> m_interpolationLogs; //!< logs of interpolation
@@ -210,6 +216,10 @@ namespace BlackMisc
private:
bool m_supportsParts = false; //!< supports parts for given callsign
};
//! \cond PRIVATE
extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CInterpolator<CInterpolatorLinear>;
//! \endcond
} // namespace
} // namespace
#endif // guard

View File

@@ -100,8 +100,8 @@ namespace BlackMisc
// do not call for XP (lazy init)
if (!hints.hasElevationProvider())
{
IInterpolator::setGroundElevationFromHint(hints, oldSituation, false);
IInterpolator::setGroundElevationFromHint(hints, newSituation, false);
CInterpolator::setGroundElevationFromHint(hints, oldSituation, false);
CInterpolator::setGroundElevationFromHint(hints, newSituation, false);
}
CAircraftSituation currentSituation(oldSituation); // also sets ground elevation if available

View File

@@ -26,22 +26,24 @@ namespace BlackMisc
namespace Simulation
{
//! Linear interpolator, calculation inbetween positions
class BLACKMISC_EXPORT CInterpolatorLinear : public IInterpolator
class BLACKMISC_EXPORT CInterpolatorLinear : public CInterpolator<CInterpolatorLinear>
{
Q_OBJECT
public:
//! Constructor
CInterpolatorLinear(QObject *parent = nullptr) :
IInterpolator("CInterpolatorLinear", parent)
CInterpolator("CInterpolatorLinear", parent)
{}
// public base class signature
using IInterpolator::getInterpolatedSituation;
using CInterpolator::getInterpolatedSituation;
//! \copydoc IInterpolator::getInterpolatedSituation
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CCallsign &callsign,
const BlackMisc::Aviation::CAircraftSituationList &situations, qint64 currentTimeSinceEpoc, const CInterpolationAndRenderingSetup &setup,
const BlackMisc::Simulation::CInterpolationHints &hints, CInterpolationStatus &status) const override;
const BlackMisc::Simulation::CInterpolationHints &hints, CInterpolationStatus &status) const;
//! Log category
static QString getLogCategory() { return "swift.interpolatorlinear"; }

View File

@@ -50,7 +50,7 @@ namespace BlackSimPlugin
void setHostAddress(const QString &hostAddress);
//! Get interpolator
BlackMisc::Simulation::IInterpolator *getInterpolator() { return &m_interpolator; }
BlackMisc::Simulation::CInterpolatorLinear *getInterpolator() { return &m_interpolator; }
//! Set interpolation setup
//! \threadsafe

View File

@@ -16,7 +16,7 @@
#include "simconnectdatadefinition.h"
#include <QSharedPointer>
namespace BlackMisc { namespace Simulation { class IInterpolator; } }
namespace BlackMisc { namespace Simulation { class CInterpolatorLinear; } }
namespace BlackSimPlugin
{
namespace Fsx
@@ -44,7 +44,7 @@ namespace BlackSimPlugin
const QString &getAircraftModelString() const { return m_aircraft.getModelString(); }
//! Interpolator
BlackMisc::Simulation::IInterpolator *getInterpolator() const { return m_interpolator.data(); }
BlackMisc::Simulation::CInterpolatorLinear *getInterpolator() const { return m_interpolator.data(); }
//! Get current lights (requested from simulator)
const BlackMisc::Aviation::CAircraftLights &getCurrentLightsInSimulator() const { return m_currentLightsInSim; }
@@ -122,7 +122,7 @@ namespace BlackSimPlugin
BlackMisc::Aviation::CAircraftLights m_currentLightsInSim { nullptr }; //!< current lights to know state for toggling
BlackMisc::Aviation::CAircraftLights m_lightsAsSent { nullptr }; //!< lights as sent to simulator
SIMCONNECT_PERIOD m_requestSimDataPeriod = SIMCONNECT_PERIOD_NEVER; //!< how often do we query ground elevation
QSharedPointer<BlackMisc::Simulation::IInterpolator> m_interpolator; //!< shared pointer because CSimConnectObject can be copied
QSharedPointer<BlackMisc::Simulation::CInterpolatorLinear> m_interpolator; //!< shared pointer because CSimConnectObject can be copied
};
//! Simulator objects (aka AI aircraft)

View File

@@ -28,14 +28,7 @@
#define XBUS_TRAFFIC_OBJECTPATH "/xbus/traffic"
//! \endcond
namespace BlackMisc
{
namespace Simulation
{
class IInterpolator;
class CInterpolationHints;
}
}
namespace BlackMisc { namespace Simulation { class CInterpolationHints; } }
namespace XBus
{
/*!