refs #865, further improved logging

* set log flag in hints, so no lock for each aircraft is needed
* as a result log functions have a bool log parameter now
* highlight situation and parts changed
This commit is contained in:
Klaus Basan
2017-01-28 02:58:55 +01:00
committed by Mathew Sutcliffe
parent ff7756db38
commit 62d4a94106
11 changed files with 133 additions and 78 deletions

View File

@@ -43,6 +43,7 @@ a:hover + .mouseoverdisplay {
.old { color: blue; } .old { color: blue; }
.new { color: green; } .new { color: green; }
.cur { color: red; } .cur { color: red; }
.changed { background-color: yellow; }
</style> </style>
</head> </head>
<body> <body>

View File

@@ -19,19 +19,19 @@ namespace BlackMisc
{ {
CAircraftEngine::CAircraftEngine(int number, bool on) : m_number(number), m_on(on) CAircraftEngine::CAircraftEngine(int number, bool on) : m_number(number), m_on(on)
{ {
Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine number have to be > 1"); Q_ASSERT_X(number > 0, "CAircraftEngine", "Engine numbers have to be > 1");
} }
void CAircraftEngine::setNumber(int number) void CAircraftEngine::setNumber(int number)
{ {
Q_ASSERT_X(number > 0, "setNumber", "Engine number have to be > 1"); Q_ASSERT_X(number > 0, "setNumber", "Engine numbers have to be > 1");
m_number = number; m_number = number;
} }
QString CAircraftEngine::convertToQString(bool i18n) const QString CAircraftEngine::convertToQString(bool i18n) const
{ {
Q_UNUSED(i18n); Q_UNUSED(i18n);
static const QString s("%1 on: %2"); static const QString s("%1: %2");
return s.arg(m_number).arg(BlackMisc::boolToOnOff(m_on)); return s.arg(m_number).arg(BlackMisc::boolToOnOff(m_on));
} }
} // namespace } // namespace

View File

@@ -27,7 +27,6 @@ namespace BlackMisc
class BLACKMISC_EXPORT CAircraftEngine : public CValueObject<CAircraftEngine> class BLACKMISC_EXPORT CAircraftEngine : public CValueObject<CAircraftEngine>
{ {
public: public:
//! Default constructor //! Default constructor
CAircraftEngine() {} CAircraftEngine() {}

View File

@@ -68,6 +68,12 @@ namespace BlackMisc
//! VTOL aircraft //! VTOL aircraft
void setVtolAircraft(bool vtol) { m_isVtol = vtol; } void setVtolAircraft(bool vtol) { m_isVtol = vtol; }
//! Log interpolation?
bool isLoggingInterpolation() const { return m_logInterpolation; }
//! Log interpolation?
void setLoggingInterpolation(bool log) { m_logInterpolation = log; }
//! Has valid aircraft parts? //! Has valid aircraft parts?
bool hasAircraftParts() const { return m_hasParts; } bool hasAircraftParts() const { return m_hasParts; }
@@ -103,6 +109,7 @@ namespace BlackMisc
private: private:
bool m_isVtol = false; //!< VTOL aircraft? bool m_isVtol = false; //!< VTOL aircraft?
bool m_hasParts = false; //!< Has valid aircraft parts? bool m_hasParts = false; //!< Has valid aircraft parts?
bool m_logInterpolation = false; //!< log interpolation
BlackMisc::Aviation::CAircraftParts m_aircraftParts; //!< Aircraft parts BlackMisc::Aviation::CAircraftParts m_aircraftParts; //!< Aircraft parts
BlackMisc::Geo::CElevationPlane m_elevation; //!< aircraft's elevation if available BlackMisc::Geo::CElevationPlane m_elevation; //!< aircraft's elevation if available
ElevationProvider m_elevationProvider; //!< Provider of ground elevation (lazy computation) ElevationProvider m_elevationProvider; //!< Provider of ground elevation (lazy computation)
@@ -114,7 +121,8 @@ namespace BlackMisc
BLACK_METAMEMBER(elevation), BLACK_METAMEMBER(elevation),
BLACK_METAMEMBER(cgAboveGround), BLACK_METAMEMBER(cgAboveGround),
BLACK_METAMEMBER(hasParts), BLACK_METAMEMBER(hasParts),
BLACK_METAMEMBER(aircraftParts) BLACK_METAMEMBER(aircraftParts),
BLACK_METAMEMBER(logInterpolation)
// elevationProvider not included // elevationProvider not included
); );
}; };

View File

@@ -52,12 +52,13 @@ namespace BlackMisc
return currentSituation; return currentSituation;
} }
CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus) const CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus, bool log) const
{ {
partsStatus.reset(); partsStatus.reset();
if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); } if (currentTimeMsSinceEpoch < 0) { currentTimeMsSinceEpoch = QDateTime::currentMSecsSinceEpoch(); }
// find the first parts not in the correct order, keep only the parts before that one // find the first parts not in the correct order, keep only the parts before that one
if (parts.isEmpty()) { return {}; }
const auto end = std::is_sorted_until(parts.begin(), parts.end(), [](auto && a, auto && b) { return b.getAdjustedMSecsSinceEpoch() < a.getAdjustedMSecsSinceEpoch(); }); const auto end = std::is_sorted_until(parts.begin(), parts.end(), [](auto && a, auto && b) { return b.getAdjustedMSecsSinceEpoch() < a.getAdjustedMSecsSinceEpoch(); });
const auto validParts = makeRange(parts.begin(), end); const auto validParts = makeRange(parts.begin(), end);
@@ -65,14 +66,17 @@ namespace BlackMisc
if (validParts.isEmpty()) { return {}; } if (validParts.isEmpty()) { return {}; }
partsStatus.setSupportsParts(true); partsStatus.setSupportsParts(true);
CAircraftParts currentParts;
do
{
// find the first parts earlier than the current time // find the first parts earlier than the current time
const auto pivot = std::partition_point(validParts.begin(), validParts.end(), [ = ](auto && p) { return p.getAdjustedMSecsSinceEpoch() > currentTimeMsSinceEpoch; }); const auto pivot = std::partition_point(validParts.begin(), validParts.end(), [ = ](auto && p) { return p.getAdjustedMSecsSinceEpoch() > currentTimeMsSinceEpoch; });
const auto partsNewer = makeRange(validParts.begin(), pivot).reverse(); const auto partsNewer = makeRange(validParts.begin(), pivot).reverse();
const auto partsOlder = makeRange(pivot, validParts.end()); const auto partsOlder = makeRange(pivot, validParts.end());
if (partsOlder.isEmpty()) { return *(partsNewer.end() - 1); } if (partsOlder.isEmpty()) { currentParts = *(partsNewer.end() - 1); break; }
CAircraftParts currentParts = partsOlder.front(); currentParts = partsOlder.front();
if (currentParts.isOnGround()) { return currentParts; } if (currentParts.isOnGround()) { break; }
// here we know aircraft is not on ground, and we check if it was recently on ground or if it will be on ground soon // here we know aircraft is not on ground, and we check if it was recently on ground or if it will be on ground soon
const auto latestTakeoff = std::adjacent_find(partsOlder.begin(), partsOlder.end(), [](auto &&, auto && p) { return p.isOnGround(); }); const auto latestTakeoff = std::adjacent_find(partsOlder.begin(), partsOlder.end(), [](auto &&, auto && p) { return p.isOnGround(); });
@@ -95,12 +99,13 @@ namespace BlackMisc
const double landingFactor = secondsUntilLanding / predictableFutureSecs; const double landingFactor = secondsUntilLanding / predictableFutureSecs;
const double airborneFactor = std::min(std::min(takeoffFactor, landingFactor), 1.0); const double airborneFactor = std::min(std::min(takeoffFactor, landingFactor), 1.0);
currentParts.setOnGroundInterpolated(1.0 - smootherStep(airborneFactor)); currentParts.setOnGroundInterpolated(1.0 - smootherStep(airborneFactor));
}
while (false);
if (log)
const CInterpolationAndRenderingSetup setup = this->getInterpolatorSetup();
if (setup.getLogCallsigns().contains(callsign))
{ {
PartsLog log; PartsLog log;
log.callsign = callsign;
log.timestamp = currentTimeMsSinceEpoch; log.timestamp = currentTimeMsSinceEpoch;
log.parts = currentParts; log.parts = currentParts;
IInterpolator::logParts(log); IInterpolator::logParts(log);
@@ -109,14 +114,11 @@ namespace BlackMisc
return currentParts; return currentParts;
} }
CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus) const CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus, bool log) const
{ {
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign"); Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
partsStatus.reset(); partsStatus.reset();
return this->getInterpolatedParts(callsign, this->remoteAircraftParts(callsign, -1), currentTimeMsSinceEpoch, partsStatus, log);
partsStatus.setSupportsParts(this->isRemoteAircraftSupportingParts(callsign));
if (!partsStatus.isSupportingParts()) { return {}; }
return this->getInterpolatedParts(callsign, this->remoteAircraftParts(callsign, -1), currentTimeMsSinceEpoch, partsStatus);
} }
void IInterpolator::setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup) void IInterpolator::setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup)
@@ -143,30 +145,47 @@ namespace BlackMisc
CWorker *worker = CWorker::fromTask(this, "WriteInterpolationLog", [interpolation, parts]() CWorker *worker = CWorker::fromTask(this, "WriteInterpolationLog", [interpolation, parts]()
{ {
const CStatusMessage msg = IInterpolator::writeLogFile(interpolation, parts); const CStatusMessageList msg = IInterpolator::writeLogFile(interpolation, parts);
CLogMessage::preformatted(msg); CLogMessage::preformatted(msg);
}); });
return worker; return worker;
} }
CStatusMessage IInterpolator::writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts) CStatusMessageList IInterpolator::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<IInterpolator *>(nullptr)).warning("No data for log"); }
const QString htmlInterpolation = IInterpolator::getHtmlInterpolationLog(interpolation); static const QString html = QLatin1Literal("Entries: %1\n\n%2");
const QString htmlParts = IInterpolator::getHtmlPartsLog(parts);
const QString html = htmlParts % QLatin1Literal("\n\n") % htmlInterpolation;
const QString htmlTemplate = CFileUtils::readFileToString(CBuildConfig::getHtmlTemplateFileName()); const QString htmlTemplate = CFileUtils::readFileToString(CBuildConfig::getHtmlTemplateFileName());
CStatusMessageList msgs;
const QString ts = QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmss"); const QString ts = QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmss");
const QString fn = CFileUtils::appendFilePaths(CDirectoryUtils::getLogDirectory(), QString("%1 interpolation.html").arg(ts)); const QString htmlInterpolation = IInterpolator::getHtmlInterpolationLog(interpolation);
const bool s = CFileUtils::writeStringToFile(htmlTemplate.arg(html), fn); if (!htmlInterpolation.isEmpty())
if (s)
{ {
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).info("Written log file '%1'") << fn; 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));
}
const QString htmlParts = IInterpolator::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));
}
return msgs;
}
CStatusMessage IInterpolator::logStatusFileWriting(bool success, const QString &fileName)
{
if (success)
{
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).info("Written log file '%1'") << fileName;
} }
else else
{ {
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).error("Failed to write log file '%1'") << fn; return CStatusMessage(static_cast<IInterpolator *>(nullptr)).error("Failed to write log file '%1'") << fileName;
} }
} }
@@ -191,10 +210,9 @@ namespace BlackMisc
QString IInterpolator::getHtmlInterpolationLog(const QList<InterpolationLog> &logs) QString IInterpolator::getHtmlInterpolationLog(const QList<InterpolationLog> &logs)
{ {
if (logs.isEmpty()) { return {}; } if (logs.isEmpty()) { return {}; }
QString tableRows;
const QString tableHeader = const QString tableHeader =
QLatin1Literal("<tr>") % QLatin1Literal("<thead><tr>") %
QLatin1Literal("<th>CS</th><th>VTOL</th><th>timestamp</th>") % QLatin1Literal("<th>c.</th><th>CS</th><th>VTOL</th><th>timestamp</th><th>since</th>") %
QLatin1Literal("<th>ts old</th><th>ts new</th><th>ts cur</th>") % QLatin1Literal("<th>ts old</th><th>ts new</th><th>ts cur</th>") %
QLatin1Literal("<th>&Delta;t</th><th>&Delta;t fr.</th><th>fraction</th>") % QLatin1Literal("<th>&Delta;t</th><th>&Delta;t fr.</th><th>fraction</th>") %
QLatin1Literal("<th>lat.old</th><th>lat.new</th><th>lat.cur</th>") % QLatin1Literal("<th>lat.old</th><th>lat.new</th><th>lat.cur</th>") %
@@ -203,18 +221,30 @@ namespace BlackMisc
QLatin1Literal("<th>elv.old</th><th>elv.new</th><th>elv.cur</th>") % QLatin1Literal("<th>elv.old</th><th>elv.new</th><th>elv.cur</th>") %
QLatin1Literal("<th>gnd.factor</th>") % QLatin1Literal("<th>gnd.factor</th>") %
QLatin1Literal("<th>onGnd.old</th><th>onGnd.new</th><th>onGnd.cur</th>") % QLatin1Literal("<th>onGnd.old</th><th>onGnd.new</th><th>onGnd.cur</th>") %
QLatin1Literal("<th>parts</th><th>parts details</th>") % QLatin1Literal("<th>parts</th><th>c.</th><th>parts details</th>") %
QLatin1Literal("</tr>\n"); QLatin1Literal("</tr></thead>\n");
static const CLengthUnit ft = CLengthUnit::ft(); static const CLengthUnit ft = CLengthUnit::ft();
const InterpolationLog firstLog = logs.first();
qint64 newPosTs = firstLog.newSituation.getMSecsSinceEpoch();
CAircraftParts lastParts; // default, so shown if parts are different from default
QString tableRows("<tbody>\n");
for (const InterpolationLog &log : logs) for (const InterpolationLog &log : logs)
{ {
const bool changedNewPosition = newPosTs != log.newSituation.getMSecsSinceEpoch();
const bool changedParts = lastParts != log.parts;
newPosTs = log.newSituation.getMSecsSinceEpoch();
lastParts = log.parts;
// concatenating in multiple steps, otherwise C4503 warnings // concatenating in multiple steps, otherwise C4503 warnings
tableRows += tableRows +=
QLatin1Literal("<tr>") % QLatin1Literal("<tr>") %
(changedNewPosition ? QLatin1Literal("<td class=\"changed\">*</td>") : QLatin1Literal("<td></td>")) %
QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") % QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") %
QLatin1Literal("<td>") % boolToYesNo(log.vtolAircraft) % QLatin1Literal("</td>") % QLatin1Literal("<td>") % boolToYesNo(log.vtolAircraft) % QLatin1Literal("</td>") %
QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % QLatin1Literal("</td>") % QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % QLatin1Literal("</td>") %
QLatin1Literal("<td>") % QString::number(log.timestamp - firstLog.timestamp) % QLatin1Literal("</td>") %
QLatin1Literal("<td class=\"old\">") % msSinceEpochToTime(log.oldSituation.getAdjustedMSecsSinceEpoch()) % QLatin1Char('-') % QString::number(log.oldSituation.getTimeOffsetMs()) % QLatin1Literal("</td>") % QLatin1Literal("<td class=\"old\">") % msSinceEpochToTime(log.oldSituation.getAdjustedMSecsSinceEpoch()) % QLatin1Char('-') % QString::number(log.oldSituation.getTimeOffsetMs()) % QLatin1Literal("</td>") %
QLatin1Literal("<td class=\"new\">") % msSinceEpochToTime(log.newSituation.getAdjustedMSecsSinceEpoch()) % QLatin1Char('-') % QString::number(log.newSituation.getTimeOffsetMs()) % QLatin1Literal("</td>") % QLatin1Literal("<td class=\"new\">") % msSinceEpochToTime(log.newSituation.getAdjustedMSecsSinceEpoch()) % QLatin1Char('-') % QString::number(log.newSituation.getTimeOffsetMs()) % QLatin1Literal("</td>") %
@@ -249,33 +279,38 @@ namespace BlackMisc
tableRows += tableRows +=
QLatin1Literal("<td>") % boolToYesNo(log.useParts) % QLatin1Literal("</td>") % QLatin1Literal("<td>") % boolToYesNo(log.useParts) % QLatin1Literal("</td>") %
(changedParts ? QLatin1String("<td>*</td>") : QLatin1String("<td></td>")) %
QLatin1Literal("<td>") % (log.useParts ? log.parts.toQString(true) : QLatin1Literal("")) % QLatin1Literal("</td>") % QLatin1Literal("<td>") % (log.useParts ? log.parts.toQString(true) : QLatin1Literal("")) % QLatin1Literal("</td>") %
QLatin1Literal("</tr>\n"); QLatin1Literal("</tr>\n");
} }
tableRows += QLatin1Literal("</tbody>\n");
return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n"); return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n");
} }
QString IInterpolator::getHtmlPartsLog(const QList<PartsLog> &logs) QString IInterpolator::getHtmlPartsLog(const QList<PartsLog> &logs)
{ {
if (logs.isEmpty()) { return {}; } if (logs.isEmpty()) { return {}; }
QString tableRows;
const QString tableHeader = const QString tableHeader =
QLatin1Literal("<tr>") % QLatin1Literal("<thead><tr>") %
QLatin1Literal("<th>CS</th><th>timestamp</th>") % QLatin1Literal("<th>CS</th><th>timestamp</th>") %
QLatin1Literal("<th>c.</th>") %
QLatin1Literal("<th>parts</th>") % QLatin1Literal("<th>parts</th>") %
QLatin1Literal("</tr>\n"); QLatin1Literal("</tr></thead>\n");
CAircraftParts lastParts; // default, so shown if parts are different from default
QString tableRows("<tbody>\n");
for (const PartsLog &log : logs) for (const PartsLog &log : logs)
{ {
// concatenating in multiple steps, otherwise C4503 warnings const bool changedParts = lastParts != log.parts;
lastParts = log.parts;
tableRows += tableRows +=
QLatin1Literal("<tr>") % QLatin1Literal("<tr>") %
QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") % QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") %
QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % QLatin1Literal("</td>") % QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % QLatin1Literal("</td>") %
(changedParts ? QLatin1String("<td class=\"changed\">*</td>") : QLatin1String("<td></td>")) %
QLatin1Literal("<td>") % log.parts.toQString() % QLatin1Literal("</td>"); QLatin1Literal("<td>") % log.parts.toQString() % QLatin1Literal("</td>");
} }
tableRows += QLatin1Literal("</tbody>\n");
return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n"); return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n");
} }

View File

@@ -111,13 +111,13 @@ namespace BlackMisc
virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts( virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
const Aviation::CCallsign &callsign, const Aviation::CCallsign &callsign,
const BlackMisc::Aviation::CAircraftPartsList &parts, qint64 cutoffTime, const BlackMisc::Aviation::CAircraftPartsList &parts, qint64 cutoffTime,
PartsStatus &partsStatus) const; PartsStatus &partsStatus, bool log = false) const;
//! Parts before given offset time (aka pending parts) //! Parts before given offset time (aka pending parts)
//! \threadsafe //! \threadsafe
virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts( virtual BlackMisc::Aviation::CAircraftParts getInterpolatedParts(
const BlackMisc::Aviation::CCallsign &callsign, qint64 cutoffTime, const BlackMisc::Aviation::CCallsign &callsign, qint64 cutoffTime,
PartsStatus &partsStatus) const; PartsStatus &partsStatus, bool log = false) const;
//! Enable debug messages etc. //! Enable debug messages etc.
//! \threadsafe //! \threadsafe
@@ -129,6 +129,11 @@ namespace BlackMisc
//! Clear log file //! Clear log file
void clearLog(); void clearLog();
//! Enable log messages etc.
//! \threadsafe
//! \remark public for FS9 to get setup in Fs9Client
CInterpolationAndRenderingSetup getInterpolatorSetup() const;
/*! /*!
* Takes input between 0 and 1 and returns output between 0 and 1 smoothed with an S-shaped curve. * Takes input between 0 and 1 and returns output between 0 and 1 smoothed with an S-shaped curve.
* *
@@ -170,16 +175,12 @@ namespace BlackMisc
//! Constructor //! Constructor
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent); IInterpolator(BlackMisc::Simulation::IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent);
//! Enable debug messages etc. //! Log current interpolation cycle, only stores in memory, for performance reasons
//! \threadsafe
CInterpolationAndRenderingSetup getInterpolatorSetup() const;
//! Log interpolation, only stores in memory, for performance reasons
//! \remark const to allow const interpolator functions //! \remark const to allow const interpolator functions
//! \threadsafe //! \threadsafe
void logInterpolation(const InterpolationLog &log) const; void logInterpolation(const InterpolationLog &log) const;
//! Log parts, only stores in memory, for performance reasons //! Log current parts cycle, only stores in memory, for performance reasons
//! \remark const to allow const interpolator functions //! \remark const to allow const interpolator functions
//! \threadsafe //! \threadsafe
void logParts(const PartsLog &parts) const; void logParts(const PartsLog &parts) const;
@@ -202,7 +203,10 @@ namespace BlackMisc
private: private:
//! Write log to file //! Write log to file
static CStatusMessage writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts); static CStatusMessageList writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts);
//! Status of file operation
static CStatusMessage logStatusFileWriting(bool success, const QString &fileName);
//! Create readable time //! Create readable time
static QString msSinceEpochToTime(qint64 ms); static QString msSinceEpochToTime(qint64 ms);

View File

@@ -67,7 +67,6 @@ namespace BlackMisc
// interpolation situations // interpolation situations
CAircraftSituation oldSituation; CAircraftSituation oldSituation;
CAircraftSituation newSituation; CAircraftSituation newSituation;
const bool logInterpolation = setup.getLogCallsigns().contains(callsign);
InterpolationLog log; InterpolationLog log;
// latest first, now 00:20 split time // latest first, now 00:20 split time
@@ -215,7 +214,7 @@ namespace BlackMisc
status.setChangedPosition(true); status.setChangedPosition(true);
} }
status.setInterpolationSucceeded(true); status.setInterpolationSucceeded(true);
if (logInterpolation) if (hints.isLoggingInterpolation())
{ {
log.timestamp = currentTimeMsSinceEpoc; log.timestamp = currentTimeMsSinceEpoc;
log.callsign = callsign; log.callsign = callsign;
@@ -224,6 +223,7 @@ namespace BlackMisc
log.oldSituation = oldSituation; log.oldSituation = oldSituation;
log.newSituation = newSituation; log.newSituation = newSituation;
log.useParts = hints.hasAircraftParts(); log.useParts = hints.hasAircraftParts();
log.parts = hints.getAircraftParts();
this->logInterpolation(log); this->logInterpolation(log);
} }

View File

@@ -120,6 +120,7 @@ namespace BlackMisc
void IRemoteAircraftProvider::removeOutdatedParts(CAircraftPartsList &partsList) void IRemoteAircraftProvider::removeOutdatedParts(CAircraftPartsList &partsList)
{ {
// remove outdated parts (but never remove the most recent one)
const auto predicate = [now = partsList.front().getMSecsSinceEpoch()](const auto & p) { return p.getMSecsSinceEpoch() >= now - PartsPerCallsignMaxAgeInSeconds * 1000; }; const auto predicate = [now = partsList.front().getMSecsSinceEpoch()](const auto & p) { return p.getMSecsSinceEpoch() >= now - PartsPerCallsignMaxAgeInSeconds * 1000; };
const auto newEnd = std::find_if(partsList.rbegin(), partsList.rend(), predicate).base(); const auto newEnd = std::find_if(partsList.rbegin(), partsList.rend(), predicate).base();
partsList.erase(newEnd, partsList.end()); partsList.erase(newEnd, partsList.end());

View File

@@ -166,7 +166,7 @@ namespace BlackMisc
std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> aircraftSnapshot std::function<void(const BlackMisc::Simulation::CAirspaceAircraftSnapshot &)> aircraftSnapshot
) = 0; ) = 0;
//! Remove outdated aircraft parts //! Remove outdated aircraft parts, but never the most recent one
void static removeOutdatedParts(Aviation::CAircraftPartsList &partsList); void static removeOutdatedParts(Aviation::CAircraftPartsList &partsList);
}; };

View File

@@ -170,7 +170,8 @@ namespace BlackSimPlugin
if (m_clientStatus == Disconnected) { return; } if (m_clientStatus == Disconnected) { return; }
IInterpolator::InterpolationStatus status; IInterpolator::InterpolationStatus status;
const CInterpolationHints hints; // \fixme 201701 #865 KB if there is an elevation provider for FS9 add it here or set elevation CInterpolationHints hints; // \fixme 201701 #865 KB if there is an elevation provider for FS9 add it here or set elevation
hints.setLoggingInterpolation(this->m_interpolator->getInterpolatorSetup().getLogCallsigns().contains(m_callsign));
const CAircraftSituation situation = this->m_interpolator->getInterpolatedSituation(m_callsign, -1, hints, status); const CAircraftSituation situation = this->m_interpolator->getInterpolatedSituation(m_callsign, -1, hints, status);
// Test only for successful interpolation. FS9 requires constant positions // Test only for successful interpolation. FS9 requires constant positions

View File

@@ -863,6 +863,9 @@ namespace BlackSimPlugin
// values used for position and parts // values used for position and parts
const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch(); const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
const QList<CSimConnectObject> simObjects(m_simConnectObjects.values()); const QList<CSimConnectObject> simObjects(m_simConnectObjects.values());
const CCallsignSet callsignsToLog(this->m_interpolationRenderingSetup.getLogCallsigns());
// interpolation for all remote aircraft
for (const CSimConnectObject &simObj : simObjects) for (const CSimConnectObject &simObj : simObjects)
{ {
// happening if aircraft is not yet added to simulator or to be deleted // happening if aircraft is not yet added to simulator or to be deleted
@@ -875,14 +878,17 @@ namespace BlackSimPlugin
// fetch parts, as they are needed for ground interpolation // fetch parts, as they are needed for ground interpolation
const bool useAircraftParts = enableAircraftParts && aircraftWithParts.contains(callsign); const bool useAircraftParts = enableAircraftParts && aircraftWithParts.contains(callsign);
const bool logInterpolationAndParts = callsignsToLog.contains(callsign);
IInterpolator::PartsStatus partsStatus; IInterpolator::PartsStatus partsStatus;
partsStatus.setSupportsParts(useAircraftParts); partsStatus.setSupportsParts(useAircraftParts);
const CAircraftParts parts = useAircraftParts ? this->m_interpolator->getInterpolatedParts(callsign, -1, partsStatus) : CAircraftParts(); const CAircraftParts parts = useAircraftParts ? this->m_interpolator->getInterpolatedParts(callsign, -1, partsStatus, logInterpolationAndParts) : CAircraftParts();
// get interpolated situation // get interpolated situation
IInterpolator::InterpolationStatus interpolatorStatus; IInterpolator::InterpolationStatus interpolatorStatus;
CInterpolationHints hints(m_hints[simObj.getCallsign()]); CInterpolationHints hints(m_hints[simObj.getCallsign()]);
hints.setAircraftParts(useAircraftParts ? parts : CAircraftParts(), useAircraftParts); hints.setAircraftParts(useAircraftParts ? parts : CAircraftParts(), useAircraftParts);
hints.setLoggingInterpolation(logInterpolationAndParts);
const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, hints, interpolatorStatus); const CAircraftSituation interpolatedSituation = this->m_interpolator->getInterpolatedSituation(callsign, currentTimestamp, hints, interpolatorStatus);
if (interpolatorStatus.allTrue()) if (interpolatorStatus.allTrue())