2021-02-26 15:25:48 -05:00
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2021 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// 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/>. //
///////////////////////////////////////////////////////////////////////////////////
# include <cmath>
# include <QMessageBox>
# include <QLineEdit>
# include <QRegExp>
# include <QtCharts/QChartView>
# include <QtCharts/QLineSeries>
# include <QtCharts/QDateTimeAxis>
# include <QtCharts/QValueAxis>
2022-02-09 11:42:51 -05:00
# include "device/deviceapi.h"
# include "device/deviceset.h"
2023-04-03 11:53:51 -04:00
# include "channel/channelwebapiutils.h"
2022-02-09 11:42:51 -05:00
# include "feature/featureset.h"
2021-02-26 15:25:48 -05:00
# include "feature/featureuiset.h"
2023-04-03 11:53:51 -04:00
# include "feature/featureutils.h"
2021-02-26 15:25:48 -05:00
# include "feature/featurewebapiutils.h"
# include "gui/basicfeaturesettingsdialog.h"
2022-12-20 05:31:15 -05:00
# include "gui/dialogpositioner.h"
2021-02-26 15:25:48 -05:00
# include "mainwindow.h"
# include "device/deviceuiset.h"
# include "util/units.h"
# include "util/astronomy.h"
# include "ui_satellitetrackergui.h"
# include "satellitetracker.h"
# include "satellitetrackergui.h"
# include "satellitetrackerreport.h"
# include "satellitetrackersettingsdialog.h"
# include "satelliteselectiondialog.h"
# include "satelliteradiocontroldialog.h"
# include "satellitetrackersgp4.h"
SatelliteTrackerGUI * SatelliteTrackerGUI : : create ( PluginAPI * pluginAPI , FeatureUISet * featureUISet , Feature * feature )
{
SatelliteTrackerGUI * gui = new SatelliteTrackerGUI ( pluginAPI , featureUISet , feature ) ;
return gui ;
}
void SatelliteTrackerGUI : : destroy ( )
{
delete this ;
}
void SatelliteTrackerGUI : : resetToDefaults ( )
{
m_settings . resetToDefaults ( ) ;
displaySettings ( ) ;
applySettings ( true ) ;
}
QByteArray SatelliteTrackerGUI : : serialize ( ) const
{
return m_settings . serialize ( ) ;
}
bool SatelliteTrackerGUI : : deserialize ( const QByteArray & data )
{
if ( m_settings . deserialize ( data ) )
{
2022-05-13 16:24:48 -04:00
m_feature - > setWorkspaceIndex ( m_settings . m_workspaceIndex ) ;
2021-02-26 15:25:48 -05:00
updateSelectedSats ( ) ;
displaySettings ( ) ;
applySettings ( true ) ;
return true ;
}
else
{
resetToDefaults ( ) ;
return false ;
}
}
QString SatelliteTrackerGUI : : convertDegreesToText ( double degrees )
{
if ( m_settings . m_azElUnits = = SatelliteTrackerSettings : : DMS )
return Units : : decimalDegreesToDegreeMinutesAndSeconds ( degrees ) ;
else if ( m_settings . m_azElUnits = = SatelliteTrackerSettings : : DM )
return Units : : decimalDegreesToDegreesAndMinutes ( degrees ) ;
else if ( m_settings . m_azElUnits = = SatelliteTrackerSettings : : D )
return Units : : decimalDegreesToDegrees ( degrees ) ;
else
return QString ( " %1 " ) . arg ( degrees , 0 , ' f ' , 2 ) ;
}
bool SatelliteTrackerGUI : : handleMessage ( const Message & message )
{
if ( SatelliteTracker : : MsgConfigureSatelliteTracker : : match ( message ) )
{
qDebug ( " SatelliteTrackerGUI::handleMessage: SatelliteTracker::MsgConfigureSatelliteTracker " ) ;
const SatelliteTracker : : MsgConfigureSatelliteTracker & cfg = ( SatelliteTracker : : MsgConfigureSatelliteTracker & ) message ;
2022-11-28 15:52:06 -05:00
if ( cfg . getForce ( ) ) {
m_settings = cfg . getSettings ( ) ;
} else {
m_settings . applySettings ( cfg . getSettingsKeys ( ) , cfg . getSettings ( ) ) ;
}
2021-02-26 15:25:48 -05:00
blockApplySettings ( true ) ;
displaySettings ( ) ;
blockApplySettings ( false ) ;
return true ;
}
else if ( SatelliteTrackerReport : : MsgReportSat : : match ( message ) )
{
SatelliteTrackerReport : : MsgReportSat & satReport = ( SatelliteTrackerReport : : MsgReportSat & ) message ;
SatelliteState * satState = satReport . getSatelliteState ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( satState - > m_name = = m_settings . m_target )
{
delete m_targetSatState ;
m_targetSatState = satState ;
ui - > azimuth - > setText ( convertDegreesToText ( satState - > m_azimuth ) ) ;
ui - > elevation - > setText ( convertDegreesToText ( satState - > m_elevation ) ) ;
2023-04-14 11:15:11 -04:00
plotChart ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( satState - > m_passes . size ( ) > 0 )
{
2022-09-18 05:59:12 -04:00
const SatellitePass & pass = satState - > m_passes [ 0 ] ;
bool geostationary = ! pass . m_aos . isValid ( ) & & ! pass . m_los . isValid ( ) ;
2022-11-28 15:52:06 -05:00
2022-09-18 05:59:12 -04:00
if ( ( m_nextTargetAOS ! = pass . m_aos ) | | ( m_nextTargetLOS ! = pass . m_los ) | | ( geostationary ! = m_geostationarySatVisible ) )
2021-02-26 15:25:48 -05:00
{
2022-09-18 05:59:12 -04:00
m_nextTargetAOS = pass . m_aos ;
m_nextTargetLOS = pass . m_los ;
2021-02-26 15:25:48 -05:00
m_geostationarySatVisible = geostationary ;
updateTimeToAOS ( ) ;
}
}
}
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
updateTable ( satState ) ;
2022-11-28 15:52:06 -05:00
if ( satState - > m_name ! = m_settings . m_target ) {
2021-02-26 15:25:48 -05:00
delete satState ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
return true ;
}
else if ( SatelliteTrackerReport : : MsgReportAOS : : match ( message ) )
{
SatelliteTrackerReport : : MsgReportAOS & aosReport = ( SatelliteTrackerReport : : MsgReportAOS & ) message ;
2022-11-09 11:59:02 -05:00
aos ( aosReport . getSpeech ( ) ) ;
2021-02-26 15:25:48 -05:00
return true ;
}
else if ( SatelliteTrackerReport : : MsgReportTarget : : match ( message ) )
{
SatelliteTrackerReport : : MsgReportTarget & targetReport = ( SatelliteTrackerReport : : MsgReportTarget & ) message ;
setTarget ( targetReport . getName ( ) ) ;
return true ;
}
else if ( SatelliteTrackerReport : : MsgReportLOS : : match ( message ) )
{
SatelliteTrackerReport : : MsgReportLOS & losReport = ( SatelliteTrackerReport : : MsgReportLOS & ) message ;
2022-11-09 11:59:02 -05:00
los ( losReport . getSpeech ( ) ) ;
2021-02-26 15:25:48 -05:00
return true ;
}
else if ( SatelliteTracker : : MsgSatData : : match ( message ) )
{
SatelliteTracker : : MsgSatData & satData = ( SatelliteTracker : : MsgSatData & ) message ;
m_satellites = satData . getSatellites ( ) ;
// Remove satellites that no longer exist
QMutableListIterator < QString > itr ( m_settings . m_satellites ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
while ( itr . hasNext ( ) )
{
QString satellite = itr . next ( ) ;
if ( ! m_satellites . contains ( satellite ) )
itr . remove ( ) ;
}
2022-11-28 15:52:06 -05:00
if ( ! m_satellites . contains ( m_settings . m_target ) ) {
2021-02-26 15:25:48 -05:00
setTarget ( " " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
// Update GUI
updateSelectedSats ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
return true ;
}
return false ;
}
// Call when m_settings.m_satellites changes
void SatelliteTrackerGUI : : updateSelectedSats ( )
{
// Remove unselects sats from target combo and table
for ( int i = 0 ; i < ui - > target - > count ( ) ; )
{
QString name = ui - > target - > itemText ( i ) ;
int idx = m_settings . m_satellites . indexOf ( name ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( idx = = - 1 )
{
ui - > target - > removeItem ( i ) ;
QList < QTableWidgetItem * > matches = ui - > satTable - > findItems ( name , Qt : : MatchExactly ) ;
2022-11-28 15:52:06 -05:00
for ( int j = 0 ; j < matches . length ( ) ; j + + ) {
2021-02-26 15:25:48 -05:00
ui - > satTable - > removeRow ( ui - > satTable - > row ( matches [ j ] ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
else
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
i + + ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
// Add new satellites to target combo
for ( int i = 0 ; i < m_settings . m_satellites . size ( ) ; i + + )
{
2022-11-28 15:52:06 -05:00
if ( ui - > target - > findText ( m_settings . m_satellites [ i ] , Qt : : MatchExactly ) = = - 1 ) {
2021-02-26 15:25:48 -05:00
ui - > target - > addItem ( m_settings . m_satellites [ i ] ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
// Select current target, if it still exists
int idx = ui - > target - > findText ( m_settings . m_target ) ;
2022-11-28 15:52:06 -05:00
if ( idx ! = - 1 ) {
2021-02-26 15:25:48 -05:00
ui - > target - > setCurrentIndex ( idx ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
setTarget ( " " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerGUI : : handleInputMessages ( )
{
Message * message ;
while ( ( message = getInputMessageQueue ( ) - > pop ( ) ) )
{
if ( handleMessage ( * message ) ) {
delete message ;
}
}
}
void SatelliteTrackerGUI : : onWidgetRolled ( QWidget * widget , bool rollDown )
{
( void ) widget ;
( void ) rollDown ;
2021-11-23 08:35:57 -05:00
2022-04-24 13:34:48 -04:00
RollupContents * rollupContents = getRollupContents ( ) ;
rollupContents - > saveState ( m_rollupState ) ;
2021-02-26 15:25:48 -05:00
}
SatelliteTrackerGUI : : SatelliteTrackerGUI ( PluginAPI * pluginAPI , FeatureUISet * featureUISet , Feature * feature , QWidget * parent ) :
FeatureGUI ( parent ) ,
ui ( new Ui : : SatelliteTrackerGUI ) ,
m_pluginAPI ( pluginAPI ) ,
m_featureUISet ( featureUISet ) ,
m_doApplySettings ( true ) ,
m_lastFeatureState ( 0 ) ,
m_lastUpdatingSatData ( false ) ,
m_targetSatState ( nullptr ) ,
m_plotPass ( 0 ) ,
m_lineChart ( nullptr ) ,
m_polarChart ( nullptr ) ,
m_geostationarySatVisible ( false )
{
2022-05-13 16:24:48 -04:00
m_feature = feature ;
2021-02-26 15:25:48 -05:00
setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
2022-04-24 13:34:48 -04:00
m_helpURL = " plugins/feature/satellitetracker/readme.md " ;
RollupContents * rollupContents = getRollupContents ( ) ;
ui - > setupUi ( rollupContents ) ;
rollupContents - > arrangeRollups ( ) ;
connect ( rollupContents , SIGNAL ( widgetRolled ( QWidget * , bool ) ) , this , SLOT ( onWidgetRolled ( QWidget * , bool ) ) ) ;
2021-02-26 15:25:48 -05:00
m_satelliteTracker = reinterpret_cast < SatelliteTracker * > ( feature ) ;
m_satelliteTracker - > setMessageQueueToGUI ( & m_inputMessageQueue ) ;
2022-01-08 23:27:12 -05:00
m_settings . setRollupState ( & m_rollupState ) ;
2021-02-26 15:25:48 -05:00
connect ( this , SIGNAL ( customContextMenuRequested ( const QPoint & ) ) , this , SLOT ( onMenuDialogCalled ( const QPoint & ) ) ) ;
connect ( getInputMessageQueue ( ) , SIGNAL ( messageEnqueued ( ) ) , this , SLOT ( handleInputMessages ( ) ) ) ;
connect ( & m_statusTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( updateStatus ( ) ) ) ;
m_statusTimer . start ( 1000 ) ;
2023-04-03 11:53:51 -04:00
connect ( & m_redrawTimer , & QTimer : : timeout , this , & SatelliteTrackerGUI : : plotChart ) ;
2021-02-26 15:25:48 -05:00
// Intialise charts
m_emptyChart . layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_emptyChart . setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
ui - > passChart - > setChart ( & m_emptyChart ) ;
ui - > passChart - > setRenderHint ( QPainter : : Antialiasing ) ;
2022-02-04 12:14:12 -05:00
ui - > dateTime - > setDateTime ( m_satelliteTracker - > currentDateTime ( ) ) ;
2022-02-09 11:42:51 -05:00
ui - > deviceFeatureSelect - > setVisible ( false ) ;
2021-02-26 15:25:48 -05:00
resizeTable ( ) ;
// Allow user to reorder columns
ui - > satTable - > horizontalHeader ( ) - > setSectionsMovable ( true ) ;
// Allow user to sort table by clicking on headers
ui - > satTable - > setSortingEnabled ( true ) ;
// Add context menu to allow hiding/showing of columns
menu = new QMenu ( ui - > satTable ) ;
2022-01-08 23:27:12 -05:00
2021-02-26 15:25:48 -05:00
for ( int i = 0 ; i < ui - > satTable - > horizontalHeader ( ) - > count ( ) ; i + + )
{
QString text = ui - > satTable - > horizontalHeaderItem ( i ) - > text ( ) ;
menu - > addAction ( createCheckableItem ( text , i , true ) ) ;
}
2022-01-08 23:27:12 -05:00
2021-02-26 15:25:48 -05:00
ui - > satTable - > horizontalHeader ( ) - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( ui - > satTable - > horizontalHeader ( ) , SIGNAL ( customContextMenuRequested ( QPoint ) ) , SLOT ( columnSelectMenu ( QPoint ) ) ) ;
// Get signals when columns change
connect ( ui - > satTable - > horizontalHeader ( ) , SIGNAL ( sectionMoved ( int , int , int ) ) , SLOT ( satTable_sectionMoved ( int , int , int ) ) ) ;
connect ( ui - > satTable - > horizontalHeader ( ) , SIGNAL ( sectionResized ( int , int , int ) ) , SLOT ( satTable_sectionResized ( int , int , int ) ) ) ;
m_speech = new QTextToSpeech ( this ) ;
displaySettings ( ) ;
applySettings ( true ) ;
2022-04-04 04:23:52 -04:00
makeUIConnections ( ) ;
2021-02-26 15:25:48 -05:00
// Get initial list of satellites
on_updateSatData_clicked ( ) ;
2022-09-26 07:14:02 -04:00
// Use My Position from preferences, if none set
if ( ( m_settings . m_latitude = = 0.0 ) & & ( m_settings . m_longitude = = 0.0 ) ) {
on_useMyPosition_clicked ( ) ;
}
2021-02-26 15:25:48 -05:00
}
SatelliteTrackerGUI : : ~ SatelliteTrackerGUI ( )
{
delete ui ;
}
2022-05-13 16:24:48 -04:00
void SatelliteTrackerGUI : : setWorkspaceIndex ( int index )
{
m_settings . m_workspaceIndex = index ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " workspaceIndex " ) ;
2022-05-13 16:24:48 -04:00
m_feature - > setWorkspaceIndex ( index ) ;
}
2021-02-26 15:25:48 -05:00
void SatelliteTrackerGUI : : blockApplySettings ( bool block )
{
m_doApplySettings = ! block ;
}
void SatelliteTrackerGUI : : displaySettings ( )
{
setTitleColor ( m_settings . m_rgbColor ) ;
setWindowTitle ( m_settings . m_title ) ;
2022-04-04 04:23:52 -04:00
setTitle ( m_settings . m_title ) ;
2021-02-26 15:25:48 -05:00
blockApplySettings ( true ) ;
ui - > latitude - > setValue ( m_settings . m_latitude ) ;
ui - > longitude - > setValue ( m_settings . m_longitude ) ;
2021-07-02 18:04:14 -04:00
2022-10-28 09:40:34 -04:00
ui - > target - > blockSignals ( true ) ;
ui - > target - > clear ( ) ;
2021-07-02 18:04:14 -04:00
for ( const QString & s : m_settings . m_satellites ) {
ui - > target - > addItem ( s ) ;
}
2022-10-28 09:40:34 -04:00
ui - > target - > blockSignals ( false ) ;
2021-02-26 15:25:48 -05:00
ui - > target - > setCurrentIndex ( ui - > target - > findText ( m_settings . m_target ) ) ;
2022-10-28 09:40:34 -04:00
2023-02-16 09:33:26 -05:00
ui - > dateTime - > setDateTime ( QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ) ;
2022-02-09 11:42:51 -05:00
ui - > dateTimeSelect - > setCurrentIndex ( ( int ) m_settings . m_dateTimeSelect ) ;
ui - > dateTime - > setVisible ( m_settings . m_dateTimeSelect = = SatelliteTrackerSettings : : CUSTOM ) ;
2021-02-26 15:25:48 -05:00
ui - > autoTarget - > setChecked ( m_settings . m_autoTarget ) ;
2021-04-19 20:27:43 -04:00
ui - > darkTheme - > setChecked ( m_settings . m_chartsDarkTheme ) ;
2022-10-28 09:40:34 -04:00
ui - > satTable - > horizontalHeader ( ) - > setSortIndicator ( m_settings . m_columnSort , m_settings . m_columnSortOrder ) ;
2022-04-04 04:23:52 -04:00
getRollupContents ( ) - > restoreState ( m_rollupState ) ;
2021-02-26 15:25:48 -05:00
plotChart ( ) ;
blockApplySettings ( false ) ;
}
void SatelliteTrackerGUI : : onMenuDialogCalled ( const QPoint & p )
{
if ( m_contextMenuType = = ContextMenuChannelSettings )
{
BasicFeatureSettingsDialog dialog ( this ) ;
dialog . setTitle ( m_settings . m_title ) ;
dialog . setUseReverseAPI ( m_settings . m_useReverseAPI ) ;
dialog . setReverseAPIAddress ( m_settings . m_reverseAPIAddress ) ;
dialog . setReverseAPIPort ( m_settings . m_reverseAPIPort ) ;
dialog . setReverseAPIFeatureSetIndex ( m_settings . m_reverseAPIFeatureSetIndex ) ;
dialog . setReverseAPIFeatureIndex ( m_settings . m_reverseAPIFeatureIndex ) ;
2022-04-18 06:08:33 -04:00
dialog . setDefaultTitle ( m_displayedName ) ;
2021-02-26 15:25:48 -05:00
dialog . move ( p ) ;
2022-12-20 05:31:15 -05:00
new DialogPositioner ( & dialog , false ) ;
2021-02-26 15:25:48 -05:00
dialog . exec ( ) ;
m_settings . m_title = dialog . getTitle ( ) ;
m_settings . m_useReverseAPI = dialog . useReverseAPI ( ) ;
m_settings . m_reverseAPIAddress = dialog . getReverseAPIAddress ( ) ;
m_settings . m_reverseAPIPort = dialog . getReverseAPIPort ( ) ;
m_settings . m_reverseAPIFeatureSetIndex = dialog . getReverseAPIFeatureSetIndex ( ) ;
m_settings . m_reverseAPIFeatureIndex = dialog . getReverseAPIFeatureIndex ( ) ;
2022-04-18 06:08:33 -04:00
setTitle ( m_settings . m_title ) ;
2021-02-26 15:25:48 -05:00
setTitleColor ( m_settings . m_rgbColor ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " title " ) ;
m_settingsKeys . append ( " rgbColor " ) ;
m_settingsKeys . append ( " useReverseAPI " ) ;
m_settingsKeys . append ( " reverseAPIAddress " ) ;
m_settingsKeys . append ( " reverseAPIPort " ) ;
m_settingsKeys . append ( " reverseAPIFeatureSetIndex " ) ;
m_settingsKeys . append ( " reverseAPIFeatureIndex " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
}
resetContextMenuType ( ) ;
}
2022-11-09 11:59:02 -05:00
void SatelliteTrackerGUI : : aos ( const QString & speech )
2021-02-26 15:25:48 -05:00
{
2022-09-26 07:14:02 -04:00
// Call plotChart() to start the periodic updates with sat position in polar chart
plotChart ( ) ;
2021-02-26 15:25:48 -05:00
// Give speech notification of pass
2022-09-29 11:50:04 -04:00
if ( ! speech . isEmpty ( ) ) {
2021-02-26 15:25:48 -05:00
m_speech - > say ( speech ) ;
}
}
2022-11-09 11:59:02 -05:00
void SatelliteTrackerGUI : : los ( const QString & speech )
2021-02-26 15:25:48 -05:00
{
// Give speech notification of end of pass
2022-09-29 11:50:04 -04:00
if ( ! speech . isEmpty ( ) ) {
2021-02-26 15:25:48 -05:00
m_speech - > say ( speech ) ;
}
}
void SatelliteTrackerGUI : : on_startStop_toggled ( bool checked )
{
if ( m_doApplySettings )
{
SatelliteTracker : : MsgStartStop * message = SatelliteTracker : : MsgStartStop : : create ( checked ) ;
m_satelliteTracker - > getInputMessageQueue ( ) - > push ( message ) ;
}
}
void SatelliteTrackerGUI : : on_latitude_valueChanged ( double value )
{
m_settings . m_latitude = value ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " latitude " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
void SatelliteTrackerGUI : : on_longitude_valueChanged ( double value )
{
m_settings . m_longitude = value ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " longitude " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
void SatelliteTrackerGUI : : setTarget ( const QString & target )
{
if ( target ! = m_settings . m_target )
{
m_settings . m_target = target ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " target " ) ;
2021-02-26 15:25:48 -05:00
ui - > azimuth - > setText ( " " ) ;
ui - > elevation - > setText ( " " ) ;
ui - > aos - > setText ( " " ) ;
ui - > target - > setCurrentIndex ( ui - > target - > findText ( m_settings . m_target ) ) ;
m_nextTargetAOS = QDateTime ( ) ;
m_nextTargetLOS = QDateTime ( ) ;
m_geostationarySatVisible = false ;
applySettings ( ) ;
delete m_targetSatState ;
m_targetSatState = nullptr ;
m_plotPass = 0 ;
ui - > passLabel - > setText ( QString ( " %1 " ) . arg ( m_plotPass ) ) ;
plotChart ( ) ;
}
}
void SatelliteTrackerGUI : : on_target_currentTextChanged ( const QString & text )
{
setTarget ( text ) ;
}
void SatelliteTrackerGUI : : on_useMyPosition_clicked ( bool checked )
{
( void ) checked ;
double stationLatitude = MainCore : : instance ( ) - > getSettings ( ) . getLatitude ( ) ;
double stationLongitude = MainCore : : instance ( ) - > getSettings ( ) . getLongitude ( ) ;
double stationAltitude = MainCore : : instance ( ) - > getSettings ( ) . getAltitude ( ) ;
ui - > latitude - > setValue ( stationLatitude ) ;
ui - > longitude - > setValue ( stationLongitude ) ;
m_settings . m_heightAboveSeaLevel = stationAltitude ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " heightAboveSeaLevel " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
// Show settings dialog
void SatelliteTrackerGUI : : on_displaySettings_clicked ( )
{
SatelliteTrackerSettingsDialog dialog ( & m_settings ) ;
2022-12-20 05:31:15 -05:00
new DialogPositioner ( & dialog , true ) ;
2021-02-26 15:25:48 -05:00
if ( dialog . exec ( ) = = QDialog : : Accepted )
{
2023-03-29 10:48:19 -04:00
m_settingsKeys . append ( " heightAboveSeaLevel " ) ;
m_settingsKeys . append ( " predictionPeriod " ) ;
m_settingsKeys . append ( " passStartTime " ) ;
m_settingsKeys . append ( " passFinishTime " ) ;
m_settingsKeys . append ( " minAOSElevation " ) ;
m_settingsKeys . append ( " minPassElevation " ) ;
m_settingsKeys . append ( " rotatorMaxAzimuth " ) ;
m_settingsKeys . append ( " rotatorMaxElevation " ) ;
m_settingsKeys . append ( " aosSpeech " ) ;
m_settingsKeys . append ( " losSpeech " ) ;
m_settingsKeys . append ( " aosCommand " ) ;
m_settingsKeys . append ( " losCommand " ) ;
m_settingsKeys . append ( " updatePeriod " ) ;
m_settingsKeys . append ( " dopplerPeriod " ) ;
m_settingsKeys . append ( " defaultFrequency " ) ;
m_settingsKeys . append ( " azElUnits " ) ;
m_settingsKeys . append ( " groundTrackPoints " ) ;
2023-04-03 11:53:51 -04:00
m_settingsKeys . append ( " drawRotators " ) ;
2023-03-29 10:48:19 -04:00
m_settingsKeys . append ( " dateFormat " ) ;
m_settingsKeys . append ( " utc " ) ;
m_settingsKeys . append ( " tles " ) ;
m_settingsKeys . append ( " replayEnabled " ) ;
m_settingsKeys . append ( " replayStartDateTime " ) ;
m_settingsKeys . append ( " sendTimeToMap " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
}
2022-02-09 11:42:51 -05:00
void SatelliteTrackerGUI : : on_dateTimeSelect_currentIndexChanged ( int index )
2021-02-26 15:25:48 -05:00
{
2022-02-09 11:42:51 -05:00
m_settings . m_dateTimeSelect = ( SatelliteTrackerSettings : : DateTimeSelect ) index ;
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
if ( m_settings . m_dateTimeSelect ! = SatelliteTrackerSettings : : CUSTOM )
2021-02-26 15:25:48 -05:00
{
m_settings . m_dateTime = " " ;
ui - > dateTime - > setVisible ( false ) ;
}
else
{
m_settings . m_dateTime = ui - > dateTime - > dateTime ( ) . toString ( Qt : : ISODateWithMs ) ;
ui - > dateTime - > setVisible ( true ) ;
}
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
ui - > deviceFeatureSelect - > setVisible ( m_settings . m_dateTimeSelect > = SatelliteTrackerSettings : : FROM_MAP ) ;
updateDeviceFeatureCombo ( ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " dateTimeSelect " ) ;
m_settingsKeys . append ( " dateTime " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
void SatelliteTrackerGUI : : on_dateTime_dateTimeChanged ( const QDateTime & datetime )
{
( void ) datetime ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( ui - > dateTimeSelect - > currentIndex ( ) = = 1 )
{
m_settings . m_dateTime = ui - > dateTime - > dateTime ( ) . toString ( Qt : : ISODateWithMs ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " dateTime " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
plotChart ( ) ;
}
}
// Find target on the Map
void SatelliteTrackerGUI : : on_viewOnMap_clicked ( )
{
2022-11-28 15:52:06 -05:00
if ( ! m_settings . m_target . isEmpty ( ) ) {
2021-02-26 15:25:48 -05:00
FeatureWebAPIUtils : : mapFind ( m_settings . m_target ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerGUI : : on_updateSatData_clicked ( )
{
m_satelliteTracker - > getInputMessageQueue ( ) - > push ( SatelliteTracker : : MsgUpdateSatData : : create ( ) ) ;
}
void SatelliteTrackerGUI : : on_selectSats_clicked ( )
{
SatelliteSelectionDialog dialog ( & m_settings , m_satellites ) ;
2022-12-20 05:31:15 -05:00
new DialogPositioner ( & dialog , true ) ;
2021-02-26 15:25:48 -05:00
if ( dialog . exec ( ) = = QDialog : : Accepted )
{
updateSelectedSats ( ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " satellites " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
}
}
void SatelliteTrackerGUI : : on_radioControl_clicked ( )
{
SatelliteRadioControlDialog dialog ( & m_settings , m_satellites ) ;
2022-12-20 05:31:15 -05:00
new DialogPositioner ( & dialog , true ) ;
2021-02-26 15:25:48 -05:00
if ( dialog . exec ( ) = = QDialog : : Accepted )
2022-11-28 15:52:06 -05:00
{
m_settingsKeys . append ( " deviceSettings " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerGUI : : on_autoTarget_clicked ( bool checked )
{
m_settings . m_autoTarget = checked ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " autoTarget " ) ;
2021-02-26 15:25:48 -05:00
applySettings ( ) ;
}
void SatelliteTrackerGUI : : updateStatus ( )
{
int state = m_satelliteTracker - > getState ( ) ;
if ( m_lastFeatureState ! = state )
{
// We set checked state of start/stop button, in case it was changed via API
bool oldState ;
switch ( state )
{
case Feature : : StNotStarted :
ui - > startStop - > setStyleSheet ( " QToolButton { background:rgb(79,79,79); } " ) ;
break ;
case Feature : : StIdle :
oldState = ui - > startStop - > blockSignals ( true ) ;
ui - > startStop - > setChecked ( false ) ;
ui - > startStop - > blockSignals ( oldState ) ;
ui - > startStop - > setStyleSheet ( " QToolButton { background-color : blue; } " ) ;
break ;
case Feature : : StRunning :
oldState = ui - > startStop - > blockSignals ( true ) ;
ui - > startStop - > setChecked ( true ) ;
ui - > startStop - > blockSignals ( oldState ) ;
ui - > startStop - > setStyleSheet ( " QToolButton { background-color : green; } " ) ;
break ;
case Feature : : StError :
ui - > startStop - > setStyleSheet ( " QToolButton { background-color : red; } " ) ;
QMessageBox : : information ( this , tr ( " Message " ) , m_satelliteTracker - > getErrorMessage ( ) ) ;
break ;
default :
break ;
}
m_lastFeatureState = state ;
}
// Indicate if satellite data is being updated
bool updatingSatData = m_satelliteTracker - > isUpdatingSatData ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( updatingSatData ! = m_lastUpdatingSatData )
{
2022-11-28 15:52:06 -05:00
if ( updatingSatData ) {
2021-02-26 15:25:48 -05:00
ui - > updateSatData - > setStyleSheet ( " QToolButton { background-color : green; } " ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
ui - > updateSatData - > setStyleSheet ( " QToolButton { background: none; } " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
m_lastUpdatingSatData = updatingSatData ;
}
updateTimeToAOS ( ) ;
2022-02-09 11:42:51 -05:00
updateDeviceFeatureCombo ( ) ;
2021-02-26 15:25:48 -05:00
}
// Update time to AOS
void SatelliteTrackerGUI : : updateTimeToAOS ( )
{
if ( m_geostationarySatVisible )
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
ui - > aos - > setText ( " Now " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
else if ( m_nextTargetAOS . isValid ( ) )
{
2022-02-04 12:14:12 -05:00
QDateTime currentTime = m_satelliteTracker - > currentDateTime ( ) ; // FIXME: UTC
2021-02-26 15:25:48 -05:00
int secondsToAOS = m_nextTargetAOS . toSecsSinceEpoch ( ) - currentTime . toSecsSinceEpoch ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( secondsToAOS > 0 )
{
int seconds = secondsToAOS % 60 ;
int minutes = ( secondsToAOS / 60 ) % 60 ;
int hours = ( secondsToAOS / ( 60 * 60 ) ) % 24 ;
int days = secondsToAOS / ( 60 * 60 * 24 ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( days = = 1 )
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
ui - > aos - > setText ( QString ( " 1 day " ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
else if ( days > 0 )
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
ui - > aos - > setText ( QString ( " %1 days " ) . arg ( days ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
else
{
ui - > aos - > setText ( QString ( " %1:%2:%3 " )
2022-11-28 15:52:06 -05:00
. arg ( hours , 2 , 10 , QLatin1Char ( ' 0 ' ) )
. arg ( minutes , 2 , 10 , QLatin1Char ( ' 0 ' ) )
. arg ( seconds , 2 , 10 , QLatin1Char ( ' 0 ' ) ) ) ;
2021-02-26 15:25:48 -05:00
}
}
else if ( m_nextTargetLOS < currentTime )
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
ui - > aos - > setText ( " " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
else
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
ui - > aos - > setText ( " Now " ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
else
ui - > aos - > setText ( " " ) ;
}
void SatelliteTrackerGUI : : applySettings ( bool force )
{
if ( m_doApplySettings )
{
2022-11-28 15:52:06 -05:00
SatelliteTracker : : MsgConfigureSatelliteTracker * message = SatelliteTracker : : MsgConfigureSatelliteTracker : : create (
m_settings , m_settingsKeys , force ) ;
2021-02-26 15:25:48 -05:00
m_satelliteTracker - > getInputMessageQueue ( ) - > push ( message ) ;
}
2022-11-28 15:52:06 -05:00
m_settingsKeys . clear ( ) ;
2021-02-26 15:25:48 -05:00
}
void SatelliteTrackerGUI : : on_nextPass_clicked ( )
{
if ( m_targetSatState ! = nullptr )
{
if ( m_plotPass < m_targetSatState - > m_passes . size ( ) - 1 )
{
m_plotPass + + ;
ui - > passLabel - > setText ( QString ( " %1 " ) . arg ( m_plotPass ) ) ;
plotChart ( ) ;
}
}
}
void SatelliteTrackerGUI : : on_prevPass_clicked ( )
{
if ( m_plotPass > 0 )
{
m_plotPass - - ;
ui - > passLabel - > setText ( QString ( " %1 " ) . arg ( m_plotPass ) ) ;
plotChart ( ) ;
}
}
2021-04-19 20:27:43 -04:00
void SatelliteTrackerGUI : : on_darkTheme_clicked ( bool checked )
{
m_settings . m_chartsDarkTheme = checked ;
plotChart ( ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " chartsDarkTheme " ) ;
2021-04-19 20:27:43 -04:00
applySettings ( ) ;
}
2021-02-26 15:25:48 -05:00
void SatelliteTrackerGUI : : on_chartSelect_currentIndexChanged ( int index )
{
2021-02-27 15:47:34 -05:00
( void ) index ;
2021-02-26 15:25:48 -05:00
plotChart ( ) ;
}
void SatelliteTrackerGUI : : plotChart ( )
{
2022-11-28 15:52:06 -05:00
if ( ui - > chartSelect - > currentIndex ( ) = = 0 ) {
2021-02-26 15:25:48 -05:00
plotPolarChart ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
plotAzElChart ( ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
// Linear interpolation
static double interpolate ( double x0 , double y0 , double x1 , double y1 , double x )
{
return ( y0 * ( x1 - x ) + y1 * ( x - x0 ) ) / ( x1 - x0 ) ;
}
2023-04-03 11:53:51 -04:00
// Reduce az/el range from 450,180 to 360,90
void SatelliteTrackerGUI : : limitAzElRange ( double & azimuth , double & elevation ) const
{
if ( elevation > 90.0 )
{
elevation = 180.0 - elevation ;
if ( azimuth < 180.0 ) {
azimuth + = 180.0 ;
} else {
azimuth - = 180.0 ;
}
}
if ( azimuth > 360.0 ) {
azimuth - = 360.0f ;
}
if ( azimuth = = 0 ) {
azimuth = 360.0 ;
}
}
2021-02-26 15:25:48 -05:00
// Plot pass in polar coords
void SatelliteTrackerGUI : : plotPolarChart ( )
{
if ( ( m_targetSatState = = nullptr ) | | ! m_satellites . contains ( m_settings . m_target ) | | ( m_targetSatState - > m_passes . size ( ) = = 0 ) )
{
ui - > passChart - > setChart ( & m_emptyChart ) ;
return ;
}
QChart * oldChart = m_polarChart ;
if ( m_plotPass > = m_targetSatState - > m_passes . size ( ) - 1 )
{
m_plotPass = m_targetSatState - > m_passes . size ( ) - 1 ;
ui - > passLabel - > setText ( QString ( " %1 " ) . arg ( m_plotPass ) ) ;
}
2022-11-28 15:52:06 -05:00
2022-09-18 05:59:12 -04:00
const SatellitePass & pass = m_targetSatState - > m_passes [ m_plotPass ] ;
2021-02-26 15:25:48 -05:00
// Always create a new chart, otherwise sometimes they aren't drawn properly
m_polarChart = new QPolarChart ( ) ;
2021-04-19 20:27:43 -04:00
m_polarChart - > setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
2021-02-26 15:25:48 -05:00
QValueAxis * angularAxis = new QValueAxis ( ) ;
QCategoryAxis * radialAxis = new QCategoryAxis ( ) ;
angularAxis - > setTickCount ( 9 ) ;
angularAxis - > setMinorTickCount ( 1 ) ;
angularAxis - > setLabelFormat ( " %d " ) ;
angularAxis - > setRange ( 0 , 360 ) ;
radialAxis - > setMin ( 0 ) ;
radialAxis - > setMax ( 90 ) ;
radialAxis - > append ( " 90 " , 0 ) ;
radialAxis - > append ( " 60 " , 30 ) ;
radialAxis - > append ( " 30 " , 60 ) ;
radialAxis - > append ( " 0 " , 90 ) ;
radialAxis - > setLabelsPosition ( QCategoryAxis : : AxisLabelsPositionOnValue ) ;
m_polarChart - > addAxis ( angularAxis , QPolarChart : : PolarOrientationAngular ) ;
m_polarChart - > addAxis ( radialAxis , QPolarChart : : PolarOrientationRadial ) ;
m_polarChart - > legend ( ) - > hide ( ) ;
m_polarChart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_polarChart - > setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
SatNogsSatellite * sat = m_satellites . value ( m_settings . m_target ) ;
2022-09-18 05:59:12 -04:00
if ( pass . m_aos . isValid ( ) & & pass . m_los . isValid ( ) )
2021-02-26 15:25:48 -05:00
{
QString title ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2022-09-18 05:59:12 -04:00
title = pass . m_aos . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
} else {
2022-09-18 05:59:12 -04:00
title = pass . m_aos . toLocalTime ( ) . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
2022-11-28 15:52:06 -05:00
m_polarChart - > setTitle ( QString ( " %1 " ) . arg ( title ) ) ;
2021-02-26 15:25:48 -05:00
QLineSeries * polarSeries = new QLineSeries ( ) ;
2022-11-28 15:52:06 -05:00
getPassAzEl (
nullptr ,
nullptr ,
polarSeries ,
sat - > m_tle - > m_tle0 ,
sat - > m_tle - > m_tle1 ,
sat - > m_tle - > m_tle2 ,
m_settings . m_latitude ,
m_settings . m_longitude ,
m_settings . m_heightAboveSeaLevel / 1000.0 ,
pass . m_aos , pass . m_los
) ;
2021-02-26 15:25:48 -05:00
// Polar charts can't handle points that are more than 180 degrees apart, so
// we need to split passes that cross from 359 -> 0 degrees (or the reverse)
QList < QLineSeries * > series ;
series . append ( new QLineSeries ( ) ) ;
QLineSeries * s = series . first ( ) ;
QPen pen ( QColor ( 32 , 159 , 223 ) , 2 , Qt : : SolidLine ) ;
s - > setPen ( pen ) ;
qreal prevAz = polarSeries - > at ( 0 ) . x ( ) ;
qreal prevEl = polarSeries - > at ( 0 ) . y ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
for ( int i = 1 ; i < polarSeries - > count ( ) ; i + + )
{
qreal az = polarSeries - > at ( i ) . x ( ) ;
qreal el = polarSeries - > at ( i ) . y ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( ( prevAz > 270.0 ) & & ( az < = 90.0 ) )
{
double elMid = interpolate ( prevAz , prevEl , az + 360.0 , el , 360.0 ) ;
s - > append ( 360.0 , elMid ) ;
series . append ( new QLineSeries ( ) ) ;
s = series . last ( ) ;
s - > setPen ( pen ) ;
s - > append ( 0.0 , elMid ) ;
s - > append ( az , el ) ;
}
else if ( ( prevAz < = 90.0 ) & & ( az > 270.0 ) )
{
double elMid = interpolate ( prevAz , prevEl , az - 360.0 , el , 0.0 ) ;
s - > append ( 0.0 , elMid ) ;
series . append ( new QLineSeries ( ) ) ;
s = series . last ( ) ;
s - > setPen ( pen ) ;
s - > append ( 360.0 , elMid ) ;
s - > append ( az , el ) ;
}
else
2022-11-28 15:52:06 -05:00
{
2021-02-26 15:25:48 -05:00
s - > append ( polarSeries - > at ( i ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
prevAz = az ;
prevEl = el ;
}
for ( int i = 0 ; i < series . length ( ) ; i + + )
{
m_polarChart - > addSeries ( series [ i ] ) ;
series [ i ] - > attachAxis ( angularAxis ) ;
series [ i ] - > attachAxis ( radialAxis ) ;
}
2023-04-03 11:53:51 -04:00
int redrawTime = 0 ;
if ( m_settings . m_drawRotators ! = SatelliteTrackerSettings : : NO_ROTATORS )
{
// Plot rotator position
QString ourSourceName = QString ( " F0:%1 %2 " ) . arg ( m_satelliteTracker - > getIndexInFeatureSet ( ) ) . arg ( m_satelliteTracker - > getIdentifier ( ) ) ; // Only one feature set in practice?
std : : vector < FeatureSet * > & featureSets = MainCore : : instance ( ) - > getFeatureeSets ( ) ;
for ( int featureSetIndex = 0 ; featureSetIndex < featureSets . size ( ) ; featureSetIndex + + )
{
FeatureSet * featureSet = featureSets [ featureSetIndex ] ;
for ( int featureIndex = 0 ; featureIndex < featureSet - > getNumberOfFeatures ( ) ; featureIndex + + )
{
Feature * feature = featureSet - > getFeatureAt ( featureIndex ) ;
if ( FeatureUtils : : compareFeatureURIs ( feature - > getURI ( ) , " sdrangel.feature.gs232controller " ) )
{
QString source ;
ChannelWebAPIUtils : : getFeatureSetting ( featureSetIndex , featureIndex , " source " , source ) ; // Will return false if source isn't set in Controller
int track = 0 ;
ChannelWebAPIUtils : : getFeatureSetting ( featureSetIndex , featureIndex , " track " , track ) ;
if ( ( m_settings . m_drawRotators = = SatelliteTrackerSettings : : ALL_ROTATORS ) | | ( ( source = = ourSourceName ) & & track ) )
{
int onTarget = 0 ;
ChannelWebAPIUtils : : getFeatureReportValue ( featureSetIndex , featureIndex , " onTarget " , onTarget ) ;
if ( ! onTarget )
{
// Target azimuth red dotted line
double targetAzimuth , targetElevation ;
bool targetAzimuthOk = ChannelWebAPIUtils : : getFeatureReportValue ( featureSetIndex , featureIndex , " targetAzimuth " , targetAzimuth ) ;
bool targetElevationOk = ChannelWebAPIUtils : : getFeatureReportValue ( featureSetIndex , featureIndex , " targetElevation " , targetElevation ) ;
if ( targetAzimuthOk & & targetElevationOk )
{
limitAzElRange ( targetAzimuth , targetElevation ) ;
QScatterSeries * rotatorSeries = new QScatterSeries ( ) ;
QColor color ( 255 , 0 , 0 , 150 ) ;
QPen pen ( color ) ;
rotatorSeries - > setPen ( pen ) ;
rotatorSeries - > setColor ( color . darker ( ) ) ;
rotatorSeries - > setMarkerSize ( 20 ) ;
rotatorSeries - > append ( targetAzimuth , 90 - targetElevation ) ;
m_polarChart - > addSeries ( rotatorSeries ) ;
rotatorSeries - > attachAxis ( angularAxis ) ;
rotatorSeries - > attachAxis ( radialAxis ) ;
redrawTime = 333 ;
}
}
// Current azimuth line. Yellow while off target, green on target.
double currentAzimuth , currentElevation ;
bool currentAzimuthOk = ChannelWebAPIUtils : : getFeatureReportValue ( featureSetIndex , featureIndex , " currentAzimuth " , currentAzimuth ) ;
bool currentElevationOk = ChannelWebAPIUtils : : getFeatureReportValue ( featureSetIndex , featureIndex , " currentElevation " , currentElevation ) ;
if ( currentAzimuthOk & & currentElevationOk )
{
limitAzElRange ( currentAzimuth , currentElevation ) ;
QScatterSeries * rotatorSeries = new QScatterSeries ( ) ;
QColor color ;
if ( onTarget ) {
color = QColor ( 0 , 255 , 0 , 150 ) ;
} else {
color = QColor ( 255 , 255 , 0 , 150 ) ;
}
rotatorSeries - > setPen ( QPen ( color ) ) ;
rotatorSeries - > setColor ( color . darker ( ) ) ;
rotatorSeries - > setMarkerSize ( 20 ) ;
rotatorSeries - > append ( currentAzimuth , 90 - currentElevation ) ;
m_polarChart - > addSeries ( rotatorSeries ) ;
rotatorSeries - > attachAxis ( angularAxis ) ;
rotatorSeries - > attachAxis ( radialAxis ) ;
redrawTime = 333 ;
}
}
}
}
}
}
2021-02-26 15:25:48 -05:00
// Create series with single point, so we can plot time of AOS
QLineSeries * aosSeries = new QLineSeries ( ) ;
aosSeries - > append ( polarSeries - > at ( 0 ) ) ;
QTime time ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2022-09-18 05:59:12 -04:00
time = pass . m_aos . time ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2022-09-18 05:59:12 -04:00
time = pass . m_aos . toLocalTime ( ) . time ( ) ;
2022-11-28 15:52:06 -05:00
}
if ( m_settings . m_utc ) {
2021-02-26 15:25:48 -05:00
aosSeries - > setPointLabelsFormat ( QString ( " AOS %1 " ) . arg ( time . toString ( " hh:mm " ) ) ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
aosSeries - > setPointLabelsFormat ( QString ( " AOS %1 " ) . arg ( time . toString ( " hh:mm " ) ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
aosSeries - > setPointLabelsVisible ( true ) ;
aosSeries - > setPointLabelsClipping ( false ) ;
m_polarChart - > addSeries ( aosSeries ) ;
aosSeries - > attachAxis ( angularAxis ) ;
aosSeries - > attachAxis ( radialAxis ) ;
// Create series with single point, so we can plot time of LOS
QLineSeries * losSeries = new QLineSeries ( ) ;
losSeries - > append ( polarSeries - > at ( polarSeries - > count ( ) - 1 ) ) ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2022-09-18 05:59:12 -04:00
time = pass . m_los . time ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2022-09-18 05:59:12 -04:00
time = pass . m_los . toLocalTime ( ) . time ( ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
losSeries - > setPointLabelsFormat ( QString ( " LOS %1 " ) . arg ( time . toString ( " hh:mm " ) ) ) ;
losSeries - > setPointLabelsVisible ( true ) ;
losSeries - > setPointLabelsClipping ( false ) ;
m_polarChart - > addSeries ( losSeries ) ;
losSeries - > attachAxis ( angularAxis ) ;
losSeries - > attachAxis ( radialAxis ) ;
QDateTime currentTime ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_dateTime = = " " ) {
2022-02-04 12:14:12 -05:00
currentTime = m_satelliteTracker - > currentDateTimeUtc ( ) ;
2022-11-28 15:52:06 -05:00
} else if ( m_settings . m_utc ) {
2021-02-26 15:25:48 -05:00
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) . toUTC ( ) ;
2022-11-28 15:52:06 -05:00
}
2022-09-18 05:59:12 -04:00
if ( ( currentTime > = pass . m_aos ) & & ( currentTime < = pass . m_los ) )
2021-02-26 15:25:48 -05:00
{
// Create series with single point, so we can plot current time
2023-04-03 11:53:51 -04:00
QScatterSeries * nowSeries = new QScatterSeries ( ) ;
nowSeries - > setMarkerSize ( 3 ) ;
2021-02-26 15:25:48 -05:00
// Find closest point to current time
2022-09-18 05:59:12 -04:00
int idx = std : : round ( polarSeries - > count ( ) * ( currentTime . toMSecsSinceEpoch ( ) - pass . m_aos . toMSecsSinceEpoch ( ) )
/ ( pass . m_los . toMSecsSinceEpoch ( ) - pass . m_aos . toMSecsSinceEpoch ( ) ) ) ;
2021-02-26 15:25:48 -05:00
nowSeries - > append ( polarSeries - > at ( idx ) ) ;
nowSeries - > setPointLabelsFormat ( m_settings . m_target ) ;
nowSeries - > setPointLabelsVisible ( true ) ;
nowSeries - > setPointLabelsClipping ( false ) ;
m_polarChart - > addSeries ( nowSeries ) ;
nowSeries - > attachAxis ( angularAxis ) ;
nowSeries - > attachAxis ( radialAxis ) ;
2023-04-03 11:53:51 -04:00
}
if ( redrawTime > 0 )
{
2023-04-14 11:15:11 -04:00
// Redraw to show updated rotator position
2023-04-03 11:53:51 -04:00
m_redrawTimer . setSingleShot ( true ) ;
m_redrawTimer . start ( redrawTime ) ;
2021-02-26 15:25:48 -05:00
}
delete polarSeries ;
}
else
{
// Possibly geostationary, just plot current position
QDateTime currentTime ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_dateTime = = " " ) {
2022-02-04 12:14:12 -05:00
currentTime = m_satelliteTracker - > currentDateTimeUtc ( ) ;
2022-11-28 15:52:06 -05:00
} else if ( m_settings . m_utc ) {
2021-02-26 15:25:48 -05:00
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) . toUTC ( ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
QString title ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2021-02-26 15:25:48 -05:00
title = currentTime . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
title = currentTime . toLocalTime ( ) . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
2022-11-28 15:52:06 -05:00
m_polarChart - > setTitle ( QString ( " %1 " ) . arg ( title ) ) ;
2021-02-26 15:25:48 -05:00
QLineSeries * nowSeries = new QLineSeries ( ) ;
2021-02-27 15:47:34 -05:00
QDateTime endTime = currentTime . addSecs ( 1 ) ;
2022-11-28 15:52:06 -05:00
getPassAzEl (
nullptr ,
nullptr ,
nowSeries ,
sat - > m_tle - > m_tle0 ,
sat - > m_tle - > m_tle1 ,
sat - > m_tle - > m_tle2 ,
m_settings . m_latitude ,
m_settings . m_longitude ,
m_settings . m_heightAboveSeaLevel / 1000.0 ,
currentTime , endTime
) ;
2021-02-26 15:25:48 -05:00
nowSeries - > setPointLabelsFormat ( m_settings . m_target ) ;
nowSeries - > setPointLabelsVisible ( true ) ;
nowSeries - > setPointLabelsClipping ( false ) ;
m_polarChart - > addSeries ( nowSeries ) ;
nowSeries - > attachAxis ( angularAxis ) ;
nowSeries - > attachAxis ( radialAxis ) ;
}
ui - > passChart - > setChart ( m_polarChart ) ;
delete oldChart ;
}
// Plot target elevation/azimuth for the next pass
void SatelliteTrackerGUI : : plotAzElChart ( )
{
if ( ( m_targetSatState = = nullptr ) | | ! m_satellites . contains ( m_settings . m_target ) | | ( m_targetSatState - > m_passes . size ( ) = = 0 ) )
{
ui - > passChart - > setChart ( & m_emptyChart ) ;
return ;
}
QChart * oldChart = m_lineChart ;
if ( m_plotPass > = m_targetSatState - > m_passes . size ( ) - 1 )
{
m_plotPass = m_targetSatState - > m_passes . size ( ) - 1 ;
ui - > passLabel - > setText ( QString ( " %1 " ) . arg ( m_plotPass ) ) ;
}
2022-11-28 15:52:06 -05:00
const SatellitePass & pass = m_targetSatState - > m_passes [ m_plotPass ] ;
2021-02-26 15:25:48 -05:00
// Always create a new chart, otherwise sometimes they aren't drawn properly
m_lineChart = new QChart ( ) ;
2021-04-19 20:27:43 -04:00
m_lineChart - > setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
2021-02-26 15:25:48 -05:00
QDateTimeAxis * xAxis = new QDateTimeAxis ( ) ;
QValueAxis * yLeftAxis = new QValueAxis ( ) ;
QValueAxis * yRightAxis = new QValueAxis ( ) ;
QString title ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2022-09-18 05:59:12 -04:00
title = pass . m_aos . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
} else {
2022-09-18 05:59:12 -04:00
title = pass . m_aos . toLocalTime ( ) . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
m_lineChart - > setTitle ( QString ( " %1 " ) . arg ( title ) ) ;
m_lineChart - > legend ( ) - > hide ( ) ;
m_lineChart - > addAxis ( xAxis , Qt : : AlignBottom ) ;
m_lineChart - > addAxis ( yLeftAxis , Qt : : AlignLeft ) ;
m_lineChart - > addAxis ( yRightAxis , Qt : : AlignRight ) ;
m_lineChart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_lineChart - > setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
SatNogsSatellite * sat = m_satellites . value ( m_settings . m_target ) ;
QLineSeries * azSeries = new QLineSeries ( ) ;
QLineSeries * elSeries = new QLineSeries ( ) ;
2022-11-28 15:52:06 -05:00
getPassAzEl (
azSeries ,
elSeries ,
nullptr ,
sat - > m_tle - > m_tle0 ,
sat - > m_tle - > m_tle1 ,
sat - > m_tle - > m_tle2 ,
m_settings . m_latitude ,
m_settings . m_longitude ,
m_settings . m_heightAboveSeaLevel / 1000.0 ,
pass . m_aos ,
pass . m_los
) ;
2021-02-26 15:25:48 -05:00
// Split crossing of 360/0 degrees in to multiple series in the same colour
QList < QLineSeries * > azSeriesList ;
QPen pen ( QColor ( 153 , 202 , 83 ) , 2 , Qt : : SolidLine ) ;
QLineSeries * s = new QLineSeries ( ) ;
azSeriesList . append ( s ) ;
s - > setPen ( pen ) ;
qreal prevAz = azSeries - > at ( 0 ) . y ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
for ( int i = 0 ; i < azSeries - > count ( ) ; i + + )
{
qreal az = azSeries - > at ( i ) . y ( ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( ( ( prevAz > = 270 ) & & ( az < 90 ) ) | | ( ( prevAz < 90 ) & & ( az > = 270 ) ) )
{
s = new QLineSeries ( ) ;
azSeriesList . append ( s ) ;
s - > setPen ( pen ) ;
}
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
s - > append ( azSeries - > at ( i ) . x ( ) , az ) ;
prevAz = az ;
}
m_lineChart - > addSeries ( elSeries ) ;
elSeries - > attachAxis ( xAxis ) ;
elSeries - > attachAxis ( yLeftAxis ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
for ( int i = 0 ; i < azSeriesList . size ( ) ; i + + )
{
m_lineChart - > addSeries ( azSeriesList [ i ] ) ;
azSeriesList [ i ] - > attachAxis ( xAxis ) ;
azSeriesList [ i ] - > attachAxis ( yRightAxis ) ;
}
2022-11-28 15:52:06 -05:00
2023-04-14 11:15:11 -04:00
// Plot current target on elevation series
if ( m_targetSatState & & ( m_targetSatState - > m_elevation > 0.0 ) )
{
QDateTime currentTime ;
if ( m_settings . m_dateTime = = " " ) {
currentTime = m_satelliteTracker - > currentDateTimeUtc ( ) ;
} else if ( m_settings . m_utc ) {
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
} else {
currentTime = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) . toUTC ( ) ;
}
QScatterSeries * posSeries = new QScatterSeries ( ) ;
posSeries - > setMarkerSize ( 3 ) ;
posSeries - > append ( currentTime . toMSecsSinceEpoch ( ) , m_targetSatState - > m_elevation ) ;
posSeries - > setPointLabelsVisible ( true ) ;
posSeries - > setPointLabelsFormat ( m_settings . m_target ) ;
posSeries - > setPointLabelsClipping ( false ) ;
m_lineChart - > addSeries ( posSeries ) ;
posSeries - > attachAxis ( xAxis ) ;
posSeries - > attachAxis ( yLeftAxis ) ;
}
2022-09-18 05:59:12 -04:00
xAxis - > setRange ( pass . m_aos , pass . m_los ) ;
2021-02-26 15:25:48 -05:00
xAxis - > setFormat ( " hh:mm " ) ;
yLeftAxis - > setRange ( 0.0 , 90.0 ) ;
yLeftAxis - > setTickCount ( 7 ) ;
yLeftAxis - > setLabelFormat ( " %d " ) ;
yLeftAxis - > setTitleText ( QString ( " Elevation (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
yRightAxis - > setRange ( 0.0 , 360.0 ) ;
yRightAxis - > setTickCount ( 7 ) ;
yRightAxis - > setLabelFormat ( " %d " ) ;
yRightAxis - > setTitleText ( QString ( " Azimuth (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
ui - > passChart - > setChart ( m_lineChart ) ;
delete azSeries ;
delete oldChart ;
}
void SatelliteTrackerGUI : : resizeTable ( )
{
// Fill table with a row of dummy data that will size the columns nicely
int row = ui - > satTable - > rowCount ( ) ;
ui - > satTable - > setRowCount ( row + 1 ) ;
ui - > satTable - > setItem ( row , SAT_COL_NAME , new QTableWidgetItem ( " Satellite123 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_AZ , new QTableWidgetItem ( " 360 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_EL , new QTableWidgetItem ( " -90 " ) ) ;
2022-10-27 10:41:46 -04:00
ui - > satTable - > setItem ( row , SAT_COL_TNE , new QTableWidgetItem ( " 99:99:99 AOS " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_DUR , new QTableWidgetItem ( " 9:99:99 " ) ) ;
2021-02-26 15:25:48 -05:00
ui - > satTable - > setItem ( row , SAT_COL_AOS , new QTableWidgetItem ( " +1 10:17 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_LOS , new QTableWidgetItem ( " +1 10:17 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_MAX_EL , new QTableWidgetItem ( " 90 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_DIR , new QTableWidgetItem ( " ^ " ) ) ;
2022-02-04 12:14:12 -05:00
ui - > satTable - > setItem ( row , SAT_COL_LATITUDE , new QTableWidgetItem ( " -90.0 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_LONGITUDE , new QTableWidgetItem ( " -180.0 " ) ) ;
2021-02-26 15:25:48 -05:00
ui - > satTable - > setItem ( row , SAT_COL_ALT , new QTableWidgetItem ( " 50000 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_RANGE , new QTableWidgetItem ( " 50000 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_RANGE_RATE , new QTableWidgetItem ( " 10.0 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_DOPPLER , new QTableWidgetItem ( " 10000 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_PATH_LOSS , new QTableWidgetItem ( " 100 " ) ) ;
ui - > satTable - > setItem ( row , SAT_COL_NORAD_ID , new QTableWidgetItem ( " 123456 " ) ) ;
ui - > satTable - > resizeColumnsToContents ( ) ;
ui - > satTable - > setRowCount ( row ) ;
}
// As we only have limited space in table, display time plus number of days to AOS/LOS
// unless it's greater than 10 days, in which case just display the date
QString SatelliteTrackerGUI : : formatDaysTime ( qint64 days , QDateTime dateTime )
{
QDateTime dt ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_utc ) {
2021-02-26 15:25:48 -05:00
dt = dateTime . toUTC ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
dt = dateTime . toLocalTime ( ) ;
2022-11-28 15:52:06 -05:00
}
if ( abs ( days ) > 10 ) {
2021-02-26 15:25:48 -05:00
return dt . date ( ) . toString ( m_settings . m_dateFormat ) ;
2022-11-28 15:52:06 -05:00
} else if ( days = = 0 ) {
2021-02-26 15:25:48 -05:00
return dt . time ( ) . toString ( " hh:mm " ) ;
2022-11-28 15:52:06 -05:00
} else if ( days > 0 ) {
2021-02-26 15:25:48 -05:00
return dt . time ( ) . toString ( QString ( " hh:mm +%1 " ) . arg ( days ) ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
return dt . time ( ) . toString ( QString ( " hh:mm %1 " ) . arg ( days ) ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
2022-10-27 10:41:46 -04:00
QString SatelliteTrackerGUI : : formatSecondsAsHHMMSS ( qint64 seconds )
2021-09-01 14:03:14 -04:00
{
char const * sign = " " ;
2022-11-28 15:52:06 -05:00
if ( seconds < 0 )
2021-09-01 14:03:14 -04:00
{
sign = " - " ;
seconds = - seconds ;
}
2022-11-28 15:52:06 -05:00
2022-10-27 10:41:46 -04:00
int minutes = seconds / 60 ;
seconds = seconds % 60 ;
int hours = minutes / 60 ;
minutes = minutes % 60 ;
2022-11-28 15:52:06 -05:00
2022-10-27 10:41:46 -04:00
if ( hours > 0 ) {
return QString ( " %1%2:%3:%4 " ) . arg ( sign ) . arg ( hours ) . arg ( minutes , 2 , 10 , QChar ( ' 0 ' ) ) . arg ( seconds , 2 , 10 , QChar ( ' 0 ' ) ) ;
} else {
return QString ( " %1%2:%3 " ) . arg ( sign ) . arg ( minutes ) . arg ( seconds , 2 , 10 , QChar ( ' 0 ' ) ) ;
}
2021-09-01 14:03:14 -04:00
}
2021-02-26 15:25:48 -05:00
// Table item showing some text, but sorted by datetime set as user data
class DateTimeSortedTableWidgetItem : public QTableWidgetItem {
public :
bool operator < ( const QTableWidgetItem & other ) const
{
QVariant v1 = data ( Qt : : UserRole ) ;
QVariant v2 = other . data ( Qt : : UserRole ) ;
2022-11-28 15:52:06 -05:00
if ( v1 . isValid ( ) & & v2 . isValid ( ) ) {
2021-02-26 15:25:48 -05:00
return v1 . toDateTime ( ) < v2 . toDateTime ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
return false ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
} ;
2022-10-28 15:51:57 -04:00
// Handle sorting for next column, which can have times as HH:MM:SS or MM:SS
class NextEventTableWidgetItem : public QTableWidgetItem
{
public :
bool operator < ( const QTableWidgetItem & other ) const override
{
QString t1 = text ( ) ;
QString t2 = other . text ( ) ;
int t1Colons = t1 . count ( " : " ) ;
int t2Colons = t2 . count ( " : " ) ;
2022-11-28 15:52:06 -05:00
2022-10-28 15:51:57 -04:00
if ( t1Colons = = t2Colons )
{
QCollator coll ;
coll . setNumericMode ( true ) ;
return coll . compare ( t1 , t2 ) < 0 ;
}
else
{
return t1Colons < t2Colons ;
}
}
} ;
2021-09-01 13:59:00 -04:00
class NaturallySortedTableWidgetItem : public QTableWidgetItem
{
public :
bool operator < ( const QTableWidgetItem & other ) const override
{
QCollator coll ;
coll . setNumericMode ( true ) ;
2022-10-28 15:51:57 -04:00
return coll . compare ( text ( ) , other . text ( ) ) < 0 ;
2021-09-01 13:59:00 -04:00
}
} ;
2021-02-26 15:25:48 -05:00
# define SPEED_OF_LIGHT 299792458.0
// Frequency in Hz, speed in m/s
static double doppler ( double frequency , double speed )
{
return frequency * speed / SPEED_OF_LIGHT ;
}
// Frequency in Hz, speed in m/s
static double freeSpaceLoss ( double frequency , double distance )
{
return 20.0 * log10 ( distance ) + 20 * log10 ( frequency ) + 20 * log10 ( 4 * M_PI / SPEED_OF_LIGHT ) ;
}
// Distance in m, delay in s
static double propagationDelay ( double distance )
{
return distance / SPEED_OF_LIGHT ;
}
// Update satellite data table with latest data for the satellite
void SatelliteTrackerGUI : : updateTable ( SatelliteState * satState )
{
// Does the table already contain this satellite?
QList < QTableWidgetItem * > matches = ui - > satTable - > findItems ( satState - > m_name , Qt : : MatchExactly ) ;
QTableWidgetItem * items [ SAT_COL_COLUMNS ] ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( matches . size ( ) = = 0 )
{
// Add a new row
2022-10-10 06:26:41 -04:00
ui - > satTable - > setSortingEnabled ( false ) ;
2021-02-26 15:25:48 -05:00
int row = ui - > satTable - > rowCount ( ) ;
ui - > satTable - > setRowCount ( row + 1 ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
for ( int i = 0 ; i < SAT_COL_COLUMNS ; i + + )
{
2022-11-28 15:52:06 -05:00
if ( ( i = = SAT_COL_AOS ) | | ( i = = SAT_COL_LOS ) ) {
2021-02-26 15:25:48 -05:00
items [ i ] = new DateTimeSortedTableWidgetItem ( ) ;
2022-11-28 15:52:06 -05:00
} else if ( ( i = = SAT_COL_NAME ) | | ( i = = SAT_COL_NORAD_ID ) ) {
2021-02-26 15:25:48 -05:00
items [ i ] = new QTableWidgetItem ( ) ;
2022-11-28 15:52:06 -05:00
} else if ( i = = SAT_COL_TNE ) {
2022-10-28 15:51:57 -04:00
items [ i ] = new NextEventTableWidgetItem ( ) ;
2022-11-28 15:52:06 -05:00
} else {
2021-09-01 13:59:00 -04:00
items [ i ] = new NaturallySortedTableWidgetItem ( ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
items [ i ] - > setToolTip ( ui - > satTable - > horizontalHeaderItem ( i ) - > toolTip ( ) ) ;
ui - > satTable - > setItem ( row , i , items [ i ] ) ;
}
2022-11-28 15:52:06 -05:00
2022-10-10 06:26:41 -04:00
ui - > satTable - > setSortingEnabled ( true ) ;
2021-02-26 15:25:48 -05:00
// Static columns
items [ SAT_COL_NAME ] - > setText ( satState - > m_name ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( m_satellites . contains ( satState - > m_name ) )
{
SatNogsSatellite * sat = m_satellites . value ( satState - > m_name ) ;
items [ SAT_COL_NORAD_ID ] - > setData ( Qt : : DisplayRole , sat - > m_noradCatId ) ;
}
2021-09-01 14:03:43 -04:00
// Text alignment
2022-02-04 12:14:12 -05:00
for ( int col : { SAT_COL_AZ , SAT_COL_EL , SAT_COL_TNE , SAT_COL_DUR , SAT_COL_MAX_EL ,
2022-11-28 15:52:06 -05:00
SAT_COL_LATITUDE , SAT_COL_LONGITUDE ,
SAT_COL_ALT , SAT_COL_RANGE , SAT_COL_RANGE_RATE , SAT_COL_DOPPLER ,
SAT_COL_PATH_LOSS , SAT_COL_DELAY } )
{
2021-09-01 14:03:43 -04:00
items [ col ] - > setTextAlignment ( Qt : : AlignRight | Qt : : AlignVCenter ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
else
{
// Update existing row
int row = ui - > satTable - > row ( matches [ 0 ] ) ;
2022-11-28 15:52:06 -05:00
for ( int i = 0 ; i < SAT_COL_COLUMNS ; i + + ) {
2021-02-26 15:25:48 -05:00
items [ i ] = ui - > satTable - > item ( row , i ) ;
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
items [ SAT_COL_AZ ] - > setData ( Qt : : DisplayRole , ( int ) round ( satState - > m_azimuth ) ) ;
items [ SAT_COL_EL ] - > setData ( Qt : : DisplayRole , ( int ) round ( satState - > m_elevation ) ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( satState - > m_passes . size ( ) > 0 )
{
// Get number of days to AOS/LOS
2022-02-04 12:14:12 -05:00
QDateTime currentDateTime = m_satelliteTracker - > currentDateTime ( ) ;
2022-09-18 05:59:12 -04:00
int daysToAOS = currentDateTime . daysTo ( satState - > m_passes [ 0 ] . m_aos ) ;
int daysToLOS = currentDateTime . daysTo ( satState - > m_passes [ 0 ] . m_los ) ;
2022-11-28 15:52:06 -05:00
if ( satState - > m_passes [ 0 ] . m_aos > currentDateTime ) {
2022-10-27 10:41:46 -04:00
items [ SAT_COL_TNE ] - > setText ( formatSecondsAsHHMMSS ( currentDateTime . secsTo ( satState - > m_passes [ 0 ] . m_aos ) ) + " AOS " ) ;
2022-11-28 15:52:06 -05:00
} else {
2022-10-27 10:41:46 -04:00
items [ SAT_COL_TNE ] - > setText ( formatSecondsAsHHMMSS ( currentDateTime . secsTo ( satState - > m_passes [ 0 ] . m_los ) ) + " LOS " ) ;
2022-11-28 15:52:06 -05:00
}
2022-10-27 10:41:46 -04:00
items [ SAT_COL_DUR ] - > setText ( formatSecondsAsHHMMSS ( satState - > m_passes [ 0 ] . m_aos . secsTo ( satState - > m_passes [ 0 ] . m_los ) ) ) ;
2022-09-18 05:59:12 -04:00
items [ SAT_COL_AOS ] - > setText ( formatDaysTime ( daysToAOS , satState - > m_passes [ 0 ] . m_aos ) ) ;
items [ SAT_COL_AOS ] - > setData ( Qt : : UserRole , satState - > m_passes [ 0 ] . m_aos ) ;
items [ SAT_COL_LOS ] - > setText ( formatDaysTime ( daysToLOS , satState - > m_passes [ 0 ] . m_los ) ) ;
items [ SAT_COL_LOS ] - > setData ( Qt : : UserRole , satState - > m_passes [ 0 ] . m_los ) ;
items [ SAT_COL_MAX_EL ] - > setData ( Qt : : DisplayRole , ( int ) round ( satState - > m_passes [ 0 ] . m_maxElevation ) ) ;
2022-11-28 15:52:06 -05:00
if ( satState - > m_passes [ 0 ] . m_northToSouth ) {
2021-02-26 15:25:48 -05:00
items [ SAT_COL_DIR ] - > setText ( QString ( " %1 " ) . arg ( QChar ( 0x2193 ) ) ) ; // Down arrow
2022-11-28 15:52:06 -05:00
} else {
2021-02-26 15:25:48 -05:00
items [ SAT_COL_DIR ] - > setText ( QString ( " %1 " ) . arg ( QChar ( 0x2191 ) ) ) ; // Up arrow
2022-11-28 15:52:06 -05:00
}
2021-02-26 15:25:48 -05:00
}
else
{
2021-09-01 14:03:14 -04:00
items [ SAT_COL_TNE ] - > setText ( " " ) ;
items [ SAT_COL_DUR ] - > setText ( " " ) ;
2021-02-26 15:25:48 -05:00
items [ SAT_COL_AOS ] - > setText ( " " ) ;
items [ SAT_COL_LOS ] - > setText ( " " ) ;
items [ SAT_COL_MAX_EL ] - > setData ( Qt : : DisplayRole , QVariant ( ) ) ;
items [ SAT_COL_DIR ] - > setText ( " " ) ;
}
2022-11-28 15:52:06 -05:00
2022-02-04 12:14:12 -05:00
items [ SAT_COL_LATITUDE ] - > setData ( Qt : : DisplayRole , satState - > m_latitude ) ;
items [ SAT_COL_LONGITUDE ] - > setData ( Qt : : DisplayRole , satState - > m_longitude ) ;
2021-02-26 15:25:48 -05:00
items [ SAT_COL_ALT ] - > setData ( Qt : : DisplayRole , ( int ) round ( satState - > m_altitude ) ) ;
items [ SAT_COL_RANGE ] - > setData ( Qt : : DisplayRole , ( int ) round ( satState - > m_range ) ) ;
items [ SAT_COL_RANGE_RATE ] - > setData ( Qt : : DisplayRole , QString : : number ( satState - > m_rangeRate , ' f ' , 3 ) ) ;
items [ SAT_COL_DOPPLER ] - > setData ( Qt : : DisplayRole , ( int ) round ( - doppler ( m_settings . m_defaultFrequency , satState - > m_rangeRate * 1000.0 ) ) ) ;
items [ SAT_COL_PATH_LOSS ] - > setData ( Qt : : DisplayRole , QString : : number ( freeSpaceLoss ( m_settings . m_defaultFrequency , satState - > m_range * 1000.0 ) , ' f ' , 1 ) ) ;
items [ SAT_COL_DELAY ] - > setData ( Qt : : DisplayRole , QString : : number ( propagationDelay ( satState - > m_range * 1000.0 ) * 1000.0 , ' f ' , 1 ) ) ;
}
void SatelliteTrackerGUI : : on_satTable_cellDoubleClicked ( int row , int column )
{
2021-02-27 15:47:34 -05:00
( void ) column ;
2021-02-26 15:25:48 -05:00
QString sat = ui - > satTable - > item ( row , SAT_COL_NAME ) - > text ( ) ;
FeatureWebAPIUtils : : mapFind ( sat ) ;
2022-10-28 09:40:34 -04:00
}
2022-02-04 12:14:12 -05:00
2022-10-28 09:40:34 -04:00
void SatelliteTrackerGUI : : on_satTableHeader_sortIndicatorChanged ( int logicalIndex , Qt : : SortOrder order )
{
m_settings . m_columnSort = logicalIndex ;
m_settings . m_columnSortOrder = order ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " columnSort " ) ;
m_settingsKeys . append ( " columnSortOrder " ) ;
2022-10-28 09:40:34 -04:00
applySettings ( ) ;
2021-02-26 15:25:48 -05:00
}
// Columns in table reordered
void SatelliteTrackerGUI : : satTable_sectionMoved ( int logicalIndex , int oldVisualIndex , int newVisualIndex )
{
( void ) oldVisualIndex ;
m_settings . m_columnIndexes [ logicalIndex ] = newVisualIndex ;
}
// Column in table resized (when hidden size is 0)
void SatelliteTrackerGUI : : satTable_sectionResized ( int logicalIndex , int oldSize , int newSize )
{
( void ) oldSize ;
m_settings . m_columnSizes [ logicalIndex ] = newSize ;
}
// Right click in table header - show column select menu
void SatelliteTrackerGUI : : columnSelectMenu ( QPoint pos )
{
menu - > popup ( ui - > satTable - > horizontalHeader ( ) - > viewport ( ) - > mapToGlobal ( pos ) ) ;
}
// Hide/show column when menu selected
void SatelliteTrackerGUI : : columnSelectMenuChecked ( bool checked )
{
( void ) checked ;
QAction * action = qobject_cast < QAction * > ( sender ( ) ) ;
2022-11-28 15:52:06 -05:00
2021-02-26 15:25:48 -05:00
if ( action ! = nullptr )
{
int idx = action - > data ( ) . toInt ( nullptr ) ;
ui - > satTable - > setColumnHidden ( idx , ! action - > isChecked ( ) ) ;
}
}
// Create column select menu item
QAction * SatelliteTrackerGUI : : createCheckableItem ( QString & text , int idx , bool checked )
{
QAction * action = new QAction ( text , this ) ;
action - > setCheckable ( true ) ;
action - > setChecked ( checked ) ;
action - > setData ( QVariant ( idx ) ) ;
connect ( action , SIGNAL ( triggered ( ) ) , this , SLOT ( columnSelectMenuChecked ( ) ) ) ;
return action ;
}
2022-02-09 11:42:51 -05:00
void SatelliteTrackerGUI : : updateDeviceFeatureCombo ( )
{
if ( m_settings . m_dateTimeSelect = = SatelliteTrackerSettings : : FROM_MAP ) {
updateMapList ( ) ;
} else if ( m_settings . m_dateTimeSelect = = SatelliteTrackerSettings : : FROM_FILE ) {
updateFileInputList ( ) ;
}
}
void SatelliteTrackerGUI : : updateDeviceFeatureCombo ( const QStringList & items , const QString & selected )
{
// Remove items no longer in list
int i = 0 ;
while ( i < ui - > deviceFeatureSelect - > count ( ) )
{
if ( ! items . contains ( ui - > deviceFeatureSelect - > itemText ( i ) ) ) {
ui - > deviceFeatureSelect - > removeItem ( i ) ;
} else {
i + + ;
}
}
// Add new items to list
for ( auto item : items )
{
int idx = ui - > deviceFeatureSelect - > findText ( item ) ;
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
if ( idx = = - 1 ) {
ui - > deviceFeatureSelect - > addItem ( item ) ;
}
}
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
ui - > deviceFeatureSelect - > setCurrentIndex ( ui - > deviceFeatureSelect - > findText ( selected ) ) ;
}
void SatelliteTrackerGUI : : updateFileInputList ( )
{
// Create list of File Input devices
std : : vector < DeviceSet * > & deviceSets = MainCore : : instance ( ) - > getDeviceSets ( ) ;
int deviceIndex = 0 ;
QStringList items ;
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
for ( std : : vector < DeviceSet * > : : const_iterator it = deviceSets . begin ( ) ; it ! = deviceSets . end ( ) ; + + it , deviceIndex + + )
{
if ( ( * it ) - > m_deviceAPI & & ( * it ) - > m_deviceAPI - > getHardwareId ( ) = = " FileInput " ) {
items . append ( QString ( " R%1 " ) . arg ( deviceIndex ) ) ;
}
}
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
updateDeviceFeatureCombo ( items , m_settings . m_fileInputDevice ) ;
}
void SatelliteTrackerGUI : : updateMapList ( )
{
// Create list of Map features
std : : vector < FeatureSet * > & featureSets = MainCore : : instance ( ) - > getFeatureeSets ( ) ;
int featureIndex = 0 ;
QStringList items ;
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
for ( std : : vector < FeatureSet * > : : const_iterator it = featureSets . begin ( ) ; it ! = featureSets . end ( ) ; + + it , featureIndex + + )
{
for ( int fi = 0 ; fi < ( * it ) - > getNumberOfFeatures ( ) ; fi + + )
{
Feature * feature = ( * it ) - > getFeatureAt ( fi ) ;
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
if ( feature - > getURI ( ) = = " sdrangel.feature.map " ) {
items . append ( QString ( " F%1:%2 " ) . arg ( featureIndex ) . arg ( fi ) ) ;
}
}
}
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
updateDeviceFeatureCombo ( items , m_settings . m_mapFeature ) ;
}
void SatelliteTrackerGUI : : on_deviceFeatureSelect_currentIndexChanged ( int index )
{
2022-02-09 11:59:24 -05:00
( void ) index ;
2022-11-28 15:52:06 -05:00
if ( m_settings . m_dateTimeSelect = = SatelliteTrackerSettings : : FROM_MAP )
{
2022-02-09 11:42:51 -05:00
m_settings . m_mapFeature = ui - > deviceFeatureSelect - > currentText ( ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " mapFeature " ) ;
} else
{
2022-02-09 11:42:51 -05:00
m_settings . m_fileInputDevice = ui - > deviceFeatureSelect - > currentText ( ) ;
2022-11-28 15:52:06 -05:00
m_settingsKeys . append ( " fileInputDevice " ) ;
2022-02-09 11:42:51 -05:00
}
2022-11-28 15:52:06 -05:00
2022-02-09 11:42:51 -05:00
applySettings ( ) ;
}
2022-04-04 04:23:52 -04:00
void SatelliteTrackerGUI : : makeUIConnections ( )
{
QObject : : connect ( ui - > startStop , & ButtonSwitch : : toggled , this , & SatelliteTrackerGUI : : on_startStop_toggled ) ;
QObject : : connect ( ui - > useMyPosition , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_useMyPosition_clicked ) ;
QObject : : connect ( ui - > latitude , qOverload < double > ( & QDoubleSpinBox : : valueChanged ) , this , & SatelliteTrackerGUI : : on_latitude_valueChanged ) ;
QObject : : connect ( ui - > longitude , qOverload < double > ( & QDoubleSpinBox : : valueChanged ) , this , & SatelliteTrackerGUI : : on_longitude_valueChanged ) ;
QObject : : connect ( ui - > target , & QComboBox : : currentTextChanged , this , & SatelliteTrackerGUI : : on_target_currentTextChanged ) ;
QObject : : connect ( ui - > displaySettings , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_displaySettings_clicked ) ;
QObject : : connect ( ui - > radioControl , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_radioControl_clicked ) ;
QObject : : connect ( ui - > dateTimeSelect , qOverload < int > ( & QComboBox : : currentIndexChanged ) , this , & SatelliteTrackerGUI : : on_dateTimeSelect_currentIndexChanged ) ;
QObject : : connect ( ui - > dateTime , & WrappingDateTimeEdit : : dateTimeChanged , this , & SatelliteTrackerGUI : : on_dateTime_dateTimeChanged ) ;
QObject : : connect ( ui - > viewOnMap , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_viewOnMap_clicked ) ;
QObject : : connect ( ui - > updateSatData , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_updateSatData_clicked ) ;
QObject : : connect ( ui - > selectSats , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_selectSats_clicked ) ;
QObject : : connect ( ui - > autoTarget , & ButtonSwitch : : clicked , this , & SatelliteTrackerGUI : : on_autoTarget_clicked ) ;
QObject : : connect ( ui - > chartSelect , qOverload < int > ( & QComboBox : : currentIndexChanged ) , this , & SatelliteTrackerGUI : : on_chartSelect_currentIndexChanged ) ;
QObject : : connect ( ui - > nextPass , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_nextPass_clicked ) ;
QObject : : connect ( ui - > prevPass , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_prevPass_clicked ) ;
QObject : : connect ( ui - > darkTheme , & QToolButton : : clicked , this , & SatelliteTrackerGUI : : on_darkTheme_clicked ) ;
QObject : : connect ( ui - > satTable , & QTableWidget : : cellDoubleClicked , this , & SatelliteTrackerGUI : : on_satTable_cellDoubleClicked ) ;
2022-10-28 09:40:34 -04:00
QObject : : connect ( ui - > satTable - > horizontalHeader ( ) , & QHeaderView : : sortIndicatorChanged , this , & SatelliteTrackerGUI : : on_satTableHeader_sortIndicatorChanged ) ;
2022-04-04 04:23:52 -04:00
QObject : : connect ( ui - > deviceFeatureSelect , qOverload < int > ( & QComboBox : : currentIndexChanged ) , this , & SatelliteTrackerGUI : : on_deviceFeatureSelect_currentIndexChanged ) ;
}
2023-04-03 11:53:51 -04:00