mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-30 22:29:13 +08:00
refs #865, added log functions to interpolator
* updated HTML template * parts use now string builder
This commit is contained in:
committed by
Mathew Sutcliffe
parent
af15929b30
commit
def51576de
@@ -9,7 +9,7 @@
|
|||||||
body {
|
body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
font-family: arial;
|
font-family: arial;
|
||||||
font-size: 12px;
|
font-size: 0.75em;
|
||||||
}
|
}
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
background-color: #c0c0c0;
|
background-color: #c0c0c0;
|
||||||
@@ -23,6 +23,9 @@ th {
|
|||||||
color:#fff;
|
color:#fff;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.small {
|
||||||
|
font-size: 0.5em;
|
||||||
|
}
|
||||||
.mouseoverdisplay {
|
.mouseoverdisplay {
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -35,6 +38,11 @@ th {
|
|||||||
a:hover + .mouseoverdisplay {
|
a:hover + .mouseoverdisplay {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** classes for interpolation log **/
|
||||||
|
.old { color: blue; }
|
||||||
|
.new { color: green; }
|
||||||
|
.cur { color: red; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "blackmisc/comparefunctions.h"
|
#include "blackmisc/comparefunctions.h"
|
||||||
#include "blackmisc/stringutils.h"
|
#include "blackmisc/stringutils.h"
|
||||||
|
|
||||||
|
#include "QStringBuilder"
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
using namespace BlackMisc;
|
using namespace BlackMisc;
|
||||||
@@ -21,18 +22,18 @@ namespace BlackMisc
|
|||||||
{
|
{
|
||||||
QString CAircraftParts::convertToQString(bool i18n) const
|
QString CAircraftParts::convertToQString(bool i18n) const
|
||||||
{
|
{
|
||||||
QString s;
|
const QString s =
|
||||||
s += m_lights.toQString(i18n);
|
m_lights.toQString(i18n) %
|
||||||
s += " gear down: ";
|
" gear down: " %
|
||||||
s += BlackMisc::boolToYesNo(m_gearDown);
|
BlackMisc::boolToYesNo(m_gearDown) %
|
||||||
s += " flaps pct: ";
|
" flaps pct: " %
|
||||||
s += QString::number(m_flapsPercentage);
|
QString::number(m_flapsPercentage) %
|
||||||
s += " spoilers out: ";
|
" spoilers out: " %
|
||||||
s += BlackMisc::boolToYesNo(m_spoilersOut);
|
BlackMisc::boolToYesNo(m_spoilersOut) %
|
||||||
s += " engines on: ";
|
" engines on: " %
|
||||||
s += m_engines.toQString(i18n);
|
m_engines.toQString(i18n) %
|
||||||
s += " on ground: ";
|
" on ground: " %
|
||||||
s += BlackMisc::boolToYesNo(m_isOnGround);
|
BlackMisc::boolToYesNo(m_isOnGround);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "interpolator.h"
|
#include "interpolator.h"
|
||||||
|
#include "blackconfig/buildconfig.h"
|
||||||
#include "blackmisc/simulation/interpolationhints.h"
|
#include "blackmisc/simulation/interpolationhints.h"
|
||||||
#include "blackmisc/aviation/callsign.h"
|
#include "blackmisc/aviation/callsign.h"
|
||||||
#include "blackmisc/pq/length.h"
|
#include "blackmisc/pq/length.h"
|
||||||
|
#include "blackmisc/logmessage.h"
|
||||||
|
#include "blackmisc/worker.h"
|
||||||
|
#include "blackmisc/directoryutils.h"
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QStringBuilder>
|
||||||
|
|
||||||
|
using namespace BlackConfig;
|
||||||
|
using namespace BlackMisc;
|
||||||
using namespace BlackMisc::Aviation;
|
using namespace BlackMisc::Aviation;
|
||||||
using namespace BlackMisc::PhysicalQuantities;
|
using namespace BlackMisc::PhysicalQuantities;
|
||||||
|
|
||||||
@@ -28,6 +35,9 @@ namespace BlackMisc
|
|||||||
this->setObjectName(objectName);
|
this->setObjectName(objectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IInterpolator::~IInterpolator()
|
||||||
|
{ }
|
||||||
|
|
||||||
BlackMisc::Aviation::CAircraftSituation IInterpolator::getInterpolatedSituation(
|
BlackMisc::Aviation::CAircraftSituation IInterpolator::getInterpolatedSituation(
|
||||||
const CCallsign &callsign, qint64 currentTimeSinceEpoc,
|
const CCallsign &callsign, qint64 currentTimeSinceEpoc,
|
||||||
const CInterpolationHints &hints, InterpolationStatus &status) const
|
const CInterpolationHints &hints, InterpolationStatus &status) const
|
||||||
@@ -37,15 +47,14 @@ namespace BlackMisc
|
|||||||
status.reset();
|
status.reset();
|
||||||
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
|
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
|
||||||
|
|
||||||
auto currentSituation = this->getInterpolatedSituation(this->remoteAircraftSituations(callsign), currentTimeSinceEpoc, hints, status);
|
auto currentSituation = this->getInterpolatedSituation(callsign, this->remoteAircraftSituations(callsign), currentTimeSinceEpoc, hints, status);
|
||||||
currentSituation.setCallsign(callsign); // make sure callsign is correct
|
currentSituation.setCallsign(callsign); // make sure callsign is correct
|
||||||
return currentSituation;
|
return currentSituation;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAircraftParts IInterpolator::getInterpolatedParts(const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus) const
|
CAircraftParts IInterpolator::getInterpolatedParts(const CCallsign &callsign, const CAircraftPartsList &parts, qint64 currentTimeMsSinceEpoch, IInterpolator::PartsStatus &partsStatus) 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
|
||||||
@@ -70,7 +79,9 @@ namespace BlackMisc
|
|||||||
const auto soonestLanding = std::find_if(partsNewer.begin(), partsNewer.end(), [](auto && p) { return p.isOnGround(); });
|
const auto soonestLanding = std::find_if(partsNewer.begin(), partsNewer.end(), [](auto && p) { return p.isOnGround(); });
|
||||||
|
|
||||||
// our clairvoyance is limited by the time offset
|
// our clairvoyance is limited by the time offset
|
||||||
const double significantPast = 5.0; // \fixme 20170121 KB would it make sense to centrally define the update time (5secs), in case it changes. I see a lot of 5.0 hardcoded here
|
const double significantPast = 5.0;
|
||||||
|
// \fixme 20170121 KB would it make sense to centrally define the update time (5secs), in case it changes. I see a lot of 5.0 hardcoded here
|
||||||
|
// I also wonder if the time is const (interim updates)
|
||||||
const double predictableFuture = soonestLanding == partsNewer.end() ? 5.0 : std::min(5.0, static_cast<double>(soonestLanding->getTimeOffsetMs()) / 1000.0);
|
const double predictableFuture = soonestLanding == partsNewer.end() ? 5.0 : std::min(5.0, static_cast<double>(soonestLanding->getTimeOffsetMs()) / 1000.0);
|
||||||
|
|
||||||
const double secondsSinceTakeoff = latestTakeoff == partsOlder.end() ? 5.0 : (currentTimeMsSinceEpoch - latestTakeoff->getAdjustedMSecsSinceEpoch()) / 1000.0;
|
const double secondsSinceTakeoff = latestTakeoff == partsOlder.end() ? 5.0 : (currentTimeMsSinceEpoch - latestTakeoff->getAdjustedMSecsSinceEpoch()) / 1000.0;
|
||||||
@@ -82,6 +93,17 @@ namespace BlackMisc
|
|||||||
const double landingFactor = secondsUntilLanding / predictableFuture;
|
const double landingFactor = secondsUntilLanding / predictableFuture;
|
||||||
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));
|
||||||
|
|
||||||
|
|
||||||
|
const CInterpolationAndRenderingSetup setup = this->getInterpolatorSetup();
|
||||||
|
if (setup.getLogCallsigns().contains(callsign))
|
||||||
|
{
|
||||||
|
PartsLog log;
|
||||||
|
log.timestamp = currentTimeMsSinceEpoch;
|
||||||
|
log.parts = currentParts;
|
||||||
|
IInterpolator::logParts(log);
|
||||||
|
}
|
||||||
|
|
||||||
return currentParts;
|
return currentParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,21 +114,171 @@ namespace BlackMisc
|
|||||||
|
|
||||||
partsStatus.setSupportsParts(this->isRemoteAircraftSupportingParts(callsign));
|
partsStatus.setSupportsParts(this->isRemoteAircraftSupportingParts(callsign));
|
||||||
if (!partsStatus.isSupportingParts()) { return {}; }
|
if (!partsStatus.isSupportingParts()) { return {}; }
|
||||||
return this->getInterpolatedParts(this->remoteAircraftParts(callsign, -1), currentTimeMsSinceEpoch, partsStatus);
|
return this->getInterpolatedParts(callsign, this->remoteAircraftParts(callsign, -1), currentTimeMsSinceEpoch, partsStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IInterpolator::setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup)
|
void IInterpolator::setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup)
|
||||||
{
|
{
|
||||||
QWriteLocker l(&m_lock);
|
QWriteLocker l(&m_lockSetup);
|
||||||
m_setup = setup;
|
m_setup = setup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CWorker *IInterpolator::writeLogInBackground()
|
||||||
|
{
|
||||||
|
// make sure logging is stopped
|
||||||
|
{
|
||||||
|
QWriteLocker l(&m_lockSetup);
|
||||||
|
m_setup.clearInterpolatorLogCallsigns();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<InterpolationLog> interpolation;
|
||||||
|
QList<PartsLog> parts;
|
||||||
|
{
|
||||||
|
QReadLocker l(&m_lockLogs);
|
||||||
|
interpolation = m_interpolationLogs;
|
||||||
|
parts = m_partsLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
CWorker *worker = CWorker::fromTask(this, "WriteInterpolationLog", [interpolation, parts]()
|
||||||
|
{
|
||||||
|
const CStatusMessage msg = IInterpolator::writeLogFile(interpolation, parts);
|
||||||
|
CLogMessage::preformatted(msg);
|
||||||
|
});
|
||||||
|
return worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
CStatusMessage 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"); }
|
||||||
|
const QString htmlInterpolation = IInterpolator::getHtmlInterpolationLog(interpolation);
|
||||||
|
const QString htmlParts = IInterpolator::getHtmlPartsLog(parts);
|
||||||
|
const QString html = htmlParts % QLatin1Literal("\n\n") % htmlInterpolation;
|
||||||
|
const QString htmlTemplate = CFileUtils::readFileToString(CBuildConfig::getHtmlTemplateFileName());
|
||||||
|
|
||||||
|
const QString ts = QDateTime::currentDateTimeUtc().toString("yyyyMMddhhmmss");
|
||||||
|
const QString fn = CFileUtils::appendFilePaths(CDirectoryUtils::getLogDirectory(), QString("%1 interpolation.html").arg(ts));
|
||||||
|
const bool s = CFileUtils::writeStringToFile(htmlTemplate.arg(html), fn);
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).info("Written log file '%1'") << fn;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return CStatusMessage(static_cast<IInterpolator *>(nullptr)).error("Failed to write log file '%1'") << fn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CInterpolationAndRenderingSetup IInterpolator::getInterpolatorSetup() const
|
CInterpolationAndRenderingSetup IInterpolator::getInterpolatorSetup() const
|
||||||
{
|
{
|
||||||
QReadLocker l(&m_lock);
|
QReadLocker l(&m_lockSetup);
|
||||||
return m_setup;
|
return m_setup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IInterpolator::logInterpolation(const IInterpolator::InterpolationLog &log) const
|
||||||
|
{
|
||||||
|
QWriteLocker l(&m_lockLogs);
|
||||||
|
m_interpolationLogs.append(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IInterpolator::logParts(const IInterpolator::PartsLog &parts) const
|
||||||
|
{
|
||||||
|
QWriteLocker l(&m_lockLogs);
|
||||||
|
m_partsLogs.append(parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IInterpolator::getHtmlInterpolationLog(const QList<InterpolationLog> &logs)
|
||||||
|
{
|
||||||
|
if (logs.isEmpty()) { return {}; }
|
||||||
|
QString tableRows;
|
||||||
|
const QString tableHeader =
|
||||||
|
QLatin1Literal("<tr>") %
|
||||||
|
QLatin1Literal("<th>CS</th><th>VTOL</th><th>timestamp</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>lat.old</th><th>lat.new</th><th>lat.cur</th>") %
|
||||||
|
QLatin1Literal("<th>lng.old</th><th>lng.new</th><th>lng.cur</th>") %
|
||||||
|
QLatin1Literal("<th>alt.old</th><th>alt.new</th><th>alt.cur</th>") %
|
||||||
|
QLatin1Literal("<th>elv.old</th><th>elv.new</th><th>elv.cur</th>") %
|
||||||
|
QLatin1Literal("<th>gnd.factor</th>") %
|
||||||
|
QLatin1Literal("<th>onGnd.old</th><th>onGnd.new</th><th>onGnd.cur</th>") %
|
||||||
|
QLatin1Literal("</tr>\n");
|
||||||
|
|
||||||
|
static const CLengthUnit ft = CLengthUnit::ft();
|
||||||
|
for (const InterpolationLog &log : logs)
|
||||||
|
{
|
||||||
|
// concatenating in multiple steps, otherwise C4503 warnings
|
||||||
|
tableRows +=
|
||||||
|
QLatin1Literal("<tr>") %
|
||||||
|
QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % boolToYesNo(log.vtolAircraft) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % 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=\"cur\">") % msSinceEpochToTime(log.currentSituation.getAdjustedMSecsSinceEpoch()) % QLatin1Char('-') % QString::number(log.currentSituation.getTimeOffsetMs()) % QLatin1Literal("</td>") %
|
||||||
|
|
||||||
|
QLatin1Literal("<td>") % QString::number(log.deltaTimeMs) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % QString::number(log.deltaTimeFractionMs) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % QString::number(log.simulationTimeFraction) % QLatin1Literal("</td>");
|
||||||
|
|
||||||
|
tableRows +=
|
||||||
|
QLatin1Literal("<td class=\"old\">") % log.oldSituation.latitudeAsString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"new\">") % log.newSituation.latitudeAsString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"cur\">") % log.currentSituation.latitudeAsString() % QLatin1Literal("</td>") %
|
||||||
|
|
||||||
|
QLatin1Literal("<td class=\"old\">") % log.oldSituation.longitudeAsString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"new\">") % log.newSituation.longitudeAsString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"cur\">") % log.currentSituation.longitudeAsString() % QLatin1Literal("</td>");
|
||||||
|
|
||||||
|
tableRows +=
|
||||||
|
QLatin1Literal("<td class=\"old\">") % log.oldSituation.getAltitude().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"new\">") % log.newSituation.getAltitude().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"cur\">") % log.currentSituation.getAltitude().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
|
||||||
|
QLatin1Literal("<td class=\"old\">") % log.oldSituation.getGroundElevation().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"new\">") % log.newSituation.getGroundElevation().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"cur\">") % log.currentSituation.getGroundElevation().valueRoundedWithUnit(ft, 1) % QLatin1Literal("</td>") %
|
||||||
|
|
||||||
|
QLatin1Literal("<td>") % QString::number(log.groundFactor) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"old\">") % log.oldSituation.getOnGroundInfo() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"new\">") % log.newSituation.getOnGroundInfo() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td class=\"cur\">") % log.currentSituation.getOnGroundInfo() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("</tr>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IInterpolator::getHtmlPartsLog(const QList<PartsLog> &logs)
|
||||||
|
{
|
||||||
|
if (logs.isEmpty()) { return {}; }
|
||||||
|
QString tableRows;
|
||||||
|
const QString tableHeader =
|
||||||
|
QLatin1Literal("<tr>") %
|
||||||
|
QLatin1Literal("<th>CS</th><th>timestamp</th>") %
|
||||||
|
QLatin1Literal("<th>parts</th>") %
|
||||||
|
QLatin1Literal("</tr>\n");
|
||||||
|
|
||||||
|
for (const PartsLog &log : logs)
|
||||||
|
{
|
||||||
|
// concatenating in multiple steps, otherwise C4503 warnings
|
||||||
|
tableRows +=
|
||||||
|
QLatin1Literal("<tr>") %
|
||||||
|
QLatin1Literal("<td>") % log.callsign.asString() % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % msSinceEpochToTime(log.timestamp) % QLatin1Literal("</td>") %
|
||||||
|
QLatin1Literal("<td>") % log.parts.toQString() % QLatin1Literal("</td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return QLatin1Literal("<table class=\"small\">\n") % tableHeader % tableRows % QLatin1Literal("</table>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void IInterpolator::clearLog()
|
||||||
|
{
|
||||||
|
QWriteLocker l(&m_lockLogs);
|
||||||
|
this->m_partsLogs.clear();
|
||||||
|
this->m_interpolationLogs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void IInterpolator::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation)
|
void IInterpolator::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation)
|
||||||
{
|
{
|
||||||
if (situation.hasGroundElevation()) { return; }
|
if (situation.hasGroundElevation()) { return; }
|
||||||
@@ -157,6 +329,18 @@ namespace BlackMisc
|
|||||||
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
|
situation.setOnGround(CAircraftSituation::OnGround, CAircraftSituation::OnGroundByGuessing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString IInterpolator::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)
|
||||||
|
{
|
||||||
|
if (t3 < 0) return QString("%1 %2").arg(msSinceEpochToTime(t1), msSinceEpochToTime(t2));
|
||||||
|
return QString("%1 %2 %3").arg(msSinceEpochToTime(t1), msSinceEpochToTime(t2), msSinceEpochToTime(t3));
|
||||||
|
}
|
||||||
|
|
||||||
bool IInterpolator::InterpolationStatus::allTrue() const
|
bool IInterpolator::InterpolationStatus::allTrue() const
|
||||||
{
|
{
|
||||||
return m_interpolationSucceeded && m_changedPosition;
|
return m_interpolationSucceeded && m_changedPosition;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "blackmisc/blackmiscexport.h"
|
#include "blackmisc/blackmiscexport.h"
|
||||||
#include "blackmisc/aviation/aircraftpartslist.h"
|
#include "blackmisc/aviation/aircraftpartslist.h"
|
||||||
#include "blackmisc/aviation/aircraftsituation.h"
|
#include "blackmisc/aviation/aircraftsituation.h"
|
||||||
|
#include "blackmisc/aviation/aircraftpartslist.h"
|
||||||
#include "blackmisc/simulation/remoteaircraftprovider.h"
|
#include "blackmisc/simulation/remoteaircraftprovider.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
|
|
||||||
namespace BlackMisc
|
namespace BlackMisc
|
||||||
{
|
{
|
||||||
|
class CWorker;
|
||||||
namespace Aviation { class CCallsign; }
|
namespace Aviation { class CCallsign; }
|
||||||
namespace Simulation
|
namespace Simulation
|
||||||
{
|
{
|
||||||
@@ -38,7 +40,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
//! Virtual destructor
|
//! Virtual destructor
|
||||||
virtual ~IInterpolator() {}
|
virtual ~IInterpolator();
|
||||||
|
|
||||||
//! Log category
|
//! Log category
|
||||||
static QString getLogCategory() { return "swift.interpolator"; }
|
static QString getLogCategory() { return "swift.interpolator"; }
|
||||||
@@ -121,6 +123,12 @@ namespace BlackMisc
|
|||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
void setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup);
|
void setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup);
|
||||||
|
|
||||||
|
//! Write a log in background
|
||||||
|
BlackMisc::CWorker *writeLogInBackground();
|
||||||
|
|
||||||
|
//! Clear log file
|
||||||
|
void clearLog();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
@@ -134,6 +142,29 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//! Log for interpolation
|
||||||
|
struct InterpolationLog
|
||||||
|
{
|
||||||
|
qint64 timestamp = -1; //!< current timestamp
|
||||||
|
double groundFactor = -1; //!< current ground factor
|
||||||
|
double vtolAircraft = false; //!< VTOL aircraft
|
||||||
|
double deltaTimeMs = 0; //!< delta time to last situation
|
||||||
|
double simulationTimeFraction = -1; //!< time fraction, normally 0..1
|
||||||
|
double deltaTimeFractionMs = -1; //!< delta time fraction
|
||||||
|
BlackMisc::Aviation::CCallsign callsign; //!< current callsign
|
||||||
|
BlackMisc::Aviation::CAircraftSituation oldSituation; //!< old situation
|
||||||
|
BlackMisc::Aviation::CAircraftSituation newSituation; //!< new situation
|
||||||
|
BlackMisc::Aviation::CAircraftSituation currentSituation; //!< interpolated situation
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Log for parts
|
||||||
|
struct PartsLog
|
||||||
|
{
|
||||||
|
qint64 timestamp = -1; //!< current timestamp
|
||||||
|
BlackMisc::Aviation::CCallsign callsign; //!< current callsign
|
||||||
|
BlackMisc::Aviation::CAircraftParts parts; //!< parts to be logged
|
||||||
|
};
|
||||||
|
|
||||||
//! Constructor
|
//! Constructor
|
||||||
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent);
|
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent);
|
||||||
|
|
||||||
@@ -141,14 +172,46 @@ namespace BlackMisc
|
|||||||
//! \threadsafe
|
//! \threadsafe
|
||||||
CInterpolationAndRenderingSetup getInterpolatorSetup() const;
|
CInterpolationAndRenderingSetup getInterpolatorSetup() const;
|
||||||
|
|
||||||
|
//! Log interpolation, only stores in memory, for performance reasons
|
||||||
|
//! \remark const to allow const interpolator functions
|
||||||
|
//! \threadsafe
|
||||||
|
void logInterpolation(const InterpolationLog &log) const;
|
||||||
|
|
||||||
|
//! Log parts, only stores in memory, for performance reasons
|
||||||
|
//! \remark const to allow const interpolator functions
|
||||||
|
//! \threadsafe
|
||||||
|
void logParts(const PartsLog &parts) const;
|
||||||
|
|
||||||
|
//! Get log as HTML table
|
||||||
|
//! \threadsafe
|
||||||
|
static QString getHtmlInterpolationLog(const QList<InterpolationLog> &logs);
|
||||||
|
|
||||||
|
//! Get log as HTML table
|
||||||
|
//! \threadsafe
|
||||||
|
static QString getHtmlPartsLog(const QList<PartsLog> &logs);
|
||||||
|
|
||||||
//! Set the ground elevation from hints, if possible and not already set
|
//! Set the ground elevation from hints, if possible and not already set
|
||||||
static void setGroundElevationFromHint(const CInterpolationHints &hints, BlackMisc::Aviation::CAircraftSituation &situation);
|
static void setGroundElevationFromHint(const CInterpolationHints &hints, BlackMisc::Aviation::CAircraftSituation &situation);
|
||||||
|
|
||||||
//! Set on ground flag
|
//! Set on ground flag
|
||||||
static void setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, BlackMisc::Aviation::CAircraftSituation &situation);
|
static void setGroundFlagFromInterpolator(const CInterpolationHints &hints, double groundFactor, BlackMisc::Aviation::CAircraftSituation &situation);
|
||||||
|
|
||||||
CInterpolationAndRenderingSetup m_setup; //!< allows to disable debug messages
|
CInterpolationAndRenderingSetup m_setup; //!< allows to enable/disable debug/log messages
|
||||||
mutable QReadWriteLock m_lock; //!< lock interpolator
|
|
||||||
|
private:
|
||||||
|
//! Write log to file
|
||||||
|
static CStatusMessage writeLogFile(const QList<InterpolationLog> &interpolation, const QList<PartsLog> &parts);
|
||||||
|
|
||||||
|
//! Create readable time
|
||||||
|
static QString msSinceEpochToTime(qint64 ms);
|
||||||
|
|
||||||
|
//! Create readable time
|
||||||
|
static QString msSinceEpochToTime(qint64 t1, qint64 t2, qint64 t3 = -1);
|
||||||
|
|
||||||
|
mutable QReadWriteLock m_lockSetup; //!< lock setup
|
||||||
|
mutable QReadWriteLock m_lockLogs; //!< lock logging
|
||||||
|
mutable QList<PartsLog> m_partsLogs; //!< logs of parts
|
||||||
|
mutable QList<InterpolationLog> m_interpolationLogs; //!< logs of interpolation
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user