Kstars

guidedriftgraph.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 SPDX-FileCopyrightText: 2021 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#include "guidedriftgraph.h"
9#include "klocalizedstring.h"
10#include "ksnotification.h"
11#include "kstarsdata.h"
12#include "guideinterface.h"
13#include "Options.h"
14
15// Qt version calming
16#include <qtendl.h>
17#include <QToolTip>
18#include <QFileDialog>
19
20GuideDriftGraph::GuideDriftGraph(QWidget *parent)
21{
22 Q_UNUSED(parent);
23 // Drift Graph Color Settings
27 xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
28 yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
29 xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
30 yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
48
49 snrAxis = axisRect()->addAxis(QCPAxis::atLeft, 0);
50 snrAxis->setVisible(false);
51 // This will be reset to the actual data values.
52 snrAxis->setRange(-100, 100);
53
54 //Horizontal Axis Time Ticker Settings
56 timeTicker->setTimeFormat("%m:%s");
57 xAxis->setTicker(timeTicker);
58
59 // Axis Labels Settings
60 yAxis2->setVisible(true);
61 yAxis2->setTickLabels(true);
62 yAxis->setLabelFont(QFont(font().family(), 10));
63 yAxis2->setLabelFont(QFont(font().family(), 10));
64 xAxis->setTickLabelFont(QFont(font().family(), 9));
65 yAxis->setTickLabelFont(QFont(font().family(), 9));
66 yAxis2->setTickLabelFont(QFont(font().family(), 9));
69 yAxis->setLabel(i18n("drift (arcsec)"));
70 yAxis2->setLabel(i18n("pulse (ms)"));
71
72 setupNSEWLabels();
73
74 int scale =
75 50; //This is a scaling value between the left and the right axes of the driftGraph, it could be stored in kstars kcfg
76
77 //Sets the default ranges
79 yAxis->setRange(-3, 3);
80 yAxis2->setRange(-3 * scale, 3 * scale);
81
82 //This sets up the legend
83 legend->setVisible(true);
84 legend->setFont(QFont(font().family(), 7));
87 legend->setIconSize(4, 12);
90
91 // RA Curve
93 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
94 graph(GuideGraph::G_RA)->setName("RA");
95 graph(GuideGraph::G_RA)->setLineStyle(QCPGraph::lsLine);
96
97 // DE Curve
99 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
100 graph(GuideGraph::G_DEC)->setName("DE");
101 graph(GuideGraph::G_DEC)->setLineStyle(QCPGraph::lsLine);
102
103 // RA highlighted Point
105 graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone);
106 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
108 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10));
109
110 // DE highlighted Point
112 graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone);
113 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
115 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10));
116
117 // RA Pulse
119 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
120 raPulseColor.setAlpha(75);
121 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor));
122 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern));
123 graph(GuideGraph::G_RA_PULSE)->setName("RA Pulse");
124 graph(GuideGraph::G_RA_PULSE)->setLineStyle(QCPGraph::lsStepLeft);
125
126 // DEC Pulse
128 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
129 dePulseColor.setAlpha(75);
130 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor));
131 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern));
132 graph(GuideGraph::G_DEC_PULSE)->setName("DEC Pulse");
133 graph(GuideGraph::G_DEC_PULSE)->setLineStyle(QCPGraph::lsStepLeft);
134
135 // SNR
136 addGraph(xAxis, snrAxis);
137 graph(GuideGraph::G_SNR)->setPen(QPen(Qt::yellow));
138 graph(GuideGraph::G_SNR)->setName("SNR");
139 graph(GuideGraph::G_SNR)->setLineStyle(QCPGraph::lsLine);
140
141 // RA RMS
143 graph(GuideGraph::G_RA_RMS)->setPen(QPen(Qt::red));
144 graph(GuideGraph::G_RA_RMS)->setName("RA RMS");
145 graph(GuideGraph::G_RA_RMS)->setLineStyle(QCPGraph::lsLine);
146
147 // DEC RMS
149 graph(GuideGraph::G_DEC_RMS)->setPen(QPen(Qt::red));
150 graph(GuideGraph::G_DEC_RMS)->setName("DEC RMS");
151 graph(GuideGraph::G_DEC_RMS)->setLineStyle(QCPGraph::lsLine);
152
153 // Total RMS
155 graph(GuideGraph::G_RMS)->setPen(QPen(Qt::red));
156 graph(GuideGraph::G_RMS)->setName("RMS");
157 graph(GuideGraph::G_RMS)->setLineStyle(QCPGraph::lsLine);
158
159 //This will prevent the highlighted points and Pulses from showing up in the legend.
160 legend->removeItem(GuideGraph::G_DEC_RMS);
161 legend->removeItem(GuideGraph::G_RA_RMS);
162 legend->removeItem(GuideGraph::G_DEC_PULSE);
163 legend->removeItem(GuideGraph::G_RA_PULSE);
164 legend->removeItem(GuideGraph::G_DEC_HIGHLIGHT);
165 legend->removeItem(GuideGraph::G_RA_HIGHLIGHT);
166
168 axisRect()->setRangeZoom(Qt::Orientation::Vertical);
170 //This sets the visibility of graph components to the stored values.
171 graph(GuideGraph::G_RA)->setVisible(Options::rADisplayedOnGuideGraph()); //RA data
172 graph(GuideGraph::G_DEC)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC data
173 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(Options::rADisplayedOnGuideGraph()); //RA highlighted point
174 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC highlighted point
175 graph(GuideGraph::G_RA_PULSE)->setVisible(Options::rACorrDisplayedOnGuideGraph()); //RA Pulses
176 graph(GuideGraph::G_DEC_PULSE)->setVisible(Options::dECorrDisplayedOnGuideGraph()); //DEC Pulses
177 graph(GuideGraph::G_SNR)->setVisible(Options::sNRDisplayedOnGuideGraph()); //SNR
178 setRMSVisibility();
179
180 updateCorrectionsScaleVisibility();
181}
182
183void GuideDriftGraph::guideHistory(int sliderValue, bool graphOnLatestPt)
184{
185 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear RA highlighted point
186 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear DEC highlighted point
187 double t = graph(GuideGraph::G_RA)->dataMainKey(sliderValue); //Get time from RA data
188 double ra = graph(GuideGraph::G_RA)->dataMainValue(sliderValue); //Get RA from RA data
189 double de = graph(GuideGraph::G_DEC)->dataMainValue(sliderValue); //Get DEC from DEC data
190 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(sliderValue); //Get RA Pulse from RA pulse data
191 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(sliderValue); //Get DEC Pulse from DEC pulse data
192 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(t, ra); //Set RA highlighted point
193 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(t, de); //Set DEC highlighted point
194
195 //This will allow the graph to scroll left and right along with the guide slider
196 if (xAxis->range().contains(t) == false)
197 {
198 if(t < xAxis->range().lower)
199 {
200 xAxis->setRange(t, t + xAxis->range().size());
201 }
202 if(t > xAxis->range().upper)
203 {
204 xAxis->setRange(t - xAxis->range().size(), t);
205 }
206 }
207 replot();
208 double snr = 0;
209 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
210 snr = graph(GuideGraph::G_SNR)->dataMainValue(sliderValue);
211 double rms = graph(GuideGraph::G_RMS)->dataMainValue(sliderValue);
212
213 if(!graphOnLatestPt)
214 {
215 QTime localTime = guideTimer;
216 localTime = localTime.addSecs(t);
217
218 QPoint localTooltipCoordinates = graph(GuideGraph::G_RA)->dataPixelPosition(sliderValue).toPoint();
219 QPoint globalTooltipCoordinates = mapToGlobal(localTooltipCoordinates);
220
221 if(raPulse == 0 && dePulse == 0)
222 {
224 globalTooltipCoordinates,
225 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",
226 "<table>"
227 "<tr><td>LT: </td><td>%1</td></tr>"
228 "<tr><td>RA: </td><td>%2 \"</td></tr>"
229 "<tr><td>DE: </td><td>%3 \"</td></tr>"
230 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
231 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
232 "</table>",
233 localTime.toString("hh:mm:ss AP"),
234 QString::number(ra, 'f', 2),
235 QString::number(de, 'f', 2),
236 QString::number(rms, 'f', 2),
237 QString::number(snr, 'f', 1)
238 ));
239 }
240 else
241 {
243 globalTooltipCoordinates,
244 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",
245 "<table>"
246 "<tr><td>LT: </td><td>%1</td></tr>"
247 "<tr><td>RA: </td><td>%2 \"</td></tr>"
248 "<tr><td>DE: </td><td>%3 \"</td></tr>"
249 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
250 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
251 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
252 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
253 "</table>",
254 localTime.toString("hh:mm:ss AP"),
255 QString::number(ra, 'f', 2),
256 QString::number(de, 'f', 2),
257 QString::number(rms, 'f', 2),
258 QString::number(snr, 'f', 1),
259 QString::number(raPulse, 'f', 2),
260 QString::number(dePulse, 'f', 2)
261 )); //The pulses were divided by 100 before they were put on the graph.
262 }
263
264 }
265}
266
267void GuideDriftGraph::handleVerticalPlotSizeChange()
268{
269}
270
271void GuideDriftGraph::handleHorizontalPlotSizeChange()
272{
273}
274
275void GuideDriftGraph::setupNSEWLabels()
276{
277 //Labels for N/S/E/W
278 QColor raLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
279 QColor deLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
280
281 QCPItemText *northLabel = new QCPItemText(this);
282 northLabel->setColor(deLabelColor);
283 northLabel->setFont(QFont(font().family(), 9));
284 northLabel->setText(i18nc("North", "N"));
285 northLabel->position->setType(QCPItemPosition::ptViewportRatio);
286 northLabel->position->setCoords(0.7, 0.12);
287 northLabel->setVisible(true);
288
289 QCPItemText *southLabel = new QCPItemText(this);
290 southLabel->setColor(deLabelColor);
291 southLabel->setFont(QFont(font().family(), 9));
292 southLabel->setText(i18nc("South", "S"));
293 southLabel->position->setType(QCPItemPosition::ptViewportRatio);
294 southLabel->position->setCoords(0.7, 0.8);
295 southLabel->setVisible(true);
296
297 QCPItemText *westLabel = new QCPItemText(this);
298 westLabel->setColor(raLabelColor);
299 westLabel->setFont(QFont(font().family(), 9));
300 westLabel->setText(i18nc("West", "W"));
301 westLabel->position->setType(QCPItemPosition::ptViewportRatio);
302 westLabel->position->setCoords(0.78, 0.12);
303 westLabel->setVisible(true);
304
305 QCPItemText *eastLabel = new QCPItemText(this);
306 eastLabel->setColor(raLabelColor);
307 eastLabel->setFont(QFont(font().family(), 9));
308 eastLabel->setText(i18nc("East", "E"));
309 eastLabel->position->setType(QCPItemPosition::ptViewportRatio);
310 eastLabel->position->setCoords(0.8, 0.8);
311 eastLabel->setVisible(true);
312
313}
314
315void GuideDriftGraph::autoScaleGraphs()
316{
317 yAxis->setRange(-3, 3);
318 // First bool below is only_enlarge, 2nd is only look at values that are visible in X.
319 // Net result is all RA & DEC points within the times being plotted should be visible.
320 // This is only called when the autoScale button is pressed.
321 graph(GuideGraph::G_RA)->rescaleValueAxis(false, true);
322 graph(GuideGraph::G_DEC)->rescaleValueAxis(true, true);
323 replot();
324}
325
326void GuideDriftGraph::zoomX(int zoomLevel)
327{
328 double key = (guideElapsedTimer.isValid() || guideTimer.isValid()
329 || guideTimer.isNull()) ? 0 : guideElapsedTimer.elapsed() / 1000.0;
330
331 // The # of seconds displayd on the x-axis of the drift-graph for the various zoom levels.
332 static std::vector<int> zoomLevels = {15, 30, 60, 120, 300, 900, 1800, 3600, 7200, 14400};
333
334 zoomLevel = std::max(0, zoomLevel);
335 driftGraphZoomLevel = std::min(static_cast<int>(zoomLevels.size() - 1), zoomLevel);
336
337 xAxis->setRange(key - zoomLevels[driftGraphZoomLevel], key);
338}
339
340void GuideDriftGraph::zoomInX()
341{
342 zoomX(driftGraphZoomLevel - 1);
343 replot();
344}
345
346void GuideDriftGraph::zoomOutX()
347{
348 zoomX(driftGraphZoomLevel + 1);
349 replot();
350}
351
352void GuideDriftGraph::setCorrectionGraphScale(int value)
353{
354 yAxis2->setRange(yAxis->range().lower * value,
355 yAxis->range().upper * value);
356 replot();
357}
358
359void GuideDriftGraph::clear()
360{
361 graph(GuideGraph::G_RA)->data()->clear(); //RA data
362 graph(GuideGraph::G_DEC)->data()->clear(); //DEC data
363 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //RA highlighted point
364 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //DEC highlighted point
365 graph(GuideGraph::G_RA_PULSE)->data()->clear(); //RA Pulses
366 graph(GuideGraph::G_DEC_PULSE)->data()->clear(); //DEC Pulses
367 graph(GuideGraph::G_SNR)->data()->clear(); //SNR
368 graph(GuideGraph::G_RA_RMS)->data()->clear(); //RA RMS
369 graph(GuideGraph::G_DEC_RMS)->data()->clear(); //DEC RMS
370 graph(GuideGraph::G_RMS)->data()->clear(); //RMS
371 clearItems(); //Clears dither text items from the graph
372 setupNSEWLabels();
373 replot();
374}
375
376void GuideDriftGraph::toggleShowPlot(GuideGraph::DRIFT_GRAPH_INDICES plot, bool isChecked)
377{
378 switch (plot)
379 {
380 case GuideGraph::G_RA:
381 Options::setRADisplayedOnGuideGraph(isChecked);
382 graph(GuideGraph::G_RA)->setVisible(isChecked);
383 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(isChecked);
384 setRMSVisibility();
385 replot();
386 break;
387 case GuideGraph::G_DEC:
388 Options::setDEDisplayedOnGuideGraph(isChecked);
389 graph(GuideGraph::G_DEC)->setVisible(isChecked);
390 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(isChecked);
391 setRMSVisibility();
392 replot();
393 break;
394 case GuideGraph::G_RA_PULSE:
395 Options::setRACorrDisplayedOnGuideGraph(isChecked);
396 graph(GuideGraph::G_RA_PULSE)->setVisible(isChecked);
397 updateCorrectionsScaleVisibility();
398 break;
399 case GuideGraph::G_DEC_PULSE:
400 Options::setDECorrDisplayedOnGuideGraph(isChecked);
401 graph(GuideGraph::G_DEC_PULSE)->setVisible(isChecked);
402 updateCorrectionsScaleVisibility();
403 break;
404 case GuideGraph::G_SNR:
405 Options::setSNRDisplayedOnGuideGraph(isChecked);
406 graph(GuideGraph::G_SNR)->setVisible(isChecked);
407 replot();
408 break;
409 case GuideGraph::G_RMS:
410 Options::setRMSDisplayedOnGuideGraph(isChecked);
411 setRMSVisibility();
412 replot();
413 break;
414 default:
415 break;
416 }
417}
418
419void GuideDriftGraph::setRMSVisibility()
420{
421 if (!Options::rMSDisplayedOnGuideGraph())
422 {
423 graph(GuideGraph::G_RA_RMS)->setVisible(false);
424 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
425 graph(GuideGraph::G_RMS)->setVisible(false);
426 return;
427 }
428
429 if ((Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph()) ||
430 (!Options::dEDisplayedOnGuideGraph() && !Options::rADisplayedOnGuideGraph()))
431 {
432 graph(GuideGraph::G_RA_RMS)->setVisible(false);
433 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
434 graph(GuideGraph::G_RMS)->setVisible(true);
435 }
436 else if (!Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph())
437 {
438 graph(GuideGraph::G_RA_RMS)->setVisible(true);
439 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
440 graph(GuideGraph::G_RMS)->setVisible(false);
441 }
442 else
443 {
444 graph(GuideGraph::G_RA_RMS)->setVisible(false);
445 graph(GuideGraph::G_DEC_RMS)->setVisible(true);
446 graph(GuideGraph::G_RMS)->setVisible(false);
447 }
448}
449
450void GuideDriftGraph::exportGuideData()
451{
452 int numPoints = graph(GuideGraph::G_RA)->dataCount();
453 if (numPoints == 0)
454 return;
455
456 QUrl exportFile = QFileDialog::getSaveFileUrl(this, i18nc("@title:window", "Export Guide Data"), guideURLPath,
457 "CSV File (*.csv)");
458 if (exportFile.isEmpty()) // if user presses cancel
459 return;
460 if (exportFile.toLocalFile().endsWith(QLatin1String(".csv")) == false)
461 exportFile.setPath(exportFile.toLocalFile() + ".csv");
462
463 QString path = exportFile.toLocalFile();
464
465 if (QFile::exists(path))
466 {
468 i18n("A file named \"%1\" already exists. "
469 "Overwrite it?",
470 exportFile.fileName()),
471 i18n("Overwrite File?"), KStandardGuiItem::overwrite());
472 if (r == KMessageBox::Cancel)
473 return;
474 }
475
476 if (!exportFile.isValid())
477 {
478 QString message = i18n("Invalid URL: %1", exportFile.url());
479 KSNotification::sorry(message, i18n("Invalid URL"));
480 return;
481 }
482
483 QFile file;
484 file.setFileName(path);
485 if (!file.open(QIODevice::WriteOnly))
486 {
487 QString message = i18n("Unable to write to file %1", path);
488 KSNotification::sorry(message, i18n("Could Not Open File"));
489 return;
490 }
491
492 QTextStream outstream(&file);
493
494 outstream <<
495 "Frame #, Time Elapsed (sec), Local Time (HMS), RA Error (arcsec), DE Error (arcsec), RA Pulse (ms), DE Pulse (ms)" <<
496 Qt::endl;
497
498 for (int i = 0; i < numPoints; i++)
499 {
500 double t = graph(GuideGraph::G_RA)->dataMainKey(i);
501 double ra = graph(GuideGraph::G_RA)->dataMainValue(i);
502 double de = graph(GuideGraph::G_DEC)->dataMainValue(i);
503 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(i);
504 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(i);
505
506 QTime localTime = guideTimer;
507 localTime = localTime.addSecs(t);
508
509 outstream << i << ',' << t << ',' << localTime.toString("hh:mm:ss AP") << ',' << ra << ',' << de << ',' << raPulse << ',' <<
510 dePulse << ',' << Qt::endl;
511 }
512 file.close();
513}
514
515void GuideDriftGraph::resetTimer()
516{
517 guideTimer = QTime::currentTime();
518 guideElapsedTimer.start();
519}
520
521void GuideDriftGraph::connectGuider(Ekos::GuideInterface *guider)
522{
523 connect(guider, &Ekos::GuideInterface::newAxisDelta, this, &GuideDriftGraph::setAxisDelta);
524 connect(guider, &Ekos::GuideInterface::newAxisPulse, this, &GuideDriftGraph::setAxisPulse);
525 connect(guider, &Ekos::GuideInterface::newAxisSigma, this, &GuideDriftGraph::setAxisSigma);
526 connect(guider, &Ekos::GuideInterface::newSNR, this, &GuideDriftGraph::setSNR);
527
528 resetTimer();
529}
530
531void GuideDriftGraph::setAxisDelta(double ra, double de)
532{
533 // Time since timer started.
534 double key = guideElapsedTimer.elapsed() / 1000.0;
535
536 // similar to same operation in Guide::setAxisDelta
537 ra = -ra;
538
539 graph(GuideGraph::G_RA)->addData(key, ra);
540 graph(GuideGraph::G_DEC)->addData(key, de);
541
542 if(graphOnLatestPt)
543 {
544 xAxis->setRange(key, xAxis->range().size(), Qt::AlignRight);
545 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear highlighted RA point
546 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear highlighted DEC point
547 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(key, ra); //Set highlighted RA point to latest point
548 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(key, de); //Set highlighted DEC point to latest point
549 }
550 replot();
551}
552
553void GuideDriftGraph::setAxisSigma(double ra, double de)
554{
555 const double key = guideElapsedTimer.elapsed() / 1000.0;
556 const double total = std::hypot(ra, de);
557 graph(GuideGraph::G_RA_RMS)->addData(key, ra);
558 graph(GuideGraph::G_DEC_RMS)->addData(key, de);
559 graph(GuideGraph::G_RMS)->addData(key, total);
560}
561
562void GuideDriftGraph::setAxisPulse(double ra, double de)
563{
564 double key = guideElapsedTimer.elapsed() / 1000.0;
565 graph(GuideGraph::G_RA_PULSE)->addData(key, ra);
566 graph(GuideGraph::G_DEC_PULSE)->addData(key, de);
567}
568
569void GuideDriftGraph::setSNR(double snr)
570{
571 double key = guideElapsedTimer.elapsed() / 1000.0;
572 graph(GuideGraph::G_SNR)->addData(key, snr);
573
574 // Sets the SNR axis to have the maximum be 95% of the way up from the middle to the top.
575 QCPGraphData snrMax = *std::min_element(graph(GuideGraph::G_SNR)->data()->begin(),
576 graph(GuideGraph::G_SNR)->data()->end(),
577 [](QCPGraphData const & s1, QCPGraphData const & s2)
578 {
579 return s1.value > s2.value;
580 });
581 snrAxis->setRange(-1.05 * snrMax.value, 1.05 * snrMax.value);
582}
583
584void GuideDriftGraph::updateCorrectionsScaleVisibility()
585{
586 bool isVisible = (Options::rACorrDisplayedOnGuideGraph() || Options::dECorrDisplayedOnGuideGraph());
588 replot();
589}
590
591void GuideDriftGraph::mouseOverLine(QMouseEvent *event)
592{
593 double key = xAxis->pixelToCoord(event->localPos().x());
594
595 if (xAxis->range().contains(key))
596 {
597 if (plottableAt(event->pos(), false))
598 {
599 int raIndex = graph(GuideGraph::G_RA)->findBegin(key);
600 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key);
601 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key);
602
603 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex);
604 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex);
605
606 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data
607 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data
608
609 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex);
610 double snr = 0;
611 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
612 {
613 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key);
614 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex);
615 }
616
617 // Compute time value:
618 QTime localTime = guideTimer;
619
620 localTime = localTime.addSecs(key);
621
623 if(raPulse == 0 && dePulse == 0)
624 {
626 event->globalPos(),
627 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",
628 "<table>"
629 "<tr><td>LT: </td><td>%1</td></tr>"
630 "<tr><td>RA: </td><td>%2 \"</td></tr>"
631 "<tr><td>DE: </td><td>%3 \"</td></tr>"
632 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
633 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
634 "</table>",
635 localTime.toString("hh:mm:ss AP"),
636 QString::number(raDelta, 'f', 2), QString::number(deDelta, 'f', 2),
637 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1)));
638 }
639 else
640 {
642 event->globalPos(),
643 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",
644 "<table>"
645 "<tr><td>LT: </td><td>%1</td></tr>"
646 "<tr><td>RA: </td><td>%2 \"</td></tr>"
647 "<tr><td>DE: </td><td>%3 \"</td></tr>"
648 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
649 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
650 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
651 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
652 "</table>",
653 localTime.toString("hh:mm:ss AP"),
654 QString::number(raDelta, 'f', 2),
655 QString::number(deDelta, 'f', 2),
656 QString::number(rms, 'f', 2),
657 QString::number(snr, 'f', 1),
658 QString::number(raPulse, 'f', 2),
659 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph.
660 }
661 }
662 else
664
665 replot();
666 }
667
668 if (xAxis->range().contains(key))
669 {
670 QCPGraph *qcpgraph = qobject_cast<QCPGraph *>(plottableAt(event->pos(), false));
671
672 if (qcpgraph)
673 {
674 int raIndex = graph(GuideGraph::G_RA)->findBegin(key);
675 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key);
676 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key);
677
678 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex);
679 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex);
680
681 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data
682 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data
683
684 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex);
685 double snr = 0;
686 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
687 {
688 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key);
689 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex);
690 }
691
692 // Compute time value:
693 QTime localTime = guideTimer;
694
695 localTime = localTime.addSecs(key);
696
698 if(raPulse == 0 && dePulse == 0)
699 {
701 event->globalPos(),
702 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",
703 "<table>"
704 "<tr><td>LT: </td><td>%1</td></tr>"
705 "<tr><td>RA: </td><td>%2 \"</td></tr>"
706 "<tr><td>DE: </td><td>%3 \"</td></tr>"
707 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
708 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
709 "</table>",
710 localTime.toString("hh:mm:ss AP"),
711 QString::number(raDelta, 'f', 2), QString::number(deDelta, 'f', 2),
712 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1)));
713 }
714 else
715 {
717 event->globalPos(),
718 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",
719 "<table>"
720 "<tr><td>LT: </td><td>%1</td></tr>"
721 "<tr><td>RA: </td><td>%2 \"</td></tr>"
722 "<tr><td>DE: </td><td>%3 \"</td></tr>"
723 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
724 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
725 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
726 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
727 "</table>",
728 localTime.toString("hh:mm:ss AP"),
729 QString::number(raDelta, 'f', 2),
730 QString::number(deDelta, 'f', 2),
731 QString::number(rms, 'f', 2),
732 QString::number(snr, 'f', 1),
733 QString::number(raPulse, 'f', 2),
734 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph.
735 }
736 }
737 else
739
740 replot();
741 }
742}
743
744void GuideDriftGraph::mouseClicked(QMouseEvent *event)
745{
746 if (event->buttons() & Qt::RightButton)
747 {
748 yAxis->setRange(-3, 3);
749 }
750}
751
752void GuideDriftGraph::refreshColorScheme()
753{
754 if (graph(GuideGraph::G_RA) && graph(GuideGraph::G_DEC) && graph(GuideGraph::G_RA_HIGHLIGHT)
755 && graph(GuideGraph::G_DEC_HIGHLIGHT) && graph(GuideGraph::G_RA_PULSE)
756 && graph(GuideGraph::G_DEC_PULSE))
757 {
758 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
759 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
760 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
762 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10));
763 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
765 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10));
766
767 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
768 raPulseColor.setAlpha(75);
769 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor));
770 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern));
771
772 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
773 dePulseColor.setAlpha(75);
774 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor));
775 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern));
776 }
777}
Interface skeleton for implementation of different guiding applications and/or routines.
virtual QPointF dataPixelPosition(int index) const override
virtual int findBegin(double sortKey, bool expandedRange=true) const override
virtual int dataCount() const override
virtual double dataMainKey(int index) const override
virtual double dataMainValue(int index) const override
void rescaleValueAxis(bool onlyEnlarge=false, bool inKeyRange=false) const
void setBrush(const QBrush &brush)
void setPen(const QPen &pen)
void setName(const QString &name)
QCPAxis * addAxis(QCPAxis::AxisType type, QCPAxis *axis=nullptr)
void setRangeZoom(Qt::Orientations orientations)
QCPLayoutInset * insetLayout() const
Specialized axis ticker for time spans in units of milliseconds to days.
void setTickLabels(bool show)
void setTickLabelFont(const QFont &font)
void setLabel(const QString &str)
void setTickLabelColor(const QColor &color)
void setLabelPadding(int padding)
void setTicker(QSharedPointer< QCPAxisTicker > ticker)
double pixelToCoord(double value) const
QCPGrid * grid() const
void setLabelColor(const QColor &color)
void setLabelFont(const QFont &font)
void setBasePen(const QPen &pen)
void setTickPen(const QPen &pen)
@ atLeft
0x01 Axis is vertical and on the left side of the axis rect
Q_SLOT void setRange(const QCPRange &range)
void setSubTickPen(const QPen &pen)
Holds the data of one single data point for QCPGraph.
A plottable representing a graph in a plot.
void setScatterStyle(const QCPScatterStyle &style)
QSharedPointer< QCPGraphDataContainer > data() const
void setLineStyle(LineStyle ls)
@ lsLine
data points are connected by a straight line
@ lsStepLeft
line is drawn as steps where the step height is the value of the left data point
@ lsNone
data points are not connected with any lines (e.g.
void addData(const QVector< double > &keys, const QVector< double > &values, bool alreadySorted=false)
void setZeroLinePen(const QPen &pen)
void setSubGridPen(const QPen &pen)
void setPen(const QPen &pen)
void setType(PositionType type)
void setCoords(double key, double value)
@ ptViewportRatio
Static positioning given by a fraction of the viewport size.
A text label.
void setText(const QString &text)
void setFont(const QFont &font)
void setColor(const QColor &color)
void setVisible(bool on)
@ foColumnsFirst
Columns are filled first, and a new element is wrapped to the next row if the column count would exce...
void setFillOrder(FillOrder order, bool rearrange=true)
void setInsetAlignment(int index, Qt::Alignment alignment)
void setBrush(const QBrush &brush)
void setIconSize(const QSize &size)
void setFont(const QFont &font)
bool removeItem(int index)
void setTextColor(const QColor &color)
double size() const
bool contains(double value) const
Represents the visual appearance of scatter points.
@ ssPlusCircle
\enumimage{ssPlusCircle.png} a circle with a plus inside
void setBackground(const QPixmap &pm)
QCPGraph * addGraph(QCPAxis *keyAxis=nullptr, QCPAxis *valueAxis=nullptr)
void setInteraction(const QCP::Interaction &interaction, bool enabled=true)
PlottableType * plottableAt(const QPointF &pos, bool onlySelectable=false, int *dataIndex=nullptr) const
void setInteractions(const QCP::Interactions &interactions)
QCPLegend * legend
QCPAxis * xAxis
Q_SLOT void replot(QCustomPlot::RefreshPriority refreshPriority=QCustomPlot::rpRefreshHint)
QCPGraph * graph() const
QCPAxisRect * axisRect(int index=0) const
QCPAxis * yAxis2
QCPAxis * yAxis
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString path(const QString &relativePath)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
KGuiItem overwrite()
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
@ iRangeDrag
0x001 Axis ranges are draggable (see QCPAxisRect::setRangeDrag, QCPAxisRect::setRangeDragAxes)
@ iRangeZoom
0x002 Axis ranges are zoomable with the mouse wheel (see QCPAxisRect::setRangeZoom,...
qint64 elapsed() const const
bool isValid() const const
bool exists() const const
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
T qobject_cast(QObject *object)
QPoint toPoint() const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString number(double n, char format, int precision)
AlignRight
Dense4Pattern
RightButton
QTextStream & endl(QTextStream &stream)
QTime addSecs(int s) const const
QTime currentTime()
bool isNull() const const
bool isValid(int h, int m, int s, int ms)
QString toString(QStringView format) const const
void hideText()
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
QString fileName(ComponentFormattingOptions options) const const
bool isEmpty() const const
bool isValid() const const
void setPath(const QString &path, ParsingMode mode)
QString toLocalFile() const const
QString url(FormattingOptions options) const const
virtual bool event(QEvent *event) override
void lower()
QPoint mapToGlobal(const QPoint &pos) const const
bool isVisible() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.