Kstars

obslistwizard.cpp
1/*
2 SPDX-FileCopyrightText: 2005 Jason Harris <jharris@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "obslistwizard.h"
8#include "Options.h"
9
10#include "geolocation.h"
11#include "kstarsdata.h"
12#include "dialogs/locationdialog.h"
13#include "skycomponents/constellationboundarylines.h"
14#include "skycomponents/catalogscomponent.h"
15#include "skycomponents/skymapcomposite.h"
16#include "catalogobject.h"
17#include "catalogsdb.h"
18
19ObsListWizardUI::ObsListWizardUI(QWidget *p) : QFrame(p)
20{
21 setupUi(this);
22}
23
24ObsListWizard::ObsListWizard(QWidget *ksparent) : QDialog(ksparent)
25{
26#ifdef Q_OS_OSX
27 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
28#endif
29 olw = new ObsListWizardUI(this);
30 QVBoxLayout *mainLayout = new QVBoxLayout;
31 mainLayout->addWidget(olw);
32 setLayout(mainLayout);
33
34 setWindowTitle(i18nc("@title:window", "Observing List Wizard"));
35
37 nextB = new QPushButton(i18n("&Next >"));
38 nextB->setDefault(true);
39 backB = new QPushButton(i18n("< &Back"));
40 backB->setEnabled(false);
41
42 buttonBox->addButton(backB, QDialogButtonBox::ActionRole);
43 buttonBox->addButton(nextB, QDialogButtonBox::ActionRole);
44 mainLayout->addWidget(buttonBox);
45
46 connect(nextB, SIGNAL(clicked()), this, SLOT(slotNextPage()));
47 connect(backB, SIGNAL(clicked()), this, SLOT(slotPrevPage()));
48 connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotApplyFilters()));
49 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
50 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
51
52 connect(olw->AllButton, SIGNAL(clicked()), this, SLOT(slotAllButton()));
53 connect(olw->NoneButton, SIGNAL(clicked()), this, SLOT(slotNoneButton()));
54 connect(olw->DeepSkyButton, SIGNAL(clicked()), this, SLOT(slotDeepSkyButton()));
55 connect(olw->SolarSystemButton, SIGNAL(clicked()), this, SLOT(slotSolarSystemButton()));
56 connect(olw->LocationButton, SIGNAL(clicked()), this, SLOT(slotChangeLocation()));
57
58 //Update the count of objects when the user asks for it
59 connect(olw->updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateObjectCount()));
60
61 // Enable the update count button when certain elements are changed
62 // -1- ObjectType
63 connect(olw->TypeList, &QListWidget::itemSelectionChanged, this, &ObsListWizard::slotObjectCountDirty);
64 // -A- By constellation
65 connect(olw->ConstellationList, &QListWidget::itemSelectionChanged, this, &ObsListWizard::slotObjectCountDirty);
66 // -B- Rectangular region
67 connect(olw->RAMin, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
68 connect(olw->RAMax, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
69 connect(olw->DecMin, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
70 connect(olw->DecMax, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
71 // -C- Circular region
72 connect(olw->RA, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
73 connect(olw->Dec, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
74 connect(olw->Radius, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion);
75 // -2- Date
76 connect(olw->SelectByDate, SIGNAL(clicked()), this, SLOT(slotToggleDateWidgets()));
77 connect(olw->Date, &QDateEdit::dateChanged, this, &ObsListWizard::slotObjectCountDirty);
78 connect(olw->timeTo, &QTimeEdit::timeChanged, this, &ObsListWizard::slotObjectCountDirty);
79 connect(olw->timeFrom, &QTimeEdit::timeChanged, this, &ObsListWizard::slotObjectCountDirty);
80 connect(olw->minAlt, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
81 &ObsListWizard::slotObjectCountDirty);
82 connect(olw->maxAlt, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
83 &ObsListWizard::slotObjectCountDirty);
84 olw->coverage->setValue(Options::obsListCoverage());
85 connect(olw->coverage, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [&](double value)
86 {
87 Options::setObsListCoverage(value);
88 slotObjectCountDirty();
89 });
90 // -3- Magnitude
91 connect(olw->SelectByMagnitude, SIGNAL(clicked()), this, SLOT(slotToggleMagWidgets()));
92 connect(olw->Mag, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
93 &ObsListWizard::slotObjectCountDirty);
94 connect(olw->IncludeNoMag, &QPushButton::clicked, this, &ObsListWizard::slotObjectCountDirty);
95
96
97
98 geo = KStarsData::Instance()->geo();
99 olw->LocationButton->setText(geo->fullName());
100 olw->Date->setDate(KStarsDateTime::currentDateTime().date());
101 olw->timeFrom->setTime(QTime(18, 0));
102 olw->timeTo->setTime(QTime(23, 59));
103
104 initialize();
105}
106
107void ObsListWizard::initialize()
108{
109 KStarsData *data = KStarsData::Instance();
110 olw->olwStack->setCurrentIndex(0);
111
112 //Populate the list of constellations
113 foreach (SkyObject *p, data->skyComposite()->constellationNames())
114 olw->ConstellationList->addItem(p->name());
115
116 //unSelect all object types
117 olw->TypeList->clearSelection();
118
119 olw->Mag->setMinimum(-5.0);
120 olw->Mag->setMaximum(20.0);
121 olw->Mag->setValue(6.0);
122
123 olw->RA->setUnits(dmsBox::HOURS);
124 olw->RAMin->setUnits(dmsBox::HOURS);
125 olw->RAMax->setUnits(dmsBox::HOURS);
126
127 //Initialize object counts
128 ObjectCount = 0; //number of objects in observing list
129
130 StarCount = data->skyComposite()->stars().size(); //total number of stars
131 PlanetCount = std::size(sun_moon_planets_list); //Sun, Moon, 7 planets (excluding Earth and Pluto)
132 AsteroidCount = data->skyComposite()->asteroids().size(); //total number of asteroids
133 CometCount = data->skyComposite()->comets().size(); //total number of comets
134 //DeepSkyObjects
135 OpenClusterCount = 0;
136 GlobClusterCount = 0;
137 GasNebCount = 0;
138 PlanNebCount = 0;
139 GalaxyCount = 0;
140
141 CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() };
142
143 const auto &stats{ manager.get_master_statistics() };
144 if (!stats.first)
145 return;
146
147 for (const auto &element : stats.second.object_counts)
148 {
149 auto cnt = element.second;
150 switch (element.first)
151 {
152 case SkyObject::GALAXY:
153 GalaxyCount += cnt;
154 break;
155 case SkyObject::STAR:// Excluded case SkyObject::CATALOG_STAR later on in filter as well.
156 break;
157 case SkyObject::OPEN_CLUSTER:
158 OpenClusterCount += cnt;
159 break;
160 case SkyObject::GLOBULAR_CLUSTER:
161 GlobClusterCount += cnt;
162 break;
163 case SkyObject::GASEOUS_NEBULA:
164 case SkyObject::SUPERNOVA_REMNANT:
165 GasNebCount += cnt;
166 break;
167 case SkyObject::PLANETARY_NEBULA:
168 PlanNebCount += cnt;
169 break;
170 default:
171 break;
172 }
173 }
174}
175
176bool ObsListWizard::isItemSelected(const QString &name, QListWidget *listWidget)
177{
178 foreach(QListWidgetItem *item, listWidget->selectedItems())
179 {
180 if (item->text().compare(name, Qt::CaseInsensitive) == 0)
181 return true;
182 }
183 return false;
184}
185
186void ObsListWizard::setItemSelected(const QString &name, QListWidget *listWidget, bool value)
187{
188 QList<QListWidgetItem *> items = listWidget->findItems(name, Qt::MatchContains);
189 if (items.size())
190 items[0]->setSelected(value);
191}
192
193//Advance to the next page in the stack. However, on page 2 the user
194//selects what regional filter they want to use, and this determines
195//what the page following page 2 should be:
196// + Constellation(s): 3
197// + Rectangular region: 4
198// + Circular region: 5
199// + No region selected (a.k.a. ALL_OVER_THE_SKY): 6
200//
201//Also, if the current page index is 3, 4 or 5, then the next page should be 6.
202//
203//NOTE: the page indexes are hard-coded here, which isn't ideal. However,
204//there's no easy way to access the pointers of widgets in the stack
205//if you didn't save them at the start.
206// The order is: MAIN, OBJECT_TYPE, REGION_TYPE, CONSTELLATION, RECTANGULAR, CIRCULAR, DATE, MAGNITUDE
207// 0, 1, 2, 3, 4, 5, 6, 7
208
209void ObsListWizard::slotNextPage()
210{
211 int NextPage = olw->olwStack->currentIndex() + 1;
212
213 if (olw->olwStack->currentIndex() == PAGE_ID_REGION_TYPE)
214 {
215 //On the Region select page. Determine what the next page index should be.
216 //No need to handle BY_CONSTELLATION, it's already currentIndex + 1.
217 if (isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList))
218 NextPage = PAGE_ID_RECTANGULAR;
219 else if (isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList))
220 NextPage = PAGE_ID_CIRCULAR;
221 else if (isItemSelected(i18n(ALL_OVER_THE_SKY), olw->RegionList))
222 NextPage = PAGE_ID_DATE;
223 }
224
225 if ( olw->olwStack->currentIndex() == PAGE_ID_CONSTELLATION ||
226 olw->olwStack->currentIndex() == PAGE_ID_RECTANGULAR)
227 NextPage = PAGE_ID_DATE;
228
229 olw->olwStack->setCurrentIndex(NextPage);
230
231 if (olw->olwStack->currentIndex() == olw->olwStack->count() - 1)
232 nextB->setEnabled(false);
233
234 backB->setEnabled(true);
235}
236
237//Advance to the previous page in the stack. However, because the
238//path through the wizard branches depending on the user's choice of
239//Region filter, the previous page is not always currentPage-1.
240//Specifically, if the current page index is 4, 5, or 6, then the Previous
241//page index should be 2 rather than currentIndex-1.
242void ObsListWizard::slotPrevPage()
243{
244 int PrevPage = olw->olwStack->currentIndex() - 1;
245
246 if ( olw->olwStack->currentIndex() == PAGE_ID_RECTANGULAR ||
247 olw->olwStack->currentIndex() == PAGE_ID_CIRCULAR ||
248 olw->olwStack->currentIndex() == PAGE_ID_DATE)
249 PrevPage = PAGE_ID_REGION_TYPE;
250
251 olw->olwStack->setCurrentIndex(PrevPage);
252
253 if (olw->olwStack->currentIndex() == 0)
254 backB->setEnabled(false);
255
256 nextB->setEnabled(true);
257}
258
259void ObsListWizard::slotAllButton()
260{
261 for (int i = 0; i < olw->TypeList->count(); ++i)
262 olw->TypeList->item(i)->setSelected(true);
263}
264
265void ObsListWizard::slotNoneButton()
266{
267 olw->TypeList->clearSelection();
268}
269
270void ObsListWizard::slotDeepSkyButton()
271{
272 olw->TypeList->clearSelection();
273 setItemSelected(i18n("Open clusters"), olw->TypeList, true);
274 setItemSelected(i18n("Globular clusters"), olw->TypeList, true);
275 setItemSelected(i18n("Gaseous nebulae"), olw->TypeList, true);
276 setItemSelected(i18n("Planetary nebulae"), olw->TypeList, true);
277 setItemSelected(i18n("Galaxies"), olw->TypeList, true);
278}
279
280void ObsListWizard::slotSolarSystemButton()
281{
282 olw->TypeList->clearSelection();
283 setItemSelected(i18n("Sun, moon, planets"), olw->TypeList, true);
284 setItemSelected(i18n("Comets"), olw->TypeList, true);
285 setItemSelected(i18n("Asteroids"), olw->TypeList, true);
286}
287
288void ObsListWizard::slotChangeLocation() {
290
291 if (ld->exec() == QDialog::Accepted)
292 {
293 //set geographic location
294 if (ld->selectedCity())
295 {
296 geo = ld->selectedCity();
297 olw->LocationButton->setText(geo->fullName());
298 }
299 }
300 delete ld;
301}
302
303void ObsListWizard::slotToggleDateWidgets()
304{
305 bool needDate = olw->SelectByDate->isChecked();
306 olw->Date->setEnabled(needDate);
307 olw->LocationButton->setEnabled(needDate);
308 olw->timeTo->setEnabled(needDate);
309 olw->timeFrom->setEnabled(needDate);
310 olw->minAlt->setEnabled(needDate);
311 olw->maxAlt->setEnabled(needDate);
312
313 slotObjectCountDirty();
314}
315
316void ObsListWizard::slotToggleMagWidgets()
317{
318 bool needMagnitude = olw->SelectByMagnitude->isChecked();
319 olw->Mag->setEnabled(needMagnitude);
320 olw->IncludeNoMag->setEnabled(needMagnitude);
321
322 slotObjectCountDirty();
323}
324
325/** Parse the user-entered info to a complete set of parameters if possible. */
326void ObsListWizard::slotParseRegion()
327{
328 if ( isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList) &&
329 (sender()->objectName() == "RAMin" || sender()->objectName() == "RAMax" ||
330 sender()->objectName() == "DecMin" || sender()->objectName() == "DecMax"))
331 {
332 if (!olw->RAMin->isEmpty() && !olw->RAMax->isEmpty() &&
333 !olw->DecMin->isEmpty() && !olw->DecMax->isEmpty())
334 {
335 bool rectOk = false;
336 xRect1 = 0.0;
337 xRect2 = 0.0;
338 yRect1 = 0.0;
339 yRect2 = 0.0;
340
341 xRect1 = olw->RAMin->createDms(&rectOk).Hours();
342 if (rectOk)
343 xRect2 = olw->RAMax->createDms(&rectOk).Hours();
344 if (rectOk)
345 yRect1 = olw->DecMin->createDms(&rectOk).Degrees();
346 if (rectOk)
347 yRect2 = olw->DecMax->createDms(&rectOk).Degrees();
348 if (xRect2 == 0.0)
349 xRect2 = 24.0;
350
351 if (!rectOk)
352 {
353 qWarning() << i18n( "Illegal rectangle specified, no region selection possible." ) ;
354 return;
355 }
356
357 if (yRect1 > yRect2)
358 std::swap(yRect1, yRect2);
359
360 //If xRect1 > xRect2, we may need to swap the two values, or subtract 24h from xRect1.
361 if (xRect1 > xRect2)
362 {
363 if (xRect1 - xRect2 > 12.0) //the user probably wants a region that straddles 0h
364 {
365 xRect1 -= 24.0;
366 }
367 else //the user probably wants xRect2 to be the lower limit
368 {
369 double temp = xRect2;
370 xRect2 = xRect1;
371 xRect1 = temp;
372 }
373 }
374 slotObjectCountDirty();
375 }
376 return; // only one selection possible.
377 }
378
379 if ( isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList) &&
380 (!olw->RA->isEmpty() && !olw->Dec->isEmpty() && !olw->Radius->isEmpty()))
381 {
382 bool circOk1;
383 bool circOk2;
384 bool circOk3;
385 dms ra = olw->RA->createDms(&circOk1);
386 dms dc = olw->Dec->createDms(&circOk2);
387 pCirc.set(ra, dc);
388 rCirc = olw->Radius->createDms(&circOk3).Degrees();
389 if (circOk1 && circOk2 && circOk3)
390 slotObjectCountDirty();
391 else
392 qWarning() << i18n("Illegal circle specified, no region selection possible.");
393 }
394}
395
396void ObsListWizard::slotObjectCountDirty()
397{
398 olw->updateButton->setDisabled(false);
399}
400
401void ObsListWizard::slotUpdateObjectCount()
402{
404 ObjectCount = 0;
405 if (isItemSelected(i18n("Stars"), olw->TypeList))
406 ObjectCount += StarCount;
407 if (isItemSelected(i18n("Sun, moon, planets"), olw->TypeList))
408 ObjectCount += PlanetCount;
409 if (isItemSelected(i18n("Comets"), olw->TypeList))
410 ObjectCount += CometCount;
411 if (isItemSelected(i18n("Asteroids"), olw->TypeList))
412 ObjectCount += AsteroidCount;
413 if (isItemSelected(i18n("Galaxies"), olw->TypeList))
414 ObjectCount += GalaxyCount;
415 if (isItemSelected(i18n("Open clusters"), olw->TypeList))
416 ObjectCount += OpenClusterCount;
417 if (isItemSelected(i18n("Globular clusters"), olw->TypeList))
418 ObjectCount += GlobClusterCount;
419 if (isItemSelected(i18n("Gaseous nebulae"), olw->TypeList))
420 ObjectCount += GasNebCount;
421 if (isItemSelected(i18n("Planetary nebulae"), olw->TypeList))
422 ObjectCount += PlanNebCount;
423
424 applyFilters(false); //false = only adjust counts, do not build list
426 olw->updateButton->setDisabled(true);
427}
428
429void ObsListWizard::applyFilters(bool doBuildList)
430{
431 KStarsData *data = KStarsData::Instance();
432 if (doBuildList)
433 obsList().clear();
434
435 //We don't need to call applyRegionFilter() if no region filter is selected.
436 bool needRegion = !isItemSelected(i18n(ALL_OVER_THE_SKY), olw->RegionList);
437
438 double maglimit = 100.;
439 bool needMagnitude = olw->SelectByMagnitude->isChecked();
440 bool needNoMagnitude = true;
441 if (needMagnitude)
442 {
443 maglimit = olw->Mag->value();
444 needNoMagnitude = olw->IncludeNoMag->isChecked();
445 }
446 bool needDate = olw->SelectByDate->isChecked();
447 FilterParameters filterParameters = { maglimit, needMagnitude, needNoMagnitude, needRegion, needDate, doBuildList};
448
449 if (isItemSelected(i18n("Stars"), olw->TypeList))
450 {
451 const QList<SkyObject *> &starList = data->skyComposite()->stars();
452 int starIndex(starList.size());
453 qDebug() << Q_FUNC_INFO << QString("starIndex: [%1] and maglimit: [%2]").arg(starIndex).arg(maglimit);
454 for (int i = 0; i < starIndex; ++i)
455 {
456 SkyObject *obj = (SkyObject *)(starList[i]);
457 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters);
458 }
459 }
460
461 if (isItemSelected(i18n("Sun, moon, planets"), olw->TypeList))
462 {
463 for (auto name : sun_moon_planets_list)
464 {
465 QString qStringName = i18n(name);
466 SkyObject *obj = data->skyComposite()->findByName(qStringName);
467 if (obj == nullptr)
468 {
469 qWarning() << Q_FUNC_INFO
470 << QString("Failed to find element by name: [%1]").arg(name);
471 ObjectCount--;
472 continue;
473 }
474 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters);
475 }
476 }
477
478 bool dso = (isItemSelected(i18n("Open clusters"), olw->TypeList) ||
479 isItemSelected(i18n("Globular clusters"), olw->TypeList) ||
480 isItemSelected(i18n("Gaseous nebulae"), olw->TypeList) ||
481 isItemSelected(i18n("Planetary nebulae"), olw->TypeList) ||
482 isItemSelected(i18n("Galaxies"), olw->TypeList));
483
484 if (dso)
485 {
486 CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() };
487 CatalogsDB::CatalogObjectList cObjectList = manager.get_objects_all(); // JFD: Can't skip faint objects because counting down
488
489 for (auto &o : cObjectList)
490 {
491 //Skip unselected object types
492 bool typeSelected = false;
493 switch (o.type())
494 {
495 case SkyObject::OPEN_CLUSTER:
496 if (isItemSelected(i18n("Open clusters"), olw->TypeList))
497 typeSelected = true;
498 break;
499
500 case SkyObject::GLOBULAR_CLUSTER:
501 if (isItemSelected(i18n("Globular clusters"), olw->TypeList))
502 typeSelected = true;
503 break;
504
505 case SkyObject::GASEOUS_NEBULA:
506 case SkyObject::SUPERNOVA_REMNANT:
507 if (isItemSelected(i18n("Gaseous nebulae"), olw->TypeList))
508 typeSelected = true;
509 break;
510
511 case SkyObject::PLANETARY_NEBULA:
512 if (isItemSelected(i18n("Planetary nebulae"), olw->TypeList))
513 typeSelected = true;
514 break;
515 case SkyObject::GALAXY:
516 if (isItemSelected(i18n("Galaxies"), olw->TypeList))
517 typeSelected = true;
518 break;
519 }
520 if (!typeSelected)
521 continue;
522
523 auto *obj = &o;
524 obj = &data->skyComposite()->catalogsComponent()->insertStaticObject(o);
525 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters);
526 } // end for objects
527 }
528
529 if (isItemSelected(i18n("Comets"), olw->TypeList))
530 {
531 foreach (SkyObject *o, data->skyComposite()->comets())
532 applyMagnitudeAndRegionAndObservableFilter(o, filterParameters);
533 }
534
535 if (isItemSelected(i18n("Asteroids"), olw->TypeList))
536 {
537 foreach (SkyObject *o, data->skyComposite()->asteroids())
538 applyMagnitudeAndRegionAndObservableFilter(o, filterParameters);
539 }
540
541 //Update the object count label
542 if (doBuildList)
543 ObjectCount = obsList().size();
544
545 olw->CountLabel->setText(i18np("Your observing list currently has 1 object",
546 "Your observing list currently has %1 objects", ObjectCount));
547}
548
549bool ObsListWizard::applyMagnitudeAndRegionAndObservableFilter(SkyObject *o, FilterParameters filterParameters )
550{
551 bool needMagnitude = filterParameters.needMagnitude;
552 bool needRegion = filterParameters.needRegion;
553 bool needDate = filterParameters.needDate;
554 bool doBuildList = filterParameters.doBuildList;
555
556 bool filterPass = true;
557
558 if (filterPass && needMagnitude)
559 filterPass = applyMagnitudeFilter(o, filterParameters);
560 if (filterPass && (needRegion || doBuildList))
561 // Call for adding to obsList even if region filtering is not needed.
562 filterPass = applyRegionFilter(o, doBuildList);
563 if (filterPass && needDate )
564 filterPass = applyObservableFilter(o, doBuildList);
565 return filterPass;
566}
567
568bool ObsListWizard::applyMagnitudeFilter(SkyObject *o, FilterParameters filterParameters)
569{
570 bool needMagnitude = filterParameters.needMagnitude;
571 bool needNoMagnitude = filterParameters.needNoMagnitude;
572 if (needMagnitude && ((std::isnan(o->mag()) && (!needNoMagnitude)) ||
573 (o->mag() > filterParameters.maglimit)))
574 {
575 ObjectCount--;
576 return false;
577 }
578 return true;
579}
580
581/** This routine will add the object to the obsList if doBuildList.
582 * NB: Call this routine even if you don't need region filtering!*/
583bool ObsListWizard::applyRegionFilter(SkyObject *o, bool doBuildList)
584{
585 //select by constellation
586 if (isItemSelected(i18n(BY_CONSTELLATION), olw->RegionList))
587 {
588 QString constellationName = KStarsData::Instance()
589 ->skyComposite()
590 ->constellationBoundary()
591 ->constellationName(o);
592
593 if (isItemSelected(constellationName, olw->ConstellationList))
594 {
595 if (doBuildList)
596 obsList().append(o);
597 return true;
598 }
599 ObjectCount--;
600 return false;
601 }
602
603 //select by rectangular region
604 else if (isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList))
605 {
606 double ra = o->ra().Hours();
607 double dec = o->dec().Degrees();
608 bool addObject = false;
609 if (dec >= yRect1 && dec <= yRect2)
610 {
611 if (xRect1 < 0.0)
612 {
613 addObject = ra >= xRect1 + 24.0 || ra <= xRect2;
614 }
615 else
616 {
617 addObject = ra >= xRect1 && ra <= xRect2;
618 }
619 }
620
621 if (addObject)
622 {
623 if (doBuildList)
624 obsList().append(o);
625 return true;
626 }
627 ObjectCount--;
628 return false;
629 }
630
631 //select by circular region
632 //make sure circ region data are valid
633 else if (isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList))
634 {
635 if (o->angularDistanceTo(&pCirc).Degrees() < rCirc)
636 {
637 if (doBuildList)
638 obsList().append(o);
639 return true;
640 }
641 ObjectCount--;
642 return false;
643 }
644
645 //No region filter, just add the object
646 else if (doBuildList)
647 {
648 obsList().append(o);
649 }
650
651 return true;
652}
653
654/** This routine will remove any item from the obsList if doBuildList is set which means
655 * it was added before in the previous filter.
656 */
657bool ObsListWizard::applyObservableFilter(SkyObject *o, bool doBuildList)
658{
659 SkyPoint p = *o;
660
661 //Check altitude of object every hour from 18:00 to midnight
662 //If it's ever above 15 degrees, flag it as visible
663 KStarsDateTime Evening(olw->Date->date(), QTime(18, 0, 0), Qt::LocalTime);
664 KStarsDateTime Midnight(olw->Date->date().addDays(1), QTime(0, 0, 0), Qt::LocalTime);
665 double minAlt = 15, maxAlt = 90;
666
667 // Or use user-selected values, if they're valid
668 if (olw->timeFrom->time().isValid() && olw->timeTo->time().isValid())
669 {
670 Evening.setTime(olw->timeFrom->time());
671 Midnight.setTime(olw->timeTo->time());
672
673 // If time from < timeTo (e.g. 06:00 PM to 9:00 PM)
674 // then we stay on the same day.
675 if (olw->timeFrom->time() < olw->timeTo->time())
676 {
677 Midnight.setDate(olw->Date->date());
678 }
679 // Otherwise we advance by one day
680 else
681 {
682 Midnight.setDate(olw->Date->date().addDays(1));
683 }
684 }
685
686 minAlt = olw->minAlt->value();
687 maxAlt = olw->maxAlt->value();
688
689 // This is the "relaxed" search mode
690 // where if the object obeys the restrictions in 50% of the time of the range
691 // then it qualifies as "visible"
692 double totalCount = 0, visibleCount = 0;
693 for (KStarsDateTime t = Evening; t < Midnight; t = t.addSecs(3600.0))
694 {
695 dms LST = geo->GSTtoLST(t.gst());
696 p.EquatorialToHorizontal(&LST, geo->lat());
697 totalCount++;
698 if (p.alt().Degrees() >= minAlt && p.alt().Degrees() <= maxAlt)
699 visibleCount++;
700 }
701
702 // If the object is within the min/max alt at least coverage % of the time range
703 // then consider it visible
704 if (visibleCount / totalCount >= olw->coverage->value() / 100.0)
705 return true;
706
707 ObjectCount--;
708 if (doBuildList)
709 obsList().takeAt(obsList().indexOf(o));
710
711 return false;
712}
CatalogObject & insertStaticObject(const CatalogObject &obj)
Insert an object obj into m_static_objects and return a reference to the newly inserted object.
Manages the catalog database and provides an interface to provide an interface to query and modify th...
Definition catalogsdb.h:183
QString fullName() const
const CachingDms * lat() const
Definition geolocation.h:70
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
GeoLocation * geo()
Definition kstarsdata.h:230
SkyMapComposite * skyComposite()
Definition kstarsdata.h:166
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addSecs(double s) const
static KStarsDateTime currentDateTime()
Dialog for changing the geographic location of the observer.
QList< SkyObject * > & obsList()
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual QString name(void) const
Definition skyobject.h:145
float mag() const
Definition skyobject.h:206
The sky coordinates of a point in the sky.
Definition skypoint.h:45
const CachingDms & dec() const
Definition skypoint.h:269
const CachingDms & ra() const
Definition skypoint.h:263
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
Definition skypoint.cpp:899
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
void set(const dms &r, const dms &d)
Sets RA, Dec and RA0, Dec0 according to arguments.
Definition skypoint.cpp:63
const dms & alt() const
Definition skypoint.h:281
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
double Hours() const
Definition dms.h:168
const double & Degrees() const
Definition dms.h:141
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
GeoCoordinates geo(const QVariant &location)
void initialize(StandardShortcut id)
void clicked(bool checked)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void dateChanged(QDate date)
void timeChanged(QTime time)
QPushButton * addButton(StandardButton button)
void valueChanged(double d)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
void editingFinished()
void append(QList< T > &&value)
void clear()
qsizetype size() const const
T takeAt(qsizetype i)
QList< QListWidgetItem * > findItems(const QString &text, Qt::MatchFlags flags) const const
void itemSelectionChanged()
QList< QListWidgetItem * > selectedItems() const const
QString text() const const
QObject * sender() const const
QString arg(Args &&... args) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
CaseInsensitive
WaitCursor
MatchContains
Horizontal
LocalTime
QTextStream & dec(QTextStream &stream)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setEnabled(bool)
void setDisabled(bool disable)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 19 2024 11:51:35 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.