Kstars

altvstime.cpp
1/*
2 SPDX-FileCopyrightText: 2002-2003 Pablo de Vicente <vicente@oan.es>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "altvstime.h"
8
9#include "avtplotwidget.h"
10#include "dms.h"
11#include "ksalmanac.h"
12#include "kstarsdata.h"
13#include "kstarsdatetime.h"
14#include "ksnumbers.h"
15#include "simclock.h"
16#include "kssun.h"
17#include "dialogs/finddialog.h"
18#include "dialogs/locationdialog.h"
19#include "geolocation.h"
20#include "skyobjects/skypoint.h"
21#include "skyobjects/skyobject.h"
22#include "skyobjects/starobject.h"
23
24#include <KLocalizedString>
25#include <kplotwidget.h>
26
27#include <QVBoxLayout>
28#include <QFrame>
29#include <QDialog>
30#include <QPainter>
31#include <QtPrintSupport/QPrinter>
32#include <QtPrintSupport/QPrintDialog>
33#include <QToolTip>
34
35#include "kstars_debug.h"
36
37AltVsTimeUI::AltVsTimeUI(QWidget *p) : QFrame(p)
38{
39 setupUi(this);
40}
41
43{
44#ifdef Q_OS_MACOS
46#endif
47
48 setWindowTitle(i18nc("@title:window", "Altitude vs. Time"));
49
50 setModal(false);
51
52 QVBoxLayout *topLayout = new QVBoxLayout;
53 setLayout(topLayout);
54 topLayout->setContentsMargins(0, 0, 0, 0);
55 avtUI = new AltVsTimeUI(this);
56
57 // Layers for setting up the plot's priority: the current curve should be above the other curves.
58 // The Rise/Set/Transit markers should be on top, with highest priority.
59 avtUI->View->addLayer("currentCurveLayer", avtUI->View->layer("main"), QCustomPlot::limAbove);
60 avtUI->View->addLayer("markersLayer", avtUI->View->layer("currentCurveLayer"), QCustomPlot::limAbove);
61
62 // Set up the Graph Window:
63 avtUI->View->setBackground(QBrush(QColor(0, 0, 0)));
64 avtUI->View->xAxis->grid()->setVisible(false);
65 avtUI->View->yAxis->grid()->setVisible(false);
66 QColor axisColor(Qt::white);
67 QPen axisPen(axisColor, 1);
68 avtUI->View->xAxis->setBasePen(axisPen);
69 avtUI->View->xAxis->setTickPen(axisPen);
70 avtUI->View->xAxis->setSubTickPen(axisPen);
71 avtUI->View->xAxis->setTickLabelColor(axisColor);
72 avtUI->View->xAxis->setLabelColor(axisColor);
73
74 avtUI->View->xAxis2->setBasePen(axisPen);
75 avtUI->View->xAxis2->setTickPen(axisPen);
76 avtUI->View->xAxis2->setSubTickPen(axisPen);
77 avtUI->View->xAxis2->setTickLabelColor(axisColor);
78 avtUI->View->xAxis2->setLabelColor(axisColor);
79
80 avtUI->View->yAxis->setBasePen(axisPen);
81 avtUI->View->yAxis->setTickPen(axisPen);
82 avtUI->View->yAxis->setSubTickPen(axisPen);
83 avtUI->View->yAxis->setTickLabelColor(axisColor);
84 avtUI->View->yAxis->setLabelColor(axisColor);
85
86 avtUI->View->yAxis2->setBasePen(axisPen);
87 avtUI->View->yAxis2->setTickPen(axisPen);
88 avtUI->View->yAxis2->setSubTickPen(axisPen);
89 avtUI->View->yAxis2->setTickLabelColor(axisColor);
90 avtUI->View->yAxis2->setLabelColor(axisColor);
91
92 // give the axis some labels:
93 avtUI->View->xAxis2->setLabel(i18n("Local Sidereal Time"));
94 avtUI->View->xAxis2->setVisible(true);
95 avtUI->View->yAxis2->setVisible(true);
96 avtUI->View->yAxis2->setTickLength(0, 0);
97 avtUI->View->xAxis->setLabel(i18n("Local Time"));
98 avtUI->View->yAxis->setLabel(i18n("Altitude"));
99 avtUI->View->xAxis->setRange(43200, 129600);
100 avtUI->View->xAxis2->setRange(61200, 147600);
101
102 // configure the bottom axis to show time instead of number:
104 xAxisTimeTicker->setTimeFormat("%h:%m");
105 xAxisTimeTicker->setTickCount(12);
106 xAxisTimeTicker->setTickStepStrategy(QCPAxisTicker::tssReadability);
107 xAxisTimeTicker->setTickOrigin(Qt::UTC);
108 avtUI->View->xAxis->setTicker(xAxisTimeTicker);
109
110 // configure the top axis to show time instead of number:
112 xAxis2TimeTicker->setTimeFormat("%h:%m");
113 xAxis2TimeTicker->setTickCount(12);
114 xAxis2TimeTicker->setTickStepStrategy(QCPAxisTicker::tssReadability);
115 xAxis2TimeTicker->setTickOrigin(Qt::UTC);
116 avtUI->View->xAxis2->setTicker(xAxis2TimeTicker);
117
118 // set up the Zoom/Pan features for the Top X Axis
119 avtUI->View->axisRect()->setRangeDragAxes(avtUI->View->xAxis2, avtUI->View->yAxis);
120 avtUI->View->axisRect()->setRangeZoomAxes(avtUI->View->xAxis2, avtUI->View->yAxis);
121
122 // set up the margins, for a nice view
123 avtUI->View->axisRect()->setAutoMargins(QCP::msBottom | QCP::msLeft | QCP::msTop);
124 avtUI->View->axisRect()->setMargins(QMargins(0, 0, 7, 0));
125
126 // set up the interaction set:
127 avtUI->View->setInteraction(QCP::iRangeZoom, true);
128 avtUI->View->setInteraction(QCP::iRangeDrag, true);
129
130 // set up the selection tolerance for checking if a certain graph is or not selected:
131 avtUI->View->setSelectionTolerance(5);
132
133 // draw the gradient:
134 drawGradient();
135
136 // set up the background image:
137 background = new QCPItemPixmap(avtUI->View);
138 background->setPixmap(*gradient);
139 background->topLeft->setType(QCPItemPosition::ptPlotCoords);
140 background->bottomRight->setType(QCPItemPosition::ptPlotCoords);
141 background->setScaled(true, Qt::IgnoreAspectRatio);
142 background->setLayer("background");
143 background->setVisible(true);
144
145 avtUI->raBox->setUnits(dmsBox::HOURS);
146 avtUI->decBox->setUnits(dmsBox::DEGREES);
147
148 //FIXME:
149 //Doesn't make sense to manually adjust long/lat unless we can modify TZ also
150 avtUI->longBox->setReadOnly(true);
151 avtUI->latBox->setReadOnly(true);
152
153 topLayout->addWidget(avtUI);
154
156 topLayout->addWidget(buttonBox);
157 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
158
159 QPushButton *printB = new QPushButton(QIcon::fromTheme("document-print"), i18n("&Print..."));
160 printB->setToolTip(i18n("Print the Altitude vs. time plot"));
161 buttonBox->addButton(printB, QDialogButtonBox::ActionRole);
162 connect(printB, SIGNAL(clicked()), this, SLOT(slotPrint()));
163
164 geo = KStarsData::Instance()->geo();
165
166 DayOffset = 0;
167 // set up the initial minimum and maximum altitude
168 minAlt = 0;
169 maxAlt = 0;
171 if (getDate().time().hour() > 12)
172 DayOffset = 1;
173
174 avtUI->longBox->show(geo->lng());
175 avtUI->latBox->show(geo->lat());
176
178 setLSTLimits();
179 setDawnDusk();
180
181 connect(avtUI->View->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(onYRangeChanged(QCPRange)));
182 connect(avtUI->View->xAxis2, SIGNAL(rangeChanged(QCPRange)), this, SLOT(onXRangeChanged(QCPRange)));
183 connect(avtUI->View, SIGNAL(plottableClick(QCPAbstractPlottable*, int, QMouseEvent*)), this,
185 connect(avtUI->View, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseOverLine(QMouseEvent*)));
186
187 connect(avtUI->browseButton, SIGNAL(clicked()), this, SLOT(slotBrowseObject()));
188 connect(avtUI->cityButton, SIGNAL(clicked()), this, SLOT(slotChooseCity()));
189 connect(avtUI->updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateDateLoc()));
190 connect(avtUI->clearButton, SIGNAL(clicked()), this, SLOT(slotClear()));
191 connect(avtUI->addButton, SIGNAL(clicked()), this, SLOT(slotAddSource()));
192 connect(avtUI->nameBox, SIGNAL(returnPressed()), this, SLOT(slotAddSource()));
193 connect(avtUI->raBox, SIGNAL(returnPressed()), this, SLOT(slotAddSource()));
194 connect(avtUI->decBox, SIGNAL(returnPressed()), this, SLOT(slotAddSource()));
195 connect(avtUI->clearFieldsButton, SIGNAL(clicked()), this, SLOT(slotClearBoxes()));
196 connect(avtUI->longBox, SIGNAL(returnPressed()), this, SLOT(slotAdvanceFocus()));
197 connect(avtUI->latBox, SIGNAL(returnPressed()), this, SLOT(slotAdvanceFocus()));
198 connect(avtUI->PlotList, SIGNAL(currentRowChanged(int)), this, SLOT(slotHighlight(int)));
199 connect(avtUI->computeButton, SIGNAL(clicked()), this, SLOT(slotComputeAltitudeByTime()));
200 connect(avtUI->riseButton, SIGNAL(clicked()), this, SLOT(slotMarkRiseTime()));
201 connect(avtUI->setButton, SIGNAL(clicked()), this, SLOT(slotMarkSetTime()));
202 connect(avtUI->transitButton, SIGNAL(clicked()), this, SLOT(slotMarkTransitTime()));
203
204 // Set up the Rise/Set/Transit buttons' icons:
205
206 QPixmap redButton(100, 100);
207 redButton.fill(Qt::transparent);
208 QPainter p;
209 p.begin(&redButton);
211 QPen pen(Qt::red, 2);
212 p.setPen(pen);
213 QBrush brush(Qt::red);
214 p.setBrush(brush);
215 p.drawEllipse(15, 15, 80, 80);
216 p.end();
217
218 QPixmap blueButton(100, 100);
219 blueButton.fill(Qt::transparent);
220 QPainter p1;
221 p1.begin(&blueButton);
223 QPen pen1(Qt::blue, 2);
224 p1.setPen(pen1);
225 QBrush brush1(Qt::blue);
226 p1.setBrush(brush1);
227 p1.drawEllipse(15, 15, 80, 80);
228 p1.end();
229
230 QPixmap greenButton(100, 100);
231 greenButton.fill(Qt::transparent);
232 QPainter p2;
233 p2.begin(&greenButton);
235 QPen pen2(Qt::green, 2);
236 p2.setPen(pen2);
237 QBrush brush2(Qt::green);
238 p2.setBrush(brush2);
239 p2.drawEllipse(15, 15, 80, 80);
240 p2.end();
241
242 avtUI->riseButton->setIcon(QIcon(redButton));
243 avtUI->setButton->setIcon(QIcon(blueButton));
244 avtUI->transitButton->setIcon(QIcon(greenButton));
245
246 setMouseTracking(true);
247}
248
250{
251 //WARNING: need to delete deleteList items!
252}
254{
255
256 SkyObject *obj = KStarsData::Instance()->objectNamed(avtUI->nameBox->text());
257 if (!obj)
258 {
259 QString name = FindDialog::processSearchText(avtUI->nameBox->text());
260 obj = KStarsData::Instance()->objectNamed(name);
261 }
262 if (obj)
263 {
264 //An object with the current name exists. If the object is not already
265 //in the avt list, add it.
266 bool found = false;
267 foreach (SkyObject *o, pList)
268 {
269 //if ( o->name() == obj->name() ) {
270 if (getObjectName(o, false) == getObjectName(obj, false))
271 {
272 found = true;
273 break;
274 }
275 }
276 if (!found)
277 processObject(obj);
278 }
279 else
280 {
281 //Object with the current name doesn't exist. It's possible that the
282 //user is trying to add a custom object. Assume this is the case if
283 //the RA and Dec fields are filled in.
284
285 if (!avtUI->nameBox->text().isEmpty() && !avtUI->raBox->text().isEmpty() && !avtUI->decBox->text().isEmpty())
286 {
287 bool okRA, okDec;
288 dms newRA = avtUI->raBox->createDms(&okRA);
289 dms newDec = avtUI->decBox->createDms(&okDec);
290 if (!okRA || !okDec)
291 return;
292
293 //If the epochName is blank (or any non-double), we assume J2000
294 //Otherwise, precess to J2000.
296 dt.setFromEpoch(getEpoch(avtUI->epochName->text()));
297 long double jd = dt.djd();
298 if (jd != J2000)
299 {
300 SkyPoint ptest(newRA, newDec);
301 //ptest.precessFromAnyEpoch(jd, J2000);
302 ptest.catalogueCoord(jd);
303 newRA.setH(ptest.ra().Hours());
304 newDec.setD(ptest.dec().Degrees());
305 }
306
307 //make sure the coords do not already exist from another object
308 bool found = false;
309 foreach (SkyObject *p, pList)
310 {
311 //within an arcsecond?
312 if (fabs(newRA.Degrees() - p->ra().Degrees()) < 0.0003 &&
313 fabs(newDec.Degrees() - p->dec().Degrees()) < 0.0003)
314 {
315 found = true;
316 break;
317 }
318 }
319 if (!found)
320 {
321 SkyObject *obj = new SkyObject(8, newRA, newDec, 1.0, avtUI->nameBox->text());
322 deleteList.append(obj); //this object will be deleted when window is destroyed
323 processObject(obj);
324 }
325 }
326
327 //If the Ra and Dec boxes are filled, but the name field is empty,
328 //move input focus to nameBox. If either coordinate box is empty,
329 //move focus there
330 if (avtUI->nameBox->text().isEmpty())
331 {
332 avtUI->nameBox->QWidget::setFocus();
333 }
334 if (avtUI->raBox->text().isEmpty())
335 {
336 avtUI->raBox->QWidget::setFocus();
337 }
338 else
339 {
340 if (avtUI->decBox->text().isEmpty())
341 avtUI->decBox->QWidget::setFocus();
342 }
343 }
344
345 avtUI->View->update();
346}
347
348//Use find dialog to choose an object
350{
351 if (FindDialog::Instance()->exec() == QDialog::Accepted)
352 {
353 SkyObject *o = FindDialog::Instance()->targetObject();
354 processObject(o);
355 }
356
357 avtUI->View->update();
358 avtUI->View->replot();
359}
360
361void AltVsTime::processObject(SkyObject *o, bool forceAdd)
362{
363 if (!o)
364 return;
365
366 KSNumbers *num = new KSNumbers(getDate().djd());
367 KSNumbers *oldNum = nullptr;
368
369 //If the object is in the solar system, recompute its position for the given epochLabel
370 KStarsData *data = KStarsData::Instance();
371 if (o->isSolarSystem())
372 {
373 oldNum = new KSNumbers(data->ut().djd());
374 o->updateCoords(num, true, geo->lat(), data->lst(), true);
375 }
376
377 //precess coords to target epoch
378 o->updateCoordsNow(num);
379
380 // vector used for computing the points needed for drawing the graph
381 QVector<double> y(100), t(100);
382
383 //If this point is not in list already, add it to list
384 bool found(false);
385 foreach (SkyObject *p, pList)
386 {
387 if (o->ra().Degrees() == p->ra().Degrees() && o->dec().Degrees() == p->dec().Degrees())
388 {
389 found = true;
390 break;
391 }
392 }
393 if (found && !forceAdd)
394 {
395 qCWarning(KSTARS) << "This point is already displayed; It will not be duplicated.";
396 }
397 else
398 {
399 pList.append(o);
400
401 // make sure existing curves are thin and red:
402
403 for (int i = 0; i < avtUI->View->graphCount(); i++)
404 {
405 if (avtUI->View->graph(i)->pen().color() == Qt::white)
406 {
407 avtUI->View->graph(i)->setPen(QPen(Qt::red, 2));
408 }
409 }
410
411 // SET up the curve's name
412 avtUI->View->addGraph()->setName(o->name());
413
414 // compute the current graph:
415 // time range: 24h
416
417 int offset = 3;
418 for (double h = -12.0, i = 0; h <= 12.0; h += 0.25, i++)
419 {
420 y[i] = findAltitude(o, h);
421 if (y[i] > maxAlt)
422 maxAlt = y[i];
423 if (y[i] < minAlt)
424 minAlt = y[i];
425 t[i] = i * 900 + 43200;
426 avtUI->View->graph(avtUI->View->graphCount() - 1)->addData(t[i], y[i]);
427 }
428 avtUI->View->graph(avtUI->View->graphCount() - 1)->setPen(QPen(Qt::white, 3));
429
430 // Go into initial state: without Zoom/Pan
431 avtUI->View->xAxis->setRange(43200, 129600);
432 avtUI->View->xAxis2->setRange(61200, 147600);
433 if (abs(minAlt) > maxAlt)
434 maxAlt = abs(minAlt);
435 else
436 minAlt = -maxAlt;
437
438 avtUI->View->yAxis->setRange(minAlt - offset, maxAlt + offset);
439
440 // Update background coordinates:
441 background->topLeft->setCoords(avtUI->View->xAxis->range().lower, avtUI->View->yAxis->range().upper);
442 background->bottomRight->setCoords(avtUI->View->xAxis->range().upper, avtUI->View->yAxis->range().lower);
443
444 avtUI->View->replot();
445
446 avtUI->PlotList->addItem(getObjectName(o));
447 avtUI->PlotList->setCurrentRow(avtUI->PlotList->count() - 1);
448 avtUI->raBox->show(o->ra());
449 avtUI->decBox->show(o->dec());
450 avtUI->nameBox->setText(getObjectName(o));
451
452 //Set epochName to epoch shown in date tab
453 avtUI->epochName->setText(QString().setNum(getDate().epoch()));
454 }
455 //qCDebug() << "Currently, there are " << avtUI->View->graphCount() << " objects displayed.";
456
457 //restore original position
458 if (o->isSolarSystem())
459 {
460 o->updateCoords(oldNum, true, data->geo()->lat(), data->lst(), true);
461 delete oldNum;
462 }
463 o->EquatorialToHorizontal(data->lst(), data->geo()->lat());
464 delete num;
465}
466
467double AltVsTime::findAltitude(SkyPoint *p, double hour)
468{
469 hour += 24.0 * DayOffset;
470
471 //getDate converts the user-entered local time to UT
472 KStarsDateTime ut = getDate().addSecs(hour * 3600.0);
473
474 CachingDms LST = geo->GSTtoLST(ut.gst());
475 p->EquatorialToHorizontal(&LST, geo->lat());
476 return p->alt().Degrees();
477}
478
480{
481 if (row < 0)
482 return;
483
484 int rowIndex = 0;
485 //highlight the curve of the selected object
486 for (int i = 0; i < avtUI->View->graphCount(); i++)
487 {
488 if (i == row)
489 rowIndex = row;
490 else
491 {
492 avtUI->View->graph(i)->setPen(QPen(Qt::red, 2));
493 avtUI->View->graph(i)->setLayer("main");
494 }
495 }
496 avtUI->View->graph(rowIndex)->setPen(QPen(Qt::white, 3));
497 avtUI->View->graph(rowIndex)->setLayer("currentCurveLayer");
498 avtUI->View->update();
499 avtUI->View->replot();
500
501 if (row >= 0 && row < pList.size())
502 {
503 SkyObject *p = pList.at(row);
504 avtUI->raBox->show(p->ra());
505 avtUI->decBox->show(p->dec());
506 avtUI->nameBox->setText(avtUI->PlotList->currentItem()->text());
507 }
508
509 SkyObject *selectedObject = KStarsData::Instance()->objectNamed(avtUI->nameBox->text());
510 const KStarsDateTime &ut = KStarsData::Instance()->ut();
511 if (selectedObject)
512 {
513 QTime rt = selectedObject->riseSetTime(ut, geo, true); //true = use rise time
514 if (rt.isValid() == false)
515 {
516 avtUI->riseButton->setEnabled(false);
517 avtUI->setButton->setEnabled(false);
518 }
519 else
520 {
521 avtUI->riseButton->setEnabled(true);
522 avtUI->setButton->setEnabled(true);
523 }
524 }
525}
526
528{
529 QCPRange aux = avtUI->View->xAxis2->range();
530 avtUI->View->xAxis->setRange(aux -= 18000);
531 avtUI->View->xAxis2->setRange(range.bounded(61200, 147600));
532 // if ZOOM is detected then remove the gold lines that indicate current position:
533 if (avtUI->View->xAxis->range().size() != 86400)
534 {
535 // Refresh the background:
536 background->setScaled(false);
537 background->setScaled(true, Qt::IgnoreAspectRatio);
538 background->setPixmap(*gradient);
539
540 avtUI->View->update();
541 avtUI->View->replot();
542 }
543}
544
546{
547 int offset = 3;
548 avtUI->View->yAxis->setRange(range.bounded(minAlt - offset, maxAlt + offset));
549}
550
551void AltVsTime::plotMousePress(QCPAbstractPlottable *abstractPlottable, int dataIndex, QMouseEvent *event)
552{
553 //Do we need this?
554 Q_UNUSED(dataIndex);
555
556 if (event->button() == Qt::RightButton)
557 {
558 QCPAbstractPlottable *plottable = abstractPlottable;
559 if (plottable)
560 {
561 double x = avtUI->View->xAxis->pixelToCoord(event->localPos().x());
562 double y = avtUI->View->yAxis->pixelToCoord(event->localPos().y());
563
564 QCPGraph *graph = qobject_cast<QCPGraph *>(plottable);
565
566 if (graph)
567 {
568 double yValue = y;
569 double xValue = x;
570
571 // Compute time value:
572 QTime localTime(0, 0, 0, 0);
573 QTime localSiderealTime(5, 0, 0, 0);
574
575 localTime = localTime.addSecs(int(xValue));
576 localSiderealTime = localSiderealTime.addSecs(int(xValue));
577
579 QToolTip::showText(event->globalPos(),
580 i18n("<table>"
581 "<tr>"
582 "<th colspan=\"2\">%1</th>"
583 "</tr>"
584 "<tr>"
585 "<td>LST: </td>"
586 "<td>%3</td>"
587 "</tr>"
588 "<tr>"
589 "<td>LT: </td>"
590 "<td>%2</td>"
591 "</tr>"
592 "<tr>"
593 "<td>Altitude: </td>"
594 "<td>%4</td>"
595 "</tr>"
596 "</table>",
597 graph->name().isEmpty() ? "???" : graph->name(),
598 localTime.toString(),
599 localSiderealTime.toString(),
600 QString::number(yValue, 'f', 2) + ' ' + QChar(176)),
601 avtUI->View, avtUI->View->rect());
602 }
603 }
604 }
605}
606
607//move input focus to the next logical widget
609{
610 if (sender()->objectName() == QString("nameBox"))
611 avtUI->addButton->setFocus();
612 if (sender()->objectName() == QString("raBox"))
613 avtUI->decBox->setFocus();
614 if (sender()->objectName() == QString("decbox"))
615 avtUI->addButton->setFocus();
616 if (sender()->objectName() == QString("longBox"))
617 avtUI->latBox->setFocus();
618 if (sender()->objectName() == QString("latBox"))
619 avtUI->updateButton->setFocus();
620}
621
623{
624 pList.clear();
625 //Need to delete the pointers in deleteList
626 while (!deleteList.isEmpty())
627 delete deleteList.takeFirst();
628
629 avtUI->PlotList->clear();
630 avtUI->nameBox->clear();
631 avtUI->raBox->clear();
632 avtUI->decBox->clear();
633 avtUI->epochName->clear();
634 // remove all graphs from the plot:
635 avtUI->View->clearGraphs();
636 // we remove all the dots (rise/set/transit) from the chart
637 // without removing the background image
638 int indexItem = 0, noItems = avtUI->View->itemCount();
639 QCPAbstractItem *item;
640 QCPItemPixmap *background;
641 // remove every item at a time:
642 while (noItems > 1 && indexItem < noItems)
643 {
644 // test if the current item is the background:
645 item = avtUI->View->item(indexItem);
646 background = qobject_cast<QCPItemPixmap *>(item);
647 if (background)
648 indexItem++;
649 else
650 {
651 // if not, then remove this item:
652 avtUI->View->removeItem(indexItem);
653 noItems--;
654 }
655 }
656 // update & replot the chart:
657 avtUI->View->update();
658 avtUI->View->replot();
659}
660
662{
663 avtUI->nameBox->clear();
664 avtUI->raBox->clear();
665 avtUI->decBox->clear();
666 avtUI->epochName->clear();
667}
668
670{
671 if (avtUI->PlotList->currentRow() < 0)
672 return;
673
674 SkyObject *selectedObject = pList.at(avtUI->PlotList->currentRow());
675 if (selectedObject == nullptr)
676 {
677 if (avtUI->PlotList->currentItem())
678 qCWarning(KSTARS) << "slotComputeAltitudeByTime: Unable to find" << avtUI->PlotList->currentItem()->text();
679 else
680 {
681 qCWarning(KSTARS) << "slotComputeAltitudeByTime: Unable to find item";
682 }
683 return;
684 }
685
686 // Get Local Date & Time
687 KStarsDateTime lt = KStarsDateTime(avtUI->DateWidget->date(), avtUI->timeSpin->time(), Qt::LocalTime);
688 // Convert to UT
689 KStarsDateTime ut = geo->LTtoUT(lt);
690 // Get LST from GST
691 CachingDms LST = geo->GSTtoLST(ut.gst());
692 SkyObject *tempObject = selectedObject->clone();
693 // Update coords
694 KSNumbers num(ut.djd());
695 tempObject->updateCoords(&num, true, geo->lat(), &LST);
696 // Find Horizontal coordinates from LST & Latitude
697 selectedObject->EquatorialToHorizontal(&LST, geo->lat());
698
699 // Set altitude
700 avtUI->altitudeBox->setText(selectedObject->altRefracted().toDMSString(true));
701
702 delete (tempObject);
703}
704
706{
707 if (avtUI->PlotList->currentRow() < 0)
708 return;
709
710 const KStarsDateTime &ut = KStarsData::Instance()->ut();
711 SkyObject *selectedObject = pList.at(avtUI->PlotList->currentRow());
712 if (selectedObject == nullptr)
713 {
714 qCWarning(KSTARS) << "Mark Rise Time: Unable to find" << avtUI->PlotList->currentItem()->text();
715 return;
716 }
717
718 QCPItemTracer *riseTimeTracer;
719 // check if at least one graph exists in the plot
720 if (avtUI->View->graphCount() > 0)
721 {
722 double time = 0;
723 double hours, minutes;
724
725 QCPGraph *selectedGraph = avtUI->View->graph(avtUI->PlotList->currentRow());
726
727 QTime rt = selectedObject->riseSetTime(ut, geo, true); //true = use rise time
728 // mark the Rise time with a solid red circle
729 if (rt.isValid() && selectedGraph)
730 {
731 hours = rt.hour();
732 minutes = rt.minute();
733 if (hours < 12)
734 hours += 24;
735 time = hours * 3600 + minutes * 60;
736 riseTimeTracer = new QCPItemTracer(avtUI->View);
737 riseTimeTracer->setLayer("markersLayer");
738 riseTimeTracer->setGraph(selectedGraph);
739 riseTimeTracer->setInterpolating(true);
740 riseTimeTracer->setStyle(QCPItemTracer::tsCircle);
741 riseTimeTracer->setPen(QPen(Qt::red));
742 riseTimeTracer->setBrush(Qt::red);
743 riseTimeTracer->setSize(10);
744 riseTimeTracer->setGraphKey(time);
745 riseTimeTracer->setVisible(true);
746 avtUI->View->update();
747 avtUI->View->replot();
748 }
749 }
750}
751
753{
754 if (avtUI->PlotList->currentRow() < 0)
755 return;
756
757 const KStarsDateTime &ut = KStarsData::Instance()->ut();
758 SkyObject *selectedObject = pList.at(avtUI->PlotList->currentRow());
759 if (selectedObject == nullptr)
760 {
761 qCWarning(KSTARS) << "Mark Set Time: Unable to find" << avtUI->PlotList->currentItem()->text();
762 return;
763 }
764 QCPItemTracer *setTimeTracer;
765 // check if at least one graph exists in the plot
766 if (avtUI->View->graphCount() > 0)
767 {
768 double time = 0;
769 double hours, minutes;
770
771 QCPGraph *selectedGraph = avtUI->View->graph(avtUI->PlotList->currentRow());
772
773 QTime rt = selectedObject->riseSetTime(ut, geo, true); //true = use rise time
774 //If set time is before rise time, use set time for tomorrow
775 QTime st = selectedObject->riseSetTime(ut, geo, false); //false = use set time
776 if (st < rt)
777 st = selectedObject->riseSetTime(ut.addDays(1), geo, false); //false = use set time
778 // mark the Set time with a solid blue circle
779 if (rt.isValid())
780 {
781 hours = st.hour();
782 minutes = st.minute();
783 if (hours < 12)
784 hours += 24;
785 time = hours * 3600 + minutes * 60;
786 setTimeTracer = new QCPItemTracer(avtUI->View);
787 setTimeTracer->setLayer("markersLayer");
788 setTimeTracer->setGraph(selectedGraph);
789 setTimeTracer->setInterpolating(true);
790 setTimeTracer->setStyle(QCPItemTracer::tsCircle);
791 setTimeTracer->setPen(QPen(Qt::blue));
792 setTimeTracer->setBrush(Qt::blue);
793 setTimeTracer->setSize(10);
794 setTimeTracer->setGraphKey(time);
795 setTimeTracer->setVisible(true);
796 avtUI->View->update();
797 avtUI->View->replot();
798 }
799 }
800}
801
803{
804 if (avtUI->PlotList->currentRow() < 0)
805 return;
806
807 const KStarsDateTime &ut = KStarsData::Instance()->ut();
808 SkyObject *selectedObject = pList.at(avtUI->PlotList->currentRow());
809 if (selectedObject == nullptr)
810 {
811 qCWarning(KSTARS) << "Mark Transit Time: Unable to find" << avtUI->PlotList->currentItem()->text();
812 return;
813 }
814 QCPItemTracer *transitTimeTracer;
815 // check if at least one graph exists in the plot
816 if (avtUI->View->graphCount() > 0)
817 {
818 double time = 0;
819 double hours, minutes;
820
821 QCPGraph *selectedGraph = avtUI->View->graph(avtUI->PlotList->currentRow());
822
823 QTime rt = selectedObject->riseSetTime(ut, geo, true); //true = use rise time
824 //If transit time is before rise time, use transit time for tomorrow
825 QTime tt = selectedObject->transitTime(ut, geo);
826
827 if (tt < rt)
828 tt = selectedObject->transitTime(ut.addDays(1), geo);
829 // mark the Transit time with a solid green circle
830 hours = tt.hour();
831 minutes = tt.minute();
832 if (hours < 12)
833 hours += 24;
834 time = hours * 3600 + minutes * 60;
835 transitTimeTracer = new QCPItemTracer(avtUI->View);
836 transitTimeTracer->setLayer("markersLayer");
837 transitTimeTracer->setGraph(selectedGraph);
838 transitTimeTracer->setInterpolating(true);
839 transitTimeTracer->setStyle(QCPItemTracer::tsCircle);
840 transitTimeTracer->setPen(QPen(Qt::green));
841 transitTimeTracer->setBrush(Qt::green);
842 transitTimeTracer->setSize(10);
843 transitTimeTracer->setGraphKey(time);
844 transitTimeTracer->setVisible(true);
845 avtUI->View->update();
846 avtUI->View->replot();
847 }
848}
849
851{
852 //Determine the time of sunset and sunrise for the desired date and location
853 //expressed as doubles, the fraction of a full day.
854
855 /* KSAlmanac ksal(getDate(), geo); */
856
857 /* ... */
858}
859
860//FIXME
861/*
862void AltVsTime::mouseOverLine(QMouseEvent *event){
863 // Get the mouse position's coordinates relative to axes:
864 double x = avtUI->View->xAxis->pixelToCoord(event->pos().x());
865 double y = avtUI->View->yAxis->pixelToCoord(event->pos().y());
866 // Save the actual values:
867 double yValue = y;
868 double xValue = x;
869 // The offset used for the Y axis: top/bottom
870 int offset = 3;
871 // Compute the Y axis maximum value:
872 int yAxisMaxValue = maxAlt + offset;
873 // Compute the X axis minimum and maximum values:
874 int xAxisMinValue = 43200;
875 int xAxisMaxValue = 129600;
876 // Ignore the upper and left margins:
877 y = yAxisMaxValue - y;
878 x -= xAxisMinValue;
879 // We make a copy to gradient background in order to have one set of lines at a time:
880 // Otherwise, the chart would have been covered by lines
881 QPixmap copy = gradient->copy(gradient->rect());
882 // If ZOOM is not active, then draw the gold lines that indicate current mouse pisition:
883 if(avtUI->View->xAxis->range().size() == 86400){
884 QPainter p;
885
886 p.begin(&copy);
887 p.setPen( QPen( QBrush("gold"), 2, Qt::SolidLine ) );
888
889 // Get the gradient background's width and height:
890 int pW = gradient->rect().width();
891 int pH = gradient->rect().height();
892
893 // Compute the real coordinates within the chart:
894 y = (y*pH/2)/yAxisMaxValue;
895 x = (x*pW)/(xAxisMaxValue-xAxisMinValue);
896
897 // Draw the horizontal line (altitude):
898 p.drawLine( QLineF( 0.5, y, avtUI->View->rect().width()-0.5,y ) );
899 // Draw the altitude value:
900 p.setPen( QPen( QBrush("gold"), 3, Qt::SolidLine ) );
901 p.drawText( 25, y + 15, QString::number(yValue,'f',2) + QChar(176) );
902 p.setPen( QPen( QBrush("gold"), 1, Qt::SolidLine ) );
903 // Draw the vertical line (time):
904 p.drawLine( QLineF( x, 0.5, x, avtUI->View->rect().height()-0.5 ) );
905 // Compute and draw the time value:
906 QTime localTime(0,0,0,0);
907 localTime = localTime.addSecs(int(xValue));
908 p.save();
909 p.translate( x + 10, pH - 20 );
910 p.rotate(-90);
911 p.setPen( QPen( QBrush("gold"), 3, Qt::SolidLine ) );
912 p.drawText( 5, 5, QLocale().toString( localTime, QLocale::ShortFormat ) ); // short format necessary to avoid false time-zone labeling
913 p.restore();
914 p.end();
915 }
916 // Refresh the background:
917 background->setScaled(false);
918 background->setScaled(true, Qt::IgnoreAspectRatio);
919 background->setPixmap(copy);
920
921 avtUI->View->update();
922 avtUI->View->replot();
923}
924*/
925
927{
928 double x = avtUI->View->xAxis->pixelToCoord(event->localPos().x());
929 double y = avtUI->View->yAxis->pixelToCoord(event->localPos().y());
930 QCPAbstractPlottable *abstractGraph = avtUI->View->plottableAt(event->pos(), false);
931 QCPGraph *graph = qobject_cast<QCPGraph *>(abstractGraph);
932
933 if (x > avtUI->View->xAxis->range().lower && x < avtUI->View->xAxis->range().upper)
934 if (y > avtUI->View->yAxis->range().lower && y < avtUI->View->yAxis->range().upper)
935 {
936 if (graph)
937 {
938 double yValue = y;
939 double xValue = x;
940
941 // Compute time value:
942 QTime localTime(0, 0, 0, 0);
943 QTime localSiderealTime(5, 0, 0, 0);
944
945 localTime = localTime.addSecs(int(xValue));
946 localSiderealTime = localSiderealTime.addSecs(int(xValue));
947
949 QToolTip::showText(event->globalPos(),
950 i18n("<table>"
951 "<tr>"
952 "<th colspan=\"2\">%1</th>"
953 "</tr>"
954 "<tr>"
955 "<td>LST: </td>"
956 "<td>%3</td>"
957 "</tr>"
958 "<tr>"
959 "<td>LT: </td>"
960 "<td>%2</td>"
961 "</tr>"
962 "<tr>"
963 "<td>Altitude: </td>"
964 "<td>%4</td>"
965 "</tr>"
966 "</table>",
967 graph->name().isEmpty() ? "???" : graph->name(),
968 localTime.toString(), localSiderealTime.toString(),
969 QString::number(yValue, 'f', 2) + ' ' + QChar(176)),
970 avtUI->View, avtUI->View->rect());
971 }
972 else
974 }
975
976 avtUI->View->update();
977 avtUI->View->replot();
978}
979
981{
982 KStarsData *data = KStarsData::Instance();
983 KStarsDateTime today = getDate();
984 KSNumbers *num = new KSNumbers(today.djd());
985 KSNumbers *oldNum = nullptr;
986 CachingDms LST = geo->GSTtoLST(today.gst());
987
988 //First determine time of sunset and sunrise
990 // Determine dawn/dusk time and min/max sun elevation
991 setDawnDusk();
992
993 for (int i = 0; i < pList.count(); ++i)
994 {
995 SkyObject *o = pList.at(i);
996 if (o)
997 {
998 //If the object is in the solar system, recompute its position for the given date
999 if (o->isSolarSystem())
1000 {
1001 oldNum = new KSNumbers(data->ut().djd());
1002 o->updateCoords(num, true, geo->lat(), &LST, true);
1003 }
1004
1005 //precess coords to target epoch
1006 o->updateCoordsNow(num);
1007
1008 //update pList entry
1009 pList.replace(i, o);
1010
1011 // We are creating a new data set (time, altitude) for the new date:
1012 QVector<double> time_dataSet, altitude_dataSet;
1013 double point_altitudeValue, point_timeValue;
1014 // compute the new graph values:
1015 // time range: 24h
1016 int offset = 3;
1017 for (double h = -12.0, i = 0; h <= 12.0; h += 0.25, i++)
1018 {
1019 point_altitudeValue = findAltitude(o, h);
1020 altitude_dataSet.push_back(point_altitudeValue);
1021 if (point_altitudeValue > maxAlt)
1022 maxAlt = point_altitudeValue;
1023 if (point_altitudeValue < minAlt)
1024 minAlt = point_altitudeValue;
1025 point_timeValue = i * 900 + 43200;
1026 time_dataSet.push_back(point_timeValue);
1027 }
1028
1029 // Replace graph data set:
1030 avtUI->View->graph(i)->setData(time_dataSet, altitude_dataSet);
1031
1032 // Go into initial state: without Zoom/Pan
1033 avtUI->View->xAxis->setRange(43200, 129600);
1034 avtUI->View->xAxis2->setRange(61200, 147600);
1035
1036 // Center the altitude axis in 0 value:
1037 if (abs(minAlt) > maxAlt)
1038 maxAlt = abs(minAlt);
1039 else
1040 minAlt = -maxAlt;
1041 avtUI->View->yAxis->setRange(minAlt - offset, maxAlt + offset);
1042
1043 // Update background coordinates:
1044 background->topLeft->setCoords(avtUI->View->xAxis->range().lower, avtUI->View->yAxis->range().upper);
1045 background->bottomRight->setCoords(avtUI->View->xAxis->range().upper, avtUI->View->yAxis->range().lower);
1046
1047 // Redraw the plot:
1048 avtUI->View->replot();
1049
1050 //restore original position
1051 if (o->isSolarSystem())
1052 {
1053 o->updateCoords(oldNum, true, data->geo()->lat(), data->lst());
1054 delete oldNum;
1055 oldNum = nullptr;
1056 }
1057 o->EquatorialToHorizontal(data->lst(), data->geo()->lat());
1058 }
1059 else //assume unfound object is a custom object
1060 {
1061 pList.at(i)->updateCoordsNow(num); //precess to desired epoch
1062
1063 // We are creating a new data set (time, altitude) for the new date:
1064 QVector<double> time_dataSet, altitude_dataSet;
1065 double point_altitudeValue, point_timeValue;
1066 // compute the new graph values:
1067 // time range: 24h
1068 int offset = 3;
1069 for (double h = -12.0, i = 0; h <= 12.0; h += 0.25, i++)
1070 {
1071 point_altitudeValue = findAltitude(pList.at(i), h);
1072 altitude_dataSet.push_back(point_altitudeValue);
1073 if (point_altitudeValue > maxAlt)
1074 maxAlt = point_altitudeValue;
1075 if (point_altitudeValue < minAlt)
1076 minAlt = point_altitudeValue;
1077 point_timeValue = i * 900 + 43200;
1078 time_dataSet.push_back(point_timeValue);
1079 }
1080
1081 // Replace graph data set:
1082 avtUI->View->graph(i)->setData(time_dataSet, altitude_dataSet);
1083
1084 // Go into initial state: without Zoom/Pan
1085 avtUI->View->xAxis->setRange(43200, 129600);
1086 avtUI->View->xAxis2->setRange(61200, 147600);
1087
1088 // Center the altitude axis in 0 value:
1089 if (abs(minAlt) > maxAlt)
1090 maxAlt = abs(minAlt);
1091 else
1092 minAlt = -maxAlt;
1093 avtUI->View->yAxis->setRange(minAlt - offset, maxAlt + offset);
1094
1095 // Update background coordinates:
1096 background->topLeft->setCoords(avtUI->View->xAxis->range().lower, avtUI->View->yAxis->range().upper);
1097 background->bottomRight->setCoords(avtUI->View->xAxis->range().upper, avtUI->View->yAxis->range().lower);
1098
1099 // Redraw the plot:
1100 avtUI->View->replot();
1101 }
1102 }
1103
1104 if (getDate().time().hour() > 12)
1105 DayOffset = 1;
1106 else
1107 DayOffset = 0;
1108
1109 setLSTLimits();
1110 slotHighlight(avtUI->PlotList->currentRow());
1111 avtUI->View->update();
1112
1113 delete num;
1114}
1115
1117{
1119 if (ld->exec() == QDialog::Accepted)
1120 {
1121 GeoLocation *newGeo = ld->selectedCity();
1122 if (newGeo)
1123 {
1124 geo = newGeo;
1125 avtUI->latBox->show(geo->lat());
1126 avtUI->longBox->show(geo->lng());
1127 }
1128 }
1129 delete ld;
1130}
1131
1132// FIXME: should we remove this method?
1134{
1135 /*
1136 //UT at noon on target date
1137 KStarsDateTime ut = getDate().addSecs(((double)DayOffset + 0.5)*86400.);
1138
1139 dms lst = geo->GSTtoLST(ut.gst());
1140 double h1 = lst.Hours();
1141 if(h1 > 12.0)
1142 h1 -= 24.0;
1143 double h2 = h1 + 24.0;
1144 avtUI->View->setSecondaryLimits(h1, h2, -90.0, 90.0);
1145 */
1146}
1147
1149{
1151 if (dt.time() > QTime(12, 0, 0))
1152 dt = dt.addDays(1);
1153 avtUI->DateWidget->setDate(dt.date());
1154}
1155
1156void AltVsTime::drawGradient()
1157{
1158 // Things needed for Gradient:
1160 GeoLocation *geoLoc = KStarsData::Instance()->geo();
1161 QDateTime midnight = QDateTime(dtt.date(), QTime());
1162 KStarsDateTime const utt = geoLoc->LTtoUT(KStarsDateTime(midnight));
1163
1164 // Variables needed for Gradient:
1165 double SunRise, SunSet, Dawn, Dusk, SunMinAlt, SunMaxAlt;
1166 double MoonRise, MoonSet, MoonIllum;
1167
1168 KSAlmanac ksal(utt, geoLoc);
1169
1170 // Get the values:
1171 SunRise = ksal.getSunRise();
1172 SunSet = ksal.getSunSet();
1173 SunMaxAlt = ksal.getSunMaxAlt();
1174 SunMinAlt = ksal.getSunMinAlt();
1175 MoonRise = ksal.getMoonRise();
1176 MoonSet = ksal.getMoonSet();
1177 MoonIllum = ksal.getMoonIllum();
1178 Dawn = ksal.getDawnAstronomicalTwilight();
1179 Dusk = ksal.getDuskAstronomicalTwilight();
1180
1181 gradient = new QPixmap(avtUI->View->rect().width(), avtUI->View->rect().height());
1182
1183 QPainter p;
1184
1185 p.begin(gradient);
1186 KPlotWidget *kPW = new KPlotWidget;
1188 p.fillRect(gradient->rect(), kPW->backgroundColor());
1189
1190 p.setClipRect(gradient->rect());
1191 p.setClipping(true);
1192
1193 int pW = gradient->rect().width();
1194 int pH = gradient->rect().height();
1195
1196 QColor SkyColor(0, 100, 200);
1197 // TODO
1198 // if( Options::darkAppColors() )
1199 // SkyColor = QColor( 200, 0, 0 ); // use something red, visible through a red filter
1200
1201 // Draw gradient representing lunar interference in the sky
1202 if (MoonIllum > 0.01) // do this only if Moon illumination is reasonable so it's important
1203 {
1204 int moonrise = int(pW * (0.5 + MoonRise));
1205 int moonset = int(pW * (MoonSet - 0.5));
1206 if (moonset < 0)
1207 moonset += pW;
1208 if (moonrise > pW)
1209 moonrise -= pW;
1210 int moonalpha = int(10 + MoonIllum * 130);
1211 int fadewidth =
1212 pW *
1213 0.01; // pW * fraction of day to fade the moon brightness over (0.01 corresponds to roughly 15 minutes, 0.007 to 10 minutes), both before and after actual set.
1214 QColor MoonColor(255, 255, 255, moonalpha);
1215
1216 if (moonset < moonrise)
1217 {
1218 QLinearGradient grad =
1219 QLinearGradient(QPointF(moonset - fadewidth, 0.0), QPointF(moonset + fadewidth, 0.0));
1220 grad.setColorAt(0, MoonColor);
1221 grad.setColorAt(1, Qt::transparent);
1222 p.fillRect(QRectF(0.0, 0.0, moonset + fadewidth, pH),
1223 grad); // gradient should be padded until moonset - fadewidth (see QLinearGradient docs)
1224 grad.setStart(QPointF(moonrise + fadewidth, 0.0));
1225 grad.setFinalStop(QPointF(moonrise - fadewidth, 0.0));
1226 p.fillRect(QRectF(moonrise - fadewidth, 0.0, pW - moonrise + fadewidth, pH), grad);
1227 }
1228 else
1229 {
1230 qreal opacity = p.opacity();
1231 p.setOpacity(opacity / 4);
1232 p.fillRect(QRectF(moonrise + fadewidth, 0.0, moonset - moonrise - 2 * fadewidth, pH), MoonColor);
1233 QLinearGradient grad =
1234 QLinearGradient(QPointF(moonrise + fadewidth, 0.0), QPointF(moonrise - fadewidth, 0.0));
1235 grad.setColorAt(0, MoonColor);
1236 grad.setColorAt(1, Qt::transparent);
1237 p.fillRect(QRectF(0.0, 0.0, moonrise + fadewidth, pH), grad);
1238 grad.setStart(QPointF(moonset - fadewidth, 0.0));
1239 grad.setFinalStop(QPointF(moonset + fadewidth, 0.0));
1240 p.fillRect(QRectF(moonset - fadewidth, 0.0, pW - moonset, pH), grad);
1241 p.setOpacity(opacity);
1242 }
1243 }
1244
1245 //draw daytime sky if the Sun rises for the current date/location
1246 if (SunMaxAlt > -18.0)
1247 {
1248 //Display centered on midnight, so need to modulate dawn/dusk by 0.5
1249 int rise = int(pW * (0.5 + SunRise));
1250 int set = int(pW * (SunSet - 0.5));
1251 int da = int(pW * (0.5 + Dawn));
1252 int du = int(pW * (Dusk - 0.5));
1253
1254 if (SunMinAlt > 0.0)
1255 {
1256 // The sun never set and the sky is always blue
1257 p.fillRect(rect(), SkyColor);
1258 }
1259 else if (SunMaxAlt < 0.0 && SunMinAlt < -18.0)
1260 {
1261 // The sun never rise but the sky is not completely dark
1262 QLinearGradient grad = QLinearGradient(QPointF(0.0, 0.0), QPointF(du, 0.0));
1263
1264 QColor gradStartColor = SkyColor;
1265 gradStartColor.setAlpha((1 - (SunMaxAlt / -18.0)) * 255);
1266
1267 grad.setColorAt(0, gradStartColor);
1268 grad.setColorAt(1, Qt::transparent);
1269 p.fillRect(QRectF(0.0, 0.0, du, pH), grad);
1270 grad.setStart(QPointF(pW, 0.0));
1271 grad.setFinalStop(QPointF(da, 0.0));
1272 p.fillRect(QRectF(da, 0.0, pW, pH), grad);
1273 }
1274 else if (SunMaxAlt < 0.0 && SunMinAlt > -18.0)
1275 {
1276 // The sun never rise but the sky is NEVER completely dark
1277 QLinearGradient grad = QLinearGradient(QPointF(0.0, 0.0), QPointF(pW, 0.0));
1278
1279 QColor gradStartEndColor = SkyColor;
1280 gradStartEndColor.setAlpha((1 - (SunMaxAlt / -18.0)) * 255);
1281 QColor gradMidColor = SkyColor;
1282 gradMidColor.setAlpha((1 - (SunMinAlt / -18.0)) * 255);
1283
1284 grad.setColorAt(0, gradStartEndColor);
1285 grad.setColorAt(0.5, gradMidColor);
1286 grad.setColorAt(1, gradStartEndColor);
1287 p.fillRect(QRectF(0.0, 0.0, pW, pH), grad);
1288 }
1289 else if (Dawn < 0.0)
1290 {
1291 // The sun sets and rises but the sky is never completely dark
1292 p.fillRect(0, 0, set, int(0.5 * pH), SkyColor);
1293 p.fillRect(rise, 0, pW, int(0.5 * pH), SkyColor);
1294
1295 QLinearGradient grad = QLinearGradient(QPointF(set, 0.0), QPointF(rise, 0.0));
1296
1297 QColor gradMidColor = SkyColor;
1298 gradMidColor.setAlpha((1 - (SunMinAlt / -18.0)) * 255);
1299
1300 grad.setColorAt(0, SkyColor);
1301 grad.setColorAt(0.5, gradMidColor);
1302 grad.setColorAt(1, SkyColor);
1303 p.fillRect(QRectF(set, 0.0, rise - set, pH), grad);
1304 }
1305 else
1306 {
1307 p.fillRect(0, 0, set, pH, SkyColor);
1308 p.fillRect(rise, 0, pW, pH, SkyColor);
1309
1310 QLinearGradient grad = QLinearGradient(QPointF(set, 0.0), QPointF(du, 0.0));
1311 grad.setColorAt(0, SkyColor);
1312 grad.setColorAt(
1313 1,
1314 Qt::transparent); // FIXME?: The sky appears black well before the actual end of twilight if the gradient is too slow (eg: latitudes above arctic circle)
1315 p.fillRect(QRectF(set, 0.0, du - set, pH), grad);
1316
1317 grad.setStart(QPointF(rise, 0.0));
1318 grad.setFinalStop(QPointF(da, 0.0));
1319 p.fillRect(QRectF(da, 0.0, rise - da, pH), grad);
1320 }
1321 }
1322
1323 p.fillRect(0, int(0.5 * pH), pW, int(0.5 * pH), KStarsData::Instance()->colorScheme()->colorNamed("HorzColor"));
1324
1325 p.setClipping(false);
1326
1327 // Add vertical line indicating "now"
1328 // Convert the current system clock time to the TZ corresponding to geo
1329 QTime t = geoLoc->UTtoLT(KStarsDateTime::currentDateTimeUtc()).time();
1330 double x = 12.0 + t.hour() + t.minute() / 60.0 + t.second() / 3600.0;
1331
1332 while (x > 24.0)
1333 x -= 24.0;
1334
1335 // Convert to screen pixel coords
1336 int ix = int(x * pW / 24.0);
1337
1338 p.setPen(QPen(QBrush("white"), 2.0, Qt::DotLine));
1339 p.drawLine(ix, 0, ix, pH);
1340
1341 QFont largeFont = p.font();
1342
1343 largeFont.setPointSize(largeFont.pointSize() + 1);
1344 // Label this vertical line with the current time
1345 p.save();
1346 p.setFont(largeFont);
1347 p.translate(ix + 15, pH - 20);
1348 p.rotate(-90);
1349 // Short format necessary to avoid false time-zone labeling
1351 p.restore();
1352 p.end();
1353}
1354
1356{
1357 //convert midnight local time to UT:
1358 QDateTime lt(avtUI->DateWidget->date(), QTime());
1359 return geo->LTtoUT(KStarsDateTime(lt));
1360}
1361
1362double AltVsTime::getEpoch(const QString &eName)
1363{
1364 //If Epoch field not a double, assume J2000
1365 bool ok;
1366 double epoch = eName.toDouble(&ok);
1367 if (!ok)
1368 {
1369 qCWarning(KSTARS) << "Invalid Epoch. Assuming 2000.0.";
1370 return 2000.0;
1371 }
1372 return epoch;
1373}
1374
1375void AltVsTime::setDawnDusk()
1376{
1377 /* TODO */
1378
1379 /*
1380 KSAlmanac almanac(getDate(), geo);
1381
1382 avtUI->View->setDawnDuskTimes(almanac.getDawnAstronomicalTwilight(), almanac.getDuskAstronomicalTwilight());
1383 avtUI->View->setMinMaxSunAlt(almanac.getSunMinAlt(), almanac.getSunMaxAlt());
1384 */
1385
1386 /* ... */
1387}
1388
1390{
1391 QPainter p; // Our painter object
1392 QPrinter printer; // Our printer object
1393 QString str_legend; // Text legend
1394 int text_height = 200; // Height of legend text zone in points
1395 QSize plot_size; // Initial plot widget size
1396 QFont plot_font; // Initial plot widget font
1397 int plot_font_size; // Initial plot widget font size
1398
1399 // Set printer resolution to 300 dpi
1400 printer.setResolution(300);
1401
1402 // Open print dialog
1403 //QPointer<QPrintDialog> dialog( KdePrint::createPrintDialog( &printer, this ) );
1404 //QPointer<QPrintDialog> dialog( &printer, this );
1405 QPrintDialog dialog(&printer, this);
1406 dialog.setWindowTitle(i18nc("@title:window", "Print elevation vs time plot"));
1407 if (dialog.exec() == QDialog::Accepted)
1408 {
1409 // Change mouse cursor
1411
1412 // Save plot widget font
1413 plot_font = avtUI->View->font();
1414 // Save plot widget font size
1415 plot_font_size = plot_font.pointSize();
1416 // Save calendar widget size
1417 plot_size = avtUI->View->size();
1418
1419 // Set text legend
1420 str_legend = i18n("Elevation vs. Time Plot");
1421 str_legend += '\n';
1422 str_legend += geo->fullName();
1423 str_legend += " - ";
1424 str_legend += avtUI->DateWidget->date().toString("dd/MM/yyyy");
1425
1426 // Create a rectangle for legend text zone
1427 QRect text_rect(0, 0, printer.width(), text_height);
1428
1429 // Increase plot widget font size so it looks good in 300 dpi
1430 plot_font.setPointSize(plot_font_size * 2.5);
1431 avtUI->View->setFont(plot_font);
1432 // Increase plot widget size to fit the entire page
1433 avtUI->View->resize(printer.width(), printer.height() - text_height);
1434
1435 // Create a pixmap and render plot widget into it
1436 QPixmap pixmap(avtUI->View->size());
1437 avtUI->View->render(&pixmap);
1438
1439 // Begin painting on printer
1440 p.begin(&printer);
1441 // Draw legend
1442 p.drawText(text_rect, Qt::AlignLeft, str_legend);
1443 // Draw plot widget
1444 p.drawPixmap(0, text_height, pixmap);
1445 // Ending painting
1446 p.end();
1447
1448 // Restore plot widget font size
1449 plot_font.setPointSize(plot_font_size);
1450 avtUI->View->setFont(plot_font);
1451 // Restore calendar widget size
1452 avtUI->View->resize(plot_size);
1453
1454 // Restore mouse cursor
1456 }
1457 //delete dialog;
1458}
1459
1461{
1462 QString finalObjectName;
1463 if (o->name() == "star")
1464 {
1465 StarObject *s = (StarObject *)o;
1466
1467 // JM: Enable HD Index stars to be added to the observing list.
1468 if (s->getHDIndex() != 0)
1469 finalObjectName = QString("HD %1").arg(QString::number(s->getHDIndex()));
1470 }
1471 else
1472 finalObjectName = translated ? o->translatedName() : o->name();
1473
1474 return finalObjectName;
1475}
AltVsTime(QWidget *parent=nullptr)
Constructor.
Definition altvstime.cpp:42
void slotAddSource()
Add an object to the list of displayed objects, according to the data entered in the edit boxes.
void slotHighlight(int)
Update the plot to highlight the altitude curve of the objects which is highlighted in the listbox.
double findAltitude(SkyPoint *p, double hour)
Determine the altitude coordinate of a SkyPoint, given an hour of the day.
void slotPrint()
Print plot widget.
void slotMarkSetTime()
Mark the set time on the curve.
void showCurrentDate()
Set the AltVsTime Date according to the current Date in the KStars main window.
void setLSTLimits()
Determine the limits for the sideral time axis, using the sidereal time at midnight for the current d...
void plotMousePress(QCPAbstractPlottable *abstractPlottable, int dataIndex, QMouseEvent *event)
Show information from the curve as a tooltip.
void slotBrowseObject()
Launch the Find Object window to select a new object for the list of displayed objects.
void slotClearBoxes()
Clear the edit boxes for specifying a new object.
void slotChooseCity()
Launch the Location dialog to choose a new location.
void slotMarkTransitTime()
Mark the transit time on the curve.
KStarsDateTime getDate()
double getEpoch(const QString &eName)
Parse a string as an epoch number.
void mouseOverLine(QMouseEvent *event)
Draw the white vertical line on click.
void onXRangeChanged(const QCPRange &range)
Update the X axis on Zoom and Drag.
void computeSunRiseSetTimes()
Determine the time of sunset and sunrise for the current date and location settings.
void slotUpdateDateLoc()
Update the plot to reflec new Date and Location settings.
void slotClear()
Clear the list of displayed objects.
void processObject(SkyObject *o, bool forceAdd=false)
Add a SkyObject to the display.
void slotMarkRiseTime()
Mark the rise time on the curve.
~AltVsTime() override
Destructor.
void onYRangeChanged(const QCPRange &range)
Update the Y axis on Zoom and Drag.
void slotAdvanceFocus()
Move input keyboard focus to the next logical widget.
void slotComputeAltitudeByTime()
Compute the altitude for a certain time.
QString getObjectName(const SkyObject *o, bool translated=true)
get object name.
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition cachingdms.h:19
SkyObject * targetObject()
Definition finddialog.h:53
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
Definition geolocation.h:28
QString fullName() const
const CachingDms * lat() const
Definition geolocation.h:70
const CachingDms * lng() const
Definition geolocation.h:64
QColor backgroundColor() const
bool antialiasing() const
A class that implements methods to find sun rise, sun set, twilight begin / end times,...
Definition ksalmanac.h:27
There are several time-dependent values used in position calculations, that are not specific to an ob...
Definition ksnumbers.h:43
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
CachingDms * lst()
Definition kstarsdata.h:224
SkyObject * objectNamed(const QString &name)
Find object by name.
const KStarsDateTime & ut() const
Definition kstarsdata.h:157
GeoLocation * geo()
Definition kstarsdata.h:230
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addDays(int nd) const
Modify the Date/Time by adding a number of days.
KStarsDateTime addSecs(double s) const
bool setFromEpoch(double e, EpochType type)
Set the Date/Time from an epoch value, represented as a double.
static KStarsDateTime currentDateTimeUtc()
static KStarsDateTime currentDateTime()
long double djd() const
Dialog for changing the geographic location of the observer.
The abstract base class for all items in a plot.
The abstract base class for all data representing objects in a plot.
Specialized axis ticker for time spans in units of milliseconds to days.
@ tssReadability
A nicely readable tick step is prioritized over matching the requested number of ticks (see setTickCo...
A plottable representing a graph in a plot.
An arbitrary pixmap.
void setPixmap(const QPixmap &pixmap)
void setScaled(bool scaled, Qt::AspectRatioMode aspectRatioMode=Qt::KeepAspectRatio, Qt::TransformationMode transformationMode=Qt::SmoothTransformation)
void setType(PositionType type)
void setCoords(double key, double value)
@ ptPlotCoords
Dynamic positioning at a plot coordinate defined by two axes (see setAxes).
Item that sticks to QCPGraph data points.
void setBrush(const QBrush &brush)
@ tsCircle
A circle.
void setStyle(TracerStyle style)
void setGraphKey(double key)
void setInterpolating(bool enabled)
void setSize(double size)
void setGraph(QCPGraph *graph)
void setPen(const QPen &pen)
void setVisible(bool on)
Q_SLOT bool setLayer(QCPLayer *layer)
Represents the range an axis is encompassing.
QCPRange bounded(double lowerBound, double upperBound) const
@ limAbove
Layer is inserted above other layer.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual SkyObject * clone() const
Create copy of object.
Definition skyobject.cpp:50
QString translatedName() const
Definition skyobject.h:148
virtual QString name(void) const
Definition skyobject.h:145
bool isSolarSystem() const
Definition skyobject.h:217
QTime transitTime(const KStarsDateTime &dt, const GeoLocation *geo) const
The same iteration technique described in riseSetTime() is used here.
QTime riseSetTime(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact=true) const
Determine the time at which the point will rise or set.
Definition skyobject.cpp:93
The sky coordinates of a point in the sky.
Definition skypoint.h:45
const CachingDms & dec() const
Definition skypoint.h:269
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
Definition skypoint.h:391
const CachingDms & ra() const
Definition skypoint.h:263
dms altRefracted() const
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
Definition skypoint.cpp:77
virtual void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false)
Determine the current coordinates (RA, Dec) from the catalog coordinates (RA0, Dec0),...
Definition skypoint.cpp:582
const dms & alt() const
Definition skypoint.h:281
SkyPoint catalogueCoord(long double jdf)
Computes the J2000.0 catalogue coordinates for this SkyPoint using the epoch removing aberration,...
Definition skypoint.cpp:710
This is a subclass of SkyObject.
Definition starobject.h:33
int getHDIndex() const
Definition starobject.h:248
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
double Hours() const
Definition dms.h:168
virtual void setH(const double &x)
Sets floating-point value of angle, in hours.
Definition dms.h:210
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition dms.cpp:287
virtual void setD(const double &x)
Sets floating-point value of angle, in degrees.
Definition dms.h:179
const double & Degrees() const
Definition dms.h:141
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
@ iRangeDrag
0x001 Axis ranges are draggable (see QCPAxisRect::setRangeDrag, QCPAxisRect::setRangeDragAxes)
@ iRangeZoom
0x002 Axis ranges are zoomable with the mouse wheel (see QCPAxisRect::setRangeZoom,...
@ msBottom
0x08 bottom margin
@ msTop
0x04 top margin
@ msLeft
0x01 left margin
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void setAlpha(int alpha)
QDate date() const const
QTime time() const const
virtual int exec()
void setModal(bool modal)
virtual void reject()
void rejected()
QPushButton * addButton(StandardButton button)
int pointSize() const const
void setPointSize(int pointSize)
void setColorAt(qreal position, const QColor &color)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
QIcon fromTheme(const QString &name)
void setContentsMargins(const QMargins &margins)
void setFinalStop(const QPointF &stop)
void setStart(const QPointF &start)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
void clear()
qsizetype count() const const
bool isEmpty() const const
void push_back(parameter_type value)
void replace(qsizetype i, parameter_type value)
qsizetype size() const const
value_type takeFirst()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QObject * sender() const const
int height() const const
int width() const const
bool begin(QPaintDevice *device)
void drawEllipse(const QPoint &center, int rx, int ry)
void drawLine(const QLine &line)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawText(const QPoint &position, const QString &text)
bool end()
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
qreal opacity() const const
void restore()
void rotate(qreal angle)
void save()
void setBrush(Qt::BrushStyle style)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setClipping(bool enable)
void setFont(const QFont &font)
void setOpacity(qreal opacity)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void translate(const QPoint &offset)
void fill(const QColor &color)
QRect rect() const const
virtual int exec() override
void setResolution(int dpi)
int height() const const
int width() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
double toDouble(bool *ok) const const
AlignLeft
IgnoreAspectRatio
WaitCursor
RightButton
QTime addSecs(int s) const const
int hour() const const
bool isValid(int h, int m, int s, int ms)
int minute() const const
int second() const const
QString toString(QStringView format) const const
void hideText()
void showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
void setEnabled(bool)
virtual bool event(QEvent *event) override
void lower()
void setMouseTracking(bool enable)
void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, RenderFlags renderFlags)
void setFocus()
void setLayout(QLayout *layout)
void show()
void setToolTip(const QString &)
void update()
virtual void setVisible(bool visible)
void setWindowFlags(Qt::WindowFlags type)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.