File indexing completed on 2024-03-24 03:47:40
0001 /* 0002 SPDX-FileCopyrightText: 2005 Jason Harris <jharris@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "obslistwizard.h" 0008 #include "Options.h" 0009 0010 #include "geolocation.h" 0011 #include "kstarsdata.h" 0012 #include "dialogs/locationdialog.h" 0013 #include "skycomponents/constellationboundarylines.h" 0014 #include "skycomponents/catalogscomponent.h" 0015 #include "skycomponents/skymapcomposite.h" 0016 #include "catalogobject.h" 0017 #include "catalogsdb.h" 0018 0019 ObsListWizardUI::ObsListWizardUI(QWidget *p) : QFrame(p) 0020 { 0021 setupUi(this); 0022 } 0023 0024 ObsListWizard::ObsListWizard(QWidget *ksparent) : QDialog(ksparent) 0025 { 0026 #ifdef Q_OS_OSX 0027 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0028 #endif 0029 olw = new ObsListWizardUI(this); 0030 QVBoxLayout *mainLayout = new QVBoxLayout; 0031 mainLayout->addWidget(olw); 0032 setLayout(mainLayout); 0033 0034 setWindowTitle(i18nc("@title:window", "Observing List Wizard")); 0035 0036 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); 0037 nextB = new QPushButton(i18n("&Next >")); 0038 nextB->setDefault(true); 0039 backB = new QPushButton(i18n("< &Back")); 0040 backB->setEnabled(false); 0041 0042 buttonBox->addButton(backB, QDialogButtonBox::ActionRole); 0043 buttonBox->addButton(nextB, QDialogButtonBox::ActionRole); 0044 mainLayout->addWidget(buttonBox); 0045 0046 connect(nextB, SIGNAL(clicked()), this, SLOT(slotNextPage())); 0047 connect(backB, SIGNAL(clicked()), this, SLOT(slotPrevPage())); 0048 connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotApplyFilters())); 0049 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 0050 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0051 0052 connect(olw->AllButton, SIGNAL(clicked()), this, SLOT(slotAllButton())); 0053 connect(olw->NoneButton, SIGNAL(clicked()), this, SLOT(slotNoneButton())); 0054 connect(olw->DeepSkyButton, SIGNAL(clicked()), this, SLOT(slotDeepSkyButton())); 0055 connect(olw->SolarSystemButton, SIGNAL(clicked()), this, SLOT(slotSolarSystemButton())); 0056 connect(olw->LocationButton, SIGNAL(clicked()), this, SLOT(slotChangeLocation())); 0057 0058 //Update the count of objects when the user asks for it 0059 connect(olw->updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateObjectCount())); 0060 0061 // Enable the update count button when certain elements are changed 0062 // -1- ObjectType 0063 connect(olw->TypeList, &QListWidget::itemSelectionChanged, this, &ObsListWizard::slotObjectCountDirty); 0064 // -A- By constellation 0065 connect(olw->ConstellationList, &QListWidget::itemSelectionChanged, this, &ObsListWizard::slotObjectCountDirty); 0066 // -B- Rectangular region 0067 connect(olw->RAMin, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0068 connect(olw->RAMax, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0069 connect(olw->DecMin, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0070 connect(olw->DecMax, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0071 // -C- Circular region 0072 connect(olw->RA, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0073 connect(olw->Dec, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0074 connect(olw->Radius, &QLineEdit::editingFinished, this, &ObsListWizard::slotParseRegion); 0075 // -2- Date 0076 connect(olw->SelectByDate, SIGNAL(clicked()), this, SLOT(slotToggleDateWidgets())); 0077 connect(olw->Date, &QDateEdit::dateChanged, this, &ObsListWizard::slotObjectCountDirty); 0078 connect(olw->timeTo, &QTimeEdit::timeChanged, this, &ObsListWizard::slotObjectCountDirty); 0079 connect(olw->timeFrom, &QTimeEdit::timeChanged, this, &ObsListWizard::slotObjectCountDirty); 0080 connect(olw->minAlt, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, 0081 &ObsListWizard::slotObjectCountDirty); 0082 connect(olw->maxAlt, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, 0083 &ObsListWizard::slotObjectCountDirty); 0084 olw->coverage->setValue(Options::obsListCoverage()); 0085 connect(olw->coverage, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [&](double value) 0086 { 0087 Options::setObsListCoverage(value); 0088 slotObjectCountDirty(); 0089 }); 0090 // -3- Magnitude 0091 connect(olw->SelectByMagnitude, SIGNAL(clicked()), this, SLOT(slotToggleMagWidgets())); 0092 connect(olw->Mag, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, 0093 &ObsListWizard::slotObjectCountDirty); 0094 connect(olw->IncludeNoMag, &QPushButton::clicked, this, &ObsListWizard::slotObjectCountDirty); 0095 0096 0097 0098 geo = KStarsData::Instance()->geo(); 0099 olw->LocationButton->setText(geo->fullName()); 0100 olw->Date->setDate(KStarsDateTime::currentDateTime().date()); 0101 olw->timeFrom->setTime(QTime(18, 0)); 0102 olw->timeTo->setTime(QTime(23, 59)); 0103 0104 initialize(); 0105 } 0106 0107 void ObsListWizard::initialize() 0108 { 0109 KStarsData *data = KStarsData::Instance(); 0110 olw->olwStack->setCurrentIndex(0); 0111 0112 //Populate the list of constellations 0113 foreach (SkyObject *p, data->skyComposite()->constellationNames()) 0114 olw->ConstellationList->addItem(p->name()); 0115 0116 //unSelect all object types 0117 olw->TypeList->clearSelection(); 0118 0119 olw->Mag->setMinimum(-5.0); 0120 olw->Mag->setMaximum(20.0); 0121 olw->Mag->setValue(6.0); 0122 0123 olw->RA->setUnits(dmsBox::HOURS); 0124 olw->RAMin->setUnits(dmsBox::HOURS); 0125 olw->RAMax->setUnits(dmsBox::HOURS); 0126 0127 //Initialize object counts 0128 ObjectCount = 0; //number of objects in observing list 0129 0130 StarCount = data->skyComposite()->stars().size(); //total number of stars 0131 PlanetCount = std::size(sun_moon_planets_list); //Sun, Moon, 7 planets (excluding Earth and Pluto) 0132 AsteroidCount = data->skyComposite()->asteroids().size(); //total number of asteroids 0133 CometCount = data->skyComposite()->comets().size(); //total number of comets 0134 //DeepSkyObjects 0135 OpenClusterCount = 0; 0136 GlobClusterCount = 0; 0137 GasNebCount = 0; 0138 PlanNebCount = 0; 0139 GalaxyCount = 0; 0140 0141 CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() }; 0142 0143 const auto &stats{ manager.get_master_statistics() }; 0144 if (!stats.first) 0145 return; 0146 0147 for (const auto &element : stats.second.object_counts) 0148 { 0149 auto cnt = element.second; 0150 switch (element.first) 0151 { 0152 case SkyObject::GALAXY: 0153 GalaxyCount += cnt; 0154 break; 0155 case SkyObject::STAR:// Excluded case SkyObject::CATALOG_STAR later on in filter as well. 0156 break; 0157 case SkyObject::OPEN_CLUSTER: 0158 OpenClusterCount += cnt; 0159 break; 0160 case SkyObject::GLOBULAR_CLUSTER: 0161 GlobClusterCount += cnt; 0162 break; 0163 case SkyObject::GASEOUS_NEBULA: 0164 case SkyObject::SUPERNOVA_REMNANT: 0165 GasNebCount += cnt; 0166 break; 0167 case SkyObject::PLANETARY_NEBULA: 0168 PlanNebCount += cnt; 0169 break; 0170 default: 0171 break; 0172 } 0173 } 0174 } 0175 0176 bool ObsListWizard::isItemSelected(const QString &name, QListWidget *listWidget) 0177 { 0178 foreach(QListWidgetItem *item, listWidget->selectedItems()) 0179 { 0180 if (item->text().compare(name, Qt::CaseInsensitive) == 0) 0181 return true; 0182 } 0183 return false; 0184 } 0185 0186 void ObsListWizard::setItemSelected(const QString &name, QListWidget *listWidget, bool value) 0187 { 0188 QList<QListWidgetItem *> items = listWidget->findItems(name, Qt::MatchContains); 0189 if (items.size()) 0190 items[0]->setSelected(value); 0191 } 0192 0193 //Advance to the next page in the stack. However, on page 2 the user 0194 //selects what regional filter they want to use, and this determines 0195 //what the page following page 2 should be: 0196 // + Constellation(s): 3 0197 // + Rectangular region: 4 0198 // + Circular region: 5 0199 // + No region selected (a.k.a. ALL_OVER_THE_SKY): 6 0200 // 0201 //Also, if the current page index is 3, 4 or 5, then the next page should be 6. 0202 // 0203 //NOTE: the page indexes are hard-coded here, which isn't ideal. However, 0204 //there's no easy way to access the pointers of widgets in the stack 0205 //if you didn't save them at the start. 0206 // The order is: MAIN, OBJECT_TYPE, REGION_TYPE, CONSTELLATION, RECTANGULAR, CIRCULAR, DATE, MAGNITUDE 0207 // 0, 1, 2, 3, 4, 5, 6, 7 0208 0209 void ObsListWizard::slotNextPage() 0210 { 0211 int NextPage = olw->olwStack->currentIndex() + 1; 0212 0213 if (olw->olwStack->currentIndex() == PAGE_ID_REGION_TYPE) 0214 { 0215 //On the Region select page. Determine what the next page index should be. 0216 //No need to handle BY_CONSTELLATION, it's already currentIndex + 1. 0217 if (isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList)) 0218 NextPage = PAGE_ID_RECTANGULAR; 0219 else if (isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList)) 0220 NextPage = PAGE_ID_CIRCULAR; 0221 else if (isItemSelected(i18n(ALL_OVER_THE_SKY), olw->RegionList)) 0222 NextPage = PAGE_ID_DATE; 0223 } 0224 0225 if ( olw->olwStack->currentIndex() == PAGE_ID_CONSTELLATION || 0226 olw->olwStack->currentIndex() == PAGE_ID_RECTANGULAR) 0227 NextPage = PAGE_ID_DATE; 0228 0229 olw->olwStack->setCurrentIndex(NextPage); 0230 0231 if (olw->olwStack->currentIndex() == olw->olwStack->count() - 1) 0232 nextB->setEnabled(false); 0233 0234 backB->setEnabled(true); 0235 } 0236 0237 //Advance to the previous page in the stack. However, because the 0238 //path through the wizard branches depending on the user's choice of 0239 //Region filter, the previous page is not always currentPage-1. 0240 //Specifically, if the current page index is 4, 5, or 6, then the Previous 0241 //page index should be 2 rather than currentIndex-1. 0242 void ObsListWizard::slotPrevPage() 0243 { 0244 int PrevPage = olw->olwStack->currentIndex() - 1; 0245 0246 if ( olw->olwStack->currentIndex() == PAGE_ID_RECTANGULAR || 0247 olw->olwStack->currentIndex() == PAGE_ID_CIRCULAR || 0248 olw->olwStack->currentIndex() == PAGE_ID_DATE) 0249 PrevPage = PAGE_ID_REGION_TYPE; 0250 0251 olw->olwStack->setCurrentIndex(PrevPage); 0252 0253 if (olw->olwStack->currentIndex() == 0) 0254 backB->setEnabled(false); 0255 0256 nextB->setEnabled(true); 0257 } 0258 0259 void ObsListWizard::slotAllButton() 0260 { 0261 for (int i = 0; i < olw->TypeList->count(); ++i) 0262 olw->TypeList->item(i)->setSelected(true); 0263 } 0264 0265 void ObsListWizard::slotNoneButton() 0266 { 0267 olw->TypeList->clearSelection(); 0268 } 0269 0270 void ObsListWizard::slotDeepSkyButton() 0271 { 0272 olw->TypeList->clearSelection(); 0273 setItemSelected(i18n("Open clusters"), olw->TypeList, true); 0274 setItemSelected(i18n("Globular clusters"), olw->TypeList, true); 0275 setItemSelected(i18n("Gaseous nebulae"), olw->TypeList, true); 0276 setItemSelected(i18n("Planetary nebulae"), olw->TypeList, true); 0277 setItemSelected(i18n("Galaxies"), olw->TypeList, true); 0278 } 0279 0280 void ObsListWizard::slotSolarSystemButton() 0281 { 0282 olw->TypeList->clearSelection(); 0283 setItemSelected(i18n("Sun, moon, planets"), olw->TypeList, true); 0284 setItemSelected(i18n("Comets"), olw->TypeList, true); 0285 setItemSelected(i18n("Asteroids"), olw->TypeList, true); 0286 } 0287 0288 void ObsListWizard::slotChangeLocation() { 0289 QPointer<LocationDialog> ld = new LocationDialog(this); 0290 0291 if (ld->exec() == QDialog::Accepted) 0292 { 0293 //set geographic location 0294 if (ld->selectedCity()) 0295 { 0296 geo = ld->selectedCity(); 0297 olw->LocationButton->setText(geo->fullName()); 0298 } 0299 } 0300 delete ld; 0301 } 0302 0303 void ObsListWizard::slotToggleDateWidgets() 0304 { 0305 bool needDate = olw->SelectByDate->isChecked(); 0306 olw->Date->setEnabled(needDate); 0307 olw->LocationButton->setEnabled(needDate); 0308 olw->timeTo->setEnabled(needDate); 0309 olw->timeFrom->setEnabled(needDate); 0310 olw->minAlt->setEnabled(needDate); 0311 olw->maxAlt->setEnabled(needDate); 0312 0313 slotObjectCountDirty(); 0314 } 0315 0316 void ObsListWizard::slotToggleMagWidgets() 0317 { 0318 bool needMagnitude = olw->SelectByMagnitude->isChecked(); 0319 olw->Mag->setEnabled(needMagnitude); 0320 olw->IncludeNoMag->setEnabled(needMagnitude); 0321 0322 slotObjectCountDirty(); 0323 } 0324 0325 /** Parse the user-entered info to a complete set of parameters if possible. */ 0326 void ObsListWizard::slotParseRegion() 0327 { 0328 if ( isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList) && 0329 (sender()->objectName() == "RAMin" || sender()->objectName() == "RAMax" || 0330 sender()->objectName() == "DecMin" || sender()->objectName() == "DecMax")) 0331 { 0332 if (!olw->RAMin->isEmpty() && !olw->RAMax->isEmpty() && 0333 !olw->DecMin->isEmpty() && !olw->DecMax->isEmpty()) 0334 { 0335 bool rectOk = false; 0336 xRect1 = 0.0; 0337 xRect2 = 0.0; 0338 yRect1 = 0.0; 0339 yRect2 = 0.0; 0340 0341 xRect1 = olw->RAMin->createDms(&rectOk).Hours(); 0342 if (rectOk) 0343 xRect2 = olw->RAMax->createDms(&rectOk).Hours(); 0344 if (rectOk) 0345 yRect1 = olw->DecMin->createDms(&rectOk).Degrees(); 0346 if (rectOk) 0347 yRect2 = olw->DecMax->createDms(&rectOk).Degrees(); 0348 if (xRect2 == 0.0) 0349 xRect2 = 24.0; 0350 0351 if (!rectOk) 0352 { 0353 qWarning() << i18n( "Illegal rectangle specified, no region selection possible." ) ; 0354 return; 0355 } 0356 0357 if (yRect1 > yRect2) 0358 std::swap(yRect1, yRect2); 0359 0360 //If xRect1 > xRect2, we may need to swap the two values, or subtract 24h from xRect1. 0361 if (xRect1 > xRect2) 0362 { 0363 if (xRect1 - xRect2 > 12.0) //the user probably wants a region that straddles 0h 0364 { 0365 xRect1 -= 24.0; 0366 } 0367 else //the user probably wants xRect2 to be the lower limit 0368 { 0369 double temp = xRect2; 0370 xRect2 = xRect1; 0371 xRect1 = temp; 0372 } 0373 } 0374 slotObjectCountDirty(); 0375 } 0376 return; // only one selection possible. 0377 } 0378 0379 if ( isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList) && 0380 (!olw->RA->isEmpty() && !olw->Dec->isEmpty() && !olw->Radius->isEmpty())) 0381 { 0382 bool circOk1; 0383 bool circOk2; 0384 bool circOk3; 0385 dms ra = olw->RA->createDms(&circOk1); 0386 dms dc = olw->Dec->createDms(&circOk2); 0387 pCirc.set(ra, dc); 0388 rCirc = olw->Radius->createDms(&circOk3).Degrees(); 0389 if (circOk1 && circOk2 && circOk3) 0390 slotObjectCountDirty(); 0391 else 0392 qWarning() << i18n("Illegal circle specified, no region selection possible."); 0393 } 0394 } 0395 0396 void ObsListWizard::slotObjectCountDirty() 0397 { 0398 olw->updateButton->setDisabled(false); 0399 } 0400 0401 void ObsListWizard::slotUpdateObjectCount() 0402 { 0403 QApplication::setOverrideCursor(Qt::WaitCursor); 0404 ObjectCount = 0; 0405 if (isItemSelected(i18n("Stars"), olw->TypeList)) 0406 ObjectCount += StarCount; 0407 if (isItemSelected(i18n("Sun, moon, planets"), olw->TypeList)) 0408 ObjectCount += PlanetCount; 0409 if (isItemSelected(i18n("Comets"), olw->TypeList)) 0410 ObjectCount += CometCount; 0411 if (isItemSelected(i18n("Asteroids"), olw->TypeList)) 0412 ObjectCount += AsteroidCount; 0413 if (isItemSelected(i18n("Galaxies"), olw->TypeList)) 0414 ObjectCount += GalaxyCount; 0415 if (isItemSelected(i18n("Open clusters"), olw->TypeList)) 0416 ObjectCount += OpenClusterCount; 0417 if (isItemSelected(i18n("Globular clusters"), olw->TypeList)) 0418 ObjectCount += GlobClusterCount; 0419 if (isItemSelected(i18n("Gaseous nebulae"), olw->TypeList)) 0420 ObjectCount += GasNebCount; 0421 if (isItemSelected(i18n("Planetary nebulae"), olw->TypeList)) 0422 ObjectCount += PlanNebCount; 0423 0424 applyFilters(false); //false = only adjust counts, do not build list 0425 QApplication::restoreOverrideCursor(); 0426 olw->updateButton->setDisabled(true); 0427 } 0428 0429 void ObsListWizard::applyFilters(bool doBuildList) 0430 { 0431 KStarsData *data = KStarsData::Instance(); 0432 if (doBuildList) 0433 obsList().clear(); 0434 0435 //We don't need to call applyRegionFilter() if no region filter is selected. 0436 bool needRegion = !isItemSelected(i18n(ALL_OVER_THE_SKY), olw->RegionList); 0437 0438 double maglimit = 100.; 0439 bool needMagnitude = olw->SelectByMagnitude->isChecked(); 0440 bool needNoMagnitude = true; 0441 if (needMagnitude) 0442 { 0443 maglimit = olw->Mag->value(); 0444 needNoMagnitude = olw->IncludeNoMag->isChecked(); 0445 } 0446 bool needDate = olw->SelectByDate->isChecked(); 0447 FilterParameters filterParameters = { maglimit, needMagnitude, needNoMagnitude, needRegion, needDate, doBuildList}; 0448 0449 if (isItemSelected(i18n("Stars"), olw->TypeList)) 0450 { 0451 const QList<SkyObject *> &starList = data->skyComposite()->stars(); 0452 int starIndex(starList.size()); 0453 qDebug() << Q_FUNC_INFO << QString("starIndex: [%1] and maglimit: [%2]").arg(starIndex).arg(maglimit); 0454 for (int i = 0; i < starIndex; ++i) 0455 { 0456 SkyObject *obj = (SkyObject *)(starList[i]); 0457 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters); 0458 } 0459 } 0460 0461 if (isItemSelected(i18n("Sun, moon, planets"), olw->TypeList)) 0462 { 0463 for (auto name : sun_moon_planets_list) 0464 { 0465 QString qStringName = i18n(name); 0466 SkyObject *obj = data->skyComposite()->findByName(qStringName); 0467 if (obj == nullptr) 0468 { 0469 qWarning() << Q_FUNC_INFO 0470 << QString("Failed to find element by name: [%1]").arg(name); 0471 ObjectCount--; 0472 continue; 0473 } 0474 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters); 0475 } 0476 } 0477 0478 bool dso = (isItemSelected(i18n("Open clusters"), olw->TypeList) || 0479 isItemSelected(i18n("Globular clusters"), olw->TypeList) || 0480 isItemSelected(i18n("Gaseous nebulae"), olw->TypeList) || 0481 isItemSelected(i18n("Planetary nebulae"), olw->TypeList) || 0482 isItemSelected(i18n("Galaxies"), olw->TypeList)); 0483 0484 if (dso) 0485 { 0486 CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() }; 0487 CatalogsDB::CatalogObjectList cObjectList = manager.get_objects_all(); // JFD: Can't skip faint objects because counting down 0488 0489 for (auto &o : cObjectList) 0490 { 0491 //Skip unselected object types 0492 bool typeSelected = false; 0493 switch (o.type()) 0494 { 0495 case SkyObject::OPEN_CLUSTER: 0496 if (isItemSelected(i18n("Open clusters"), olw->TypeList)) 0497 typeSelected = true; 0498 break; 0499 0500 case SkyObject::GLOBULAR_CLUSTER: 0501 if (isItemSelected(i18n("Globular clusters"), olw->TypeList)) 0502 typeSelected = true; 0503 break; 0504 0505 case SkyObject::GASEOUS_NEBULA: 0506 case SkyObject::SUPERNOVA_REMNANT: 0507 if (isItemSelected(i18n("Gaseous nebulae"), olw->TypeList)) 0508 typeSelected = true; 0509 break; 0510 0511 case SkyObject::PLANETARY_NEBULA: 0512 if (isItemSelected(i18n("Planetary nebulae"), olw->TypeList)) 0513 typeSelected = true; 0514 break; 0515 case SkyObject::GALAXY: 0516 if (isItemSelected(i18n("Galaxies"), olw->TypeList)) 0517 typeSelected = true; 0518 break; 0519 } 0520 if (!typeSelected) 0521 continue; 0522 0523 auto *obj = &o; 0524 obj = &data->skyComposite()->catalogsComponent()->insertStaticObject(o); 0525 applyMagnitudeAndRegionAndObservableFilter(obj, filterParameters); 0526 } // end for objects 0527 } 0528 0529 if (isItemSelected(i18n("Comets"), olw->TypeList)) 0530 { 0531 foreach (SkyObject *o, data->skyComposite()->comets()) 0532 applyMagnitudeAndRegionAndObservableFilter(o, filterParameters); 0533 } 0534 0535 if (isItemSelected(i18n("Asteroids"), olw->TypeList)) 0536 { 0537 foreach (SkyObject *o, data->skyComposite()->asteroids()) 0538 applyMagnitudeAndRegionAndObservableFilter(o, filterParameters); 0539 } 0540 0541 //Update the object count label 0542 if (doBuildList) 0543 ObjectCount = obsList().size(); 0544 0545 olw->CountLabel->setText(i18np("Your observing list currently has 1 object", 0546 "Your observing list currently has %1 objects", ObjectCount)); 0547 } 0548 0549 bool ObsListWizard::applyMagnitudeAndRegionAndObservableFilter(SkyObject *o, FilterParameters filterParameters ) 0550 { 0551 bool needMagnitude = filterParameters.needMagnitude; 0552 bool needRegion = filterParameters.needRegion; 0553 bool needDate = filterParameters.needDate; 0554 bool doBuildList = filterParameters.doBuildList; 0555 0556 bool filterPass = true; 0557 0558 if (filterPass && needMagnitude) 0559 filterPass = applyMagnitudeFilter(o, filterParameters); 0560 if (filterPass && (needRegion || doBuildList)) 0561 // Call for adding to obsList even if region filtering is not needed. 0562 filterPass = applyRegionFilter(o, doBuildList); 0563 if (filterPass && needDate ) 0564 filterPass = applyObservableFilter(o, doBuildList); 0565 return filterPass; 0566 } 0567 0568 bool ObsListWizard::applyMagnitudeFilter(SkyObject *o, FilterParameters filterParameters) 0569 { 0570 bool needMagnitude = filterParameters.needMagnitude; 0571 bool needNoMagnitude = filterParameters.needNoMagnitude; 0572 if (needMagnitude && ((std::isnan(o->mag()) && (!needNoMagnitude)) || 0573 (o->mag() > filterParameters.maglimit))) 0574 { 0575 ObjectCount--; 0576 return false; 0577 } 0578 return true; 0579 } 0580 0581 /** This routine will add the object to the obsList if doBuildList. 0582 * NB: Call this routine even if you don't need region filtering!*/ 0583 bool ObsListWizard::applyRegionFilter(SkyObject *o, bool doBuildList) 0584 { 0585 //select by constellation 0586 if (isItemSelected(i18n(BY_CONSTELLATION), olw->RegionList)) 0587 { 0588 QString constellationName = KStarsData::Instance() 0589 ->skyComposite() 0590 ->constellationBoundary() 0591 ->constellationName(o); 0592 0593 if (isItemSelected(constellationName, olw->ConstellationList)) 0594 { 0595 if (doBuildList) 0596 obsList().append(o); 0597 return true; 0598 } 0599 ObjectCount--; 0600 return false; 0601 } 0602 0603 //select by rectangular region 0604 else if (isItemSelected(i18n(IN_A_RECTANGULAR_REGION), olw->RegionList)) 0605 { 0606 double ra = o->ra().Hours(); 0607 double dec = o->dec().Degrees(); 0608 bool addObject = false; 0609 if (dec >= yRect1 && dec <= yRect2) 0610 { 0611 if (xRect1 < 0.0) 0612 { 0613 addObject = ra >= xRect1 + 24.0 || ra <= xRect2; 0614 } 0615 else 0616 { 0617 addObject = ra >= xRect1 && ra <= xRect2; 0618 } 0619 } 0620 0621 if (addObject) 0622 { 0623 if (doBuildList) 0624 obsList().append(o); 0625 return true; 0626 } 0627 ObjectCount--; 0628 return false; 0629 } 0630 0631 //select by circular region 0632 //make sure circ region data are valid 0633 else if (isItemSelected(i18n(IN_A_CIRCULAR_REGION), olw->RegionList)) 0634 { 0635 if (o->angularDistanceTo(&pCirc).Degrees() < rCirc) 0636 { 0637 if (doBuildList) 0638 obsList().append(o); 0639 return true; 0640 } 0641 ObjectCount--; 0642 return false; 0643 } 0644 0645 //No region filter, just add the object 0646 else if (doBuildList) 0647 { 0648 obsList().append(o); 0649 } 0650 0651 return true; 0652 } 0653 0654 /** This routine will remove any item from the obsList if doBuildList is set which means 0655 * it was added before in the previous filter. 0656 */ 0657 bool ObsListWizard::applyObservableFilter(SkyObject *o, bool doBuildList) 0658 { 0659 SkyPoint p = *o; 0660 0661 //Check altitude of object every hour from 18:00 to midnight 0662 //If it's ever above 15 degrees, flag it as visible 0663 KStarsDateTime Evening(olw->Date->date(), QTime(18, 0, 0), Qt::LocalTime); 0664 KStarsDateTime Midnight(olw->Date->date().addDays(1), QTime(0, 0, 0), Qt::LocalTime); 0665 double minAlt = 15, maxAlt = 90; 0666 0667 // Or use user-selected values, if they're valid 0668 if (olw->timeFrom->time().isValid() && olw->timeTo->time().isValid()) 0669 { 0670 Evening.setTime(olw->timeFrom->time()); 0671 Midnight.setTime(olw->timeTo->time()); 0672 0673 // If time from < timeTo (e.g. 06:00 PM to 9:00 PM) 0674 // then we stay on the same day. 0675 if (olw->timeFrom->time() < olw->timeTo->time()) 0676 { 0677 Midnight.setDate(olw->Date->date()); 0678 } 0679 // Otherwise we advance by one day 0680 else 0681 { 0682 Midnight.setDate(olw->Date->date().addDays(1)); 0683 } 0684 } 0685 0686 minAlt = olw->minAlt->value(); 0687 maxAlt = olw->maxAlt->value(); 0688 0689 // This is the "relaxed" search mode 0690 // where if the object obeys the restrictions in 50% of the time of the range 0691 // then it qualifies as "visible" 0692 double totalCount = 0, visibleCount = 0; 0693 for (KStarsDateTime t = Evening; t < Midnight; t = t.addSecs(3600.0)) 0694 { 0695 dms LST = geo->GSTtoLST(t.gst()); 0696 p.EquatorialToHorizontal(&LST, geo->lat()); 0697 totalCount++; 0698 if (p.alt().Degrees() >= minAlt && p.alt().Degrees() <= maxAlt) 0699 visibleCount++; 0700 } 0701 0702 // If the object is within the min/max alt at least coverage % of the time range 0703 // then consider it visible 0704 if (visibleCount / totalCount >= olw->coverage->value() / 100.0) 0705 return true; 0706 0707 ObjectCount--; 0708 if (doBuildList) 0709 obsList().takeAt(obsList().indexOf(o)); 0710 0711 return false; 0712 }