File indexing completed on 2024-04-28 15:09:53
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 SPDX-FileCopyrightText: 2021 Wolfgang Reissenberger <sterne-jaeger@openfuture.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "guidedriftgraph.h" 0009 #include "klocalizedstring.h" 0010 #include "ksnotification.h" 0011 #include "kstarsdata.h" 0012 #include "guideinterface.h" 0013 #include "Options.h" 0014 0015 // Qt version calming 0016 #include <qtendl.h> 0017 0018 GuideDriftGraph::GuideDriftGraph(QWidget *parent) 0019 { 0020 Q_UNUSED(parent); 0021 // Drift Graph Color Settings 0022 setBackground(QBrush(Qt::black)); 0023 xAxis->setBasePen(QPen(Qt::white, 1)); 0024 yAxis->setBasePen(QPen(Qt::white, 1)); 0025 xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 0026 yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 0027 xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 0028 yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 0029 xAxis->grid()->setZeroLinePen(Qt::NoPen); 0030 yAxis->grid()->setZeroLinePen(QPen(Qt::white, 1)); 0031 xAxis->setBasePen(QPen(Qt::white, 1)); 0032 yAxis->setBasePen(QPen(Qt::white, 1)); 0033 yAxis2->setBasePen(QPen(Qt::white, 1)); 0034 xAxis->setTickPen(QPen(Qt::white, 1)); 0035 yAxis->setTickPen(QPen(Qt::white, 1)); 0036 yAxis2->setTickPen(QPen(Qt::white, 1)); 0037 xAxis->setSubTickPen(QPen(Qt::white, 1)); 0038 yAxis->setSubTickPen(QPen(Qt::white, 1)); 0039 yAxis2->setSubTickPen(QPen(Qt::white, 1)); 0040 xAxis->setTickLabelColor(Qt::white); 0041 yAxis->setTickLabelColor(Qt::white); 0042 yAxis2->setTickLabelColor(Qt::white); 0043 xAxis->setLabelColor(Qt::white); 0044 yAxis->setLabelColor(Qt::white); 0045 yAxis2->setLabelColor(Qt::white); 0046 0047 snrAxis = axisRect()->addAxis(QCPAxis::atLeft, 0); 0048 snrAxis->setVisible(false); 0049 // This will be reset to the actual data values. 0050 snrAxis->setRange(-100, 100); 0051 0052 //Horizontal Axis Time Ticker Settings 0053 QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); 0054 timeTicker->setTimeFormat("%m:%s"); 0055 xAxis->setTicker(timeTicker); 0056 0057 // Axis Labels Settings 0058 yAxis2->setVisible(true); 0059 yAxis2->setTickLabels(true); 0060 yAxis->setLabelFont(QFont(font().family(), 10)); 0061 yAxis2->setLabelFont(QFont(font().family(), 10)); 0062 xAxis->setTickLabelFont(QFont(font().family(), 9)); 0063 yAxis->setTickLabelFont(QFont(font().family(), 9)); 0064 yAxis2->setTickLabelFont(QFont(font().family(), 9)); 0065 yAxis->setLabelPadding(1); 0066 yAxis2->setLabelPadding(1); 0067 yAxis->setLabel(i18n("drift (arcsec)")); 0068 yAxis2->setLabel(i18n("pulse (ms)")); 0069 0070 setupNSEWLabels(); 0071 0072 int scale = 0073 50; //This is a scaling value between the left and the right axes of the driftGraph, it could be stored in kstars kcfg 0074 0075 //Sets the default ranges 0076 xAxis->setRange(0, 120, Qt::AlignRight); 0077 yAxis->setRange(-3, 3); 0078 yAxis2->setRange(-3 * scale, 3 * scale); 0079 0080 //This sets up the legend 0081 legend->setVisible(true); 0082 legend->setFont(QFont(font().family(), 7)); 0083 legend->setTextColor(Qt::white); 0084 legend->setBrush(QBrush(Qt::black)); 0085 legend->setIconSize(4, 12); 0086 legend->setFillOrder(QCPLegend::foColumnsFirst); 0087 axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft | Qt::AlignBottom); 0088 0089 // RA Curve 0090 addGraph(xAxis, yAxis); 0091 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); 0092 graph(GuideGraph::G_RA)->setName("RA"); 0093 graph(GuideGraph::G_RA)->setLineStyle(QCPGraph::lsLine); 0094 0095 // DE Curve 0096 addGraph(xAxis, yAxis); 0097 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); 0098 graph(GuideGraph::G_DEC)->setName("DE"); 0099 graph(GuideGraph::G_DEC)->setLineStyle(QCPGraph::lsLine); 0100 0101 // RA highlighted Point 0102 addGraph(xAxis, yAxis); 0103 graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone); 0104 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); 0105 graph(GuideGraph::G_RA_HIGHLIGHT)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssPlusCircle, 0106 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10)); 0107 0108 // DE highlighted Point 0109 addGraph(xAxis, yAxis); 0110 graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone); 0111 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); 0112 graph(GuideGraph::G_DEC_HIGHLIGHT)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssPlusCircle, 0113 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10)); 0114 0115 // RA Pulse 0116 addGraph(xAxis, yAxis2); 0117 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")); 0118 raPulseColor.setAlpha(75); 0119 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor)); 0120 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern)); 0121 graph(GuideGraph::G_RA_PULSE)->setName("RA Pulse"); 0122 graph(GuideGraph::G_RA_PULSE)->setLineStyle(QCPGraph::lsStepLeft); 0123 0124 // DEC Pulse 0125 addGraph(xAxis, yAxis2); 0126 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")); 0127 dePulseColor.setAlpha(75); 0128 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor)); 0129 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern)); 0130 graph(GuideGraph::G_DEC_PULSE)->setName("DEC Pulse"); 0131 graph(GuideGraph::G_DEC_PULSE)->setLineStyle(QCPGraph::lsStepLeft); 0132 0133 // SNR 0134 addGraph(xAxis, snrAxis); 0135 graph(GuideGraph::G_SNR)->setPen(QPen(Qt::yellow)); 0136 graph(GuideGraph::G_SNR)->setName("SNR"); 0137 graph(GuideGraph::G_SNR)->setLineStyle(QCPGraph::lsLine); 0138 0139 // RA RMS 0140 addGraph(xAxis, yAxis); 0141 graph(GuideGraph::G_RA_RMS)->setPen(QPen(Qt::red)); 0142 graph(GuideGraph::G_RA_RMS)->setName("RA RMS"); 0143 graph(GuideGraph::G_RA_RMS)->setLineStyle(QCPGraph::lsLine); 0144 0145 // DEC RMS 0146 addGraph(xAxis, yAxis); 0147 graph(GuideGraph::G_DEC_RMS)->setPen(QPen(Qt::red)); 0148 graph(GuideGraph::G_DEC_RMS)->setName("DEC RMS"); 0149 graph(GuideGraph::G_DEC_RMS)->setLineStyle(QCPGraph::lsLine); 0150 0151 // Total RMS 0152 addGraph(xAxis, yAxis); 0153 graph(GuideGraph::G_RMS)->setPen(QPen(Qt::red)); 0154 graph(GuideGraph::G_RMS)->setName("RMS"); 0155 graph(GuideGraph::G_RMS)->setLineStyle(QCPGraph::lsLine); 0156 0157 //This will prevent the highlighted points and Pulses from showing up in the legend. 0158 legend->removeItem(GuideGraph::G_DEC_RMS); 0159 legend->removeItem(GuideGraph::G_RA_RMS); 0160 legend->removeItem(GuideGraph::G_DEC_PULSE); 0161 legend->removeItem(GuideGraph::G_RA_PULSE); 0162 legend->removeItem(GuideGraph::G_DEC_HIGHLIGHT); 0163 legend->removeItem(GuideGraph::G_RA_HIGHLIGHT); 0164 0165 setInteractions(QCP::iRangeZoom); 0166 axisRect()->setRangeZoom(Qt::Orientation::Vertical); 0167 setInteraction(QCP::iRangeDrag, true); 0168 //This sets the visibility of graph components to the stored values. 0169 graph(GuideGraph::G_RA)->setVisible(Options::rADisplayedOnGuideGraph()); //RA data 0170 graph(GuideGraph::G_DEC)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC data 0171 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(Options::rADisplayedOnGuideGraph()); //RA highlighted point 0172 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC highlighted point 0173 graph(GuideGraph::G_RA_PULSE)->setVisible(Options::rACorrDisplayedOnGuideGraph()); //RA Pulses 0174 graph(GuideGraph::G_DEC_PULSE)->setVisible(Options::dECorrDisplayedOnGuideGraph()); //DEC Pulses 0175 graph(GuideGraph::G_SNR)->setVisible(Options::sNRDisplayedOnGuideGraph()); //SNR 0176 setRMSVisibility(); 0177 0178 updateCorrectionsScaleVisibility(); 0179 } 0180 0181 void GuideDriftGraph::guideHistory(int sliderValue, bool graphOnLatestPt) 0182 { 0183 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear RA highlighted point 0184 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear DEC highlighted point 0185 double t = graph(GuideGraph::G_RA)->dataMainKey(sliderValue); //Get time from RA data 0186 double ra = graph(GuideGraph::G_RA)->dataMainValue(sliderValue); //Get RA from RA data 0187 double de = graph(GuideGraph::G_DEC)->dataMainValue(sliderValue); //Get DEC from DEC data 0188 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(sliderValue); //Get RA Pulse from RA pulse data 0189 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(sliderValue); //Get DEC Pulse from DEC pulse data 0190 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(t, ra); //Set RA highlighted point 0191 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(t, de); //Set DEC highlighted point 0192 0193 //This will allow the graph to scroll left and right along with the guide slider 0194 if (xAxis->range().contains(t) == false) 0195 { 0196 if(t < xAxis->range().lower) 0197 { 0198 xAxis->setRange(t, t + xAxis->range().size()); 0199 } 0200 if(t > xAxis->range().upper) 0201 { 0202 xAxis->setRange(t - xAxis->range().size(), t); 0203 } 0204 } 0205 replot(); 0206 double snr = 0; 0207 if (graph(GuideGraph::G_SNR)->data()->size() > 0) 0208 snr = graph(GuideGraph::G_SNR)->dataMainValue(sliderValue); 0209 double rms = graph(GuideGraph::G_RMS)->dataMainValue(sliderValue); 0210 0211 if(!graphOnLatestPt) 0212 { 0213 QTime localTime = guideTimer; 0214 localTime = localTime.addSecs(t); 0215 0216 QPoint localTooltipCoordinates = graph(GuideGraph::G_RA)->dataPixelPosition(sliderValue).toPoint(); 0217 QPoint globalTooltipCoordinates = mapToGlobal(localTooltipCoordinates); 0218 0219 if(raPulse == 0 && dePulse == 0) 0220 { 0221 QToolTip::showText( 0222 globalTooltipCoordinates, 0223 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR", 0224 "<table>" 0225 "<tr><td>LT: </td><td>%1</td></tr>" 0226 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0227 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0228 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0229 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0230 "</table>", 0231 localTime.toString("hh:mm:ss AP"), 0232 QString::number(ra, 'f', 2), 0233 QString::number(de, 'f', 2), 0234 QString::number(rms, 'f', 2), 0235 QString::number(snr, 'f', 1) 0236 )); 0237 } 0238 else 0239 { 0240 QToolTip::showText( 0241 globalTooltipCoordinates, 0242 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR; %6 is RA Pulse in ms; %7 is DE Pulse in ms", 0243 "<table>" 0244 "<tr><td>LT: </td><td>%1</td></tr>" 0245 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0246 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0247 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0248 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0249 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>" 0250 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>" 0251 "</table>", 0252 localTime.toString("hh:mm:ss AP"), 0253 QString::number(ra, 'f', 2), 0254 QString::number(de, 'f', 2), 0255 QString::number(rms, 'f', 2), 0256 QString::number(snr, 'f', 1), 0257 QString::number(raPulse, 'f', 2), 0258 QString::number(dePulse, 'f', 2) 0259 )); //The pulses were divided by 100 before they were put on the graph. 0260 } 0261 0262 } 0263 } 0264 0265 void GuideDriftGraph::handleVerticalPlotSizeChange() 0266 { 0267 } 0268 0269 void GuideDriftGraph::handleHorizontalPlotSizeChange() 0270 { 0271 } 0272 0273 void GuideDriftGraph::setupNSEWLabels() 0274 { 0275 //Labels for N/S/E/W 0276 QColor raLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")); 0277 QColor deLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")); 0278 0279 QCPItemText *northLabel = new QCPItemText(this); 0280 northLabel->setColor(deLabelColor); 0281 northLabel->setFont(QFont(font().family(), 9)); 0282 northLabel->setText(i18nc("North", "N")); 0283 northLabel->position->setType(QCPItemPosition::ptViewportRatio); 0284 northLabel->position->setCoords(0.7, 0.12); 0285 northLabel->setVisible(true); 0286 0287 QCPItemText *southLabel = new QCPItemText(this); 0288 southLabel->setColor(deLabelColor); 0289 southLabel->setFont(QFont(font().family(), 9)); 0290 southLabel->setText(i18nc("South", "S")); 0291 southLabel->position->setType(QCPItemPosition::ptViewportRatio); 0292 southLabel->position->setCoords(0.7, 0.8); 0293 southLabel->setVisible(true); 0294 0295 QCPItemText *westLabel = new QCPItemText(this); 0296 westLabel->setColor(raLabelColor); 0297 westLabel->setFont(QFont(font().family(), 9)); 0298 westLabel->setText(i18nc("West", "W")); 0299 westLabel->position->setType(QCPItemPosition::ptViewportRatio); 0300 westLabel->position->setCoords(0.78, 0.12); 0301 westLabel->setVisible(true); 0302 0303 QCPItemText *eastLabel = new QCPItemText(this); 0304 eastLabel->setColor(raLabelColor); 0305 eastLabel->setFont(QFont(font().family(), 9)); 0306 eastLabel->setText(i18nc("East", "E")); 0307 eastLabel->position->setType(QCPItemPosition::ptViewportRatio); 0308 eastLabel->position->setCoords(0.8, 0.8); 0309 eastLabel->setVisible(true); 0310 0311 } 0312 0313 void GuideDriftGraph::autoScaleGraphs() 0314 { 0315 yAxis->setRange(-3, 3); 0316 // First bool below is only_enlarge, 2nd is only look at values that are visible in X. 0317 // Net result is all RA & DEC points within the times being plotted should be visible. 0318 // This is only called when the autoScale button is pressed. 0319 graph(GuideGraph::G_RA)->rescaleValueAxis(false, true); 0320 graph(GuideGraph::G_DEC)->rescaleValueAxis(true, true); 0321 replot(); 0322 } 0323 0324 void GuideDriftGraph::zoomX(int zoomLevel) 0325 { 0326 double key = (guideElapsedTimer.isValid() || guideTimer.isValid() 0327 || guideTimer.isNull()) ? 0 : guideElapsedTimer.elapsed() / 1000.0; 0328 0329 // The # of seconds displayd on the x-axis of the drift-graph for the various zoom levels. 0330 static std::vector<int> zoomLevels = {15, 30, 60, 120, 300, 900, 1800, 3600, 7200, 14400}; 0331 0332 zoomLevel = std::max(0, zoomLevel); 0333 driftGraphZoomLevel = std::min(static_cast<int>(zoomLevels.size() - 1), zoomLevel); 0334 0335 xAxis->setRange(key - zoomLevels[driftGraphZoomLevel], key); 0336 } 0337 0338 void GuideDriftGraph::zoomInX() 0339 { 0340 zoomX(driftGraphZoomLevel - 1); 0341 replot(); 0342 } 0343 0344 void GuideDriftGraph::zoomOutX() 0345 { 0346 zoomX(driftGraphZoomLevel + 1); 0347 replot(); 0348 } 0349 0350 void GuideDriftGraph::setCorrectionGraphScale(int value) 0351 { 0352 yAxis2->setRange(yAxis->range().lower * value, 0353 yAxis->range().upper * value); 0354 replot(); 0355 } 0356 0357 void GuideDriftGraph::clear() 0358 { 0359 graph(GuideGraph::G_RA)->data()->clear(); //RA data 0360 graph(GuideGraph::G_DEC)->data()->clear(); //DEC data 0361 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //RA highlighted point 0362 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //DEC highlighted point 0363 graph(GuideGraph::G_RA_PULSE)->data()->clear(); //RA Pulses 0364 graph(GuideGraph::G_DEC_PULSE)->data()->clear(); //DEC Pulses 0365 graph(GuideGraph::G_SNR)->data()->clear(); //SNR 0366 graph(GuideGraph::G_RA_RMS)->data()->clear(); //RA RMS 0367 graph(GuideGraph::G_DEC_RMS)->data()->clear(); //DEC RMS 0368 graph(GuideGraph::G_RMS)->data()->clear(); //RMS 0369 clearItems(); //Clears dither text items from the graph 0370 setupNSEWLabels(); 0371 replot(); 0372 } 0373 0374 void GuideDriftGraph::toggleShowPlot(GuideGraph::DRIFT_GRAPH_INDICES plot, bool isChecked) 0375 { 0376 switch (plot) 0377 { 0378 case GuideGraph::G_RA: 0379 Options::setRADisplayedOnGuideGraph(isChecked); 0380 graph(GuideGraph::G_RA)->setVisible(isChecked); 0381 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(isChecked); 0382 setRMSVisibility(); 0383 replot(); 0384 break; 0385 case GuideGraph::G_DEC: 0386 Options::setDEDisplayedOnGuideGraph(isChecked); 0387 graph(GuideGraph::G_DEC)->setVisible(isChecked); 0388 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(isChecked); 0389 setRMSVisibility(); 0390 replot(); 0391 break; 0392 case GuideGraph::G_RA_PULSE: 0393 Options::setRACorrDisplayedOnGuideGraph(isChecked); 0394 graph(GuideGraph::G_RA_PULSE)->setVisible(isChecked); 0395 updateCorrectionsScaleVisibility(); 0396 break; 0397 case GuideGraph::G_DEC_PULSE: 0398 Options::setDECorrDisplayedOnGuideGraph(isChecked); 0399 graph(GuideGraph::G_DEC_PULSE)->setVisible(isChecked); 0400 updateCorrectionsScaleVisibility(); 0401 break; 0402 case GuideGraph::G_SNR: 0403 Options::setSNRDisplayedOnGuideGraph(isChecked); 0404 graph(GuideGraph::G_SNR)->setVisible(isChecked); 0405 replot(); 0406 break; 0407 case GuideGraph::G_RMS: 0408 Options::setRMSDisplayedOnGuideGraph(isChecked); 0409 setRMSVisibility(); 0410 replot(); 0411 break; 0412 default: 0413 break; 0414 } 0415 } 0416 0417 void GuideDriftGraph::setRMSVisibility() 0418 { 0419 if (!Options::rMSDisplayedOnGuideGraph()) 0420 { 0421 graph(GuideGraph::G_RA_RMS)->setVisible(false); 0422 graph(GuideGraph::G_DEC_RMS)->setVisible(false); 0423 graph(GuideGraph::G_RMS)->setVisible(false); 0424 return; 0425 } 0426 0427 if ((Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph()) || 0428 (!Options::dEDisplayedOnGuideGraph() && !Options::rADisplayedOnGuideGraph())) 0429 { 0430 graph(GuideGraph::G_RA_RMS)->setVisible(false); 0431 graph(GuideGraph::G_DEC_RMS)->setVisible(false); 0432 graph(GuideGraph::G_RMS)->setVisible(true); 0433 } 0434 else if (!Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph()) 0435 { 0436 graph(GuideGraph::G_RA_RMS)->setVisible(true); 0437 graph(GuideGraph::G_DEC_RMS)->setVisible(false); 0438 graph(GuideGraph::G_RMS)->setVisible(false); 0439 } 0440 else 0441 { 0442 graph(GuideGraph::G_RA_RMS)->setVisible(false); 0443 graph(GuideGraph::G_DEC_RMS)->setVisible(true); 0444 graph(GuideGraph::G_RMS)->setVisible(false); 0445 } 0446 } 0447 0448 void GuideDriftGraph::exportGuideData() 0449 { 0450 int numPoints = graph(GuideGraph::G_RA)->dataCount(); 0451 if (numPoints == 0) 0452 return; 0453 0454 QUrl exportFile = QFileDialog::getSaveFileUrl(this, i18nc("@title:window", "Export Guide Data"), guideURLPath, 0455 "CSV File (*.csv)"); 0456 if (exportFile.isEmpty()) // if user presses cancel 0457 return; 0458 if (exportFile.toLocalFile().endsWith(QLatin1String(".csv")) == false) 0459 exportFile.setPath(exportFile.toLocalFile() + ".csv"); 0460 0461 QString path = exportFile.toLocalFile(); 0462 0463 if (QFile::exists(path)) 0464 { 0465 int r = KMessageBox::warningContinueCancel(nullptr, 0466 i18n("A file named \"%1\" already exists. " 0467 "Overwrite it?", 0468 exportFile.fileName()), 0469 i18n("Overwrite File?"), KStandardGuiItem::overwrite()); 0470 if (r == KMessageBox::Cancel) 0471 return; 0472 } 0473 0474 if (!exportFile.isValid()) 0475 { 0476 QString message = i18n("Invalid URL: %1", exportFile.url()); 0477 KSNotification::sorry(message, i18n("Invalid URL")); 0478 return; 0479 } 0480 0481 QFile file; 0482 file.setFileName(path); 0483 if (!file.open(QIODevice::WriteOnly)) 0484 { 0485 QString message = i18n("Unable to write to file %1", path); 0486 KSNotification::sorry(message, i18n("Could Not Open File")); 0487 return; 0488 } 0489 0490 QTextStream outstream(&file); 0491 0492 outstream << 0493 "Frame #, Time Elapsed (sec), Local Time (HMS), RA Error (arcsec), DE Error (arcsec), RA Pulse (ms), DE Pulse (ms)" << 0494 Qt::endl; 0495 0496 for (int i = 0; i < numPoints; i++) 0497 { 0498 double t = graph(GuideGraph::G_RA)->dataMainKey(i); 0499 double ra = graph(GuideGraph::G_RA)->dataMainValue(i); 0500 double de = graph(GuideGraph::G_DEC)->dataMainValue(i); 0501 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(i); 0502 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(i); 0503 0504 QTime localTime = guideTimer; 0505 localTime = localTime.addSecs(t); 0506 0507 outstream << i << ',' << t << ',' << localTime.toString("hh:mm:ss AP") << ',' << ra << ',' << de << ',' << raPulse << ',' << 0508 dePulse << ',' << Qt::endl; 0509 } 0510 file.close(); 0511 } 0512 0513 void GuideDriftGraph::resetTimer() 0514 { 0515 guideTimer = QTime::currentTime(); 0516 guideElapsedTimer.start(); 0517 } 0518 0519 void GuideDriftGraph::connectGuider(Ekos::GuideInterface *guider) 0520 { 0521 connect(guider, &Ekos::GuideInterface::newAxisDelta, this, &GuideDriftGraph::setAxisDelta); 0522 connect(guider, &Ekos::GuideInterface::newAxisPulse, this, &GuideDriftGraph::setAxisPulse); 0523 connect(guider, &Ekos::GuideInterface::newAxisSigma, this, &GuideDriftGraph::setAxisSigma); 0524 connect(guider, &Ekos::GuideInterface::newSNR, this, &GuideDriftGraph::setSNR); 0525 0526 resetTimer(); 0527 } 0528 0529 void GuideDriftGraph::setAxisDelta(double ra, double de) 0530 { 0531 // Time since timer started. 0532 double key = guideElapsedTimer.elapsed() / 1000.0; 0533 0534 // similar to same operation in Guide::setAxisDelta 0535 ra = -ra; 0536 0537 graph(GuideGraph::G_RA)->addData(key, ra); 0538 graph(GuideGraph::G_DEC)->addData(key, de); 0539 0540 if(graphOnLatestPt) 0541 { 0542 xAxis->setRange(key, xAxis->range().size(), Qt::AlignRight); 0543 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear highlighted RA point 0544 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear highlighted DEC point 0545 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(key, ra); //Set highlighted RA point to latest point 0546 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(key, de); //Set highlighted DEC point to latest point 0547 } 0548 replot(); 0549 } 0550 0551 void GuideDriftGraph::setAxisSigma(double ra, double de) 0552 { 0553 const double key = guideElapsedTimer.elapsed() / 1000.0; 0554 const double total = std::hypot(ra, de); 0555 graph(GuideGraph::G_RA_RMS)->addData(key, ra); 0556 graph(GuideGraph::G_DEC_RMS)->addData(key, de); 0557 graph(GuideGraph::G_RMS)->addData(key, total); 0558 } 0559 0560 void GuideDriftGraph::setAxisPulse(double ra, double de) 0561 { 0562 double key = guideElapsedTimer.elapsed() / 1000.0; 0563 graph(GuideGraph::G_RA_PULSE)->addData(key, ra); 0564 graph(GuideGraph::G_DEC_PULSE)->addData(key, de); 0565 } 0566 0567 void GuideDriftGraph::setSNR(double snr) 0568 { 0569 double key = guideElapsedTimer.elapsed() / 1000.0; 0570 graph(GuideGraph::G_SNR)->addData(key, snr); 0571 0572 // Sets the SNR axis to have the maximum be 95% of the way up from the middle to the top. 0573 QCPGraphData snrMax = *std::min_element(graph(GuideGraph::G_SNR)->data()->begin(), 0574 graph(GuideGraph::G_SNR)->data()->end(), 0575 [](QCPGraphData const & s1, QCPGraphData const & s2) 0576 { 0577 return s1.value > s2.value; 0578 }); 0579 snrAxis->setRange(-1.05 * snrMax.value, 1.05 * snrMax.value); 0580 } 0581 0582 void GuideDriftGraph::updateCorrectionsScaleVisibility() 0583 { 0584 bool isVisible = (Options::rACorrDisplayedOnGuideGraph() || Options::dECorrDisplayedOnGuideGraph()); 0585 yAxis2->setVisible(isVisible); 0586 replot(); 0587 } 0588 0589 void GuideDriftGraph::mouseOverLine(QMouseEvent *event) 0590 { 0591 double key = xAxis->pixelToCoord(event->localPos().x()); 0592 0593 if (xAxis->range().contains(key)) 0594 { 0595 if (plottableAt(event->pos(), false)) 0596 { 0597 int raIndex = graph(GuideGraph::G_RA)->findBegin(key); 0598 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key); 0599 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key); 0600 0601 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex); 0602 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex); 0603 0604 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data 0605 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data 0606 0607 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex); 0608 double snr = 0; 0609 if (graph(GuideGraph::G_SNR)->data()->size() > 0) 0610 { 0611 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key); 0612 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex); 0613 } 0614 0615 // Compute time value: 0616 QTime localTime = guideTimer; 0617 0618 localTime = localTime.addSecs(key); 0619 0620 QToolTip::hideText(); 0621 if(raPulse == 0 && dePulse == 0) 0622 { 0623 QToolTip::showText( 0624 event->globalPos(), 0625 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR", 0626 "<table>" 0627 "<tr><td>LT: </td><td>%1</td></tr>" 0628 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0629 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0630 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0631 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0632 "</table>", 0633 localTime.toString("hh:mm:ss AP"), 0634 QString::number(raDelta, 'f', 2), QString::number(deDelta, 'f', 2), 0635 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1))); 0636 } 0637 else 0638 { 0639 QToolTip::showText( 0640 event->globalPos(), 0641 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR; %6 is RA Pulse in ms; %7 is DE Pulse in ms", 0642 "<table>" 0643 "<tr><td>LT: </td><td>%1</td></tr>" 0644 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0645 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0646 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0647 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0648 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>" 0649 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>" 0650 "</table>", 0651 localTime.toString("hh:mm:ss AP"), 0652 QString::number(raDelta, 'f', 2), 0653 QString::number(deDelta, 'f', 2), 0654 QString::number(rms, 'f', 2), 0655 QString::number(snr, 'f', 1), 0656 QString::number(raPulse, 'f', 2), 0657 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph. 0658 } 0659 } 0660 else 0661 QToolTip::hideText(); 0662 0663 replot(); 0664 } 0665 0666 if (xAxis->range().contains(key)) 0667 { 0668 QCPGraph *qcpgraph = qobject_cast<QCPGraph *>(plottableAt(event->pos(), false)); 0669 0670 if (qcpgraph) 0671 { 0672 int raIndex = graph(GuideGraph::G_RA)->findBegin(key); 0673 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key); 0674 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key); 0675 0676 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex); 0677 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex); 0678 0679 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data 0680 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data 0681 0682 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex); 0683 double snr = 0; 0684 if (graph(GuideGraph::G_SNR)->data()->size() > 0) 0685 { 0686 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key); 0687 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex); 0688 } 0689 0690 // Compute time value: 0691 QTime localTime = guideTimer; 0692 0693 localTime = localTime.addSecs(key); 0694 0695 QToolTip::hideText(); 0696 if(raPulse == 0 && dePulse == 0) 0697 { 0698 QToolTip::showText( 0699 event->globalPos(), 0700 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR", 0701 "<table>" 0702 "<tr><td>LT: </td><td>%1</td></tr>" 0703 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0704 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0705 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0706 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0707 "</table>", 0708 localTime.toString("hh:mm:ss AP"), 0709 QString::number(raDelta, 'f', 2), QString::number(deDelta, 'f', 2), 0710 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1))); 0711 } 0712 else 0713 { 0714 QToolTip::showText( 0715 event->globalPos(), 0716 i18nc("Drift graphics tooltip; %1 is local time; %2 is RA deviation; %3 is DE deviation in arcseconds; %4 is the RMS error in arcseconds; %5 is the SNR; %6 is RA Pulse in ms; %7 is DE Pulse in ms", 0717 "<table>" 0718 "<tr><td>LT: </td><td>%1</td></tr>" 0719 "<tr><td>RA: </td><td>%2 \"</td></tr>" 0720 "<tr><td>DE: </td><td>%3 \"</td></tr>" 0721 "<tr><td>RMS: </td><td>%4 \"</td></tr>" 0722 "<tr><td>SNR: </td><td>%5 \"</td></tr>" 0723 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>" 0724 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>" 0725 "</table>", 0726 localTime.toString("hh:mm:ss AP"), 0727 QString::number(raDelta, 'f', 2), 0728 QString::number(deDelta, 'f', 2), 0729 QString::number(rms, 'f', 2), 0730 QString::number(snr, 'f', 1), 0731 QString::number(raPulse, 'f', 2), 0732 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph. 0733 } 0734 } 0735 else 0736 QToolTip::hideText(); 0737 0738 replot(); 0739 } 0740 } 0741 0742 void GuideDriftGraph::mouseClicked(QMouseEvent *event) 0743 { 0744 if (event->buttons() & Qt::RightButton) 0745 { 0746 yAxis->setRange(-3, 3); 0747 } 0748 } 0749 0750 void GuideDriftGraph::refreshColorScheme() 0751 { 0752 if (graph(GuideGraph::G_RA) && graph(GuideGraph::G_DEC) && graph(GuideGraph::G_RA_HIGHLIGHT) 0753 && graph(GuideGraph::G_DEC_HIGHLIGHT) && graph(GuideGraph::G_RA_PULSE) 0754 && graph(GuideGraph::G_DEC_PULSE)) 0755 { 0756 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); 0757 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); 0758 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"))); 0759 graph(GuideGraph::G_RA_HIGHLIGHT)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssPlusCircle, 0760 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10)); 0761 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"))); 0762 graph(GuideGraph::G_DEC_HIGHLIGHT)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssPlusCircle, 0763 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10)); 0764 0765 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")); 0766 raPulseColor.setAlpha(75); 0767 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor)); 0768 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern)); 0769 0770 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")); 0771 dePulseColor.setAlpha(75); 0772 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor)); 0773 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern)); 0774 } 0775 }