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
18GuideDriftGraph::GuideDriftGraph(QWidget *parent)
19{
21 // Drift Graph Color Settings
25 xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
26 yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
27 xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
28 yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
46
47 snrAxis = axisRect()->addAxis(QCPAxis::atLeft, 0);
48 snrAxis->setVisible(false);
49 // This will be reset to the actual data values.
50 snrAxis->setRange(-100, 100);
51
52 //Horizontal Axis Time Ticker Settings
54 timeTicker->setTimeFormat("%m:%s");
56
57 // Axis Labels Settings
58 yAxis2->setVisible(true);
59 yAxis2->setTickLabels(true);
60 yAxis->setLabelFont(QFont(font().family(), 10));
61 yAxis2->setLabelFont(QFont(font().family(), 10));
62 xAxis->setTickLabelFont(QFont(font().family(), 9));
63 yAxis->setTickLabelFont(QFont(font().family(), 9));
64 yAxis2->setTickLabelFont(QFont(font().family(), 9));
67 yAxis->setLabel(i18n("drift (arcsec)"));
68 yAxis2->setLabel(i18n("pulse (ms)"));
69
70 setupNSEWLabels();
71
72 int scale =
73 50; //This is a scaling value between the left and the right axes of the driftGraph, it could be stored in kstars kcfg
74
75 //Sets the default ranges
77 yAxis->setRange(-3, 3);
78 yAxis2->setRange(-3 * scale, 3 * scale);
79
80 //This sets up the legend
81 legend->setVisible(true);
82 legend->setFont(QFont(font().family(), 7));
85 legend->setIconSize(4, 12);
88
89 // RA Curve
91 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
92 graph(GuideGraph::G_RA)->setName("RA");
93 graph(GuideGraph::G_RA)->setLineStyle(QCPGraph::lsLine);
94
95 // DE Curve
97 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
98 graph(GuideGraph::G_DEC)->setName("DE");
99 graph(GuideGraph::G_DEC)->setLineStyle(QCPGraph::lsLine);
100
101 // RA highlighted Point
103 graph(GuideGraph::G_RA_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone);
104 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
106 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10));
107
108 // DE highlighted Point
110 graph(GuideGraph::G_DEC_HIGHLIGHT)->setLineStyle(QCPGraph::lsNone);
111 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
113 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10));
114
115 // RA Pulse
117 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
118 raPulseColor.setAlpha(75);
119 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor));
120 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern));
121 graph(GuideGraph::G_RA_PULSE)->setName("RA Pulse");
122 graph(GuideGraph::G_RA_PULSE)->setLineStyle(QCPGraph::lsStepLeft);
123
124 // DEC Pulse
126 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
127 dePulseColor.setAlpha(75);
128 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor));
129 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern));
130 graph(GuideGraph::G_DEC_PULSE)->setName("DEC Pulse");
131 graph(GuideGraph::G_DEC_PULSE)->setLineStyle(QCPGraph::lsStepLeft);
132
133 // SNR
134 addGraph(xAxis, snrAxis);
135 graph(GuideGraph::G_SNR)->setPen(QPen(Qt::yellow));
136 graph(GuideGraph::G_SNR)->setName("SNR");
137 graph(GuideGraph::G_SNR)->setLineStyle(QCPGraph::lsLine);
138
139 // RA RMS
141 graph(GuideGraph::G_RA_RMS)->setPen(QPen(Qt::red));
142 graph(GuideGraph::G_RA_RMS)->setName("RA RMS");
143 graph(GuideGraph::G_RA_RMS)->setLineStyle(QCPGraph::lsLine);
144
145 // DEC RMS
147 graph(GuideGraph::G_DEC_RMS)->setPen(QPen(Qt::red));
148 graph(GuideGraph::G_DEC_RMS)->setName("DEC RMS");
149 graph(GuideGraph::G_DEC_RMS)->setLineStyle(QCPGraph::lsLine);
150
151 // Total RMS
153 graph(GuideGraph::G_RMS)->setPen(QPen(Qt::red));
154 graph(GuideGraph::G_RMS)->setName("RMS");
155 graph(GuideGraph::G_RMS)->setLineStyle(QCPGraph::lsLine);
156
157 //This will prevent the highlighted points and Pulses from showing up in the legend.
158 legend->removeItem(GuideGraph::G_DEC_RMS);
159 legend->removeItem(GuideGraph::G_RA_RMS);
160 legend->removeItem(GuideGraph::G_DEC_PULSE);
161 legend->removeItem(GuideGraph::G_RA_PULSE);
162 legend->removeItem(GuideGraph::G_DEC_HIGHLIGHT);
163 legend->removeItem(GuideGraph::G_RA_HIGHLIGHT);
164
166 axisRect()->setRangeZoom(Qt::Orientation::Vertical);
168 //This sets the visibility of graph components to the stored values.
169 graph(GuideGraph::G_RA)->setVisible(Options::rADisplayedOnGuideGraph()); //RA data
170 graph(GuideGraph::G_DEC)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC data
171 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(Options::rADisplayedOnGuideGraph()); //RA highlighted point
172 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(Options::dEDisplayedOnGuideGraph()); //DEC highlighted point
173 graph(GuideGraph::G_RA_PULSE)->setVisible(Options::rACorrDisplayedOnGuideGraph()); //RA Pulses
174 graph(GuideGraph::G_DEC_PULSE)->setVisible(Options::dECorrDisplayedOnGuideGraph()); //DEC Pulses
175 graph(GuideGraph::G_SNR)->setVisible(Options::sNRDisplayedOnGuideGraph()); //SNR
176 setRMSVisibility();
177
178 updateCorrectionsScaleVisibility();
179}
180
181void GuideDriftGraph::guideHistory(int sliderValue, bool graphOnLatestPt)
182{
183 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear RA highlighted point
184 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear DEC highlighted point
185 double t = graph(GuideGraph::G_RA)->dataMainKey(sliderValue); //Get time from RA data
186 double ra = graph(GuideGraph::G_RA)->dataMainValue(sliderValue); //Get RA from RA data
187 double de = graph(GuideGraph::G_DEC)->dataMainValue(sliderValue); //Get DEC from DEC data
188 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(sliderValue); //Get RA Pulse from RA pulse data
189 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(sliderValue); //Get DEC Pulse from DEC pulse data
190 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(t, ra); //Set RA highlighted point
191 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(t, de); //Set DEC highlighted point
192
193 //This will allow the graph to scroll left and right along with the guide slider
194 if (xAxis->range().contains(t) == false)
195 {
196 if(t < xAxis->range().lower)
197 {
198 xAxis->setRange(t, t + xAxis->range().size());
199 }
200 if(t > xAxis->range().upper)
201 {
202 xAxis->setRange(t - xAxis->range().size(), t);
203 }
204 }
205 replot();
206 double snr = 0;
207 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
208 snr = graph(GuideGraph::G_SNR)->dataMainValue(sliderValue);
209 double rms = graph(GuideGraph::G_RMS)->dataMainValue(sliderValue);
210
211 if(!graphOnLatestPt)
212 {
213 QTime localTime = guideTimer;
214 localTime = localTime.addSecs(t);
215
216 QPoint localTooltipCoordinates = graph(GuideGraph::G_RA)->dataPixelPosition(sliderValue).toPoint();
218
219 if(raPulse == 0 && dePulse == 0)
220 {
223 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",
224 "<table>"
225 "<tr><td>LT: </td><td>%1</td></tr>"
226 "<tr><td>RA: </td><td>%2 \"</td></tr>"
227 "<tr><td>DE: </td><td>%3 \"</td></tr>"
228 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
229 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
230 "</table>",
231 localTime.toString("hh:mm:ss AP"),
232 QString::number(ra, 'f', 2),
233 QString::number(de, 'f', 2),
234 QString::number(rms, 'f', 2),
235 QString::number(snr, 'f', 1)
236 ));
237 }
238 else
239 {
242 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",
243 "<table>"
244 "<tr><td>LT: </td><td>%1</td></tr>"
245 "<tr><td>RA: </td><td>%2 \"</td></tr>"
246 "<tr><td>DE: </td><td>%3 \"</td></tr>"
247 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
248 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
249 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
250 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
251 "</table>",
252 localTime.toString("hh:mm:ss AP"),
253 QString::number(ra, 'f', 2),
254 QString::number(de, 'f', 2),
255 QString::number(rms, 'f', 2),
256 QString::number(snr, 'f', 1),
257 QString::number(raPulse, 'f', 2),
258 QString::number(dePulse, 'f', 2)
259 )); //The pulses were divided by 100 before they were put on the graph.
260 }
261
262 }
263}
264
265void GuideDriftGraph::handleVerticalPlotSizeChange()
266{
267}
268
269void GuideDriftGraph::handleHorizontalPlotSizeChange()
270{
271}
272
273void GuideDriftGraph::setupNSEWLabels()
274{
275 //Labels for N/S/E/W
276 QColor raLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
277 QColor deLabelColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
278
280 northLabel->setColor(deLabelColor);
281 northLabel->setFont(QFont(font().family(), 9));
282 northLabel->setText(i18nc("North", "N"));
284 northLabel->position->setCoords(0.7, 0.12);
285 northLabel->setVisible(true);
286
288 southLabel->setColor(deLabelColor);
289 southLabel->setFont(QFont(font().family(), 9));
290 southLabel->setText(i18nc("South", "S"));
292 southLabel->position->setCoords(0.7, 0.8);
293 southLabel->setVisible(true);
294
295 QCPItemText *westLabel = new QCPItemText(this);
296 westLabel->setColor(raLabelColor);
297 westLabel->setFont(QFont(font().family(), 9));
298 westLabel->setText(i18nc("West", "W"));
300 westLabel->position->setCoords(0.78, 0.12);
301 westLabel->setVisible(true);
302
303 QCPItemText *eastLabel = new QCPItemText(this);
304 eastLabel->setColor(raLabelColor);
305 eastLabel->setFont(QFont(font().family(), 9));
306 eastLabel->setText(i18nc("East", "E"));
308 eastLabel->position->setCoords(0.8, 0.8);
309 eastLabel->setVisible(true);
310
311}
312
313void GuideDriftGraph::autoScaleGraphs()
314{
315 yAxis->setRange(-3, 3);
316 // First bool below is only_enlarge, 2nd is only look at values that are visible in X.
317 // Net result is all RA & DEC points within the times being plotted should be visible.
318 // This is only called when the autoScale button is pressed.
319 graph(GuideGraph::G_RA)->rescaleValueAxis(false, true);
320 graph(GuideGraph::G_DEC)->rescaleValueAxis(true, true);
321 replot();
322}
323
324void GuideDriftGraph::zoomX(int zoomLevel)
325{
326 double key = (guideElapsedTimer.isValid() || guideTimer.isValid()
327 || guideTimer.isNull()) ? 0 : guideElapsedTimer.elapsed() / 1000.0;
328
329 // The # of seconds displayd on the x-axis of the drift-graph for the various zoom levels.
330 static std::vector<int> zoomLevels = {15, 30, 60, 120, 300, 900, 1800, 3600, 7200, 14400};
331
332 zoomLevel = std::max(0, zoomLevel);
333 driftGraphZoomLevel = std::min(static_cast<int>(zoomLevels.size() - 1), zoomLevel);
334
335 xAxis->setRange(key - zoomLevels[driftGraphZoomLevel], key);
336}
337
338void GuideDriftGraph::zoomInX()
339{
340 zoomX(driftGraphZoomLevel - 1);
341 replot();
342}
343
344void GuideDriftGraph::zoomOutX()
345{
346 zoomX(driftGraphZoomLevel + 1);
347 replot();
348}
349
350void GuideDriftGraph::setCorrectionGraphScale(int value)
351{
352 yAxis2->setRange(yAxis->range().lower * value,
353 yAxis->range().upper * value);
354 replot();
355}
356
357void GuideDriftGraph::clear()
358{
359 graph(GuideGraph::G_RA)->data()->clear(); //RA data
360 graph(GuideGraph::G_DEC)->data()->clear(); //DEC data
361 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //RA highlighted point
362 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //DEC highlighted point
363 graph(GuideGraph::G_RA_PULSE)->data()->clear(); //RA Pulses
364 graph(GuideGraph::G_DEC_PULSE)->data()->clear(); //DEC Pulses
365 graph(GuideGraph::G_SNR)->data()->clear(); //SNR
366 graph(GuideGraph::G_RA_RMS)->data()->clear(); //RA RMS
367 graph(GuideGraph::G_DEC_RMS)->data()->clear(); //DEC RMS
368 graph(GuideGraph::G_RMS)->data()->clear(); //RMS
369 clearItems(); //Clears dither text items from the graph
370 setupNSEWLabels();
371 replot();
372}
373
374void GuideDriftGraph::toggleShowPlot(GuideGraph::DRIFT_GRAPH_INDICES plot, bool isChecked)
375{
376 switch (plot)
377 {
378 case GuideGraph::G_RA:
379 Options::setRADisplayedOnGuideGraph(isChecked);
380 graph(GuideGraph::G_RA)->setVisible(isChecked);
381 graph(GuideGraph::G_RA_HIGHLIGHT)->setVisible(isChecked);
382 setRMSVisibility();
383 replot();
384 break;
385 case GuideGraph::G_DEC:
386 Options::setDEDisplayedOnGuideGraph(isChecked);
387 graph(GuideGraph::G_DEC)->setVisible(isChecked);
388 graph(GuideGraph::G_DEC_HIGHLIGHT)->setVisible(isChecked);
389 setRMSVisibility();
390 replot();
391 break;
392 case GuideGraph::G_RA_PULSE:
393 Options::setRACorrDisplayedOnGuideGraph(isChecked);
394 graph(GuideGraph::G_RA_PULSE)->setVisible(isChecked);
395 updateCorrectionsScaleVisibility();
396 break;
397 case GuideGraph::G_DEC_PULSE:
398 Options::setDECorrDisplayedOnGuideGraph(isChecked);
399 graph(GuideGraph::G_DEC_PULSE)->setVisible(isChecked);
400 updateCorrectionsScaleVisibility();
401 break;
402 case GuideGraph::G_SNR:
403 Options::setSNRDisplayedOnGuideGraph(isChecked);
404 graph(GuideGraph::G_SNR)->setVisible(isChecked);
405 replot();
406 break;
407 case GuideGraph::G_RMS:
408 Options::setRMSDisplayedOnGuideGraph(isChecked);
409 setRMSVisibility();
410 replot();
411 break;
412 default:
413 break;
414 }
415}
416
417void GuideDriftGraph::setRMSVisibility()
418{
419 if (!Options::rMSDisplayedOnGuideGraph())
420 {
421 graph(GuideGraph::G_RA_RMS)->setVisible(false);
422 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
423 graph(GuideGraph::G_RMS)->setVisible(false);
424 return;
425 }
426
427 if ((Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph()) ||
428 (!Options::dEDisplayedOnGuideGraph() && !Options::rADisplayedOnGuideGraph()))
429 {
430 graph(GuideGraph::G_RA_RMS)->setVisible(false);
431 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
432 graph(GuideGraph::G_RMS)->setVisible(true);
433 }
434 else if (!Options::dEDisplayedOnGuideGraph() && Options::rADisplayedOnGuideGraph())
435 {
436 graph(GuideGraph::G_RA_RMS)->setVisible(true);
437 graph(GuideGraph::G_DEC_RMS)->setVisible(false);
438 graph(GuideGraph::G_RMS)->setVisible(false);
439 }
440 else
441 {
442 graph(GuideGraph::G_RA_RMS)->setVisible(false);
443 graph(GuideGraph::G_DEC_RMS)->setVisible(true);
444 graph(GuideGraph::G_RMS)->setVisible(false);
445 }
446}
447
448void GuideDriftGraph::exportGuideData()
449{
450 int numPoints = graph(GuideGraph::G_RA)->dataCount();
451 if (numPoints == 0)
452 return;
453
454 QUrl exportFile = QFileDialog::getSaveFileUrl(this, i18nc("@title:window", "Export Guide Data"), guideURLPath,
455 "CSV File (*.csv)");
456 if (exportFile.isEmpty()) // if user presses cancel
457 return;
458 if (exportFile.toLocalFile().endsWith(QLatin1String(".csv")) == false)
459 exportFile.setPath(exportFile.toLocalFile() + ".csv");
460
461 QString path = exportFile.toLocalFile();
462
463 if (QFile::exists(path))
464 {
466 i18n("A file named \"%1\" already exists. "
467 "Overwrite it?",
468 exportFile.fileName()),
469 i18n("Overwrite File?"), KStandardGuiItem::overwrite());
470 if (r == KMessageBox::Cancel)
471 return;
472 }
473
474 if (!exportFile.isValid())
475 {
476 QString message = i18n("Invalid URL: %1", exportFile.url());
477 KSNotification::sorry(message, i18n("Invalid URL"));
478 return;
479 }
480
481 QFile file;
482 file.setFileName(path);
483 if (!file.open(QIODevice::WriteOnly))
484 {
485 QString message = i18n("Unable to write to file %1", path);
486 KSNotification::sorry(message, i18n("Could Not Open File"));
487 return;
488 }
489
490 QTextStream outstream(&file);
491
492 outstream <<
493 "Frame #, Time Elapsed (sec), Local Time (HMS), RA Error (arcsec), DE Error (arcsec), RA Pulse (ms), DE Pulse (ms)" <<
494 Qt::endl;
495
496 for (int i = 0; i < numPoints; i++)
497 {
498 double t = graph(GuideGraph::G_RA)->dataMainKey(i);
499 double ra = graph(GuideGraph::G_RA)->dataMainValue(i);
500 double de = graph(GuideGraph::G_DEC)->dataMainValue(i);
501 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(i);
502 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(i);
503
504 QTime localTime = guideTimer;
505 localTime = localTime.addSecs(t);
506
507 outstream << i << ',' << t << ',' << localTime.toString("hh:mm:ss AP") << ',' << ra << ',' << de << ',' << raPulse << ',' <<
508 dePulse << ',' << Qt::endl;
509 }
510 file.close();
511}
512
513void GuideDriftGraph::resetTimer()
514{
515 guideTimer = QTime::currentTime();
516 guideElapsedTimer.start();
517}
518
519void GuideDriftGraph::connectGuider(Ekos::GuideInterface *guider)
520{
521 connect(guider, &Ekos::GuideInterface::newAxisDelta, this, &GuideDriftGraph::setAxisDelta);
522 connect(guider, &Ekos::GuideInterface::newAxisPulse, this, &GuideDriftGraph::setAxisPulse);
523 connect(guider, &Ekos::GuideInterface::newAxisSigma, this, &GuideDriftGraph::setAxisSigma);
524 connect(guider, &Ekos::GuideInterface::newSNR, this, &GuideDriftGraph::setSNR);
525
526 resetTimer();
527}
528
529void GuideDriftGraph::setAxisDelta(double ra, double de)
530{
531 // Time since timer started.
532 double key = guideElapsedTimer.elapsed() / 1000.0;
533
534 // similar to same operation in Guide::setAxisDelta
535 ra = -ra;
536
537 graph(GuideGraph::G_RA)->addData(key, ra);
538 graph(GuideGraph::G_DEC)->addData(key, de);
539
540 if(graphOnLatestPt)
541 {
542 xAxis->setRange(key, xAxis->range().size(), Qt::AlignRight);
543 graph(GuideGraph::G_RA_HIGHLIGHT)->data()->clear(); //Clear highlighted RA point
544 graph(GuideGraph::G_DEC_HIGHLIGHT)->data()->clear(); //Clear highlighted DEC point
545 graph(GuideGraph::G_RA_HIGHLIGHT)->addData(key, ra); //Set highlighted RA point to latest point
546 graph(GuideGraph::G_DEC_HIGHLIGHT)->addData(key, de); //Set highlighted DEC point to latest point
547 }
548 replot();
549}
550
551void GuideDriftGraph::setAxisSigma(double ra, double de)
552{
553 const double key = guideElapsedTimer.elapsed() / 1000.0;
554 const double total = std::hypot(ra, de);
555 graph(GuideGraph::G_RA_RMS)->addData(key, ra);
556 graph(GuideGraph::G_DEC_RMS)->addData(key, de);
557 graph(GuideGraph::G_RMS)->addData(key, total);
558}
559
560void GuideDriftGraph::setAxisPulse(double ra, double de)
561{
562 double key = guideElapsedTimer.elapsed() / 1000.0;
563 graph(GuideGraph::G_RA_PULSE)->addData(key, ra);
564 graph(GuideGraph::G_DEC_PULSE)->addData(key, de);
565}
566
567void GuideDriftGraph::setSNR(double snr)
568{
569 double key = guideElapsedTimer.elapsed() / 1000.0;
570 graph(GuideGraph::G_SNR)->addData(key, snr);
571
572 // Sets the SNR axis to have the maximum be 95% of the way up from the middle to the top.
573 QCPGraphData snrMax = *std::min_element(graph(GuideGraph::G_SNR)->data()->begin(),
574 graph(GuideGraph::G_SNR)->data()->end(),
575 [](QCPGraphData const & s1, QCPGraphData const & s2)
576 {
577 return s1.value > s2.value;
578 });
579 snrAxis->setRange(-1.05 * snrMax.value, 1.05 * snrMax.value);
580}
581
582void GuideDriftGraph::updateCorrectionsScaleVisibility()
583{
584 bool isVisible = (Options::rACorrDisplayedOnGuideGraph() || Options::dECorrDisplayedOnGuideGraph());
586 replot();
587}
588
589void GuideDriftGraph::mouseOverLine(QMouseEvent *event)
590{
591 double key = xAxis->pixelToCoord(event->localPos().x());
592
593 if (xAxis->range().contains(key))
594 {
595 if (plottableAt(event->pos(), false))
596 {
597 int raIndex = graph(GuideGraph::G_RA)->findBegin(key);
598 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key);
599 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key);
600
601 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex);
602 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex);
603
604 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data
605 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data
606
607 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex);
608 double snr = 0;
609 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
610 {
611 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key);
612 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex);
613 }
614
615 // Compute time value:
616 QTime localTime = guideTimer;
617
618 localTime = localTime.addSecs(key);
619
621 if(raPulse == 0 && dePulse == 0)
622 {
624 event->globalPos(),
625 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",
626 "<table>"
627 "<tr><td>LT: </td><td>%1</td></tr>"
628 "<tr><td>RA: </td><td>%2 \"</td></tr>"
629 "<tr><td>DE: </td><td>%3 \"</td></tr>"
630 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
631 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
632 "</table>",
633 localTime.toString("hh:mm:ss AP"),
635 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1)));
636 }
637 else
638 {
640 event->globalPos(),
641 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",
642 "<table>"
643 "<tr><td>LT: </td><td>%1</td></tr>"
644 "<tr><td>RA: </td><td>%2 \"</td></tr>"
645 "<tr><td>DE: </td><td>%3 \"</td></tr>"
646 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
647 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
648 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
649 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
650 "</table>",
651 localTime.toString("hh:mm:ss AP"),
652 QString::number(raDelta, 'f', 2),
653 QString::number(deDelta, 'f', 2),
654 QString::number(rms, 'f', 2),
655 QString::number(snr, 'f', 1),
656 QString::number(raPulse, 'f', 2),
657 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph.
658 }
659 }
660 else
662
663 replot();
664 }
665
666 if (xAxis->range().contains(key))
667 {
669
670 if (qcpgraph)
671 {
672 int raIndex = graph(GuideGraph::G_RA)->findBegin(key);
673 int deIndex = graph(GuideGraph::G_DEC)->findBegin(key);
674 int rmsIndex = graph(GuideGraph::G_RMS)->findBegin(key);
675
676 double raDelta = graph(GuideGraph::G_RA)->dataMainValue(raIndex);
677 double deDelta = graph(GuideGraph::G_DEC)->dataMainValue(deIndex);
678
679 double raPulse = graph(GuideGraph::G_RA_PULSE)->dataMainValue(raIndex); //Get RA Pulse from RA pulse data
680 double dePulse = graph(GuideGraph::G_DEC_PULSE)->dataMainValue(deIndex); //Get DEC Pulse from DEC pulse data
681
682 double rms = graph(GuideGraph::G_RMS)->dataMainValue(rmsIndex);
683 double snr = 0;
684 if (graph(GuideGraph::G_SNR)->data()->size() > 0)
685 {
686 int snrIndex = graph(GuideGraph::G_SNR)->findBegin(key);
687 snr = graph(GuideGraph::G_SNR)->dataMainValue(snrIndex);
688 }
689
690 // Compute time value:
691 QTime localTime = guideTimer;
692
693 localTime = localTime.addSecs(key);
694
696 if(raPulse == 0 && dePulse == 0)
697 {
699 event->globalPos(),
700 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",
701 "<table>"
702 "<tr><td>LT: </td><td>%1</td></tr>"
703 "<tr><td>RA: </td><td>%2 \"</td></tr>"
704 "<tr><td>DE: </td><td>%3 \"</td></tr>"
705 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
706 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
707 "</table>",
708 localTime.toString("hh:mm:ss AP"),
710 QString::number(rms, 'f', 2), QString::number(snr, 'f', 1)));
711 }
712 else
713 {
715 event->globalPos(),
716 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",
717 "<table>"
718 "<tr><td>LT: </td><td>%1</td></tr>"
719 "<tr><td>RA: </td><td>%2 \"</td></tr>"
720 "<tr><td>DE: </td><td>%3 \"</td></tr>"
721 "<tr><td>RMS: </td><td>%4 \"</td></tr>"
722 "<tr><td>SNR: </td><td>%5 \"</td></tr>"
723 "<tr><td>RA Pulse: </td><td>%6 ms</td></tr>"
724 "<tr><td>DE Pulse: </td><td>%7 ms</td></tr>"
725 "</table>",
726 localTime.toString("hh:mm:ss AP"),
727 QString::number(raDelta, 'f', 2),
728 QString::number(deDelta, 'f', 2),
729 QString::number(rms, 'f', 2),
730 QString::number(snr, 'f', 1),
731 QString::number(raPulse, 'f', 2),
732 QString::number(dePulse, 'f', 2))); //The pulses were divided by 100 before they were put on the graph.
733 }
734 }
735 else
737
738 replot();
739 }
740}
741
742void GuideDriftGraph::mouseClicked(QMouseEvent *event)
743{
744 if (event->buttons() & Qt::RightButton)
745 {
746 yAxis->setRange(-3, 3);
747 }
748}
749
750void GuideDriftGraph::refreshColorScheme()
751{
752 if (graph(GuideGraph::G_RA) && graph(GuideGraph::G_DEC) && graph(GuideGraph::G_RA_HIGHLIGHT)
753 && graph(GuideGraph::G_DEC_HIGHLIGHT) && graph(GuideGraph::G_RA_PULSE)
754 && graph(GuideGraph::G_DEC_PULSE))
755 {
756 graph(GuideGraph::G_RA)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
757 graph(GuideGraph::G_DEC)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
758 graph(GuideGraph::G_RA_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError")));
760 QPen(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"), 2), QBrush(), 10));
761 graph(GuideGraph::G_DEC_HIGHLIGHT)->setPen(QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError")));
763 QPen(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"), 2), QBrush(), 10));
764
765 QColor raPulseColor(KStarsData::Instance()->colorScheme()->colorNamed("RAGuideError"));
766 raPulseColor.setAlpha(75);
767 graph(GuideGraph::G_RA_PULSE)->setPen(QPen(raPulseColor));
768 graph(GuideGraph::G_RA_PULSE)->setBrush(QBrush(raPulseColor, Qt::Dense4Pattern));
769
770 QColor dePulseColor(KStarsData::Instance()->colorScheme()->colorNamed("DEGuideError"));
771 dePulseColor.setAlpha(75);
772 graph(GuideGraph::G_DEC_PULSE)->setPen(QPen(dePulseColor));
773 graph(GuideGraph::G_DEC_PULSE)->setBrush(QBrush(dePulseColor, Qt::Dense4Pattern));
774 }
775}
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)
@ ptViewportRatio
Static positioning given by a fraction of the viewport size.
A text label.
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)
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)
QCPLegend * legend
PlottableType * plottableAt(const QPointF &pos, bool onlySelectable=false, int *dataIndex=nullptr) const
void setInteractions(const QCP::Interactions &interactions)
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...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
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
QString number(double n, char format, int precision)
AlignRight
Dense4Pattern
RightButton
QTextStream & endl(QTextStream &stream)
QTime currentTime()
bool isNull() const const
bool isValid(int h, int m, int s, int ms)
void hideText()
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
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 Fri May 24 2024 11:49:21 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.