mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-05-04 08:55:43 +08:00
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:
committed by
Mathew Sutcliffe
parent
ff7756db38
commit
62d4a94106
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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>Δt</th><th>Δt fr.</th><th>fraction</th>") %
|
QLatin1Literal("<th>Δt</th><th>Δ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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user