refs #840, moved interpolator classes into Simulation namespace

This commit is contained in:
Klaus Basan
2016-12-23 23:32:55 +00:00
committed by Mathew Sutcliffe
parent 46fafde7a0
commit 667009c85e
28 changed files with 875 additions and 860 deletions

View File

@@ -0,0 +1,212 @@
/* Copyright (C) 2016
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "interpolationrenderingsetup.h"
#include "stringutils.h"
using namespace BlackMisc::PhysicalQuantities;
namespace BlackMisc
{
namespace Simulation
{
CInterpolationAndRenderingSetup::CInterpolationAndRenderingSetup()
{ }
int CInterpolationAndRenderingSetup::InfiniteAircraft()
{
return 100;
}
bool CInterpolationAndRenderingSetup::isRenderingEnabled() const
{
if (m_maxRenderedAircraft < 1) { return false; }
if (!isMaxDistanceRestricted()) { return true; }
return m_maxRenderedDistance.isPositiveWithEpsilonConsidered();
}
bool CInterpolationAndRenderingSetup::isRenderingRestricted() const
{
return isRenderingEnabled() && (isMaxAircraftRestricted() || isMaxDistanceRestricted());
}
bool CInterpolationAndRenderingSetup::isAircraftPartsEnabled() const
{
return this->m_enabledAircraftParts;
}
int CInterpolationAndRenderingSetup::getMaxRenderedAircraft() const
{
return (m_maxRenderedAircraft <= InfiniteAircraft()) ? m_maxRenderedAircraft : InfiniteAircraft();
}
bool CInterpolationAndRenderingSetup::setMaxRenderedAircraft(int maxRenderedAircraft)
{
if (maxRenderedAircraft == m_maxRenderedAircraft) { return false; }
if (maxRenderedAircraft < 1)
{
// disable, we set both values to 0
this->disableRendering();
}
else if (maxRenderedAircraft >= InfiniteAircraft())
{
m_maxRenderedAircraft = InfiniteAircraft();
}
else
{
m_maxRenderedAircraft = maxRenderedAircraft;
}
return true;
}
bool CInterpolationAndRenderingSetup::setMaxRenderedDistance(const CLength &distance)
{
if (distance == m_maxRenderedDistance) { return false; }
if (distance.isNull() || distance.isNegativeWithEpsilonConsidered())
{
m_maxRenderedDistance = CLength(0.0, nullptr);
}
else if (distance.isZeroEpsilonConsidered())
{
// zero means disabled, we disable max aircraft too
this->disableRendering();
}
else
{
Q_ASSERT(!distance.isNegativeWithEpsilonConsidered());
m_maxRenderedDistance = distance;
}
return true;
}
bool CInterpolationAndRenderingSetup::setEnabledAircraftParts(bool enabled)
{
if (this->m_enabledAircraftParts == enabled) { return false; }
m_enabledAircraftParts = enabled;
return true;
}
void CInterpolationAndRenderingSetup::clearMaxRenderedDistance()
{
this->setMaxRenderedDistance(CLength(0.0, nullptr));
}
bool CInterpolationAndRenderingSetup::isMaxAircraftRestricted() const
{
return m_maxRenderedAircraft < InfiniteAircraft();
}
void CInterpolationAndRenderingSetup::clearAllRenderingRestrictions()
{
this->m_maxRenderedDistance = CLength(0, nullptr);
this->m_maxRenderedAircraft = InfiniteAircraft();
}
void CInterpolationAndRenderingSetup::disableRendering()
{
this->m_maxRenderedAircraft = 0;
this->m_maxRenderedDistance = CLength(0, CLengthUnit::NM()); // zero distance
}
bool CInterpolationAndRenderingSetup::isMaxDistanceRestricted() const
{
return !m_maxRenderedDistance.isNull();
}
QString CInterpolationAndRenderingSetup::getRenderRestrictionText() const
{
if (!this->isRenderingRestricted()) { return "none"; }
QString rt;
if (this->isMaxAircraftRestricted())
{
rt.append(QString::number(this->getMaxRenderedAircraft())).append(" A/C");
}
if (this->isMaxDistanceRestricted())
{
if (!rt.isEmpty()) { rt.append(" ");}
rt.append(this->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
}
return rt;
}
QString CInterpolationAndRenderingSetup::convertToQString(bool i18n) const
{
Q_UNUSED(i18n);
QString s("Setup: debug sim: ");
s += boolToYesNo(this->m_simulatorDebugMessages);
s += " debug interpolator: ";
s += boolToYesNo(this->m_interpolatorDebugMessage);
s += " force full interpolation: ";
s += boolToYesNo(this->m_forceFullInterpolation);
s += " max.aircraft:";
s += QString::number(m_maxRenderedAircraft);
s += " max.distance:";
s += m_maxRenderedDistance.valueRoundedWithUnit(CLengthUnit::NM(), 2);
return s;
}
CVariant CInterpolationAndRenderingSetup::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
{
if (index.isMyself()) { return CVariant::from(*this); }
ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexInterpolatorDebugMessages:
return CVariant::fromValue(m_interpolatorDebugMessage);
case IndexSimulatorDebugMessages:
return CVariant::fromValue(m_simulatorDebugMessages);
case IndexForceFullInterpolation:
return CVariant::fromValue(m_forceFullInterpolation);
case IndexMaxRenderedAircraft:
return CVariant::fromValue(m_maxRenderedAircraft);
case IndexMaxRenderedDistance:
return CVariant::fromValue(m_maxRenderedDistance);
case IndexEnabledAircraftParts:
return CVariant::fromValue(m_enabledAircraftParts);
default:
return CValueObject::propertyByIndex(index);
}
}
void CInterpolationAndRenderingSetup::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant)
{
if (index.isMyself())
{
*this = variant.value<CInterpolationAndRenderingSetup>();
return;
}
ColumnIndex i = index.frontCasted<ColumnIndex>();
switch (i)
{
case IndexInterpolatorDebugMessages:
this->m_interpolatorDebugMessage = variant.toBool();
break;
case IndexSimulatorDebugMessages:
this->m_simulatorDebugMessages = variant.toBool();
break;
case IndexForceFullInterpolation:
this->m_forceFullInterpolation = variant.toBool();
break;
case IndexMaxRenderedAircraft:
this->m_maxRenderedAircraft = variant.toInt();
break;
case IndexMaxRenderedDistance:
this->m_maxRenderedDistance = variant.value<CLength>();
break;
case IndexEnabledAircraftParts:
this->m_enabledAircraftParts = variant.toBool();
break;
default:
CValueObject::setPropertyByIndex(index, variant);
break;
}
}
} // ns
} // ns

View File

@@ -0,0 +1,141 @@
/* Copyright (C) 2016
* swift Project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_SIMULATION_INTERPOLATIONRENDERINGSETUP_H
#define BLACKMISC_SIMULATION_INTERPOLATIONRENDERINGSETUP_H
#include "blackmisc/pq/length.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/propertyindex.h"
#include "blackmisc/valueobject.h"
#include <QString>
namespace BlackMisc
{
namespace Simulation
{
/*!
* Value object for interpolator and rendering
*/
class BLACKMISC_EXPORT CInterpolationAndRenderingSetup :
public CValueObject<CInterpolationAndRenderingSetup>
{
public:
//! Properties by index
enum ColumnIndex
{
IndexInterpolatorDebugMessages = BlackMisc::CPropertyIndex::GlobalIndexCInterpolatioRenderingSetup,
IndexSimulatorDebugMessages,
IndexForceFullInterpolation,
IndexMaxRenderedAircraft,
IndexMaxRenderedDistance,
IndexEnabledAircraftParts
};
//! Constructor.
CInterpolationAndRenderingSetup();
//! Considered as "all aircraft"
static int InfiniteAircraft();
//! Debugging messages
bool showInterpolatorDebugMessages() const { return m_interpolatorDebugMessage; }
//! Debugging messages
void setInterpolatorDebuggingMessages(bool debug) { m_interpolatorDebugMessage = debug; }
//! Debugging messages
bool showSimulatorDebugMessages() const { return m_simulatorDebugMessages; }
//! Debugging messages
void setDriverDebuggingMessages(bool debug) { m_simulatorDebugMessages = debug; }
//! Full interpolation
bool isForcingFullInterpolation() const { return m_forceFullInterpolation; }
//! Force full interpolation
void setForceFullInterpolation(bool force) { m_forceFullInterpolation = force; }
//! Max. number of aircraft rendered
int getMaxRenderedAircraft() const;
//! Max. number of aircraft rendered
bool setMaxRenderedAircraft(int maxRenderedAircraft);
//! Max. distance for rendering
bool setMaxRenderedDistance(const BlackMisc::PhysicalQuantities::CLength &distance);
//! Set enabled aircraft parts
bool setEnabledAircraftParts(bool enabled);
//! Disable
void clearMaxRenderedDistance();
//! Rendering enabled (at all)
bool isRenderingEnabled() const;
//! Rendering enabled, but restricted
bool isRenderingRestricted() const;
//! Aircraft parts enabled
bool isAircraftPartsEnabled() const;
//! Max.distance for rendering
BlackMisc::PhysicalQuantities::CLength getMaxRenderedDistance() const { return m_maxRenderedDistance; }
//! Restricted by distance?
bool isMaxDistanceRestricted() const;
//! Restricted by quantity?
bool isMaxAircraftRestricted() const;
//! Remove all render restrictions
void clearAllRenderingRestrictions();
//! Entirely disable rendering
void disableRendering();
//! Text describing the restrictions
QString getRenderRestrictionText() const;
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const;
//! \copydoc BlackMisc::Mixin::Index::propertyByIndex
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
//! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex
void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const CVariant &variant);
private:
bool m_interpolatorDebugMessage = false; //! Debug messages in interpolator
bool m_simulatorDebugMessages = false; //! Debug messages of simulator (aka plugin)
bool m_forceFullInterpolation = false; //! always do a full interpolation, even if aircraft is not moving
bool m_enabledAircraftParts = true; //! Update aircraft parts
int m_maxRenderedAircraft = InfiniteAircraft(); //!< max.rendered aircraft
BlackMisc::PhysicalQuantities::CLength m_maxRenderedDistance { 0, nullptr }; //!< max.distance for rendering
BLACK_METACLASS(
CInterpolationAndRenderingSetup,
BLACK_METAMEMBER(interpolatorDebugMessage),
BLACK_METAMEMBER(simulatorDebugMessages),
BLACK_METAMEMBER(forceFullInterpolation),
BLACK_METAMEMBER(enabledAircraftParts),
BLACK_METAMEMBER(maxRenderedAircraft),
BLACK_METAMEMBER(maxRenderedDistance)
);
};
} // namespace
} // namespace
Q_DECLARE_METATYPE(BlackMisc::Simulation::CInterpolationAndRenderingSetup)
#endif // guard

View File

@@ -0,0 +1,102 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "interpolator.h"
#include "blackmisc/aviation/callsign.h"
#include "blackmisc/simulation/interpolationhints.h"
using namespace BlackMisc::Aviation;
namespace BlackMisc
{
namespace Simulation
{
IInterpolator::IInterpolator(IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent) :
QObject(parent),
CRemoteAircraftAware(provider)
{
Q_ASSERT_X(provider, Q_FUNC_INFO, "missing provider");
this->setObjectName(objectName);
}
BlackMisc::Aviation::CAircraftSituation IInterpolator::getInterpolatedSituation(
const CCallsign &callsign, qint64 currentTimeSinceEpoc,
const CInterpolationHints &hints, InterpolationStatus &status) const
{
// has to be thread safe
status.reset();
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
auto currentSituation = this->getInterpolatedSituation(this->remoteAircraftSituations(callsign), currentTimeSinceEpoc, hints, status);
currentSituation.setCallsign(callsign); // make sure callsign is correct
return currentSituation;
}
CAircraftPartsList IInterpolator::getPartsBeforeTime(const CAircraftPartsList &parts, qint64 cutoffTime, IInterpolator::PartsStatus &partsStatus) const
{
partsStatus.reset();
partsStatus.setSupportsParts(true);
if (cutoffTime < 0) { return parts; }
return parts.findBefore(cutoffTime);
}
CAircraftPartsList IInterpolator::getPartsBeforeTime(const CCallsign &callsign, qint64 cutoffTime, IInterpolator::PartsStatus &partsStatus) const
{
Q_ASSERT_X(!callsign.isEmpty(), Q_FUNC_INFO, "empty callsign");
partsStatus.reset();
partsStatus.setSupportsParts(this->isRemoteAircraftSupportingParts(callsign));
if (!partsStatus.isSupportingParts()) { return {}; }
return this->remoteAircraftParts(callsign, cutoffTime);
}
void IInterpolator::setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup)
{
QWriteLocker l(&m_lock);
m_setup = setup;
}
CInterpolationAndRenderingSetup IInterpolator::getInterpolatorSetup() const
{
QReadLocker l(&m_lock);
return m_setup;
}
void IInterpolator::setGroundElevationFromHint(const CInterpolationHints &hints, CAircraftSituation &situation)
{
if (hints.getElevation().isNull()) return;
if (situation.hasGroundElevation()) return;
if (!hints.isWithinRange(situation)) return;
situation.setGroundElevation(hints.getElevation().geodeticHeight());
}
bool IInterpolator::InterpolationStatus::allTrue() const
{
return m_interpolationSucceeded && m_changedPosition;
}
void IInterpolator::InterpolationStatus::reset()
{
m_changedPosition = false;
m_interpolationSucceeded = false;
}
bool IInterpolator::PartsStatus::allTrue() const
{
return m_supportsParts;
}
void IInterpolator::PartsStatus::reset()
{
m_supportsParts = false;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,138 @@
/* Copyright (C) 2014
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_SIMULATION_INTERPOLATOR_H
#define BLACKMISC_SIMULATION_INTERPOLATOR_H
#include "interpolationrenderingsetup.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/aviation/aircraftpartslist.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include "blackmisc/simulation/remoteaircraftprovider.h"
#include <QObject>
#include <QString>
#include <QtGlobal>
namespace BlackMisc
{
namespace Aviation { class CCallsign; }
namespace Simulation
{
class CInterpolationHints;
//! Interpolator, calculation inbetween positions
class BLACKMISC_EXPORT IInterpolator :
public QObject,
public BlackMisc::Simulation::CRemoteAircraftAware
{
Q_OBJECT
public:
//! Virtual destructor
virtual ~IInterpolator() {}
//! Log category
static QString getLogCategory() { return "swift.interpolator"; }
//! Status of interpolation
struct BLACKMISC_EXPORT InterpolationStatus // does not link without export/allTrue, reset
{
public:
//! Did interpolation succeed?
bool didInterpolationSucceed() const { return m_interpolationSucceeded; }
//! Set succeeded
void setInterpolationSucceeded(bool succeeded) { m_interpolationSucceeded = succeeded; }
//! Changed position?
bool hasChangedPosition() const { return m_changedPosition; }
//! Set as changed
void setChangedPosition(bool changed) { m_changedPosition = changed; }
//! all OK
bool allTrue() const;
//! Reset to default values
void reset();
private:
bool m_changedPosition = false; //!< position was changed
bool m_interpolationSucceeded = false; //!< interpolation succeeded (means enough values, etc.)
};
//! Status regarding parts
struct BLACKMISC_EXPORT PartsStatus // does not link without export/allTrue, resetx
{
public:
//! all OK
bool allTrue() const;
//! Supporting parts
bool isSupportingParts() const { return m_supportsParts; }
//! Set support flag
void setSupportsParts(bool supports) { m_supportsParts = supports; }
//! Reset to default values
void reset();
private:
bool m_supportsParts = false; //!< supports parts for given callsign
};
//! Current interpolated situation
//! \threadsafe
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CCallsign &callsign, qint64 currentTimeSinceEpoc,
const CInterpolationHints &hints, InterpolationStatus &status) const;
//! Current interpolated situation, to be implemented by subclass
//! \threadsafe
//! \remark public only for XP driver
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(
const BlackMisc::Aviation::CAircraftSituationList &situations, qint64 currentTimeSinceEpoc,
const CInterpolationHints &hints, InterpolationStatus &status) const = 0;
//! Parts before given offset time (aka pending parts)
//! \threadsafe
virtual BlackMisc::Aviation::CAircraftPartsList getPartsBeforeTime(
const BlackMisc::Aviation::CAircraftPartsList &parts, qint64 cutoffTime,
PartsStatus &partsStatus) const;
//! Parts before given offset time (aka pending parts)
//! \threadsafe
virtual BlackMisc::Aviation::CAircraftPartsList getPartsBeforeTime(
const BlackMisc::Aviation::CCallsign &callsign, qint64 cutoffTime,
PartsStatus &partsStatus) const;
//! Enable debug messages etc.
//! \threadsafe
void setInterpolatorSetup(const CInterpolationAndRenderingSetup &setup);
protected:
//! Constructor
IInterpolator(BlackMisc::Simulation::IRemoteAircraftProvider *provider, const QString &objectName, QObject *parent);
//! Enable debug messages etc.
//! \threadsafe
CInterpolationAndRenderingSetup getInterpolatorSetup() const;
//! Set the ground elevation from hints, if possible and not already set
static void setGroundElevationFromHint(const CInterpolationHints &hints, BlackMisc::Aviation::CAircraftSituation &situation);
CInterpolationAndRenderingSetup m_setup; //!< allows to disable debug messages
mutable QReadWriteLock m_lock; //!< lock interpolator
};
} // namespace
} // namespace
#endif // guard

View File

@@ -0,0 +1,189 @@
/* Copyright (C) 2014
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "interpolatorlinear.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include "blackmisc/aviation/aircraftsituationlist.h"
#include "blackmisc/aviation/altitude.h"
#include "blackmisc/aviation/callsign.h"
#include "blackmisc/aviation/heading.h"
#include "blackmisc/geo/coordinategeodetic.h"
#include "blackmisc/pq/angle.h"
#include "blackmisc/pq/length.h"
#include "blackmisc/pq/physicalquantity.h"
#include "blackmisc/pq/speed.h"
#include "blackmisc/pq/units.h"
#include "blackmisc/simulation/interpolationhints.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/compare.h"
#include "blackmisc/range.h"
#include "blackmisc/sequence.h"
#include "blackmisc/statusmessage.h"
#include <QDateTime>
#include <QList>
#include <array>
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Geo;
using namespace BlackMisc::Math;
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Simulation;
namespace BlackMisc
{
namespace Simulation
{
CAircraftSituation CInterpolatorLinear::getInterpolatedSituation(const CAircraftSituationList &situations, qint64 currentTimeMsSinceEpoc, const CInterpolationHints &hints, InterpolationStatus &status) const
{
// has to be thread safe
const CInterpolationAndRenderingSetup setup = this->getInterpolatorSetup();
status.reset();
// any data at all?
if (situations.isEmpty()) { return {}; }
// data, split situations by time
if (currentTimeMsSinceEpoc < 0) { currentTimeMsSinceEpoc = QDateTime::currentMSecsSinceEpoch(); }
// find the first situation not in the correct order, keep only the situations before that one
auto end = std::is_sorted_until(situations.begin(), situations.end(), [](auto && a, auto && b) { return b.getAdjustedMSecsSinceEpoch() < a.getAdjustedMSecsSinceEpoch(); });
auto validSituations = makeRange(situations.begin(), end);
// find the first situation earlier than the current time
auto pivot = std::partition_point(validSituations.begin(), validSituations.end(), [ = ](auto && s) { return s.getAdjustedMSecsSinceEpoch() > currentTimeMsSinceEpoc; });
auto situationsNewer = makeRange(validSituations.begin(), pivot);
auto situationsOlder = makeRange(pivot, validSituations.end());
// interpolation situations
CAircraftSituation oldSituation;
CAircraftSituation newSituation;
status.setInterpolationSucceeded(true);
status.setChangedPosition(true); //! \todo efficiently determine whether the position has changed
// latest first, now 00:20 split time
// time pos
// 00:25 10 newer
// 00:20 11 newer
// <----- split
// 00:15 12 older
// 00:10 13 older
// 00:05 14 older
// The first condition covers a situation, when there are no before / after situations.
// We just place at he last position until we get before / after situations
if (situationsOlder.isEmpty() || situationsNewer.isEmpty())
{
// no before situations
if (situationsOlder.isEmpty()) { return *(situationsNewer.end() - 1); } // oldest newest
// only one before situation
if (situationsOlder.size() < 2) { return situationsOlder.front(); } // latest older
// extrapolate from two before situations
oldSituation = *(situationsOlder.begin() + 1); // before newest
newSituation = situationsOlder.front(); // newest
}
else
{
oldSituation = situationsOlder.front(); // first oldest (aka newest oldest)
newSituation = *(situationsNewer.end() - 1); // latest newest (aka oldest of newer block)
Q_ASSERT(oldSituation.getAdjustedMSecsSinceEpoch() < newSituation.getAdjustedMSecsSinceEpoch());
}
// take hint into account to calculate elevation and above ground level
if (!hints.getElevation().isNull())
{
setGroundElevationFromHint(hints, oldSituation);
setGroundElevationFromHint(hints, newSituation);
}
CAircraftSituation currentSituation(oldSituation);
CCoordinateGeodetic currentPosition;
// Time between start and end packet
double deltaTime = std::abs(oldSituation.getAdjustedMSecsSinceEpoch() - newSituation.getAdjustedMSecsSinceEpoch());
// Fraction of the deltaTime, ideally [0.0 - 1.0]
// < 0 should not happen due to the split, > 1 can happen if new values are delayed beyond split time
// 1) values > 1 mean extrapolation
// 2) values > 2 mean no new situations coming in
const double distanceToSplitTime = newSituation.getAdjustedMSecsSinceEpoch() - currentTimeMsSinceEpoc;
const double simulationTimeFraction = 1.0 - (distanceToSplitTime / deltaTime);
if (simulationTimeFraction > 2.0)
{
if (setup.showInterpolatorDebugMessages())
{
CLogMessage(this).warning("Extrapolation, fraction > 1: %1 for callsign: %2") << simulationTimeFraction << oldSituation.getCallsign();
}
}
const std::array<double, 3> oldVec(oldSituation.getPosition().normalVectorDouble());
const std::array<double, 3> newVec(newSituation.getPosition().normalVectorDouble());
// Interpolate position: pos = (posB - posA) * t + posA
currentPosition.setNormalVector((newVec[0] - oldVec[0]) * simulationTimeFraction + oldVec[0],
(newVec[1] - oldVec[1]) * simulationTimeFraction + oldVec[1],
(newVec[2] - oldVec[2]) * simulationTimeFraction + oldVec[2]);
currentSituation.setPosition(currentPosition);
// Interpolate altitude: Alt = (AltB - AltA) * t + AltA
const CAltitude oldAlt(oldSituation.getCorrectedAltitude(hints.getCGAboveGround()));
const CAltitude newAlt(newSituation.getCorrectedAltitude(hints.getCGAboveGround()));
Q_ASSERT_X(oldAlt.getReferenceDatum() == newAlt.getReferenceDatum(), Q_FUNC_INFO, "mismatch in reference"); // otherwise no calculation is possible
currentSituation.setAltitude(CAltitude((newAlt - oldAlt)
* simulationTimeFraction
+ oldAlt,
oldAlt.getReferenceDatum()));
if (!setup.isForcingFullInterpolation() && !hints.isVtolAircraft() && newVec == oldVec && oldAlt == newAlt)
{
// stop interpolation here, does not work for VTOL aircraft. We need a flag for VTOL aircraft
return currentSituation;
}
// Interpolate heading: HDG = (HdgB - HdgA) * t + HdgA
const CHeading headingBegin = oldSituation.getHeading();
CHeading headingEnd = newSituation.getHeading();
if ((headingEnd - headingBegin).value(CAngleUnit::deg()) < -180)
{
headingEnd += CHeading(360, CHeading::Magnetic, CAngleUnit::deg());
}
if ((headingEnd - headingBegin).value(CAngleUnit::deg()) > 180)
{
headingEnd -= CHeading(360, CHeading::Magnetic, CAngleUnit::deg());
}
currentSituation.setHeading(CHeading((headingEnd - headingBegin)
* simulationTimeFraction
+ headingBegin,
headingBegin.getReferenceNorth()));
// Interpolate Pitch: Pitch = (PitchB - PitchA) * t + PitchA
const CAngle pitchBegin = oldSituation.getPitch();
const CAngle pitchEnd = newSituation.getPitch();
const CAngle pitch = (pitchEnd - pitchBegin) * simulationTimeFraction + pitchBegin;
currentSituation.setPitch(pitch);
// Interpolate bank: Bank = (BankB - BankA) * t + BankA
const CAngle bankBegin = oldSituation.getBank();
const CAngle bankEnd = newSituation.getBank();
const CAngle bank = (bankEnd - bankBegin) * simulationTimeFraction + bankBegin;
currentSituation.setBank(bank);
currentSituation.setGroundSpeed((newSituation.getGroundSpeed() - oldSituation.getGroundSpeed())
* simulationTimeFraction
+ oldSituation.getGroundSpeed());
return currentSituation;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,51 @@
/* Copyright (C) 2014
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKMISC_SIMULATION_INTERPOLATORLINEAR_H
#define BLACKMISC_SIMULATION_INTERPOLATORLINEAR_H
#include "interpolator.h"
#include "blackmisc/blackmiscexport.h"
#include "blackmisc/aviation/aircraftsituation.h"
#include <QString>
#include <QtGlobal>
class QObject;
namespace BlackMisc
{
namespace Aviation { class CCallsign; }
namespace Simulation
{
class IRemoteAircraftProvider;
//! Linear interpolator, calculation inbetween positions
class BLACKMISC_EXPORT CInterpolatorLinear : public IInterpolator
{
public:
//! Constructor
CInterpolatorLinear(BlackMisc::Simulation::IRemoteAircraftProvider *provider, QObject *parent = nullptr) :
IInterpolator(provider, "CInterpolatorLinear", parent)
{}
// public base class signature
using IInterpolator::getInterpolatedSituation;
//! \copydoc IInterpolator::getInterpolatedSituation
virtual BlackMisc::Aviation::CAircraftSituation getInterpolatedSituation(const BlackMisc::Aviation::CAircraftSituationList &situations, qint64 currentTimeSinceEpoc, const BlackMisc::Simulation::CInterpolationHints &hints, InterpolationStatus &status) const override;
//! Log category
static QString getLogCategory() { return "swift.interpolatorlinear"; }
};
} // ns
} // ns
#endif // guard

View File

@@ -20,6 +20,7 @@
#include "blackmisc/simulation/distributorlist.h"
#include "blackmisc/simulation/distributorlistpreferences.h"
#include "blackmisc/simulation/interpolationhints.h"
#include "blackmisc/simulation/interpolationrenderingsetup.h"
#include "blackmisc/simulation/modelsettings.h"
#include "blackmisc/simulation/simulatedaircraft.h"
#include "blackmisc/simulation/simulatedaircraftlist.h"