Kstars

analyze.h
1/*
2 SPDX-FileCopyrightText: 2020 Hy Murveit <hy@murveit.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#ifndef ANALYZE_H
8#define ANALYZE_H
9
10#include <memory>
11#include "ekos/ekos.h"
12#include "ekos/mount/mount.h"
13#include "indi/indimount.h"
14#include "yaxistool.h"
15#include "ui_analyze.h"
16#include "ekos/manager/meridianflipstate.h"
17
18class FITSViewer;
19class OffsetDateTimeTicker;
20class QCustomPlot;
21
22namespace Ekos
23{
24
25class RmsFilter;
26
27/**
28 *@class Analyze
29 *@short Analysis tab for Ekos sessions.
30 *@author Hy Murveit
31 *@version 1.0
32 */
33class Analyze : public QWidget, public Ui::Analyze
34{
36
37 public:
38 Analyze();
39 ~Analyze();
40
41 // Baseclass used to represent a segment of Timeline data.
42 class Session
43 {
44 public:
45 // Start and end time in seconds since start of the log.
46 double start, end;
47 // y-offset for the timeline plot. Each line uses a different integer.
48 int offset;
49 // Variables used in temporary sessions. A temporary session
50 // represents a process that has started but not yet finished.
51 // Those are plotted "for now", but will be replaced by the
52 // finished line when the process completes.
53 // Rect is the temporary graphic on the Timeline, and
54 // temporaryBrush defines its look.
55 QCPItemRect *rect;
56 QBrush temporaryBrush;
57
58 Session(double s, double e, int o, QCPItemRect *r)
59 : start(s), end(e), offset(o), rect(r) {}
60
61 Session() : start(0), end(0), offset(0), rect(nullptr) {}
62
63 // These 2 are used to build tables for the details display.
64 void setupTable(const QString &name, const QString &status,
66 QTableWidget *table);
67 void addRow(const QString &key, const QString &value);
68
69 // True if this session is temporary.
70 bool isTemporary() const;
71
72 private:
73 QTableWidget *details;
74 QString htmlString;
75 };
76 // Below are subclasses of Session used to represent all the different
77 // lines in the Timeline. Each of those hold different types of information
78 // about the process it represents.
79 class CaptureSession : public Session
80 {
81 public:
82 bool aborted;
83 QString filename;
84 double duration;
85 QString filter;
86 double hfr;
87 CaptureSession(double start_, double end_, QCPItemRect *rect,
88 bool aborted_, const QString &filename_,
89 double duration_, const QString &filter_)
90 : Session(start_, end_, CAPTURE_Y, rect),
91 aborted(aborted_), filename(filename_),
92 duration(duration_), filter(filter_), hfr(0) {}
93 CaptureSession() : Session(0, 0, CAPTURE_Y, nullptr) {}
94 };
95 // Guide sessions collapse some of the possible guiding states.
96 // SimpleGuideState are those collapsed states.
97 typedef enum
98 {
99 G_IDLE, G_GUIDING, G_CALIBRATING, G_SUSPENDED, G_DITHERING, G_IGNORE
100 } SimpleGuideState;
101 class GuideSession : public Session
102 {
103 public:
104 SimpleGuideState simpleState;
105 GuideSession(double start_, double end_, QCPItemRect *rect, SimpleGuideState state_)
106 : Session(start_, end_, GUIDE_Y, rect), simpleState(state_) {}
107 GuideSession() : Session(0, 0, GUIDE_Y, nullptr) {}
108 };
109 class AlignSession : public Session
110 {
111 public:
112 AlignState state;
113 AlignSession(double start_, double end_, QCPItemRect *rect, AlignState state_)
114 : Session(start_, end_, ALIGN_Y, rect), state(state_) {}
115 AlignSession() : Session(0, 0, ALIGN_Y, nullptr) {}
116 };
117 class MountSession : public Session
118 {
119 public:
120 ISD::Mount::Status state;
121 MountSession(double start_, double end_, QCPItemRect *rect, ISD::Mount::Status state_)
122 : Session(start_, end_, MOUNT_Y, rect), state(state_) {}
123 MountSession() : Session(0, 0, MOUNT_Y, nullptr) {}
124 };
125 class MountFlipSession : public Session
126 {
127 public:
128 MeridianFlipState::MeridianFlipMountState state;
129 MountFlipSession(double start_, double end_, QCPItemRect *rect, MeridianFlipState::MeridianFlipMountState state_)
130 : Session(start_, end_, MERIDIAN_MOUNT_FLIP_Y, rect), state(state_) {}
131 MountFlipSession() : Session(0, 0, MERIDIAN_MOUNT_FLIP_Y, nullptr) {}
132 };
133 class SchedulerJobSession : public Session
134 {
135 public:
136 SchedulerJobSession(double start_, double end_, QCPItemRect *rect,
137 const QString &jobName_, const QString &reason_)
138 : Session(start_, end_, SCHEDULER_Y, rect), jobName(jobName_), reason(reason_) {}
139 SchedulerJobSession() : Session(0, 0, SCHEDULER_Y, nullptr) {}
140 QString jobName;
141 QString reason;
142 };
143 class FocusSession : public Session
144 {
145 public:
146 bool success;
147 double temperature;
148 QString filter;
149
150 // Standard focus parameters
151 QString points;
152 QString curve;
153 QString title;
154 QVector<double> positions; // Double to be more friendly to QCustomPlot addData.
155 QVector<double> hfrs;
156
157 // Adaptive focus parameters
158 double tempTicks, altitude, altTicks;
159 int prevPosError, thisPosError, totalTicks, adaptedPosition;
160
161 // false for adaptiveFocus.
162 bool standardSession = true;
163
164 FocusSession() : Session(0, 0, FOCUS_Y, nullptr) {}
165 FocusSession(double start_, double end_, QCPItemRect *rect, bool ok, double temperature_,
166 const QString &filter_, const QString &points_, const QString &curve_, const QString &title_);
167 FocusSession(double start_, double end_, QCPItemRect *rect,
168 const QString &filter_, double temperature_, double tempTicks_, double altitude_,
169 double altTicks_, int prevPosError, int thisPosError, int totalTicks_, int position_);
170 double focusPosition();
171 };
172
173 void clearLog();
174 QStringList logText()
175 {
176 return m_LogText;
177 }
178 QString getLogText()
179 {
180 return m_LogText.join("\n");
181 }
182
183 public slots:
184 // These slots are messages received from the different Ekos processes
185 // used to gather data about those processes.
186
187 // From Capture
188 void captureComplete(const QVariantMap &metadata);
189 void captureStarting(double exposureSeconds, const QString &filter);
190 void captureAborted(double exposureSeconds);
191
192 // From Guide
193 void guideState(Ekos::GuideState status);
194 void guideStats(double raError, double decError, int raPulse, int decPulse,
195 double snr, double skyBg, int numStars);
196
197 // From Focus
198 void autofocusStarting(double temperature, const QString &filter);
199 void autofocusComplete(const QString &filter, const QString &points, const QString &curve, const QString &title);
200 void adaptiveFocusComplete(const QString &filter, double temperature, double tempTicks,
201 double altitude, double altTicks, int prevPosError, int thisPosError, int totalTicks,
202 int position, bool focuserMoved);
203 void autofocusAborted(const QString &filter, const QString &points);
204 void newTemperature(double temperatureDelta, double temperature);
205
206 // From Align
207 void alignState(Ekos::AlignState state);
208
209 // From Mount
210 void mountState(ISD::Mount::Status status);
211 void mountCoords(const SkyPoint &position, ISD::Mount::PierSide pierSide, const dms &haValue);
212 void mountFlipStatus(Ekos::MeridianFlipState::MeridianFlipMountState status);
213
214 void schedulerJobStarted(const QString &jobName);
215 void schedulerJobEnded(const QString &jobName, const QString &endReason);
216 void newTargetDistance(double targetDistance);
217
218 // From YAxisTool
219 void userChangedYAxis(QObject *key, const YAxisInfo &axisInfo);
220 void userSetLeftAxis(QCPAxis *axis);
221 void userSetAxisColor(QObject *key, const YAxisInfo &axisInfo, const QColor &color);
222
223 void yAxisRangeChanged(const QCPRange &newRange);
224
225 void appendLogText(const QString &);
226
227 private slots:
228
229 signals:
230 void newLog(const QString &text);
231
232 private:
233
234 // The file-reading, processInputLine(), and signal-slot codepaths share the methods below
235 // to process their messages. Time is the offset in seconds from the start of the log.
236 // BatchMode is true in the file reading path. It means don't call replot() as there may be
237 // many more messages to come. The rest of the args are specific to the message type.
238 void processCaptureStarting(double time, double exposureSeconds, const QString &filter);
239 void processCaptureComplete(double time, const QString &filename, double exposureSeconds, const QString &filter,
240 double hfr, int numStars, int median, double eccentricity, bool batchMode = false);
241 void processCaptureAborted(double time, double exposureSeconds, bool batchMode = false);
242 void processAutofocusStarting(double time, double temperature, const QString &filter);
243 void processAutofocusComplete(double time, const QString &filter, const QString &points, const QString &curve,
244 const QString &title, bool batchMode = false);
245 void processAdaptiveFocusComplete(double time, const QString &filter, double temperature, double tempTicks,
246 double altitude, double altTicks, int prevPosError, int thisPosError, int totalTicks,
247 int position, bool focuserMoved, bool batchMode = false);
248 void processAutofocusAborted(double time, const QString &filter, const QString &points, bool batchMode = false);
249 void processTemperature(double time, double temperature, bool batchMode = false);
250 void processGuideState(double time, const QString &state, bool batchMode = false);
251 void processGuideStats(double time, double raError, double decError, int raPulse,
252 int decPulse, double snr, double skyBg, int numStars, bool batchMode = false);
253 void processMountCoords(double time, double ra, double dec, double az, double alt,
254 int pierSide, double ha, bool batchMode = false);
255
256 void processMountState(double time, const QString &statusString, bool batchMode = false);
257 void processAlignState(double time, const QString &statusString, bool batchMode = false);
258 void processMountFlipState(double time, const QString &statusString, bool batchMode = false);
259
260 void processSchedulerJobStarted(double time, const QString &jobName);
261 void processSchedulerJobEnded(double time, const QString &jobName, const QString &reason, bool batchMode = false);
262 void checkForMissingSchedulerJobEnd(double time);
263 void processTargetDistance(double time, double targetDistance, bool batchMode = false);
264
265 // Plotting primatives.
266 void replot(bool adjustSlider = true);
267 void zoomIn();
268 void zoomOut();
269 void scroll(int value);
270 void scrollRight();
271 void scrollLeft();
272 void statsYZoom(double zoomAmount);
273 void statsYZoomIn();
274 void statsYZoomOut();
275 // Return true if the session is visible on the plots.
276 bool isVisible(const Session &s) const;
277 // Shift the view so that time is at the center (keeping the current plot width).
278 void adjustView(double time);
279
280
281 // maxXValue keeps the largest time offset we've received so far.
282 // It represents the extent of the plots (0 -> maxXValue).
283 // This is called each time a message is received in case that message's
284 // time is past the current value of maxXValue.
285 void updateMaxX(double time);
286
287 // Callbacks for when the timeline is clicked. ProcessTimelineClick
288 // will determine which segment on which line was clicked and then
289 // call captureSessionClicked() or focusSessionClicked, etc.
290 void processTimelineClick(QMouseEvent *event, bool doubleClick);
291 void captureSessionClicked(CaptureSession &c, bool doubleClick);
292 void focusSessionClicked(FocusSession &c, bool doubleClick);
293 void guideSessionClicked(GuideSession &c, bool doubleClick);
294 void mountSessionClicked(MountSession &c, bool doubleClick);
295 void alignSessionClicked(AlignSession &c, bool doubleClick);
296 void mountFlipSessionClicked(MountFlipSession &c, bool doubleClick);
297 void schedulerSessionClicked(SchedulerJobSession &c, bool doubleClick);
298
299 // Low-level callbacks.
300 // These two call processTimelineClick().
301 void timelineMousePress(QMouseEvent *event);
302 void timelineMouseDoubleClick(QMouseEvent *event);
303 // Calls zoomIn or zoomOut.
304 void timelineMouseWheel(QWheelEvent *event);
305 // Sets the various displays visbile or not according to the checkboxes.
306 void setVisibility();
307
308 void processStatsClick(QMouseEvent *event, bool doubleClick);
309 void statsMousePress(QMouseEvent *event);
310 void statsMouseDoubleClick(QMouseEvent *event);
311 void statsMouseMove(QMouseEvent *event);
312 void setupKeyboardShortcuts(QWidget *plot);
313
314 // (Un)highlights a segment on the timeline after one is clicked.
315 // This indicates which segment's data is displayed in the
316 // graphicsPlot and details table.
317 void highlightTimelineItem(const Session &session);
318 void unhighlightTimelineItem();
319
320 // Tied to the keyboard shortcuts that go to the next or previous
321 // items on the timeline. next==true means next, otherwise previous.
322 void changeTimelineItem(bool next);
323 // These are assigned to various keystrokes.
324 void nextTimelineItem();
325 void previousTimelineItem();
326
327 // logTime() returns the number of seconds between "now" or "time" and
328 // the start of the log. They are useful for recording signal and storing
329 // them to file. They are not useful when reading data from files.
330 double logTime();
331 // Returns the number of seconds between time and the start of the log.
332 double logTime(const QDateTime &time);
333 // Goes back from logSeconds to human-readable clock time.
334 QDateTime clockTime(double logSeconds);
335
336 // Add a new segment to the Timeline graph.
337 // Returns a rect item, which is only important temporary objects, who
338 // need to erase the item when the temporary session is removed.
339 // This memory is owned by QCustomPlot and shouldn't be freed.
340 // This pointer is stored in Session::rect.
341 QCPItemRect * addSession(double start, double end, double y,
342 const QBrush &brush, const QBrush *stripeBrush = nullptr);
343
344 // Manage temporary sessions (only used for live data--file-reading doesn't
345 // need temporary sessions). For example, when an image capture has started
346 // but not yet completed, a temporary session is added to the timeline to
347 // represent the not-yet-completed capture.
348 void addTemporarySession(Session *session, double time, double duration,
349 int y_offset, const QBrush &brush);
350 void removeTemporarySession(Session *session);
351 void removeTemporarySessions();
352 void adjustTemporarySession(Session *session);
353 void adjustTemporarySessions();
354
355 // Add new stats to the statsPlot.
356 void addGuideStats(double raDrift, double decDrift, int raPulse, int decPulse,
357 double snr, int numStars, double skyBackground, double time);
358 void addGuideStatsInternal(double raDrift, double decDrift, double raPulse,
359 double decPulse, double snr, double numStars,
360 double skyBackground, double drift, double rms, double time);
361 void addMountCoords(double ra, double dec, double az, double alt, int pierSide,
362 double ha, double time);
363 void addHFR(double hfr, int numCaptureStars, int median, double eccentricity,
364 const double time, double startTime);
365 void addTemperature(double temperature, const double time);
366 void addFocusPosition(double focusPosition, double time);
367 void addTargetDistance(double targetDistance, const double time);
368
369 // Initialize the graphs (axes, linestyle, pen, name, checkbox callbacks).
370 // Returns the graph index.
371 int initGraph(QCustomPlot *plot, QCPAxis *yAxis, QCPGraph::LineStyle lineStyle,
372 const QColor &color, const QString &name);
373 template <typename Func>
374 int initGraphAndCB(QCustomPlot *plot, QCPAxis *yAxis, QCPGraph::LineStyle lineStyle,
375 const QColor &color, const QString &name, const QString &shortName,
376 QCheckBox *cb, Func setCb, QLineEdit *out = nullptr);
377
378 // Make graphs visible/invisible & add/delete them from the legend.
379 void toggleGraph(int graph_id, bool show);
380
381 // Initializes the main QCustomPlot windows.
382 void initStatsPlot();
383 void initTimelinePlot();
384 void initGraphicsPlot();
385 void initInputSelection();
386
387 // Displays the focus positions and HFRs on the graphics plot.
388 void displayFocusGraphics(const QVector<double> &positions, const QVector<double> &hfrs, const QString &curve,
389 const QString &title, bool success);
390 // Displays the guider ra and dec drift plot, and computes RMS errors.
391 void displayGuideGraphics(double start, double end, double *raRMS,
392 double *decRMS, double *totalRMS, int *numSamples);
393
394 // Updates the stats value display boxes next to their checkboxes.
395 void updateStatsValues();
396 // Manages the statsPlot cursor.
397 void setStatsCursor(double time);
398 void removeStatsCursor();
399 void keepCurrent(int state);
400
401 // Restore checkboxs from Options.
402 void initStatsCheckboxes();
403
404 // Clears the data, resets the various plots & displays.
405 void reset();
406 void resetGraphicsPlot();
407
408 // Resets the variables used to process the signals received.
409 void resetCaptureState();
410 void resetAutofocusState();
411 void resetGuideState();
412 void resetGuideStats();
413 void resetAlignState();
414 void resetMountState();
415 void resetMountCoords();
416 void resetMountFlipState();
417 void resetSchedulerJob();
418 void resetTemperature();
419
420 // Read and display an input .analyze file.
421 double readDataFromFile(const QString &filename);
422 double processInputLine(const QString &line);
423
424 // Opens a FITS file for viewing.
425 void displayFITS(const QString &filename);
426
427 // Pop up a help-message window.
428 void helpMessage();
429
430 // Write the analyze log file message.
431 void saveMessage(const QString &type, const QString &message);
432 // low level file writing.
433 void startLog();
434 void appendToLog(const QString &lines);
435
436 // Used to capture double clicks on stats output QLineEdits to set y-axis limits.
437 bool eventFilter(QObject *o, QEvent *e) override;
438 QTimer clickTimer;
439 YAxisInfo m_ClickTimerInfo;
440
441 // Utility that adds a y-axis to the stats plot.
442 QCPAxis *newStatsYAxis(const QString &label, double lower = YAxisInfo::LOWER_RESCALE,
443 double upper = YAxisInfo::UPPER_RESCALE);
444
445 // Save and restore user-updated y-axis limits.
446 QString serializeYAxes();
447 bool restoreYAxes(const QString &encoding);
448
449 // Sets the y-axis to be displayed on the left of the statsPlot.
450 void setLeftAxis(QCPAxis *axis);
451 void updateYAxisMap(QObject *key, const YAxisInfo &axisInfo);
452
453 // The pop-up allowing users to edit y-axis lower and upper graph values.
454 YAxisTool m_YAxisTool;
455
456 // The y-axis values displayed to the left of the stat's graph.
457 QCPAxis *activeYAxis { nullptr };
458
459 void startYAxisTool(QObject *key, const YAxisInfo &info);
460
461 // Map connecting QLineEdits to Y-Axes, so when a QLineEdit is double clicked,
462 // the corresponding y-axis can be found.
463 std::map<QObject*, YAxisInfo> yAxisMap;
464
465 // The .analyze log file being written.
466 QString logFilename { "" };
467 QFile logFile;
468 bool logInitialized { false };
469
470 // These define the view for the timeline and stats plots.
471 // The plots start plotStart seconds from the start of the session, and
472 // are plotWidth seconds long. The end of the X-axis is maxXValue.
473 double plotStart { 0.0 };
474 double plotWidth { 10.0 };
475 double maxXValue { 10.0 };
476
477 // Data are displayed in seconds since the session started.
478 // analyzeStartTime is when the session started, used to translate to clock time.
479 QDateTime analyzeStartTime;
480 QString analyzeTimeZone { "" };
481 bool startTimeInitialized { false };
482
483 // displayStartTime is similar to analyzeStartTime, but references the
484 // start of the log being displayed (e.g. if reading from a file).
485 // When displaying the current session it should equal analyzeStartTime.
486 QDateTime displayStartTime;
487
488 // AddGuideStats uses RmsFilter to compute RMS values of the squared
489 // RA and DEC errors, thus calculating the RMS error.
490 std::unique_ptr<RmsFilter> guiderRms;
491 std::unique_ptr<RmsFilter> captureRms;
492
493 // Used to keep track of the y-axis position when moving it with the mouse.
494 double yAxisInitialPos = { 0 };
495
496 // Used to display clock-time on the X-axis.
498
499 // The rectangle over the current selection.
500 // Memory owned by QCustomPlot.
501 QCPItemRect *selectionHighlight { nullptr };
502
503 // FITS Viewer to display FITS images.
505 // When trying to load a FITS file, if the original file path doesn't
506 // work, Analyze tries to find the file under the alternate folder.
507 QString alternateFolder;
508
509 // The vertical line in the stats plot.
510 QCPItemLine *statsCursor { nullptr };
511 QCPItemLine *timelineCursor { nullptr };
512 double statsCursorTime { -1 };
513
514 // Keeps the directory from the last time the user loaded a .analyze file.
515 QUrl dirPath;
516
517 // True if Analyze is displaying data as it comes in from the other modules.
518 // False if Analyze is displaying data read from a file.
519 bool runtimeDisplay { true };
520
521 // When a module's session is ongoing, we represent it as a "temporary session"
522 // which will be replaced once the session is done.
523 CaptureSession temporaryCaptureSession;
524 FocusSession temporaryFocusSession;
525 GuideSession temporaryGuideSession;
526 AlignSession temporaryAlignSession;
527 MountSession temporaryMountSession;
528 MountFlipSession temporaryMountFlipSession;
529 SchedulerJobSession temporarySchedulerJobSession;
530
531 // Capture state-machine variables.
532 double captureStartedTime { -1 };
533 double previousCaptureStartedTime { 1 };
534 double previousCaptureCompletedTime { 1 };
535 QString captureStartedFilter { "" };
536
537 // Autofocus state-machine variables.
538 double autofocusStartedTime { -1 };
539 QString autofocusStartedFilter { "" };
540 double autofocusStartedTemperature { 0 };
541
542 // GuideState state-machine variables.
543 SimpleGuideState lastGuideStateStarted { G_IDLE };
544 double guideStateStartedTime { -1 };
545
546 // GuideStats state-machine variables.
547 double lastGuideStatsTime { -1 };
548 double lastCaptureRmsTime { -1 };
549 int numStarsMax { 0 };
550 double snrMax { 0 };
551 double skyBgMax { 0 };
552 int medianMax { 0 };
553 int numCaptureStarsMax { 0 };
554 double lastTemperature { -1000 };
555
556 // AlignState state-machine variables.
557 AlignState lastAlignStateReceived { ALIGN_IDLE };
558 AlignState lastAlignStateStarted { ALIGN_IDLE };
559 double lastAlignStateStartedTime { -1 };
560
561 // MountState state-machine variables.
562 double mountStateStartedTime { -1 };
563 ISD::Mount::Status lastMountState { ISD::Mount::Status::MOUNT_IDLE };
564
565 // Mount coords state machine variables.
566 // Used to filter out mount Coords messages--we only process ones
567 // where the values have changed significantly.
568 double lastMountRa { -1 };
569 double lastMountDec { -1 };
570 double lastMountHa { -1 };
571 double lastMountAz { -1 };
572 double lastMountAlt { -1 };
573 int lastMountPierSide { -1 };
574
575 // Flip state machine variables
576 MeridianFlipState::MeridianFlipMountState lastMountFlipStateReceived { MeridianFlipState::MOUNT_FLIP_NONE};
577 MeridianFlipState::MeridianFlipMountState lastMountFlipStateStarted { MeridianFlipState::MOUNT_FLIP_NONE };
578 double mountFlipStateStartedTime { -1 };
579
580 // SchedulerJob state machine variables
581 double schedulerJobStartedTime;
582 QString schedulerJobStartedJobName;
583
584 QMap<QString, QColor> schedulerJobColors;
585 QBrush schedulerJobBrush(const QString &jobName, bool temporary);
586
587 void setSelectedSession(const Session &s);
588 void clearSelectedSession();
589 Session m_selectedSession;
590
591 // Analyze log file info.
592 QStringList m_LogText;
593
594 // Y-offsets for the timeline plot for the various modules.
595 static constexpr int CAPTURE_Y = 1;
596 static constexpr int FOCUS_Y = 2;
597 static constexpr int ALIGN_Y = 3;
598 static constexpr int GUIDE_Y = 4;
599 static constexpr int MERIDIAN_MOUNT_FLIP_Y = 5;
600 static constexpr int MOUNT_Y = 6;
601 static constexpr int SCHEDULER_Y = 7;
602 static constexpr int LAST_Y = 8;
603};
604}
605
606
607#endif // Analyze
Analysis tab for Ekos sessions.
Definition analyze.h:34
Primary window to view monochrome and color FITS images.
Definition fitsviewer.h:50
Manages a single axis inside a QCustomPlot.
A line from one point to another.
A rectangle.
Represents the range an axis is encompassing.
The central class of the library. This is the QWidget which displays the plot and interacts with the ...
The sky coordinates of a point in the sky.
Definition skypoint.h:45
Manages adjusting the Y-axis of Analyze stats graphs.
Definition yaxistool.h:69
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
AlignState
Definition ekos.h:145
@ ALIGN_IDLE
No ongoing operations.
Definition ekos.h:146
Q_OBJECTQ_OBJECT
QString join(const QString &separator) const const
virtual bool event(QEvent *event) override
void lower()
void show()
bool isVisible() const const
Used to keep track of the various Y-axes and connect them to the QLineEdits.
Definition yaxistool.h:25
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:45:33 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.