2021-01-13 15:51:38 -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>
2021-01-29 07:57:58 -05:00
# include <algorithm>
2021-01-13 15:51:38 -05:00
# include <QMessageBox>
# include <QLineEdit>
# include <QRegExp>
2021-01-22 11:58:24 -05:00
# include <QNetworkAccessManager>
# include <QNetworkReply>
2021-01-13 15:51:38 -05:00
# include <QtCharts/QChartView>
# include <QtCharts/QLineSeries>
# include <QtCharts/QDateTimeAxis>
# include <QtCharts/QValueAxis>
# include "feature/featureuiset.h"
# include "feature/featurewebapiutils.h"
# include "gui/basicfeaturesettingsdialog.h"
# include "mainwindow.h"
# include "device/deviceuiset.h"
# include "util/units.h"
# include "util/astronomy.h"
# include "ui_startrackergui.h"
# include "startracker.h"
# include "startrackergui.h"
# include "startrackerreport.h"
# include "startrackersettingsdialog.h"
2021-02-26 15:33:39 -05:00
// Linear extrapolation
static double extrapolate ( double x0 , double y0 , double x1 , double y1 , double x )
{
return y0 + ( ( x - x0 ) / ( x1 - x0 ) ) * ( y1 - y0 ) ;
}
// Linear interpolation
static double interpolate ( double x0 , double y0 , double x1 , double y1 , double x )
{
return ( y0 * ( x1 - x ) + y1 * ( x - x0 ) ) / ( x1 - x0 ) ;
}
2021-01-29 07:57:58 -05:00
2021-01-13 15:51:38 -05:00
StarTrackerGUI * StarTrackerGUI : : create ( PluginAPI * pluginAPI , FeatureUISet * featureUISet , Feature * feature )
{
StarTrackerGUI * gui = new StarTrackerGUI ( pluginAPI , featureUISet , feature ) ;
return gui ;
}
void StarTrackerGUI : : destroy ( )
{
delete this ;
}
void StarTrackerGUI : : resetToDefaults ( )
{
m_settings . resetToDefaults ( ) ;
displaySettings ( ) ;
applySettings ( true ) ;
}
QByteArray StarTrackerGUI : : serialize ( ) const
{
return m_settings . serialize ( ) ;
}
bool StarTrackerGUI : : deserialize ( const QByteArray & data )
{
if ( m_settings . deserialize ( data ) )
{
displaySettings ( ) ;
applySettings ( true ) ;
return true ;
}
else
{
resetToDefaults ( ) ;
return false ;
}
}
QString StarTrackerGUI : : convertDegreesToText ( double degrees )
{
if ( m_settings . m_azElUnits = = StarTrackerSettings : : DMS )
return Units : : decimalDegreesToDegreeMinutesAndSeconds ( degrees ) ;
else if ( m_settings . m_azElUnits = = StarTrackerSettings : : DM )
return Units : : decimalDegreesToDegreesAndMinutes ( degrees ) ;
else if ( m_settings . m_azElUnits = = StarTrackerSettings : : D )
return Units : : decimalDegreesToDegrees ( degrees ) ;
else
return QString ( " %1 " ) . arg ( degrees , 0 , ' f ' , 2 ) ;
}
bool StarTrackerGUI : : handleMessage ( const Message & message )
{
if ( StarTracker : : MsgConfigureStarTracker : : match ( message ) )
{
qDebug ( " StarTrackerGUI::handleMessage: StarTracker::MsgConfigureStarTracker " ) ;
const StarTracker : : MsgConfigureStarTracker & cfg = ( StarTracker : : MsgConfigureStarTracker & ) message ;
m_settings = cfg . getSettings ( ) ;
blockApplySettings ( true ) ;
displaySettings ( ) ;
blockApplySettings ( false ) ;
return true ;
}
else if ( StarTrackerReport : : MsgReportAzAl : : match ( message ) )
{
StarTrackerReport : : MsgReportAzAl & azAl = ( StarTrackerReport : : MsgReportAzAl & ) message ;
ui - > azimuth - > setText ( convertDegreesToText ( azAl . getAzimuth ( ) ) ) ;
ui - > elevation - > setText ( convertDegreesToText ( azAl . getElevation ( ) ) ) ;
return true ;
}
else if ( StarTrackerReport : : MsgReportRADec : : match ( message ) )
{
StarTrackerReport : : MsgReportRADec & raDec = ( StarTrackerReport : : MsgReportRADec & ) message ;
m_settings . m_ra = Units : : decimalHoursToHoursMinutesAndSeconds ( raDec . getRA ( ) ) ;
m_settings . m_dec = Units : : decimalDegreesToDegreeMinutesAndSeconds ( raDec . getDec ( ) ) ;
ui - > rightAscension - > setText ( m_settings . m_ra ) ;
ui - > declination - > setText ( m_settings . m_dec ) ;
2021-01-29 07:57:58 -05:00
raDecChanged ( ) ;
2021-01-13 15:51:38 -05:00
return true ;
}
return false ;
}
void StarTrackerGUI : : handleInputMessages ( )
{
Message * message ;
while ( ( message = getInputMessageQueue ( ) - > pop ( ) ) )
{
if ( handleMessage ( * message ) ) {
delete message ;
}
}
}
void StarTrackerGUI : : onWidgetRolled ( QWidget * widget , bool rollDown )
{
( void ) widget ;
( void ) rollDown ;
}
StarTrackerGUI : : StarTrackerGUI ( PluginAPI * pluginAPI , FeatureUISet * featureUISet , Feature * feature , QWidget * parent ) :
FeatureGUI ( parent ) ,
ui ( new Ui : : StarTrackerGUI ) ,
m_pluginAPI ( pluginAPI ) ,
m_featureUISet ( featureUISet ) ,
m_doApplySettings ( true ) ,
2021-01-22 11:58:24 -05:00
m_lastFeatureState ( 0 ) ,
2021-02-26 15:33:39 -05:00
m_azElLineChart ( nullptr ) ,
m_azElPolarChart ( nullptr ) ,
2021-01-22 11:58:24 -05:00
m_networkManager ( nullptr ) ,
2021-01-29 07:57:58 -05:00
m_solarFlux ( 0.0 ) ,
m_solarFluxesValid ( false ) ,
m_images { QImage ( " :/startracker/startracker/150mhz_ra_dec.png " ) ,
QImage ( " :/startracker/startracker/150mhz_galactic.png " ) ,
QImage ( " :/startracker/startracker/408mhz_ra_dec.png " ) ,
QImage ( " :/startracker/startracker/408mhz_galactic.png " ) ,
QImage ( " :/startracker/startracker/1420mhz_ra_dec.png " ) ,
QImage ( " :/startracker/startracker/1420mhz_galactic.png " ) } ,
m_temps { FITS ( " :/startracker/startracker/150mhz_ra_dec.fits " ) ,
FITS ( " :/startracker/startracker/408mhz_ra_dec.fits " ) ,
FITS ( " :/startracker/startracker/1420mhz_ra_dec.fits " ) } ,
m_spectralIndex ( " :/startracker/startracker/408mhz_ra_dec_spectral_index.fits " )
2021-01-13 15:51:38 -05:00
{
ui - > setupUi ( this ) ;
setAttribute ( Qt : : WA_DeleteOnClose , true ) ;
setChannelWidget ( false ) ;
connect ( this , SIGNAL ( widgetRolled ( QWidget * , bool ) ) , this , SLOT ( onWidgetRolled ( QWidget * , bool ) ) ) ;
m_starTracker = reinterpret_cast < StarTracker * > ( feature ) ;
m_starTracker - > setMessageQueueToGUI ( & m_inputMessageQueue ) ;
m_featureUISet - > addRollupWidget ( this ) ;
connect ( this , SIGNAL ( customContextMenuRequested ( const QPoint & ) ) , this , SLOT ( onMenuDialogCalled ( const QPoint & ) ) ) ;
connect ( getInputMessageQueue ( ) , SIGNAL ( messageEnqueued ( ) ) , this , SLOT ( handleInputMessages ( ) ) ) ;
2021-01-29 07:57:58 -05:00
connect ( & m_dlm , & HttpDownloadManager : : downloadComplete , this , & StarTrackerGUI : : downloadFinished ) ;
2021-01-13 15:51:38 -05:00
connect ( & m_statusTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( updateStatus ( ) ) ) ;
m_statusTimer . start ( 1000 ) ;
// Intialise chart
m_chart . legend ( ) - > hide ( ) ;
2021-01-29 07:57:58 -05:00
ui - > chart - > setChart ( & m_chart ) ;
ui - > chart - > setRenderHint ( QPainter : : Antialiasing ) ;
2021-01-13 15:51:38 -05:00
m_chart . addAxis ( & m_chartXAxis , Qt : : AlignBottom ) ;
m_chart . addAxis ( & m_chartYAxis , Qt : : AlignLeft ) ;
2021-01-29 07:57:58 -05:00
m_chart . layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_chart . setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
2021-02-26 15:33:39 -05:00
m_solarFluxChart . setTitle ( " " ) ;
m_solarFluxChart . legend ( ) - > hide ( ) ;
m_solarFluxChart . addAxis ( & m_chartSolarFluxXAxis , Qt : : AlignBottom ) ;
m_solarFluxChart . addAxis ( & m_chartSolarFluxYAxis , Qt : : AlignLeft ) ;
m_solarFluxChart . layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_solarFluxChart . setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
m_chartSolarFluxXAxis . setTitleText ( QString ( " Frequency (MHz) " ) ) ;
m_chartSolarFluxXAxis . setMinorTickCount ( - 1 ) ;
m_chartSolarFluxYAxis . setTitleText ( QString ( " Solar flux density (%1) " ) . arg ( solarFluxUnit ( ) ) ) ;
2021-01-29 07:57:58 -05:00
// Create axes that are static
m_skyTempGalacticLXAxis . setTitleText ( QString ( " Galactic longitude (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
m_skyTempGalacticLXAxis . setMin ( 0 ) ;
m_skyTempGalacticLXAxis . setMax ( 360 ) ;
m_skyTempGalacticLXAxis . append ( " 180 " , 0 ) ;
m_skyTempGalacticLXAxis . append ( " 90 " , 90 ) ;
m_skyTempGalacticLXAxis . append ( " 0/360 " , 180 ) ;
m_skyTempGalacticLXAxis . append ( " 270 " , 270 ) ;
//m_skyTempGalacticLXAxis.append("180", 360); // Note - labels need to be unique, so can't have 180 at start and end
m_skyTempGalacticLXAxis . setLabelsPosition ( QCategoryAxis : : AxisLabelsPositionOnValue ) ;
m_skyTempGalacticLXAxis . setGridLineVisible ( false ) ;
m_skyTempRAXAxis . setTitleText ( QString ( " Right ascension (hours) " ) ) ;
m_skyTempRAXAxis . setMin ( 0 ) ;
m_skyTempRAXAxis . setMax ( 24 ) ;
m_skyTempRAXAxis . append ( " 12 " , 0 ) ;
m_skyTempRAXAxis . append ( " 9 " , 3 ) ;
m_skyTempRAXAxis . append ( " 6 " , 6 ) ;
m_skyTempRAXAxis . append ( " 3 " , 9 ) ;
m_skyTempRAXAxis . append ( " 0 " , 12 ) ;
m_skyTempRAXAxis . append ( " 21 " , 15 ) ;
m_skyTempRAXAxis . append ( " 18 " , 18 ) ;
m_skyTempRAXAxis . append ( " 15 " , 21 ) ;
//m_skyTempRAXAxis.append("12", 24); // Note - labels need to be unique, so can't have 12 at start and end
m_skyTempRAXAxis . setLabelsPosition ( QCategoryAxis : : AxisLabelsPositionOnValue ) ;
m_skyTempRAXAxis . setGridLineVisible ( false ) ;
m_skyTempYAxis . setGridLineVisible ( false ) ;
m_skyTempYAxis . setRange ( - 90.0 , 90.0 ) ;
m_skyTempYAxis . setGridLineVisible ( false ) ;
2021-01-13 15:51:38 -05:00
ui - > dateTime - > setDateTime ( QDateTime : : currentDateTime ( ) ) ;
displaySettings ( ) ;
applySettings ( true ) ;
2021-02-26 15:33:39 -05:00
// Populate subchart menu
on_chartSelect_currentIndexChanged ( 0 ) ;
2021-01-13 15:51:38 -05: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 ( ) ;
/*
printf ( " saemundsson=[ " ) ;
for ( int i = 0 ; i < = 90 ; i + = 5 )
printf ( " %f " , Astronomy : : refractionSaemundsson ( i , m_settings . m_pressure , m_settings . m_temperature ) ) ;
printf ( " ]; \n " ) ;
printf ( " palRadio=[ " ) ;
for ( int i = 0 ; i < = 90 ; i + = 5 )
printf ( " %f " , Astronomy : : refractionPAL ( i , m_settings . m_pressure , m_settings . m_temperature , m_settings . m_humidity ,
100000000 , m_settings . m_latitude , m_settings . m_heightAboveSeaLevel ,
m_settings . m_temperatureLapseRate ) ) ;
printf ( " ]; \n " ) ;
printf ( " palLight=[ " ) ;
for ( int i = 0 ; i < = 90 ; i + = 5 )
printf ( " %f " , Astronomy : : refractionPAL ( i , m_settings . m_pressure , m_settings . m_temperature , m_settings . m_humidity ,
7.5e14 , m_settings . m_latitude , m_settings . m_heightAboveSeaLevel ,
m_settings . m_temperatureLapseRate ) ) ;
printf ( " ]; \n " ) ;
2021-01-29 07:57:58 -05:00
*/
2021-01-22 11:58:24 -05:00
m_networkManager = new QNetworkAccessManager ( ) ;
connect ( m_networkManager , SIGNAL ( finished ( QNetworkReply * ) ) , this , SLOT ( networkManagerFinished ( QNetworkReply * ) ) ) ;
2021-01-29 07:57:58 -05:00
readSolarFlux ( ) ;
connect ( & m_solarFluxTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( autoUpdateSolarFlux ( ) ) ) ;
2021-01-22 11:58:24 -05:00
m_solarFluxTimer . start ( 1000 * 60 * 60 * 24 ) ; // Update every 24hours
2021-01-29 07:57:58 -05:00
autoUpdateSolarFlux ( ) ;
2021-01-13 15:51:38 -05:00
}
StarTrackerGUI : : ~ StarTrackerGUI ( )
{
2021-01-22 11:58:24 -05:00
disconnect ( m_networkManager , SIGNAL ( finished ( QNetworkReply * ) ) , this , SLOT ( networkManagerFinished ( QNetworkReply * ) ) ) ;
delete m_networkManager ;
2021-01-13 15:51:38 -05:00
delete ui ;
}
void StarTrackerGUI : : blockApplySettings ( bool block )
{
m_doApplySettings = ! block ;
}
void StarTrackerGUI : : displaySettings ( )
{
setTitleColor ( m_settings . m_rgbColor ) ;
setWindowTitle ( m_settings . m_title ) ;
blockApplySettings ( true ) ;
2021-04-19 20:27:43 -04:00
ui - > darkTheme - > setChecked ( m_settings . m_chartsDarkTheme ) ;
m_solarFluxChart . setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
m_chart . setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
2021-01-13 15:51:38 -05:00
ui - > latitude - > setValue ( m_settings . m_latitude ) ;
ui - > longitude - > setValue ( m_settings . m_longitude ) ;
ui - > target - > setCurrentIndex ( ui - > target - > findText ( m_settings . m_target ) ) ;
if ( m_settings . m_target = = " Custom " )
{
ui - > rightAscension - > setText ( m_settings . m_ra ) ;
ui - > declination - > setText ( m_settings . m_dec ) ;
}
if ( m_settings . m_dateTime = = " " )
{
ui - > dateTimeSelect - > setCurrentIndex ( 0 ) ;
ui - > dateTime - > setVisible ( false ) ;
}
else
{
ui - > dateTime - > setDateTime ( QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ) ;
ui - > dateTime - > setVisible ( true ) ;
ui - > dateTimeSelect - > setCurrentIndex ( 1 ) ;
}
2021-01-29 07:57:58 -05:00
if ( ( m_settings . m_solarFluxData ! = StarTrackerSettings : : DRAO_2800 ) & & ! m_solarFluxesValid )
autoUpdateSolarFlux ( ) ;
ui - > frequency - > setValue ( m_settings . m_frequency / 1000000.0 ) ;
ui - > beamwidth - > setValue ( m_settings . m_beamwidth ) ;
2021-01-13 15:51:38 -05:00
updateForTarget ( ) ;
plotChart ( ) ;
blockApplySettings ( false ) ;
}
void StarTrackerGUI : : leaveEvent ( QEvent * )
{
}
void StarTrackerGUI : : enterEvent ( QEvent * )
{
}
void StarTrackerGUI : : onMenuDialogCalled ( const QPoint & p )
{
if ( m_contextMenuType = = ContextMenuChannelSettings )
{
BasicFeatureSettingsDialog dialog ( this ) ;
dialog . setTitle ( m_settings . m_title ) ;
dialog . setColor ( m_settings . m_rgbColor ) ;
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 ) ;
dialog . move ( p ) ;
dialog . exec ( ) ;
m_settings . m_rgbColor = dialog . getColor ( ) . rgb ( ) ;
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 ( ) ;
setWindowTitle ( m_settings . m_title ) ;
setTitleColor ( m_settings . m_rgbColor ) ;
applySettings ( ) ;
}
resetContextMenuType ( ) ;
}
void StarTrackerGUI : : on_startStop_toggled ( bool checked )
{
if ( m_doApplySettings )
{
StarTracker : : MsgStartStop * message = StarTracker : : MsgStartStop : : create ( checked ) ;
m_starTracker - > getInputMessageQueue ( ) - > push ( message ) ;
}
}
void StarTrackerGUI : : on_latitude_valueChanged ( double value )
{
m_settings . m_latitude = value ;
applySettings ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : on_longitude_valueChanged ( double value )
{
m_settings . m_longitude = value ;
applySettings ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : on_rightAscension_editingFinished ( )
{
m_settings . m_ra = ui - > rightAscension - > text ( ) ;
applySettings ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : on_declination_editingFinished ( )
{
m_settings . m_dec = ui - > declination - > text ( ) ;
applySettings ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : updateForTarget ( )
{
if ( m_settings . m_target = = " Sun " )
{
ui - > rightAscension - > setReadOnly ( true ) ;
ui - > declination - > setReadOnly ( true ) ;
ui - > rightAscension - > setText ( " " ) ;
ui - > declination - > setText ( " " ) ;
}
else if ( m_settings . m_target = = " Moon " )
{
ui - > rightAscension - > setReadOnly ( true ) ;
ui - > declination - > setReadOnly ( true ) ;
ui - > rightAscension - > setText ( " " ) ;
ui - > declination - > setText ( " " ) ;
}
else if ( m_settings . m_target = = " Custom " )
{
ui - > rightAscension - > setReadOnly ( false ) ;
ui - > declination - > setReadOnly ( false ) ;
}
else
{
ui - > rightAscension - > setReadOnly ( true ) ;
ui - > declination - > setReadOnly ( true ) ;
if ( m_settings . m_target = = " PSR B0329+54 " )
{
ui - > rightAscension - > setText ( " 03h32m59.35s " ) ;
ui - > declination - > setText ( QString ( " 54%0134'45.05 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " PSR B0833-45 " )
{
ui - > rightAscension - > setText ( " 08h35m20.66s " ) ;
ui - > declination - > setText ( QString ( " -45%0110'35.15 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " Sagittarius A " )
{
ui - > rightAscension - > setText ( " 17h45m40.04s " ) ;
ui - > declination - > setText ( QString ( " -29%0100'28.17 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " Cassiopeia A " )
{
ui - > rightAscension - > setText ( " 23h23m24s " ) ;
ui - > declination - > setText ( QString ( " 58%0148'54 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " Cygnus A " )
{
ui - > rightAscension - > setText ( " 19h59m28.36s " ) ;
ui - > declination - > setText ( QString ( " 40%0144'02.1 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " Taurus A (M1) " )
{
ui - > rightAscension - > setText ( " 05h34m31.94s " ) ;
ui - > declination - > setText ( QString ( " 22%0100'52.2 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
else if ( m_settings . m_target = = " Virgo A (M87) " )
{
ui - > rightAscension - > setText ( " 12h30m49.42s " ) ;
ui - > declination - > setText ( QString ( " 12%0123'28.04 \" " ) . arg ( QChar ( 0xb0 ) ) ) ;
}
on_rightAscension_editingFinished ( ) ;
on_declination_editingFinished ( ) ;
}
// Clear as no longer valid when target has changed
ui - > azimuth - > setText ( " " ) ;
ui - > elevation - > setText ( " " ) ;
}
void StarTrackerGUI : : on_target_currentTextChanged ( const QString & text )
{
m_settings . m_target = text ;
applySettings ( ) ;
updateForTarget ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : updateLST ( )
{
QDateTime dt ;
if ( m_settings . m_dateTime . isEmpty ( ) )
dt = QDateTime : : currentDateTime ( ) ;
else
dt = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
double lst = Astronomy : : localSiderealTime ( dt , m_settings . m_longitude ) ;
ui - > lst - > setText ( Units : : decimalHoursToHoursMinutesAndSeconds ( lst / 15.0 , 0 ) ) ;
}
void StarTrackerGUI : : updateStatus ( )
{
int state = m_starTracker - > 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_starTracker - > getErrorMessage ( ) ) ;
break ;
default :
break ;
}
m_lastFeatureState = state ;
}
updateLST ( ) ;
}
void StarTrackerGUI : : applySettings ( bool force )
{
if ( m_doApplySettings )
{
StarTracker : : MsgConfigureStarTracker * message = StarTracker : : MsgConfigureStarTracker : : create ( m_settings , force ) ;
m_starTracker - > getInputMessageQueue ( ) - > push ( message ) ;
}
}
void StarTrackerGUI : : on_useMyPosition_clicked ( bool checked )
{
2021-01-13 18:03:55 -05:00
( void ) checked ;
2021-01-13 15:51:38 -05:00
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 ;
applySettings ( ) ;
plotChart ( ) ;
}
// Show settings dialog
void StarTrackerGUI : : on_displaySettings_clicked ( )
{
StarTrackerSettingsDialog dialog ( & m_settings ) ;
if ( dialog . exec ( ) = = QDialog : : Accepted )
{
applySettings ( ) ;
2021-01-22 11:58:24 -05:00
displaySolarFlux ( ) ;
2021-01-29 07:57:58 -05:00
if ( ui - > chartSelect - > currentIndex ( ) = = 1 )
plotChart ( ) ;
2021-01-13 15:51:38 -05:00
}
}
void StarTrackerGUI : : on_dateTimeSelect_currentTextChanged ( const QString & text )
{
if ( text = = " Now " )
{
m_settings . m_dateTime = " " ;
ui - > dateTime - > setVisible ( false ) ;
}
else
{
m_settings . m_dateTime = ui - > dateTime - > dateTime ( ) . toString ( Qt : : ISODateWithMs ) ;
ui - > dateTime - > setVisible ( true ) ;
}
applySettings ( ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : on_dateTime_dateTimeChanged ( const QDateTime & datetime )
{
2021-01-13 18:03:55 -05:00
( void ) datetime ;
2021-01-13 15:51:38 -05:00
if ( ui - > dateTimeSelect - > currentIndex ( ) = = 1 )
{
m_settings . m_dateTime = ui - > dateTime - > dateTime ( ) . toString ( Qt : : ISODateWithMs ) ;
applySettings ( ) ;
plotChart ( ) ;
}
}
void StarTrackerGUI : : plotChart ( )
2021-01-29 07:57:58 -05:00
{
if ( ui - > chartSelect - > currentIndex ( ) = = 0 )
2021-02-26 15:33:39 -05:00
{
if ( ui - > chartSubSelect - > currentIndex ( ) = = 0 )
plotElevationLineChart ( ) ;
else
plotElevationPolarChart ( ) ;
}
2021-01-29 07:57:58 -05:00
else if ( ui - > chartSelect - > currentIndex ( ) = = 1 )
plotSolarFluxChart ( ) ;
else if ( ui - > chartSelect - > currentIndex ( ) = = 2 )
plotSkyTemperatureChart ( ) ;
}
void StarTrackerGUI : : raDecChanged ( )
{
if ( ui - > chartSelect - > currentIndex ( ) = = 2 )
plotSkyTemperatureChart ( ) ;
}
void StarTrackerGUI : : on_frequency_valueChanged ( int value )
{
m_settings . m_frequency = value * 1000000.0 ;
applySettings ( ) ;
if ( ui - > chartSelect - > currentIndex ( ) ! = 0 )
{
updateChartSubSelect ( ) ;
plotChart ( ) ;
}
displaySolarFlux ( ) ;
}
void StarTrackerGUI : : on_beamwidth_valueChanged ( double value )
{
m_settings . m_beamwidth = value ;
applySettings ( ) ;
updateChartSubSelect ( ) ;
if ( ui - > chartSelect - > currentIndex ( ) = = 2 )
plotChart ( ) ;
}
void StarTrackerGUI : : plotSolarFluxChart ( )
2021-01-13 15:51:38 -05:00
{
2021-02-26 15:33:39 -05:00
m_solarFluxChart . removeAllSeries ( ) ;
2021-01-29 07:57:58 -05:00
if ( m_solarFluxesValid )
{
double maxValue = - std : : numeric_limits < double > : : infinity ( ) ;
double minValue = std : : numeric_limits < double > : : infinity ( ) ;
QLineSeries * series = new QLineSeries ( ) ;
for ( int i = 0 ; i < 8 ; i + + )
{
double value = convertSolarFluxUnits ( m_solarFluxes [ i ] ) ;
series - > append ( m_solarFluxFrequencies [ i ] , value ) ;
maxValue = std : : max ( value , maxValue ) ;
minValue = std : : min ( value , minValue ) ;
}
series - > setPointLabelsVisible ( true ) ;
series - > setPointLabelsFormat ( " @yPoint " ) ;
series - > setPointLabelsClipping ( false ) ;
2021-02-26 15:33:39 -05:00
m_solarFluxChart . addSeries ( series ) ;
2021-01-29 07:57:58 -05:00
series - > attachAxis ( & m_chartSolarFluxXAxis ) ;
2021-02-26 15:33:39 -05:00
series - > attachAxis ( & m_chartSolarFluxYAxis ) ;
2021-01-29 07:57:58 -05:00
if ( m_settings . m_solarFluxUnits = = StarTrackerSettings : : SFU )
{
2021-02-26 15:33:39 -05:00
m_chartSolarFluxYAxis . setLabelFormat ( " %d " ) ;
m_chartSolarFluxYAxis . setRange ( 0.0 , ( ( ( ( int ) maxValue ) + 99 ) / 100 ) * 100 ) ;
2021-01-29 07:57:58 -05:00
}
else if ( m_settings . m_solarFluxUnits = = StarTrackerSettings : : JANSKY )
{
2021-02-26 15:33:39 -05:00
m_chartSolarFluxYAxis . setLabelFormat ( " %.2g " ) ;
m_chartSolarFluxYAxis . setRange ( 0 , ( ( ( ( int ) maxValue ) + 999999 ) / 100000 ) * 100000 ) ;
2021-01-29 07:57:58 -05:00
}
else
{
2021-02-26 15:33:39 -05:00
m_chartSolarFluxYAxis . setLabelFormat ( " %.2g " ) ;
m_chartSolarFluxYAxis . setRange ( minValue , maxValue ) ;
2021-01-29 07:57:58 -05:00
}
}
else
2021-02-26 15:33:39 -05:00
m_solarFluxChart . setTitle ( " Press download Solar flux density data to view " ) ;
ui - > chart - > setChart ( & m_solarFluxChart ) ;
// m_chart.setPlotAreaBackgroundVisible(false);
// disconnect(&m_chart, SIGNAL(plotAreaChanged(QRectF)), this, SLOT(plotAreaChanged(QRectF)));
2021-01-29 07:57:58 -05:00
}
void StarTrackerGUI : : plotSkyTemperatureChart ( )
{
bool galactic = ( ui - > chartSubSelect - > currentIndex ( ) & 1 ) = = 1 ;
m_chart . removeAllSeries ( ) ;
removeAllAxes ( ) ;
QScatterSeries * series = new QScatterSeries ( ) ;
float ra = Astronomy : : raToDecimal ( m_settings . m_ra ) ;
float dec = Astronomy : : decToDecimal ( m_settings . m_dec ) ;
double beamWidth = m_settings . m_beamwidth ;
// Ellipse not supported, so draw circle on shorter axis
double degPerPixelW = 360.0 / m_chart . plotArea ( ) . width ( ) ;
double degPerPixelH = 180.0 / m_chart . plotArea ( ) . height ( ) ;
double degPerPixel = std : : min ( degPerPixelW , degPerPixelH ) ;
double markerSize ;
if ( galactic )
{
// Convert to category coordinates
double l , b ;
Astronomy : : equatorialToGalactic ( ra , dec , l , b ) ;
// Map to linear axis
double lAxis ;
if ( l < 180.0 )
lAxis = 180.0 - l ;
else
lAxis = 360.0 - l + 180.0 ;
series - > append ( lAxis , b ) ;
}
else
{
// Map to category axis
double raAxis ;
if ( ra < = 12.0 )
raAxis = 12.0 - ra ;
else
raAxis = 24 - ra + 12 ;
series - > append ( raAxis , dec ) ;
}
// Get temperature
int idx = ui - > chartSubSelect - > currentIndex ( ) ;
if ( ( idx = = 6 ) | | ( idx = = 7 ) )
{
// Adjust temperature from 408MHz FITS file, taking in to account
// observation frequency and beamwidth
FITS * fits = & m_temps [ 1 ] ;
if ( fits - > valid ( ) )
{
const double beamwidth = m_settings . m_beamwidth ;
const double halfBeamwidth = beamwidth / 2.0 ;
// Use cos^p(x) for approximation of radiation pattern
// (Essentially the same as Gaussian of exp(-4*ln(theta^2/beamwidth^2))
// (See a2 in https://arxiv.org/pdf/1812.10084.pdf for Elliptical equivalent))
// We have gain of 0dB (1) at 0 degrees, and -3dB (~0.5) at half-beamwidth degrees
// Find exponent that correponds to -3dB at that angle
double minus3dBLinear = pow ( 10.0 , - 3.0 / 10.0 ) ;
double p = log ( minus3dBLinear ) / log ( cos ( Units : : degreesToRadians ( halfBeamwidth ) ) ) ;
// Create an matrix with gain as a function of angle
double degreesPerPixelH = abs ( fits - > degreesPerPixelH ( ) ) ;
double degreesPerPixelV = abs ( fits - > degreesPerPixelV ( ) ) ;
int numberOfCoeffsH = ceil ( beamwidth / degreesPerPixelH ) ;
int numberOfCoeffsV = ceil ( beamwidth / degreesPerPixelV ) ;
if ( ( numberOfCoeffsH & 1 ) = = 0 )
numberOfCoeffsH + + ;
if ( ( numberOfCoeffsV & 1 ) = = 0 )
numberOfCoeffsV + + ;
double * beam = new double [ numberOfCoeffsH * numberOfCoeffsV ] ;
double sum = 0.0 ;
int y0 = numberOfCoeffsV / 2 ;
int x0 = numberOfCoeffsH / 2 ;
int nonZeroCount = 0 ;
for ( int y = 0 ; y < numberOfCoeffsV ; y + + )
{
for ( int x = 0 ; x < numberOfCoeffsH ; x + + )
{
double xp = ( x - x0 ) * degreesPerPixelH ;
double yp = ( y - y0 ) * degreesPerPixelV ;
double r = sqrt ( xp * xp + yp * yp ) ;
if ( r < halfBeamwidth )
{
beam [ y * numberOfCoeffsH + x ] = pow ( cos ( Units : : degreesToRadians ( r ) ) , p ) ;
sum + = beam [ y * numberOfCoeffsH + x ] ;
nonZeroCount + + ;
}
else
beam [ y * numberOfCoeffsH + x ] = 0.0 ;
}
}
// Get centre pixel coordinates
double centreX ;
if ( ra < = 12.0 )
centreX = ( 12.0 - ra ) / 24.0 ;
else
centreX = ( 24 - ra + 12 ) / 24.0 ;
double centreY = ( 90.0 - dec ) / 180.0 ;
int imgX = centreX * fits - > width ( ) ;
int imgY = centreY * fits - > height ( ) ;
// Apply weighting to temperature data
double weightedSum = 0.0 ;
for ( int y = 0 ; y < numberOfCoeffsV ; y + + )
{
for ( int x = 0 ; x < numberOfCoeffsH ; x + + )
{
weightedSum + = beam [ y * numberOfCoeffsH + x ] * fits - > scaledWrappedValue ( imgX + ( x - x0 ) , imgY + ( y - y0 ) ) ;
}
}
// From: https://www.cv.nrao.edu/~sransom/web/Ch3.html
// The antenna temperature equals the source brightness temperature multiplied by the fraction of the beam solid angle filled by the source
// So we scale the sum by the total number of non-zero pixels (i.e. beam area)
// If we compare to some maps with different beamwidths here: https://www.cv.nrao.edu/~demerson/radiosky/sky_jun96.pdf
// The values we've computed are a bit higher..
double temp408 = weightedSum / nonZeroCount ;
// Scale according to frequency - CMB contribution constant
// Power law at low frequencies, with slight variation in spectral index
// See:
// Global Sky Model: https://ascl.net/1011.010
// An improved Model of Diffuse Galactic Radio Emission: https://arxiv.org/pdf/1605.04920.pdf
// A high-resolution self-consistent whole sky foreground model: https://arxiv.org/abs/1812.10084
// (De-striping:) Full sky study of diffuse Galactic emission at decimeter wavelength https://www.aanda.org/articles/aa/pdf/2003/42/aah4363.pdf
// Data here: http://cdsarc.u-strasbg.fr/viz-bin/cat/J/A+A/410/847
// LFmap: https://www.faculty.ece.vt.edu/swe/lwa/memo/lwa0111.pdf
double iso408 = 50 * pow ( 150e6 / 408e6 , 2.75 ) ; // Extra-galactic isotropic in reference map at 408MHz
double isoT = 50 * pow ( 150e6 / m_settings . m_frequency , 2.75 ) ; // Extra-galactic isotropic at target frequency
double cmbT = 2.725 ; // Cosmic microwave backgroud;
double spectralIndex ;
if ( m_spectralIndex . valid ( ) )
{
// See https://www.aanda.org/articles/aa/pdf/2003/42/aah4363.pdf
spectralIndex = m_spectralIndex . scaledValue ( imgX , imgY ) ;
}
else
{
// See https://arxiv.org/abs/1812.10084 fig 2
if ( m_settings . m_frequency < 200e6 )
spectralIndex = 2.55 ;
else if ( m_settings . m_frequency < 20e9 )
spectralIndex = 2.695 ;
else
spectralIndex = 3.1 ;
}
double galactic480 = temp408 - cmbT - iso408 ;
double galacticT = galactic480 * pow ( 408e6 / m_settings . m_frequency , spectralIndex ) ; // Scale galactic contribution by frequency
double temp = galacticT + cmbT + isoT ; // Final temperature
series - > setPointLabelsVisible ( true ) ;
series - > setPointLabelsColor ( Qt : : red ) ;
series - > setPointLabelsFormat ( QString ( " %1 K " ) . arg ( std : : round ( temp ) ) ) ;
// Scale marker size by beamwidth
markerSize = std : : max ( ( int ) round ( beamWidth * degPerPixel ) , 5 ) ;
}
else
qDebug ( ) < < " StarTrackerGUI::plotSkyTemperatureChart: FITS temperature file not valid " ;
}
else
{
// Read temperature from selected FITS file at target RA/Dec
QImage * img = & m_images [ idx ] ;
FITS * fits = & m_temps [ idx / 2 ] ;
double x ;
if ( ra < = 12.0 )
x = ( 12.0 - ra ) / 24.0 ;
else
x = ( 24 - ra + 12 ) / 24.0 ;
int imgX = x * img - > width ( ) ;
if ( imgX > = img - > width ( ) )
imgX = img - > width ( ) ;
int imgY = ( 90.0 - dec ) / 180.0 * img - > height ( ) ;
if ( imgY > = img - > height ( ) )
imgY = img - > height ( ) ;
if ( fits - > valid ( ) )
{
double temp = fits - > scaledValue ( imgX , imgY ) ;
series - > setPointLabelsVisible ( true ) ;
series - > setPointLabelsColor ( Qt : : red ) ;
series - > setPointLabelsFormat ( QString ( " %1 K " ) . arg ( std : : round ( temp ) ) ) ;
}
// Temperature from just one pixel, but need to make marker visbile
markerSize = 5 ;
}
series - > setMarkerSize ( markerSize ) ;
m_chart . setTitle ( " " ) ;
m_chart . addSeries ( series ) ;
if ( galactic )
{
m_chart . addAxis ( & m_skyTempGalacticLXAxis , Qt : : AlignBottom ) ;
series - > attachAxis ( & m_skyTempGalacticLXAxis ) ;
m_skyTempYAxis . setTitleText ( QString ( " Galactic latitude (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
m_chart . addAxis ( & m_skyTempYAxis , Qt : : AlignLeft ) ;
series - > attachAxis ( & m_skyTempYAxis ) ;
}
else
{
m_chart . addAxis ( & m_skyTempRAXAxis , Qt : : AlignBottom ) ;
series - > attachAxis ( & m_skyTempRAXAxis ) ;
m_skyTempYAxis . setTitleText ( QString ( " Declination (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
m_chart . addAxis ( & m_skyTempYAxis , Qt : : AlignLeft ) ;
series - > attachAxis ( & m_skyTempYAxis ) ;
}
2021-02-26 15:33:39 -05:00
ui - > chart - > setChart ( & m_chart ) ;
2021-01-29 07:57:58 -05:00
plotAreaChanged ( m_chart . plotArea ( ) ) ;
connect ( & m_chart , SIGNAL ( plotAreaChanged ( QRectF ) ) , this , SLOT ( plotAreaChanged ( QRectF ) ) ) ;
}
void StarTrackerGUI : : plotAreaChanged ( const QRectF & plotArea )
{
2021-01-29 12:00:56 -05:00
int width = static_cast < int > ( plotArea . width ( ) ) ;
int height = static_cast < int > ( plotArea . height ( ) ) ;
2021-01-29 07:57:58 -05:00
int viewW = static_cast < int > ( ui - > chart - > width ( ) ) ;
int viewH = static_cast < int > ( ui - > chart - > height ( ) ) ;
// Scale the image to fit plot area
int imageIdx = ui - > chartSubSelect - > currentIndex ( ) ;
if ( imageIdx = = 6 )
imageIdx = 2 ;
else if ( imageIdx = = 7 )
imageIdx = 3 ;
QImage image = m_images [ imageIdx ] . scaled ( QSize ( width , height ) , Qt : : IgnoreAspectRatio ) ;
QImage translated ( viewW , viewH , QImage : : Format_ARGB32 ) ;
translated . fill ( Qt : : white ) ;
QPainter painter ( & translated ) ;
2021-01-29 12:00:56 -05:00
painter . drawImage ( plotArea . topLeft ( ) , image ) ;
2021-01-29 07:57:58 -05:00
m_chart . setPlotAreaBackgroundBrush ( translated ) ;
m_chart . setPlotAreaBackgroundVisible ( true ) ;
}
void StarTrackerGUI : : removeAllAxes ( )
{
QList < QAbstractAxis * > axes ;
axes = m_chart . axes ( Qt : : Horizontal ) ;
for ( QAbstractAxis * axis : axes )
m_chart . removeAxis ( axis ) ;
axes = m_chart . axes ( Qt : : Vertical ) ;
for ( QAbstractAxis * axis : axes )
m_chart . removeAxis ( axis ) ;
}
// Plot target elevation angle over the day
2021-02-26 15:33:39 -05:00
void StarTrackerGUI : : plotElevationLineChart ( )
2021-01-29 07:57:58 -05:00
{
2021-02-26 15:33:39 -05:00
QChart * oldChart = m_azElLineChart ;
m_azElLineChart = new QChart ( ) ;
2021-04-19 20:27:43 -04:00
m_azElLineChart - > setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
2021-02-26 15:33:39 -05:00
QDateTimeAxis * xAxis = new QDateTimeAxis ( ) ;
QValueAxis * yLeftAxis = new QValueAxis ( ) ;
QValueAxis * yRightAxis = new QValueAxis ( ) ;
m_azElLineChart - > legend ( ) - > hide ( ) ;
m_azElLineChart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_azElLineChart - > setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
2021-01-29 07:57:58 -05:00
2021-01-13 15:51:38 -05:00
double maxElevation = - 90.0 ;
2021-02-26 15:33:39 -05:00
QLineSeries * elSeries = new QLineSeries ( ) ;
QList < QLineSeries * > azSeriesList ;
QLineSeries * azSeries = new QLineSeries ( ) ;
azSeriesList . append ( azSeries ) ;
QPen pen ( QColor ( 153 , 202 , 83 ) , 2 , Qt : : SolidLine ) ;
azSeries - > setPen ( pen ) ;
2021-01-13 15:51:38 -05:00
QDateTime dt ;
if ( m_settings . m_dateTime . isEmpty ( ) )
dt = QDateTime : : currentDateTime ( ) ;
else
dt = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
dt . setTime ( QTime ( 0 , 0 ) ) ;
QDateTime startTime = dt ;
QDateTime endTime = dt ;
2021-02-26 15:33:39 -05:00
double prevAz ;
int timestep = 10 * 60 ;
for ( int step = 0 ; step < = 24 * 60 * 60 / timestep ; step + + )
2021-01-13 15:51:38 -05:00
{
AzAlt aa ;
RADec rd ;
// Calculate elevation of desired object
if ( m_settings . m_target = = " Sun " )
Astronomy : : sunPosition ( aa , rd , m_settings . m_latitude , m_settings . m_longitude , dt ) ;
else if ( m_settings . m_target = = " Moon " )
Astronomy : : moonPosition ( aa , rd , m_settings . m_latitude , m_settings . m_longitude , dt ) ;
else
{
rd . ra = Astronomy : : raToDecimal ( m_settings . m_ra ) ;
rd . dec = Astronomy : : decToDecimal ( m_settings . m_dec ) ;
aa = Astronomy : : raDecToAzAlt ( rd , m_settings . m_latitude , m_settings . m_longitude , dt , ! m_settings . m_jnow ) ;
}
if ( aa . alt > maxElevation )
maxElevation = aa . alt ;
// Adjust for refraction
if ( m_settings . m_refraction = = " Positional Astronomy Library " )
{
aa . alt + = Astronomy : : refractionPAL ( aa . alt , m_settings . m_pressure , m_settings . m_temperature , m_settings . m_humidity ,
m_settings . m_frequency , m_settings . m_latitude , m_settings . m_heightAboveSeaLevel ,
m_settings . m_temperatureLapseRate ) ;
if ( aa . alt > 90.0 )
aa . alt = 90.0f ;
}
else if ( m_settings . m_refraction = = " Saemundsson " )
{
aa . alt + = Astronomy : : refractionSaemundsson ( aa . alt , m_settings . m_pressure , m_settings . m_temperature ) ;
if ( aa . alt > 90.0 )
aa . alt = 90.0f ;
}
2021-02-26 15:33:39 -05:00
if ( step = = 0 )
prevAz = aa . az ;
if ( ( ( prevAz > = 270 ) & & ( aa . az < 90 ) ) | | ( ( prevAz < 90 ) & & ( aa . az > = 270 ) ) )
{
azSeries = new QLineSeries ( ) ;
azSeriesList . append ( azSeries ) ;
azSeries - > setPen ( pen ) ;
}
elSeries - > append ( dt . toMSecsSinceEpoch ( ) , aa . alt ) ;
azSeries - > append ( dt . toMSecsSinceEpoch ( ) , aa . az ) ;
2021-01-13 15:51:38 -05:00
endTime = dt ;
2021-02-26 15:33:39 -05:00
prevAz = aa . az ;
dt = dt . addSecs ( timestep ) ; // addSecs accounts for daylight savings jumps
}
m_azElLineChart - > addAxis ( xAxis , Qt : : AlignBottom ) ;
m_azElLineChart - > addAxis ( yLeftAxis , Qt : : AlignLeft ) ;
m_azElLineChart - > addAxis ( yRightAxis , Qt : : AlignRight ) ;
m_azElLineChart - > addSeries ( elSeries ) ;
for ( int i = 0 ; i < azSeriesList . size ( ) ; i + + )
{
m_azElLineChart - > addSeries ( azSeriesList [ i ] ) ;
azSeriesList [ i ] - > attachAxis ( xAxis ) ;
azSeriesList [ i ] - > attachAxis ( yRightAxis ) ;
2021-01-13 15:51:38 -05:00
}
2021-02-26 15:33:39 -05:00
elSeries - > attachAxis ( xAxis ) ;
elSeries - > attachAxis ( yLeftAxis ) ;
xAxis - > setTitleText ( QString ( " %1 %2 " ) . arg ( startTime . date ( ) . toString ( ) ) . arg ( startTime . timeZoneAbbreviation ( ) ) ) ;
xAxis - > setFormat ( " hh " ) ;
xAxis - > setTickCount ( 7 ) ;
xAxis - > setRange ( startTime , endTime ) ;
yLeftAxis - > setRange ( 0.0 , 90.0 ) ;
yLeftAxis - > setTitleText ( QString ( " Elevation (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
yRightAxis - > setRange ( 0.0 , 360.0 ) ;
yRightAxis - > setTitleText ( QString ( " Azimuth (%1) " ) . arg ( QChar ( 0xb0 ) ) ) ;
2021-01-13 15:51:38 -05:00
if ( maxElevation < 0 )
2021-02-26 15:33:39 -05:00
m_azElLineChart - > setTitle ( " Not visible from this latitude " ) ;
2021-01-13 15:51:38 -05:00
else
2021-02-26 15:33:39 -05:00
m_azElLineChart - > setTitle ( " " ) ;
ui - > chart - > setChart ( m_azElLineChart ) ;
delete oldChart ;
}
// Plot target elevation angle over the day
void StarTrackerGUI : : plotElevationPolarChart ( )
{
QChart * oldChart = m_azElPolarChart ;
m_azElPolarChart = new QPolarChart ( ) ;
2021-04-19 20:27:43 -04:00
m_azElPolarChart - > setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
2021-02-26 15:33:39 -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_azElPolarChart - > addAxis ( angularAxis , QPolarChart : : PolarOrientationAngular ) ;
m_azElPolarChart - > addAxis ( radialAxis , QPolarChart : : PolarOrientationRadial ) ;
m_azElPolarChart - > legend ( ) - > hide ( ) ;
m_azElPolarChart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
m_azElPolarChart - > setMargins ( QMargins ( 1 , 1 , 1 , 1 ) ) ;
double maxElevation = - 90.0 ;
QLineSeries * polarSeries = new QLineSeries ( ) ;
QDateTime dt ;
if ( m_settings . m_dateTime . isEmpty ( ) )
dt = QDateTime : : currentDateTime ( ) ;
else
dt = QDateTime : : fromString ( m_settings . m_dateTime , Qt : : ISODateWithMs ) ;
dt . setTime ( QTime ( 0 , 0 ) ) ;
QDateTime startTime = dt ;
QDateTime endTime = dt ;
QDateTime riseTime ;
QDateTime setTime ;
int riseIdx = - 1 ;
int setIdx = - 1 ;
int idx = 0 ;
int timestep = 10 * 60 ; // Rise/set times accurate to nearest 10 minutes
double prevAlt ;
for ( int step = 0 ; step < = 24 * 60 * 60 / timestep ; step + + )
{
AzAlt aa ;
RADec rd ;
// Calculate elevation of desired object
if ( m_settings . m_target = = " Sun " )
Astronomy : : sunPosition ( aa , rd , m_settings . m_latitude , m_settings . m_longitude , dt ) ;
else if ( m_settings . m_target = = " Moon " )
Astronomy : : moonPosition ( aa , rd , m_settings . m_latitude , m_settings . m_longitude , dt ) ;
else
{
rd . ra = Astronomy : : raToDecimal ( m_settings . m_ra ) ;
rd . dec = Astronomy : : decToDecimal ( m_settings . m_dec ) ;
aa = Astronomy : : raDecToAzAlt ( rd , m_settings . m_latitude , m_settings . m_longitude , dt , ! m_settings . m_jnow ) ;
}
if ( aa . alt > maxElevation )
maxElevation = aa . alt ;
// Adjust for refraction
if ( m_settings . m_refraction = = " Positional Astronomy Library " )
{
aa . alt + = Astronomy : : refractionPAL ( aa . alt , m_settings . m_pressure , m_settings . m_temperature , m_settings . m_humidity ,
m_settings . m_frequency , m_settings . m_latitude , m_settings . m_heightAboveSeaLevel ,
m_settings . m_temperatureLapseRate ) ;
if ( aa . alt > 90.0 )
aa . alt = 90.0f ;
}
else if ( m_settings . m_refraction = = " Saemundsson " )
{
aa . alt + = Astronomy : : refractionSaemundsson ( aa . alt , m_settings . m_pressure , m_settings . m_temperature ) ;
if ( aa . alt > 90.0 )
aa . alt = 90.0f ;
}
if ( idx = = 0 )
prevAlt = aa . alt ;
// We can have set before rise in a day, if the object starts > 0
if ( ( aa . alt > = 0.0 ) & & ( prevAlt < 0.0 ) )
{
riseTime = dt ;
riseIdx = idx ;
}
if ( ( aa . alt < 0.0 ) & & ( prevAlt > = 0.0 ) )
{
setTime = endTime ;
setIdx = idx ;
}
polarSeries - > append ( aa . az , 90 - aa . alt ) ;
idx + + ;
endTime = dt ;
prevAlt = aa . alt ;
dt = dt . addSecs ( timestep ) ; // addSecs accounts for daylight savings jumps
}
// 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 ( ) ;
for ( int i = 1 ; i < polarSeries - > count ( ) ; i + + )
{
qreal az = polarSeries - > at ( i ) . x ( ) ;
qreal el = polarSeries - > at ( i ) . y ( ) ;
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
s - > append ( polarSeries - > at ( i ) ) ;
prevAz = az ;
prevEl = el ;
}
for ( int i = 0 ; i < series . length ( ) ; i + + )
{
m_azElPolarChart - > addSeries ( series [ i ] ) ;
series [ i ] - > attachAxis ( angularAxis ) ;
series [ i ] - > attachAxis ( radialAxis ) ;
}
// Create series with single point, so we can plot time of rising
if ( riseTime . isValid ( ) )
{
QLineSeries * riseSeries = new QLineSeries ( ) ;
riseSeries - > append ( polarSeries - > at ( riseIdx ) ) ;
riseSeries - > setPointLabelsFormat ( QString ( " Rise %1 " ) . arg ( riseTime . time ( ) . toString ( " hh:mm " ) ) ) ;
riseSeries - > setPointLabelsVisible ( true ) ;
riseSeries - > setPointLabelsClipping ( false ) ;
m_azElPolarChart - > addSeries ( riseSeries ) ;
riseSeries - > attachAxis ( angularAxis ) ;
riseSeries - > attachAxis ( radialAxis ) ;
}
// Create series with single point, so we can plot time of setting
if ( setTime . isValid ( ) )
{
QLineSeries * setSeries = new QLineSeries ( ) ;
setSeries - > append ( polarSeries - > at ( setIdx ) ) ;
setSeries - > setPointLabelsFormat ( QString ( " Set %1 " ) . arg ( setTime . time ( ) . toString ( " hh:mm " ) ) ) ;
setSeries - > setPointLabelsVisible ( true ) ;
setSeries - > setPointLabelsClipping ( false ) ;
m_azElPolarChart - > addSeries ( setSeries ) ;
setSeries - > attachAxis ( angularAxis ) ;
setSeries - > attachAxis ( radialAxis ) ;
}
if ( maxElevation < 0 )
m_azElPolarChart - > setTitle ( " Not visible from this latitude " ) ;
else
m_azElPolarChart - > setTitle ( " " ) ;
ui - > chart - > setChart ( m_azElPolarChart ) ;
delete polarSeries ;
delete oldChart ;
2021-01-13 15:51:38 -05:00
}
// Find target on the Map
void StarTrackerGUI : : on_viewOnMap_clicked ( )
{
QString target = m_settings . m_target = = " Sun " | | m_settings . m_target = = " Moon " ? m_settings . m_target : " Star " ;
FeatureWebAPIUtils : : mapFind ( target ) ;
}
2021-01-22 11:58:24 -05:00
2021-01-29 07:57:58 -05:00
void StarTrackerGUI : : updateChartSubSelect ( )
{
if ( ui - > chartSelect - > currentIndex ( ) = = 2 )
{
ui - > chartSubSelect - > setItemText ( 6 , QString ( " %1 MHz %2%3 Equatorial " )
. arg ( ( int ) std : : round ( m_settings . m_frequency / 1e6 ) )
. arg ( ( int ) std : : round ( m_settings . m_beamwidth ) )
. arg ( QChar ( 0xb0 ) ) ) ;
ui - > chartSubSelect - > setItemText ( 7 , QString ( " %1 MHz %2%3 Galactic " )
. arg ( ( int ) std : : round ( m_settings . m_frequency / 1e6 ) )
. arg ( ( int ) std : : round ( m_settings . m_beamwidth ) )
. arg ( QChar ( 0xb0 ) ) ) ;
}
}
void StarTrackerGUI : : on_chartSelect_currentIndexChanged ( int index )
{
bool oldState = ui - > chartSubSelect - > blockSignals ( true ) ;
ui - > chartSubSelect - > clear ( ) ;
2021-02-26 15:33:39 -05:00
if ( index = = 0 )
{
ui - > chartSubSelect - > addItem ( " Az/El vs time " ) ;
ui - > chartSubSelect - > addItem ( " Polar " ) ;
}
else if ( index = = 2 )
2021-01-29 07:57:58 -05:00
{
ui - > chartSubSelect - > addItem ( QString ( " 150 MHz 5%1 Equatorial " ) . arg ( QChar ( 0xb0 ) ) ) ;
ui - > chartSubSelect - > addItem ( QString ( " 150 MHz 5%1 Galactic " ) . arg ( QChar ( 0xb0 ) ) ) ;
ui - > chartSubSelect - > addItem ( " 408 MHz 51' Equatorial " ) ;
ui - > chartSubSelect - > addItem ( " 408 MHz 51' Galactic " ) ;
ui - > chartSubSelect - > addItem ( " 1420 MHz 35' Equatorial " ) ;
ui - > chartSubSelect - > addItem ( " 1420 MHz 35' Galactic " ) ;
ui - > chartSubSelect - > addItem ( " Custom Equatorial " ) ;
ui - > chartSubSelect - > addItem ( " Custom Galactic " ) ;
ui - > chartSubSelect - > setCurrentIndex ( 2 ) ;
updateChartSubSelect ( ) ;
}
ui - > chartSubSelect - > blockSignals ( oldState ) ;
plotChart ( ) ;
}
void StarTrackerGUI : : on_chartSubSelect_currentIndexChanged ( int index )
{
2021-01-29 12:00:56 -05:00
( void ) index ;
2021-01-29 07:57:58 -05:00
plotChart ( ) ;
}
double StarTrackerGUI : : convertSolarFluxUnits ( double sfu )
{
switch ( m_settings . m_solarFluxUnits )
{
case StarTrackerSettings : : SFU :
return sfu ;
case StarTrackerSettings : : JANSKY :
return Units : : solarFluxUnitsToJansky ( sfu ) ;
case StarTrackerSettings : : WATTS_M_HZ :
return Units : : solarFluxUnitsToWattsPerMetrePerHertz ( sfu ) ;
}
return 0.0 ;
}
QString StarTrackerGUI : : solarFluxUnit ( )
{
switch ( m_settings . m_solarFluxUnits )
{
case StarTrackerSettings : : SFU :
return " sfu " ;
case StarTrackerSettings : : JANSKY :
return " Jy " ;
case StarTrackerSettings : : WATTS_M_HZ :
return " Wm^-2Hz^-1 " ;
}
return " " ;
}
2021-01-22 11:58:24 -05:00
void StarTrackerGUI : : displaySolarFlux ( )
{
2021-01-29 07:57:58 -05:00
if ( ( ( m_settings . m_solarFluxData = = StarTrackerSettings : : DRAO_2800 ) & & ( m_solarFlux = = 0.0 ) )
| | ( ( m_settings . m_solarFluxData ! = StarTrackerSettings : : DRAO_2800 ) & & ! m_solarFluxesValid ) )
2021-01-22 11:58:24 -05:00
ui - > solarFlux - > setText ( " " ) ;
else
{
2021-01-29 07:57:58 -05:00
double solarFlux ;
if ( m_settings . m_solarFluxData = = StarTrackerSettings : : DRAO_2800 )
{
solarFlux = m_solarFlux ;
ui - > solarFlux - > setToolTip ( QString ( " Solar flux density at 2800 MHz " ) ) ;
}
else if ( m_settings . m_solarFluxData = = StarTrackerSettings : : TARGET_FREQ )
{
double freqMhz = m_settings . m_frequency / 1000000.0 ;
const int fluxes = sizeof ( m_solarFluxFrequencies ) / sizeof ( * m_solarFluxFrequencies ) ;
int i ;
for ( i = 0 ; i < fluxes ; i + + )
{
if ( freqMhz < m_solarFluxFrequencies [ i ] )
break ;
}
if ( i = = 0 )
{
solarFlux = extrapolate ( m_solarFluxFrequencies [ 0 ] , m_solarFluxes [ 0 ] ,
m_solarFluxFrequencies [ 1 ] , m_solarFluxes [ 1 ] ,
freqMhz
) ;
}
else if ( i = = fluxes )
{
solarFlux = extrapolate ( m_solarFluxFrequencies [ fluxes - 2 ] , m_solarFluxes [ fluxes - 2 ] ,
m_solarFluxFrequencies [ fluxes - 1 ] , m_solarFluxes [ fluxes - 1 ] ,
freqMhz
) ;
}
else
{
solarFlux = interpolate ( m_solarFluxFrequencies [ i - 1 ] , m_solarFluxes [ i - 1 ] ,
m_solarFluxFrequencies [ i ] , m_solarFluxes [ i ] ,
freqMhz
) ;
}
ui - > solarFlux - > setToolTip ( QString ( " Solar flux density interpolated to %1 MHz " ) . arg ( freqMhz ) ) ;
}
else
2021-01-22 11:58:24 -05:00
{
2021-01-29 07:57:58 -05:00
int idx = m_settings . m_solarFluxData - StarTrackerSettings : : L_245 ;
solarFlux = m_solarFluxes [ idx ] ;
ui - > solarFlux - > setToolTip ( QString ( " Solar flux density at %1 MHz " ) . arg ( m_solarFluxFrequencies [ idx ] ) ) ;
2021-01-22 11:58:24 -05:00
}
2021-01-29 07:57:58 -05:00
ui - > solarFlux - > setText ( QString ( " %1 %2 " ) . arg ( convertSolarFluxUnits ( solarFlux ) ) . arg ( solarFluxUnit ( ) ) ) ;
2021-01-22 11:58:24 -05:00
ui - > solarFlux - > setCursorPosition ( 0 ) ;
}
}
2021-01-29 07:57:58 -05:00
bool StarTrackerGUI : : readSolarFlux ( )
{
2021-01-29 12:00:56 -05:00
QFile file ( getSolarFluxFilename ( ) ) ;
2021-01-29 07:57:58 -05:00
QDateTime lastModified = file . fileTime ( QFileDevice : : FileModificationTime ) ;
if ( QDateTime : : currentDateTime ( ) . secsTo ( lastModified ) > = - ( 60 * 60 * 24 ) )
{
if ( file . open ( QIODevice : : ReadOnly | QIODevice : : Text ) )
{
QByteArray bytes = file . readLine ( ) ;
QString string ( bytes ) ;
// HHMMSS 245 410 610 1415 2695 4995 8800 15400 Mhz
// 000000 000019 000027 000037 000056 000073 000116 000202 000514 sfu
QRegExp re ( " ([0-9]{2}) ( [ 0 - 9 ] { 2 } ) ( [ 0 - 9 ] { 2 } ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) ( [ 0 - 9 ] + ) " );
if ( re . indexIn ( string ) ! = - 1 )
{
for ( int i = 0 ; i < 8 ; i + + )
m_solarFluxes [ i ] = re . capturedTexts ( ) [ i + 4 ] . toInt ( ) ;
m_solarFluxesValid = true ;
displaySolarFlux ( ) ;
plotChart ( ) ;
return true ;
}
}
}
else
qDebug ( ) < < " StarTrackerGUI::readSolarFlux: Solar flux data is more than 1 day old " ;
return false ;
}
2021-01-22 11:58:24 -05:00
void StarTrackerGUI : : networkManagerFinished ( QNetworkReply * reply )
{
ui - > solarFlux - > setText ( " " ) ; // Don't show obsolete data
QNetworkReply : : NetworkError replyError = reply - > error ( ) ;
if ( replyError )
{
qWarning ( ) < < " StarTrackerGUI::networkManagerFinished: "
< < " error( " < < ( int ) replyError
< < " ): " < < replyError
< < " : " < < reply - > errorString ( ) ;
}
else
{
QString answer = reply - > readAll ( ) ;
QRegExp re ( " \\ <th \\ >Observed Flux Density \\ < \\ /th \\ > \\ <td \\ >([0-9]+( \\ .[0-9]+) ? ) \ \ < \ \ / td \ \ > " ) ;
if ( re . indexIn ( answer ) ! = - 1 )
{
m_solarFlux = re . capturedTexts ( ) [ 1 ] . toDouble ( ) ;
displaySolarFlux ( ) ;
}
else
2021-01-29 07:57:58 -05:00
qDebug ( ) < < " StarTrackerGUI::networkManagerFinished - No Solar flux found: " < < answer ;
2021-01-22 11:58:24 -05:00
}
reply - > deleteLater ( ) ;
}
2021-01-29 07:57:58 -05:00
2021-01-29 12:00:56 -05:00
QString StarTrackerGUI : : getSolarFluxFilename ( )
2021-01-29 07:57:58 -05:00
{
return HttpDownloadManager : : downloadDir ( ) + " /solar_flux.srd " ;
}
void StarTrackerGUI : : updateSolarFlux ( bool all )
{
qDebug ( ) < < " StarTrackerGUI: Updating Solar flux data " ;
if ( ( m_settings . m_solarFluxData ! = StarTrackerSettings : : DRAO_2800 ) | | all )
{
QDate today = QDateTime : : currentDateTimeUtc ( ) . date ( ) ;
2021-01-29 12:00:56 -05:00
QString solarFluxFile = getSolarFluxFilename ( ) ;
2021-01-31 10:44:16 -05:00
if ( m_dlm . confirmDownload ( solarFluxFile , nullptr , 1 ) )
2021-01-29 07:57:58 -05:00
{
2021-04-19 20:27:43 -04:00
QString urlString = QString ( " https://www.sws.bom.gov.au/Category/World Data Centre/Data Display and Download/Solar Radio/station/learmonth/SRD/%1/L%2.SRD " )
2021-01-29 07:57:58 -05:00
. arg ( today . year ( ) ) . arg ( today . toString ( " yyMMdd " ) ) ;
m_dlm . download ( QUrl ( urlString ) , solarFluxFile , this ) ;
}
}
if ( ( m_settings . m_solarFluxData = = StarTrackerSettings : : DRAO_2800 ) | | all )
{
m_networkRequest . setUrl ( QUrl ( " https://www.spaceweather.gc.ca/solarflux/sx-4-en.php " ) ) ;
m_networkManager - > get ( m_networkRequest ) ;
}
}
void StarTrackerGUI : : autoUpdateSolarFlux ( )
{
updateSolarFlux ( false ) ;
}
void StarTrackerGUI : : on_downloadSolarFlux_clicked ( )
{
updateSolarFlux ( true ) ;
}
2021-04-19 20:27:43 -04:00
void StarTrackerGUI : : on_darkTheme_clicked ( bool checked )
{
m_settings . m_chartsDarkTheme = checked ;
m_solarFluxChart . setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
m_chart . setTheme ( m_settings . m_chartsDarkTheme ? QChart : : ChartThemeDark : QChart : : ChartThemeLight ) ;
plotChart ( ) ;
applySettings ( ) ;
}
2021-01-29 07:57:58 -05:00
void StarTrackerGUI : : downloadFinished ( const QString & filename , bool success )
{
2021-01-29 12:00:56 -05:00
( void ) filename ;
2021-01-29 07:57:58 -05:00
if ( success )
readSolarFlux ( ) ;
}