2023-02-14 14:46:08 +00:00
///////////////////////////////////////////////////////////////////////////////////
2023-11-18 13:12:18 +01:00
// Copyright (C) 2023 Jon Beniston, M7RCE <jon@beniston.com> //
2023-02-14 14:46:08 +00:00
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
2023-08-06 09:08:53 +01:00
2023-02-14 14:46:08 +00:00
# include "mapitem.h"
MapItem : : MapItem ( const QObject * sourcePipe , const QString & group , MapSettings : : MapItemSettings * itemSettings , SWGSDRangel : : SWGMapItem * mapItem ) :
m_altitude ( 0.0 )
{
m_sourcePipe = sourcePipe ;
m_group = group ;
m_itemSettings = itemSettings ;
m_name = * mapItem - > getName ( ) ;
m_hashKey = m_sourcePipe - > objectName ( ) + m_name ;
}
void MapItem : : update ( SWGSDRangel : : SWGMapItem * mapItem )
{
if ( mapItem - > getLabel ( ) ) {
m_label = * mapItem - > getLabel ( ) ;
} else {
m_label = " " ;
}
2025-06-09 10:44:17 +01:00
if ( mapItem - > getLabelDateTime ( ) ) {
m_labelDateTime = QDateTime : : fromString ( * mapItem - > getLabelDateTime ( ) , Qt : : ISODateWithMs ) ;
} else {
m_labelDateTime = QDateTime ( ) ;
}
2023-02-14 14:46:08 +00:00
m_latitude = mapItem - > getLatitude ( ) ;
m_longitude = mapItem - > getLongitude ( ) ;
m_altitude = mapItem - > getAltitude ( ) ;
}
2023-05-15 16:47:29 +01:00
QGeoCoordinate MapItem : : getCoordinates ( )
{
QGeoCoordinate coords ;
coords . setLatitude ( m_latitude ) ;
coords . setLongitude ( m_longitude ) ;
return coords ;
}
2025-06-09 10:44:17 +01:00
WhittakerEilers ObjectMapItem : : m_filter ;
2023-02-14 14:46:08 +00:00
void ObjectMapItem : : update ( SWGSDRangel : : SWGMapItem * mapItem )
{
MapItem : : update ( mapItem ) ;
if ( mapItem - > getPositionDateTime ( ) ) {
m_positionDateTime = QDateTime : : fromString ( * mapItem - > getPositionDateTime ( ) , Qt : : ISODateWithMs ) ;
} else {
m_positionDateTime = QDateTime ( ) ;
}
2025-06-09 10:44:17 +01:00
if ( mapItem - > getAltitudeDateTime ( ) ) {
m_altitudeDateTime = QDateTime : : fromString ( * mapItem - > getAltitudeDateTime ( ) , Qt : : ISODateWithMs ) ;
} else {
m_altitudeDateTime = QDateTime ( ) ;
}
2023-02-14 14:46:08 +00:00
m_useHeadingPitchRoll = mapItem - > getOrientation ( ) = = 1 ;
m_heading = mapItem - > getHeading ( ) ;
m_pitch = mapItem - > getPitch ( ) ;
m_roll = mapItem - > getRoll ( ) ;
if ( mapItem - > getOrientationDateTime ( ) ) {
m_orientationDateTime = QDateTime : : fromString ( * mapItem - > getOrientationDateTime ( ) , Qt : : ISODateWithMs ) ;
} else {
m_orientationDateTime = QDateTime ( ) ;
}
m_image = * mapItem - > getImage ( ) ;
m_imageRotation = mapItem - > getImageRotation ( ) ;
QString * text = mapItem - > getText ( ) ;
if ( text ! = nullptr ) {
m_text = text - > replace ( " \n " , " <br> " ) ; // Convert to HTML
} else {
m_text = " " ;
}
if ( mapItem - > getModel ( ) ) {
m_model = * mapItem - > getModel ( ) ;
} else {
m_model = " " ;
}
m_labelAltitudeOffset = mapItem - > getLabelAltitudeOffset ( ) ;
m_modelAltitudeOffset = mapItem - > getModelAltitudeOffset ( ) ;
2025-06-09 10:44:17 +01:00
// FIXME: See nodeTransformations comment in czml.cpp
// We can't use nodeTransformations, so adjust altitude instead
if ( m_modelAltitudeOffset ! = 0 )
{
m_labelAltitudeOffset - = m_modelAltitudeOffset ;
m_altitude + = m_modelAltitudeOffset ;
m_modelAltitudeOffset = 0 ;
}
2023-02-14 14:46:08 +00:00
m_altitudeReference = mapItem - > getAltitudeReference ( ) ;
m_fixedPosition = mapItem - > getFixedPosition ( ) ;
QList < SWGSDRangel : : SWGMapAnimation * > * animations = mapItem - > getAnimations ( ) ;
if ( animations )
{
for ( auto animation : * animations ) {
m_animations . append ( new CesiumInterface : : Animation ( animation ) ) ;
}
}
2023-12-05 12:30:25 +00:00
findFrequencies ( ) ;
2023-02-14 14:46:08 +00:00
if ( ! m_fixedPosition )
{
2025-06-09 10:44:17 +01:00
updateTrack ( mapItem - > getTrack ( ) , m_itemSettings ) ;
2023-02-14 14:46:08 +00:00
updatePredictedTrack ( mapItem - > getPredictedTrack ( ) ) ;
}
2024-04-05 10:41:24 +01:00
if ( mapItem - > getAvailableFrom ( ) ) {
m_availableFrom = QDateTime : : fromString ( * mapItem - > getAvailableFrom ( ) , Qt : : ISODateWithMs ) ;
} else {
m_availableFrom = QDateTime ( ) ;
}
2023-02-14 14:46:08 +00:00
if ( mapItem - > getAvailableUntil ( ) ) {
m_availableUntil = QDateTime : : fromString ( * mapItem - > getAvailableUntil ( ) , Qt : : ISODateWithMs ) ;
} else {
m_availableUntil = QDateTime ( ) ;
}
2025-06-09 10:44:17 +01:00
if ( mapItem - > getAircraftState ( ) ) {
if ( ! m_aircraftState ) {
m_aircraftState = new MapAircraftState ( ) ;
}
SWGSDRangel : : SWGMapAircraftState * as = mapItem - > getAircraftState ( ) ;
if ( as - > getCallsign ( ) ) {
m_aircraftState - > m_callsign = * as - > getCallsign ( ) ;
}
if ( as - > getAircraftType ( ) ) {
m_aircraftState - > m_aircraftType = * as - > getAircraftType ( ) ;
}
m_aircraftState - > m_onSurface = as - > getOnSurface ( ) ;
m_aircraftState - > m_indicatedAirspeed = as - > getAirspeed ( ) ;
if ( as - > getAirspeedDateTime ( ) ) {
m_aircraftState - > m_indicatedAirspeedDateTime = * as - > getAirspeedDateTime ( ) ;
} else {
m_aircraftState - > m_indicatedAirspeedDateTime = QString ( ) ;
}
m_aircraftState - > m_trueAirspeed = as - > getTrueAirspeed ( ) ;
m_aircraftState - > m_groundspeed = as - > getGroundspeed ( ) ;
m_aircraftState - > m_mach = as - > getMach ( ) ;
m_aircraftState - > m_altitude = as - > getAltitude ( ) ;
if ( as - > getAltitudeDateTime ( ) ) {
m_aircraftState - > m_altitudeDateTime = * as - > getAltitudeDateTime ( ) ;
} else {
m_aircraftState - > m_altitudeDateTime = QString ( ) ;
}
m_aircraftState - > m_qnh = as - > getQnh ( ) ;
m_aircraftState - > m_verticalSpeed = as - > getVerticalSpeed ( ) ;
m_aircraftState - > m_heading = as - > getHeading ( ) ;
m_aircraftState - > m_track = as - > getTrack ( ) ;
m_aircraftState - > m_selectedAltitude = as - > getSelectedAltitude ( ) ;
m_aircraftState - > m_selectedHeading = as - > getSelectedHeading ( ) ;
m_aircraftState - > m_autopilot = as - > getAutopilot ( ) ;
m_aircraftState - > m_verticalMode = ( MapAircraftState : : VerticalMode ) as - > getVerticalMode ( ) ;
m_aircraftState - > m_lateralMode = ( MapAircraftState : : LateralMode ) as - > getLateralMode ( ) ;
m_aircraftState - > m_tcasMode = ( MapAircraftState : : TCASMode ) as - > getTcasMode ( ) ;
m_aircraftState - > m_windSpeed = as - > getWindSpeed ( ) ;
m_aircraftState - > m_windDirection = as - > getWindDirection ( ) ;
m_aircraftState - > m_staticAirTemperature = as - > getStaticAirTemperature ( ) ;
}
2023-02-14 14:46:08 +00:00
}
void ImageMapItem : : update ( SWGSDRangel : : SWGMapItem * mapItem )
{
MapItem : : update ( mapItem ) ;
m_image = " data:image/png;base64, " + * mapItem - > getImage ( ) ;
m_imageZoomLevel = mapItem - > getImageZoomLevel ( ) ;
float east = mapItem - > getImageTileEast ( ) ;
float west = mapItem - > getImageTileWest ( ) ;
float north = mapItem - > getImageTileNorth ( ) ;
float south = mapItem - > getImageTileSouth ( ) ;
m_latitude = north - ( north - south ) / 2.0 ;
m_longitude = east - ( east - west ) / 2.0 ;
m_bounds = QGeoRectangle ( QGeoCoordinate ( north , west ) , QGeoCoordinate ( south , east ) ) ;
}
void PolygonMapItem : : update ( SWGSDRangel : : SWGMapItem * mapItem )
{
MapItem : : update ( mapItem ) ;
m_extrudedHeight = mapItem - > getExtrudedHeight ( ) ;
2023-03-21 11:07:25 +00:00
m_colorValid = mapItem - > getColorValid ( ) ;
m_color = mapItem - > getColor ( ) ;
m_altitudeReference = mapItem - > getAltitudeReference ( ) ;
2023-05-15 16:47:29 +01:00
m_deleted = * mapItem - > getImage ( ) = = " " ;
2023-02-14 14:46:08 +00:00
qDeleteAll ( m_points ) ;
m_points . clear ( ) ;
QList < SWGSDRangel : : SWGMapCoordinate * > * coords = mapItem - > getCoordinates ( ) ;
if ( coords )
{
for ( int i = 0 ; i < coords - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = coords - > at ( i ) ;
QGeoCoordinate * c = new QGeoCoordinate ( p - > getLatitude ( ) , p - > getLongitude ( ) , p - > getAltitude ( ) ) ;
m_points . append ( c ) ;
}
}
// Calculate bounds
m_polygon . clear ( ) ;
qreal latMin = 90.0 , latMax = - 90.0 , lonMin = 180.0 , lonMax = - 180.0 ;
for ( const auto p : m_points )
{
QGeoCoordinate coord = * p ;
latMin = std : : min ( latMin , coord . latitude ( ) ) ;
latMax = std : : max ( latMax , coord . latitude ( ) ) ;
lonMin = std : : min ( lonMin , coord . longitude ( ) ) ;
lonMax = std : : max ( lonMax , coord . longitude ( ) ) ;
m_polygon . push_back ( QVariant : : fromValue ( coord ) ) ;
}
m_bounds = QGeoRectangle ( QGeoCoordinate ( latMax , lonMin ) , QGeoCoordinate ( latMin , lonMax ) ) ;
}
void PolylineMapItem : : update ( SWGSDRangel : : SWGMapItem * mapItem )
{
MapItem : : update ( mapItem ) ;
2023-03-21 11:07:25 +00:00
m_colorValid = mapItem - > getColorValid ( ) ;
m_color = mapItem - > getColor ( ) ;
m_altitudeReference = mapItem - > getAltitudeReference ( ) ;
2023-05-15 16:47:29 +01:00
m_deleted = * mapItem - > getImage ( ) = = " " ;
2023-02-14 14:46:08 +00:00
qDeleteAll ( m_points ) ;
m_points . clear ( ) ;
QList < SWGSDRangel : : SWGMapCoordinate * > * coords = mapItem - > getCoordinates ( ) ;
if ( coords )
{
for ( int i = 0 ; i < coords - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = coords - > at ( i ) ;
QGeoCoordinate * c = new QGeoCoordinate ( p - > getLatitude ( ) , p - > getLongitude ( ) , p - > getAltitude ( ) ) ;
m_points . append ( c ) ;
}
}
// Calculate bounds
m_polyline . clear ( ) ;
qreal latMin = 90.0 , latMax = - 90.0 , lonMin = 180.0 , lonMax = - 180.0 ;
for ( const auto p : m_points )
{
QGeoCoordinate coord = * p ;
latMin = std : : min ( latMin , coord . latitude ( ) ) ;
latMax = std : : max ( latMax , coord . latitude ( ) ) ;
lonMin = std : : min ( lonMin , coord . longitude ( ) ) ;
lonMax = std : : max ( lonMax , coord . longitude ( ) ) ;
m_polyline . push_back ( QVariant : : fromValue ( coord ) ) ;
}
m_bounds = QGeoRectangle ( QGeoCoordinate ( latMax , lonMin ) , QGeoCoordinate ( latMin , lonMax ) ) ;
}
2023-12-05 12:30:25 +00:00
// Look for a frequency in the text for this object
void ObjectMapItem : : findFrequencies ( )
2023-02-14 14:46:08 +00:00
{
2023-12-05 12:30:25 +00:00
m_frequencies . clear ( ) ;
m_frequencyStrings . clear ( ) ;
const QRegularExpression re ( " (([0-9]+( \\ .[0-9]+) ? ) * ( [ kMG ] ) ? Hz ) " ) ;
QRegularExpressionMatchIterator itr = re . globalMatch ( m_text ) ;
while ( itr . hasNext ( ) )
2023-02-14 14:46:08 +00:00
{
2023-12-05 12:30:25 +00:00
QRegularExpressionMatch match = itr . next ( ) ;
QStringList capture = match . capturedTexts ( ) ;
double frequency = capture [ 2 ] . toDouble ( ) ;
2023-02-14 14:46:08 +00:00
if ( capture . length ( ) = = 5 )
{
QChar unit = capture [ 4 ] [ 0 ] ;
2023-12-05 12:30:25 +00:00
if ( unit = = ' k ' ) {
frequency * = 1000 ;
} else if ( unit = = ' M ' ) {
frequency * = 1000000 ;
} else if ( unit = = ' G ' ) {
frequency * = 1000000000 ;
}
2023-02-14 14:46:08 +00:00
}
2023-12-05 12:30:25 +00:00
m_frequencies . append ( ( qint64 ) frequency ) ;
m_frequencyStrings . append ( capture [ 0 ] ) ;
2023-02-14 14:46:08 +00:00
}
}
2025-06-09 10:44:17 +01:00
void ObjectMapItem : : extrapolatePosition ( QGeoCoordinate * c , const QDateTime & dateTime )
{
int p1 ;
int p2 ;
// Find last two non extrapolated position
for ( p2 = m_takenTrackPositionExtrapolated . size ( ) - 1 ; p2 > = 0 ; p2 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p2 ] ) {
break ;
}
}
for ( p1 = p2 - 1 ; p1 > = 0 ; p1 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p1 ] ) {
break ;
}
}
if ( p1 < 0 ) {
return ;
}
qint64 t1 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( * m_takenTrackDateTimes [ p2 ] ) ;
qint64 t2 = m_takenTrackDateTimes [ p2 ] - > msecsTo ( dateTime ) ;
double latV = ( m_takenTrackCoords [ p2 ] - > latitude ( ) - m_takenTrackCoords [ p1 ] - > latitude ( ) ) / t1 ;
double lonV = ( m_takenTrackCoords [ p2 ] - > longitude ( ) - m_takenTrackCoords [ p1 ] - > longitude ( ) ) / t1 ;
double newLat = m_takenTrackCoords [ p2 ] - > latitude ( ) + latV * t2 ;
double newLon = m_takenTrackCoords [ p2 ] - > longitude ( ) + lonV * t2 ;
c - > setLatitude ( newLat ) ;
c - > setLongitude ( newLon ) ;
}
void ObjectMapItem : : extrapolateAltitude ( QGeoCoordinate * c , const QDateTime & dateTime )
{
int p1 ;
int p2 ;
// Find last two non extrapolated position
for ( p2 = m_takenTrackPositionExtrapolated . size ( ) - 1 ; p2 > = 0 ; p2 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p2 ] ) {
break ;
}
}
for ( p1 = p2 - 1 ; p1 > = 0 ; p1 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p1 ] ) {
break ;
}
}
if ( p1 < 0 ) {
return ;
}
qint64 t1 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( * m_takenTrackDateTimes [ p2 ] ) ;
qint64 t2 = m_takenTrackDateTimes [ p2 ] - > msecsTo ( dateTime ) ;
double vertV = ( m_takenTrackCoords [ p2 ] - > altitude ( ) - m_takenTrackCoords [ p1 ] - > altitude ( ) ) / t1 ;
double newAlt = m_takenTrackCoords [ p2 ] - > latitude ( ) + vertV * t2 ;
c - > setAltitude ( newAlt ) ;
}
void ObjectMapItem : : interpolatePosition ( int p2 , const float p3Latitude , const float p3Longitude , const QDateTime & p3DateTime )
{
// p1 last non extrapolated position
// p2 interpolated position
// p3 current non extrapolated position
// Find last non extrapolated position
int p1 ;
for ( p1 = p2 - 1 ; p1 > = 0 ; p1 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p1 ] ) {
break ;
}
}
if ( p1 < 0 ) {
return ;
}
qint64 t1 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( p3DateTime ) ;
qint64 t2 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( * m_takenTrackDateTimes [ p2 ] ) ;
double latV = ( p3Latitude - m_takenTrackCoords [ p1 ] - > latitude ( ) ) / t1 ;
double lonV = ( p3Longitude - m_takenTrackCoords [ p1 ] - > longitude ( ) ) / t1 ;
double newLat = m_takenTrackCoords [ p1 ] - > latitude ( ) + latV * t2 ;
double newLon = m_takenTrackCoords [ p1 ] - > longitude ( ) + lonV * t2 ;
m_takenTrackCoords [ p2 ] - > setLatitude ( newLat ) ;
m_takenTrackCoords [ p2 ] - > setLongitude ( newLon ) ;
m_interpolatedCoords . append ( m_takenTrackCoords [ p2 ] ) ;
m_interpolatedDateTimes . append ( m_takenTrackDateTimes [ p2 ] ) ;
}
void ObjectMapItem : : interpolateAltitude ( int p2 , const float p3Altitude , const QDateTime & p3DateTime )
{
// p1 last non extrapolated position
// p2 interpolated position
// p3 current non extrapolated position
// Find last non extrapolated position
int p1 ;
for ( p1 = p2 - 1 ; p1 > = 0 ; p1 - - )
{
if ( ! m_takenTrackPositionExtrapolated [ p1 ] ) {
break ;
}
}
if ( p1 < 0 ) {
return ;
}
qint64 t1 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( p3DateTime ) ;
qint64 t2 = m_takenTrackDateTimes [ p1 ] - > msecsTo ( * m_takenTrackDateTimes [ p2 ] ) ;
double vertV = ( p3Altitude - m_takenTrackCoords [ p1 ] - > altitude ( ) ) / t1 ;
double newAlt = m_takenTrackCoords [ p1 ] - > altitude ( ) + vertV * t2 ;
m_takenTrackCoords [ p2 ] - > setAltitude ( newAlt ) ;
m_interpolatedCoords . append ( m_takenTrackCoords [ p2 ] ) ;
m_interpolatedDateTimes . append ( m_takenTrackDateTimes [ p2 ] ) ;
}
void ObjectMapItem : : updateTrack ( QList < SWGSDRangel : : SWGMapCoordinate * > * track , MapSettings : : MapItemSettings * itemSettings )
2023-02-14 14:46:08 +00:00
{
if ( track ! = nullptr )
{
qDeleteAll ( m_takenTrackCoords ) ;
m_takenTrackCoords . clear ( ) ;
qDeleteAll ( m_takenTrackDateTimes ) ;
m_takenTrackDateTimes . clear ( ) ;
2025-06-09 10:44:17 +01:00
m_takenTrackPositionExtrapolated . clear ( ) ;
m_takenTrackAltitudeExtrapolated . clear ( ) ;
2023-02-14 14:46:08 +00:00
m_takenTrack . clear ( ) ;
m_takenTrack1 . clear ( ) ;
m_takenTrack2 . clear ( ) ;
for ( int i = 0 ; i < track - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = track - > at ( i ) ;
QGeoCoordinate * c = new QGeoCoordinate ( p - > getLatitude ( ) , p - > getLongitude ( ) , p - > getAltitude ( ) ) ;
QDateTime * d = new QDateTime ( QDateTime : : fromString ( * p - > getDateTime ( ) , Qt : : ISODate ) ) ;
m_takenTrackCoords . push_back ( c ) ;
m_takenTrackDateTimes . push_back ( d ) ;
2025-06-09 10:44:17 +01:00
m_takenTrackPositionExtrapolated . push_back ( false ) ;
m_takenTrackAltitudeExtrapolated . push_back ( false ) ;
2023-02-14 14:46:08 +00:00
m_takenTrack . push_back ( QVariant : : fromValue ( * c ) ) ;
}
}
else
{
// Automatically create a track
if ( m_takenTrackCoords . size ( ) = = 0 )
{
QGeoCoordinate * c = new QGeoCoordinate ( m_latitude , m_longitude , m_altitude ) ;
m_takenTrackCoords . push_back ( c ) ;
2025-06-09 10:44:17 +01:00
if ( m_altitudeDateTime . isValid ( ) ) {
m_takenTrackDateTimes . push_back ( new QDateTime ( m_altitudeDateTime ) ) ;
} else if ( m_positionDateTime . isValid ( ) ) {
2023-02-14 14:46:08 +00:00
m_takenTrackDateTimes . push_back ( new QDateTime ( m_positionDateTime ) ) ;
} else {
m_takenTrackDateTimes . push_back ( new QDateTime ( QDateTime : : currentDateTime ( ) ) ) ;
}
2025-06-09 10:44:17 +01:00
m_takenTrackPositionExtrapolated . push_back ( false ) ;
m_takenTrackAltitudeExtrapolated . push_back ( false ) ;
2023-02-14 14:46:08 +00:00
m_takenTrack . push_back ( QVariant : : fromValue ( * c ) ) ;
}
else
{
2025-06-09 10:44:17 +01:00
// For Whittaker-Eilers filtering, we need to make sure we don't have 2 data with the same time
// so we just update the last item if the prev time is the same
// To reduce size of list for stationary items, we only store two items with same position
// We store two, rather than one, so that we have the times this position was arrived at and left
const bool interpolate = false ;
2025-06-12 09:46:00 +01:00
const bool onlyActual2D = true ; // Extrapolation / smoothing doesn't look good on 2D map, so only use actual data from aircraft, not extrapolated/interpolated points
2025-06-09 10:44:17 +01:00
QGeoCoordinate * prev1 = m_takenTrackCoords . last ( ) ;
bool samePos1 = ( prev1 - > latitude ( ) = = m_latitude ) & & ( prev1 - > longitude ( ) = = m_longitude ) & & ( prev1 - > altitude ( ) = = m_altitude ) ;
QGeoCoordinate * prev2 = m_takenTrackCoords . size ( ) > 1 ? m_takenTrackCoords [ m_takenTrackCoords . size ( ) - 2 ] : nullptr ;
bool samePos2 = prev2 & & samePos1 ? ( prev2 - > latitude ( ) = = m_latitude ) & & ( prev2 - > longitude ( ) = = m_longitude ) & & ( prev2 - > altitude ( ) = = m_altitude ) : false ;
2023-02-14 14:46:08 +00:00
QDateTime * prevDateTime = m_takenTrackDateTimes . last ( ) ;
2025-06-09 10:44:17 +01:00
QGeoCoordinate c ( m_latitude , m_longitude , m_altitude ) ;
2025-06-12 09:46:00 +01:00
QGeoCoordinate cActual = c ;
2025-06-09 10:44:17 +01:00
int prevSize = m_takenTrackPositionExtrapolated . size ( ) ;
if ( m_altitudeDateTime . isValid ( ) & & m_positionDateTime . isValid ( ) & & ( m_altitudeDateTime > m_positionDateTime ) )
{
if ( interpolate )
{
for ( int i = m_takenTrackAltitudeExtrapolated . size ( ) - 1 ; ( i > = 0 ) & & m_takenTrackAltitudeExtrapolated [ i ] ; i - - )
{
interpolateAltitude ( i , m_altitude , m_altitudeDateTime ) ;
m_takenTrackAltitudeExtrapolated [ i ] = false ;
}
}
if ( samePos2 )
{
* m_takenTrackDateTimes . last ( ) = m_altitudeDateTime ;
}
else
{
extrapolatePosition ( & c , m_altitudeDateTime ) ;
if ( m_altitudeDateTime = = * prevDateTime )
{
m_takenTrackPositionExtrapolated [ m_takenTrackPositionExtrapolated . size ( ) - 1 ] = true ;
* m_takenTrackCoords . last ( ) = c ;
2025-06-12 09:46:00 +01:00
m_takenTrack . last ( ) = QVariant : : fromValue ( onlyActual2D ? cActual : c ) ;
2025-06-09 10:44:17 +01:00
}
else
{
m_takenTrackDateTimes . push_back ( new QDateTime ( m_altitudeDateTime ) ) ;
m_takenTrackPositionExtrapolated . push_back ( true ) ;
m_takenTrackAltitudeExtrapolated . push_back ( false ) ;
m_takenTrackCoords . push_back ( new QGeoCoordinate ( c ) ) ;
2025-06-12 09:46:00 +01:00
m_takenTrack . push_back ( QVariant : : fromValue ( onlyActual2D ? cActual : c ) ) ;
2025-06-09 10:44:17 +01:00
}
}
}
else if ( m_positionDateTime . isValid ( ) )
{
if ( interpolate )
{
for ( int i = m_takenTrackPositionExtrapolated . size ( ) - 1 ; ( i > = 0 ) & & m_takenTrackPositionExtrapolated [ i ] ; i - - )
{
interpolatePosition ( i , m_latitude , m_longitude , m_positionDateTime ) ;
m_takenTrackPositionExtrapolated [ i ] = false ;
}
}
if ( m_positionDateTime > * m_takenTrackDateTimes . last ( ) )
{
if ( samePos2 )
{
* m_takenTrackDateTimes . last ( ) = m_positionDateTime ;
}
else
{
bool extrapolateAlt = m_altitudeDateTime . isValid ( ) & & ( m_positionDateTime > m_altitudeDateTime ) ;
if ( extrapolateAlt ) {
extrapolateAltitude ( & c , m_positionDateTime ) ;
}
if ( m_positionDateTime = = * prevDateTime )
{
m_takenTrackAltitudeExtrapolated [ m_takenTrackPositionExtrapolated . size ( ) - 1 ] = extrapolateAlt ;
* m_takenTrackCoords . last ( ) = c ;
2025-06-12 09:46:00 +01:00
m_takenTrack . last ( ) = QVariant : : fromValue ( onlyActual2D ? cActual : c ) ;
2025-06-09 10:44:17 +01:00
}
else
{
m_takenTrackDateTimes . push_back ( new QDateTime ( m_positionDateTime ) ) ;
m_takenTrackPositionExtrapolated . push_back ( false ) ;
m_takenTrackAltitudeExtrapolated . push_back ( extrapolateAlt ) ;
m_takenTrackCoords . push_back ( new QGeoCoordinate ( c ) ) ;
2025-06-12 09:46:00 +01:00
m_takenTrack . push_back ( QVariant : : fromValue ( onlyActual2D ? cActual : c ) ) ;
2025-06-09 10:44:17 +01:00
}
}
}
else
{
//qDebug() << "m_positionDateTime matches last datetime" << samePos1 << samePos2;
}
}
else
2023-02-14 14:46:08 +00:00
{
2025-06-09 10:44:17 +01:00
m_takenTrackDateTimes . push_back ( new QDateTime ( QDateTime : : currentDateTime ( ) ) ) ;
m_takenTrackPositionExtrapolated . push_back ( false ) ;
m_takenTrackAltitudeExtrapolated . push_back ( false ) ;
m_takenTrackCoords . push_back ( new QGeoCoordinate ( c ) ) ;
2025-06-12 09:46:00 +01:00
m_takenTrack . push_back ( QVariant : : fromValue ( onlyActual2D ? cActual : c ) ) ;
2025-06-09 10:44:17 +01:00
}
2025-06-11 10:37:45 +01:00
/*if (m_takenTrackDateTimes.size() >= 2) {
2025-06-09 10:44:17 +01:00
if ( * m_takenTrackDateTimes [ m_takenTrackDateTimes . size ( ) - 1 ] < * m_takenTrackDateTimes [ m_takenTrackDateTimes . size ( ) - 2 ] ) {
2025-06-11 10:37:45 +01:00
qDebug ( ) < < " ObjectMapItem::updateTrack: Out of order " ;
2025-06-09 10:44:17 +01:00
}
2025-06-11 10:37:45 +01:00
} */
2025-06-09 10:44:17 +01:00
if ( ( m_takenTrackPositionExtrapolated . size ( ) > 0 ) & & ( prevSize ! = m_takenTrackPositionExtrapolated . size ( ) ) )
{
const int filterLen = itemSettings - > m_smoothingWindow ;
if ( ( filterLen > 0 ) & & ( m_takenTrackCoords . size ( ) > = filterLen ) & & ( m_takenTrackCoords . size ( ) % ( filterLen / 2 ) ) = = 0 )
{
// Filter last filterLen coords
QVector < double > x ( filterLen ) ;
QVector < double > y1 ( filterLen ) ;
QVector < double > y2 ( filterLen ) ;
QVector < double > y3 ( filterLen ) ;
QVector < double > w1 ( filterLen ) ;
QVector < double > w3 ( filterLen ) ;
2025-06-11 10:37:45 +01:00
//qDebug() << "Filter from" << (m_takenTrackCoords.size() - (filterLen - 0)) << "to" << (m_takenTrackCoords.size() - 1);
2025-06-09 10:44:17 +01:00
for ( int i = 0 ; i < filterLen ; i + + )
{
int idx = m_takenTrackCoords . size ( ) - ( filterLen - i ) ;
x [ i ] = ( m_takenTrackDateTimes [ idx ] - > toMSecsSinceEpoch ( ) - m_takenTrackDateTimes [ 0 ] - > toMSecsSinceEpoch ( ) ) / 1000.0 ;
y1 [ i ] = m_takenTrackCoords [ idx ] - > latitude ( ) ;
y2 [ i ] = m_takenTrackCoords [ idx ] - > longitude ( ) ;
y3 [ i ] = m_takenTrackCoords [ idx ] - > altitude ( ) ;
if ( i < ( filterLen / 4 ) )
{
w1 [ i ] = 10.0 ; // Try to avoid discontinuities between windows
w3 [ i ] = 10.0 ;
}
else if ( i = = filterLen - 1 )
{
w1 [ i ] = 1.0 ;
w3 [ i ] = 1.0 ;
}
else
{
w1 [ i ] = m_takenTrackPositionExtrapolated [ idx ] ? 0.0 : 1.0 ;
w3 [ i ] = m_takenTrackAltitudeExtrapolated [ idx ] ? 0.0 : 1.0 ;
}
}
const double lambda = itemSettings - > m_smoothingLambda ;
m_filter . filter ( x . data ( ) , y1 . data ( ) , w1 . data ( ) , filterLen , lambda ) ;
m_filter . filter ( x . data ( ) , y2 . data ( ) , w1 . data ( ) , filterLen , lambda ) ;
m_filter . filter ( x . data ( ) , y3 . data ( ) , w3 . data ( ) , filterLen , lambda ) ;
for ( int i = 0 ; i < filterLen ; i + + )
{
int idx = m_takenTrackCoords . size ( ) - ( filterLen - i ) ;
m_takenTrackCoords [ idx ] - > setLatitude ( y1 [ i ] ) ;
m_takenTrackCoords [ idx ] - > setLongitude ( y2 [ i ] ) ;
m_takenTrackCoords [ idx ] - > setAltitude ( y3 [ i ] ) ;
m_takenTrackPositionExtrapolated [ idx ] = false ;
m_takenTrackAltitudeExtrapolated [ idx ] = false ;
2025-06-12 09:46:00 +01:00
if ( ! onlyActual2D ) {
m_takenTrack [ idx ] = QVariant : : fromValue ( QGeoCoordinate ( y1 [ i ] , y2 [ i ] , y3 [ i ] ) ) ;
}
2025-06-09 10:44:17 +01:00
m_interpolatedCoords . append ( m_takenTrackCoords [ idx ] ) ;
m_interpolatedDateTimes . append ( m_takenTrackDateTimes [ idx ] ) ;
}
2025-06-12 09:46:00 +01:00
// Update current position - Don't do this, as it can make aircraft move backwards on 2D map
if ( ! onlyActual2D )
{
m_latitude = m_takenTrackCoords . back ( ) - > latitude ( ) ;
m_longitude = m_takenTrackCoords . back ( ) - > longitude ( ) ;
m_altitude = m_takenTrackCoords . back ( ) - > altitude ( ) ;
}
2023-02-14 14:46:08 +00:00
}
}
}
}
}
void ObjectMapItem : : updatePredictedTrack ( QList < SWGSDRangel : : SWGMapCoordinate * > * track )
{
if ( track ! = nullptr )
{
qDeleteAll ( m_predictedTrackCoords ) ;
m_predictedTrackCoords . clear ( ) ;
qDeleteAll ( m_predictedTrackDateTimes ) ;
m_predictedTrackDateTimes . clear ( ) ;
m_predictedTrack . clear ( ) ;
m_predictedTrack1 . clear ( ) ;
m_predictedTrack2 . clear ( ) ;
for ( int i = 0 ; i < track - > size ( ) ; i + + )
{
SWGSDRangel : : SWGMapCoordinate * p = track - > at ( i ) ;
QGeoCoordinate * c = new QGeoCoordinate ( p - > getLatitude ( ) , p - > getLongitude ( ) , p - > getAltitude ( ) ) ;
QDateTime * d = new QDateTime ( QDateTime : : fromString ( * p - > getDateTime ( ) , Qt : : ISODate ) ) ;
m_predictedTrackCoords . push_back ( c ) ;
m_predictedTrackDateTimes . push_back ( d ) ;
m_predictedTrack . push_back ( QVariant : : fromValue ( * c ) ) ;
}
}
}