File indexing completed on 2024-04-14 03:43:21

0001 /*
0002     SPDX-FileCopyrightText: 2004-2005 Pablo de Vicente <p.devicentea@wanadoo.es>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "modcalcplanets.h"
0008 
0009 #include "geolocation.h"
0010 #include "kstarsdata.h"
0011 #include "ksnotification.h"
0012 #include "dialogs/locationdialog.h"
0013 #include "skyobjects/ksmoon.h"
0014 #include "skyobjects/kssun.h"
0015 
0016 modCalcPlanets::modCalcPlanets(QWidget *parentSplit) : QFrame(parentSplit)
0017 {
0018     setupUi(this);
0019 
0020     KStarsDateTime dt(KStarsDateTime::currentDateTime());
0021 
0022     DateTimeBox->setDateTime(dt);
0023     DateBoxBatch->setDate(dt.date());
0024     UTBoxBatch->setTime(dt.time());
0025 
0026     geoPlace = KStarsData::Instance()->geo();
0027     LocationButton->setText(geoPlace->fullName());
0028 
0029     RABox->setUnits(dmsBox::HOURS);
0030 
0031     // signals and slots connections
0032     connect(PlanetComboBox, SIGNAL(activated(int)), this, SLOT(slotComputePosition()));
0033     connect(DateTimeBox, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(slotComputePosition()));
0034     connect(LocationButton, SIGNAL(clicked()), this, SLOT(slotLocation()));
0035 
0036     connect(UTCheckBatch, SIGNAL(clicked()), this, SLOT(slotUtCheckedBatch()));
0037     connect(DateCheckBatch, SIGNAL(clicked()), this, SLOT(slotDateCheckedBatch()));
0038     connect(LatCheckBatch, SIGNAL(clicked()), this, SLOT(slotLatCheckedBatch()));
0039     connect(LongCheckBatch, SIGNAL(clicked()), this, SLOT(slotLongCheckedBatch()));
0040     connect(PlanetCheckBatch, SIGNAL(clicked()), this, SLOT(slotPlanetsCheckedBatch()));
0041 
0042     slotComputePosition();
0043     show();
0044 }
0045 
0046 void modCalcPlanets::slotLocation()
0047 {
0048     QPointer<LocationDialog> ld = new LocationDialog(this);
0049 
0050     if (ld->exec() == QDialog::Accepted)
0051     {
0052         geoPlace = ld->selectedCity();
0053         LocationButton->setText(geoPlace->fullName());
0054         slotComputePosition();
0055     }
0056     delete ld;
0057 }
0058 
0059 void modCalcPlanets::slotComputePosition()
0060 {
0061     KStarsDateTime dt(DateTimeBox->dateTime());
0062     long double julianDay = dt.djd();
0063     KSNumbers num(julianDay);
0064     CachingDms LST(geoPlace->GSTtoLST(dt.gst()));
0065 
0066     // Earth
0067     KSPlanet Earth(i18n("Earth"));
0068     Earth.findPosition(&num);
0069 
0070     // Earth is special case!
0071     if (PlanetComboBox->currentIndex() == 2)
0072     {
0073         showCoordinates(Earth);
0074         return;
0075     }
0076 
0077     // Pointer to hold planet data. Pointer is used since it has to
0078     // hold objects of different type. It's safe to use new/delete
0079     // because exceptions are disallowed.
0080     std::unique_ptr<KSPlanetBase> p;
0081 
0082     switch (PlanetComboBox->currentIndex())
0083     {
0084         case 0:
0085             p.reset(new KSPlanet(KSPlanetBase::MERCURY));
0086             break;
0087         case 1:
0088             p.reset(new KSPlanet(KSPlanetBase::VENUS));
0089             break;
0090         case 3:
0091             p.reset(new KSPlanet(KSPlanetBase::MARS));
0092             break;
0093         case 4:
0094             p.reset(new KSPlanet(KSPlanetBase::JUPITER));
0095             break;
0096         case 5:
0097             p.reset(new KSPlanet(KSPlanetBase::SATURN));
0098             break;
0099         case 6:
0100             p.reset(new KSPlanet(KSPlanetBase::URANUS));
0101             break;
0102         case 7:
0103             p.reset(new KSPlanet(KSPlanetBase::NEPTUNE));
0104             break;
0105         /*case 8:
0106             p.reset(new KSPluto(); break;*/
0107         case 8:
0108             p.reset(new KSMoon());
0109             break;
0110         case 9:
0111             p.reset(new KSSun());
0112             p->setRsun(0.0);
0113             break;
0114     }
0115     if (p.get() == nullptr)
0116         return;
0117 
0118     // Show data.
0119     p->findPosition(&num, geoPlace->lat(), &LST, &Earth);
0120     p->EquatorialToHorizontal(&LST, geoPlace->lat());
0121     showCoordinates(*p);
0122 }
0123 
0124 void modCalcPlanets::showCoordinates(const KSPlanetBase &ksp)
0125 {
0126     showHeliocentricEclipticCoords(ksp.helEcLong(), ksp.helEcLat(), ksp.rsun());
0127     showGeocentricEclipticCoords(ksp.ecLong(), ksp.ecLat(), ksp.rearth());
0128     showEquatorialCoords(ksp.ra(), ksp.dec());
0129     showTopocentricCoords(ksp.az(), ksp.alt());
0130 }
0131 
0132 void modCalcPlanets::showHeliocentricEclipticCoords(const dms &hLong, const dms &hLat, double dist)
0133 {
0134     HelioLongBox->show(hLong);
0135     HelioLatBox->show(hLat);
0136     HelioDistBox->setText(QLocale().toString(dist, 6));
0137 }
0138 
0139 void modCalcPlanets::showGeocentricEclipticCoords(const dms &eLong, const dms &eLat, double dist)
0140 {
0141     GeoLongBox->show(eLong);
0142     GeoLatBox->show(eLat);
0143     GeoDistBox->setText(QLocale().toString(dist, 6));
0144 }
0145 
0146 void modCalcPlanets::showEquatorialCoords(const dms &ra, const dms &dec)
0147 {
0148     RABox->show(ra);
0149     DecBox->show(dec);
0150 }
0151 
0152 void modCalcPlanets::showTopocentricCoords(const dms &az, const dms &el)
0153 {
0154     AzBox->show(az);
0155     AltBox->show(el);
0156 }
0157 
0158 void modCalcPlanets::slotPlanetsCheckedBatch()
0159 {
0160     PlanetComboBoxBatch->setEnabled(!PlanetCheckBatch->isChecked());
0161 }
0162 
0163 void modCalcPlanets::slotUtCheckedBatch()
0164 {
0165     UTBoxBatch->setEnabled(!UTCheckBatch->isChecked());
0166 }
0167 
0168 void modCalcPlanets::slotDateCheckedBatch()
0169 {
0170     DateBoxBatch->setEnabled(!DateCheckBatch->isChecked());
0171 }
0172 
0173 void modCalcPlanets::slotLongCheckedBatch()
0174 {
0175     LongBoxBatch->setEnabled(!LongCheckBatch->isChecked());
0176 }
0177 
0178 void modCalcPlanets::slotLatCheckedBatch()
0179 {
0180     LatBoxBatch->setEnabled(!LatCheckBatch->isChecked());
0181 }
0182 
0183 void modCalcPlanets::slotRunBatch()
0184 {
0185     const QString inputFileName = InputFileBoxBatch->url().toLocalFile();
0186 
0187     // We open the input file and read its content
0188 
0189     if (QFile::exists(inputFileName))
0190     {
0191         QFile f(inputFileName);
0192         if (!f.open(QIODevice::ReadOnly))
0193         {
0194             QString message = i18n("Could not open file %1.", f.fileName());
0195             KSNotification::sorry(message, i18n("Could Not Open File"));
0196             return;
0197         }
0198 
0199         QTextStream istream(&f);
0200         processLines(istream);
0201         f.close();
0202     }
0203     else
0204     {
0205         QString message = i18n("Invalid file: %1", inputFileName);
0206         KSNotification::sorry(message, i18n("Invalid file"));
0207         InputFileBoxBatch->setUrl(QUrl());
0208     }
0209 }
0210 
0211 unsigned int modCalcPlanets::requiredBatchFields()
0212 {
0213     unsigned int i = 0;
0214 
0215     if (PlanetCheckBatch->isChecked())
0216         i++;
0217     if (UTCheckBatch->isChecked())
0218         i++;
0219     if (DateCheckBatch->isChecked())
0220         i++;
0221     if (LongCheckBatch->isChecked())
0222         i++;
0223     if (LatCheckBatch->isChecked())
0224         i++;
0225 
0226     return i;
0227 }
0228 
0229 void modCalcPlanets::processLines(QTextStream &istream)
0230 {
0231     // we open the output file
0232 
0233     const QString outputFileName = OutputFileBoxBatch->url().toLocalFile();
0234     QFile fOut(outputFileName);
0235     fOut.open(QIODevice::WriteOnly);
0236     QTextStream ostream(&fOut);
0237     bool lineIsValid = true;
0238 
0239     QChar space = ' ';
0240     QString planetB;
0241     unsigned int i = 0, nline = 0;
0242     QTime utB;
0243     QDate dtB;
0244     CachingDms longB, latB, hlongB, hlatB, glongB, glatB, raB, decB, azmB, altB;
0245     double rSunB(0.0), rEarthB(0.0);
0246 
0247     //Initialize planet names
0248     QString pn;
0249     QStringList pNames, pNamesi18n;
0250     pNames << "Mercury"
0251            << "Venus"
0252            << "Earth"
0253            << "Mars"
0254            << "Jupiter"
0255            << "Saturn"
0256            << "Uranus"
0257            << "Neptune" /* << "Pluto" */
0258            << "Sun"
0259            << "Moon";
0260     pNamesi18n << i18n("Mercury") << i18n("Venus") << i18n("Earth") << i18n("Mars") << i18n("Jupiter") << i18n("Saturn")
0261                << i18n("Uranus") << i18n("Neptune") /* << i18nc("Asteroid name (optional)", "Pluto") */
0262                << i18n("Sun") << i18n("Moon");
0263 
0264     ///Parse the input file
0265     int numberOfRequiredFields = requiredBatchFields();
0266     while (!istream.atEnd())
0267     {
0268         QString lineToWrite;
0269         QString line = istream.readLine();
0270         line = line.trimmed();
0271 
0272         //Go through the line, looking for parameters
0273 
0274         QStringList fields = line.split(' ');
0275 
0276         if (fields.count() != numberOfRequiredFields)
0277         {
0278             lineIsValid = false;
0279             qWarning() << i18n("Incorrect number of fields in line %1: ", nline)
0280                        << i18n("Present fields %1. ", fields.count())
0281                        << i18n("Required fields %1. ", numberOfRequiredFields);
0282             nline++;
0283             continue;
0284         }
0285 
0286         i = 0;
0287         if (PlanetCheckBatch->isChecked())
0288         {
0289             planetB = fields[i];
0290             int j   = pNamesi18n.indexOf(planetB);
0291             if (j == -1)
0292             {
0293                 qWarning() << i18n("Unknown planet ") << fields[i] << i18n(" in line %1: ", nline);
0294                 continue;
0295             }
0296             pn = pNames.at(j); //untranslated planet name
0297             i++;
0298         }
0299         else
0300         {
0301             planetB = PlanetComboBoxBatch->currentText();
0302         }
0303         if (AllRadioBatch->isChecked() || PlanetCheckBatch->isChecked())
0304         {
0305             lineToWrite = planetB;
0306             lineToWrite += space;
0307         }
0308 
0309         // Read Ut and write in ostream if corresponds
0310         if (UTCheckBatch->isChecked())
0311         {
0312             utB = QTime::fromString(fields[i]);
0313             if (!utB.isValid())
0314             {
0315                 qWarning() << i18n("Line %1 contains an invalid time", nline);
0316                 lineIsValid = false;
0317                 nline++;
0318                 continue;
0319             }
0320             i++;
0321         }
0322         else
0323         {
0324             utB = UTBoxBatch->time();
0325         }
0326         if (AllRadioBatch->isChecked() || UTCheckBatch->isChecked())
0327             lineToWrite += QLocale().toString(utB).append(space);
0328 
0329         // Read date and write in ostream if corresponds
0330         if (DateCheckBatch->isChecked())
0331         {
0332             dtB = QDate::fromString(fields[i], Qt::ISODate);
0333             if (!dtB.isValid())
0334             {
0335                 qWarning() << i18n("Line %1 contains an invalid date: ", nline) << fields[i];
0336                 lineIsValid = false;
0337                 nline++;
0338                 continue;
0339             }
0340             i++;
0341         }
0342         else
0343         {
0344             dtB = DateBoxBatch->date();
0345         }
0346         if (AllRadioBatch->isChecked() || DateCheckBatch->isChecked())
0347             lineToWrite += QLocale().toString(dtB, QLocale::LongFormat).append(space);
0348 
0349         // Read Longitude and write in ostream if corresponds
0350 
0351         if (LongCheckBatch->isChecked())
0352         {
0353             longB = CachingDms::fromString(fields[i], true);
0354             i++;
0355         }
0356         else
0357         {
0358             longB = LongBoxBatch->createDms();
0359         }
0360         if (AllRadioBatch->isChecked() || LongCheckBatch->isChecked())
0361             lineToWrite += longB.toDMSString() + space;
0362 
0363         // Read Latitude
0364         if (LatCheckBatch->isChecked())
0365         {
0366             latB = CachingDms::fromString(fields[i], true);
0367             i++;
0368         }
0369         else
0370         {
0371             latB = LatBoxBatch->createDms();
0372         }
0373         if (AllRadioBatch->isChecked() || LatCheckBatch->isChecked())
0374             lineToWrite += latB.toDMSString() + space;
0375 
0376         KStarsDateTime edt(dtB, utB);
0377         CachingDms LST = edt.gst() + longB;
0378 
0379         KSNumbers num(edt.djd());
0380         KSPlanet Earth(i18n("Earth"));
0381         Earth.findPosition(&num);
0382 
0383         // FIXME: allocate new object for every iteration is probably not wisest idea.
0384         KSPlanetBase *kspb = nullptr;
0385         /*if ( pn == "Pluto" ) {
0386             kspb = new KSPluto();
0387         } else*/
0388         if (pn == i18n("Sun"))
0389         {
0390             kspb = new KSSun();
0391         }
0392         else if (pn == i18n("Moon"))
0393         {
0394             kspb = new KSMoon();
0395         }
0396         else
0397         {
0398             kspb = new KSPlanet(i18n(pn.toLocal8Bit()), QString(), Qt::white, 1.0);
0399         }
0400         kspb->findPosition(&num, &latB, &LST, &Earth);
0401         kspb->EquatorialToHorizontal(&LST, &latB);
0402 
0403         // Heliocentric Ecl. coords.
0404         hlongB = kspb->helEcLong();
0405         hlatB  = kspb->helEcLat();
0406         rSunB  = kspb->rsun();
0407         // Geocentric Ecl. coords.
0408         glongB  = kspb->ecLong();
0409         glatB   = kspb->ecLat();
0410         rEarthB = kspb->rearth();
0411         // Equatorial coords.
0412         decB = kspb->dec();
0413         raB  = kspb->ra();
0414         // Topocentric Coords.
0415         azmB = kspb->az();
0416         altB = kspb->alt();
0417 
0418         ostream << lineToWrite;
0419 
0420         if (HelioEclCheckBatch->isChecked())
0421             ostream << hlongB.toDMSString() << space << hlatB.toDMSString() << space << rSunB << space;
0422         if (GeoEclCheckBatch->isChecked())
0423             ostream << glongB.toDMSString() << space << glatB.toDMSString() << space << rEarthB << space;
0424         if (EquatorialCheckBatch->isChecked())
0425             ostream << raB.toHMSString() << space << decB.toDMSString() << space;
0426         if (HorizontalCheckBatch->isChecked())
0427             ostream << azmB.toDMSString() << space << altB.toDMSString() << space;
0428         ostream << '\n';
0429 
0430         // Delete object
0431         delete kspb;
0432 
0433         nline++;
0434     }
0435 
0436     if (!lineIsValid)
0437     {
0438         QString message = i18n("Errors found while parsing some lines in the input file");
0439         KSNotification::sorry(message, i18n("Errors in lines"));
0440     }
0441 
0442     fOut.close();
0443 }