File indexing completed on 2024-04-21 14:46:54

0001 /*
0002     SPDX-FileCopyrightText: 2002 Pablo de Vicente <vicente@oan.es>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "modcalcdaylength.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 #include "skyobjects/skyobject.h"
0016 
0017 #include <KLineEdit>
0018 
0019 // Qt version calming
0020 #include <qtendl.h>
0021 
0022 modCalcDayLength::modCalcDayLength(QWidget *parentSplit) : QFrame(parentSplit)
0023 {
0024     setupUi(this);
0025 
0026     showCurrentDate();
0027     initGeo();
0028     slotComputeAlmanac();
0029 
0030     connect(Date, SIGNAL(dateChanged(QDate)), this, SLOT(slotComputeAlmanac()));
0031     connect(Location, SIGNAL(clicked()), this, SLOT(slotLocation()));
0032 
0033     connect(LocationBatch, SIGNAL(clicked()), this, SLOT(slotLocationBatch()));
0034     connect(InputFileBatch, SIGNAL(urlSelected(QUrl)), this, SLOT(slotCheckFiles()));
0035     connect(OutputFileBatch, SIGNAL(urlSelected(QUrl)), this, SLOT(slotCheckFiles()));
0036     connect(RunButtonBatch, SIGNAL(clicked()), this, SLOT(slotRunBatch()));
0037     connect(ViewButtonBatch, SIGNAL(clicked()), this, SLOT(slotViewBatch()));
0038 
0039     RunButtonBatch->setEnabled(false);
0040     ViewButtonBatch->setEnabled(false);
0041 
0042     show();
0043 }
0044 
0045 void modCalcDayLength::showCurrentDate(void)
0046 {
0047     KStarsDateTime dt(KStarsDateTime::currentDateTime());
0048     Date->setDate(dt.date());
0049 }
0050 
0051 void modCalcDayLength::initGeo(void)
0052 {
0053     KStarsData *data = KStarsData::Instance();
0054     geoPlace         = data->geo();
0055     geoBatch         = data->geo();
0056     Location->setText(geoPlace->fullName());
0057     LocationBatch->setText(geoBatch->fullName());
0058 }
0059 
0060 QTime modCalcDayLength::lengthOfDay(const QTime &setQTime, const QTime &riseQTime)
0061 {
0062     QTime dL(0, 0, 0);
0063     int dds       = riseQTime.secsTo(setQTime);
0064     QTime dLength = dL.addSecs(dds);
0065 
0066     return dLength;
0067 }
0068 
0069 void modCalcDayLength::slotLocation()
0070 {
0071     QPointer<LocationDialog> ld = new LocationDialog(this);
0072     if (ld->exec() == QDialog::Accepted)
0073     {
0074         GeoLocation *newGeo = ld->selectedCity();
0075         if (newGeo)
0076         {
0077             geoPlace = newGeo;
0078             Location->setText(geoPlace->fullName());
0079         }
0080     }
0081     delete ld;
0082 
0083     slotComputeAlmanac();
0084 }
0085 
0086 void modCalcDayLength::slotLocationBatch()
0087 {
0088     QPointer<LocationDialog> ld = new LocationDialog(this);
0089     if (ld->exec() == QDialog::Accepted)
0090     {
0091         GeoLocation *newGeo = ld->selectedCity();
0092         if (newGeo)
0093         {
0094             geoBatch = newGeo;
0095             LocationBatch->setText(geoBatch->fullName());
0096         }
0097     }
0098     delete ld;
0099 }
0100 
0101 void modCalcDayLength::updateAlmanac(const QDate &d, GeoLocation *geo)
0102 {
0103     //Determine values needed for the Almanac
0104     long double jd0 = KStarsDateTime(d, QTime(8, 0, 0)).djd();
0105     KSNumbers num(jd0);
0106 
0107     //Sun
0108     KSSun Sun;
0109     Sun.findPosition(&num);
0110 
0111     QTime ssTime = Sun.riseSetTime(KStarsDateTime(jd0), geo, false);
0112     QTime srTime = Sun.riseSetTime(KStarsDateTime(jd0), geo, true);
0113     QTime stTime = Sun.transitTime(KStarsDateTime(jd0), geo);
0114 
0115     dms ssAz  = Sun.riseSetTimeAz(KStarsDateTime(jd0), geo, false);
0116     dms srAz  = Sun.riseSetTimeAz(KStarsDateTime(jd0), geo, true);
0117     dms stAlt = Sun.transitAltitude(KStarsDateTime(jd0), geo);
0118 
0119     //In most cases, the Sun will rise and set:
0120     if (ssTime.isValid())
0121     {
0122         ssAzString  = ssAz.toDMSString();
0123         stAltString = stAlt.toDMSString();
0124         srAzString  = srAz.toDMSString();
0125 
0126         ssTimeString = QLocale().toString(ssTime, "hh:mm:ss");
0127         srTimeString = QLocale().toString(srTime, "hh:mm:ss");
0128         stTimeString = QLocale().toString(stTime, "hh:mm:ss");
0129 
0130         QTime daylength = lengthOfDay(ssTime, srTime);
0131         //daylengthString = QLocale().toString(daylength);
0132         daylengthString = QLocale().toString(daylength, "hh:mm:ss");
0133 
0134         //...but not always!
0135     }
0136     else if (stAlt.Degrees() > 0.)
0137     {
0138         ssAzString  = i18n("Circumpolar");
0139         stAltString = stAlt.toDMSString();
0140         srAzString  = i18n("Circumpolar");
0141 
0142         ssTimeString    = "--:--";
0143         srTimeString    = "--:--";
0144         stTimeString    = QLocale().toString(stTime, "hh:mm:ss");
0145         daylengthString = "24:00";
0146     }
0147     else if (stAlt.Degrees() < 0.)
0148     {
0149         ssAzString  = i18n("Does not rise");
0150         stAltString = stAlt.toDMSString();
0151         srAzString  = i18n("Does not set");
0152 
0153         ssTimeString    = "--:--";
0154         srTimeString    = "--:--";
0155         stTimeString    = QLocale().toString(stTime, "hh:mm:ss");
0156         daylengthString = "00:00";
0157     }
0158 
0159     //Moon
0160     KSMoon Moon;
0161 
0162     QTime msTime = Moon.riseSetTime(KStarsDateTime(jd0), geo, false);
0163     QTime mrTime = Moon.riseSetTime(KStarsDateTime(jd0), geo, true);
0164     QTime mtTime = Moon.transitTime(KStarsDateTime(jd0), geo);
0165 
0166     dms msAz  = Moon.riseSetTimeAz(KStarsDateTime(jd0), geo, false);
0167     dms mrAz  = Moon.riseSetTimeAz(KStarsDateTime(jd0), geo, true);
0168     dms mtAlt = Moon.transitAltitude(KStarsDateTime(jd0), geo);
0169 
0170     //In most cases, the Moon will rise and set:
0171     if (msTime.isValid())
0172     {
0173         msAzString  = msAz.toDMSString();
0174         mtAltString = mtAlt.toDMSString();
0175         mrAzString  = mrAz.toDMSString();
0176 
0177         msTimeString = QLocale().toString(msTime, "hh:mm:ss");
0178         mrTimeString = QLocale().toString(mrTime, "hh:mm:ss");
0179         mtTimeString = QLocale().toString(mtTime, "hh:mm:ss");
0180 
0181         //...but not always!
0182     }
0183     else if (mtAlt.Degrees() > 0.)
0184     {
0185         msAzString  = i18n("Circumpolar");
0186         mtAltString = mtAlt.toDMSString();
0187         mrAzString  = i18n("Circumpolar");
0188 
0189         msTimeString = "--:--";
0190         mrTimeString = "--:--";
0191         mtTimeString = QLocale().toString(mtTime, "hh:mm:ss");
0192     }
0193     else if (mtAlt.Degrees() < 0.)
0194     {
0195         msAzString  = i18n("Does not rise");
0196         mtAltString = mtAlt.toDMSString();
0197         mrAzString  = i18n("Does not rise");
0198 
0199         msTimeString = "--:--";
0200         mrTimeString = "--:--";
0201         mtTimeString = QLocale().toString(mtTime, "hh:mm:ss");
0202     }
0203 
0204     //after calling riseSetTime Phase needs to reset, setting it before causes Phase to set nan
0205     Moon.findPosition(&num);
0206     Moon.findPhase(nullptr);
0207     lunarphaseString = Moon.phaseName() + " (" + QString::number(int(100 * Moon.illum())) + "%)";
0208 
0209     //Fix length of Az strings
0210     if (srAz.Degrees() < 100.0)
0211         srAzString = ' ' + srAzString;
0212     if (ssAz.Degrees() < 100.0)
0213         ssAzString = ' ' + ssAzString;
0214     if (mrAz.Degrees() < 100.0)
0215         mrAzString = ' ' + mrAzString;
0216     if (msAz.Degrees() < 100.0)
0217         msAzString = ' ' + msAzString;
0218 }
0219 
0220 void modCalcDayLength::slotComputeAlmanac()
0221 {
0222     updateAlmanac(Date->date(), geoPlace);
0223 
0224     SunSet->setText(ssTimeString);
0225     SunRise->setText(srTimeString);
0226     SunTransit->setText(stTimeString);
0227     SunSetAz->setText(ssAzString);
0228     SunRiseAz->setText(srAzString);
0229     SunTransitAlt->setText(stAltString);
0230     DayLength->setText(daylengthString);
0231 
0232     MoonSet->setText(msTimeString);
0233     MoonRise->setText(mrTimeString);
0234     MoonTransit->setText(mtTimeString);
0235     MoonSetAz->setText(msAzString);
0236     MoonRiseAz->setText(mrAzString);
0237     MoonTransitAlt->setText(mtAltString);
0238     LunarPhase->setText(lunarphaseString);
0239 }
0240 
0241 void modCalcDayLength::slotCheckFiles()
0242 {
0243     bool flag = !InputFileBatch->lineEdit()->text().isEmpty() && !OutputFileBatch->lineEdit()->text().isEmpty();
0244     RunButtonBatch->setEnabled(flag);
0245 }
0246 
0247 void modCalcDayLength::slotRunBatch()
0248 {
0249     QString inputFileName = InputFileBatch->url().toLocalFile();
0250 
0251     if (QFile::exists(inputFileName))
0252     {
0253         QFile f(inputFileName);
0254         if (!f.open(QIODevice::ReadOnly))
0255         {
0256             QString message = i18n("Could not open file %1.", f.fileName());
0257             KSNotification::sorry(message, i18n("Could Not Open File"));
0258             return;
0259         }
0260 
0261         QTextStream istream(&f);
0262         processLines(istream);
0263         ViewButtonBatch->setEnabled(true);
0264 
0265         f.close();
0266     }
0267     else
0268     {
0269         QString message = i18n("Invalid file: %1", inputFileName);
0270         KSNotification::sorry(message, i18n("Invalid file"));
0271         return;
0272     }
0273 }
0274 
0275 void modCalcDayLength::processLines(QTextStream &istream)
0276 {
0277     QFile fOut(OutputFileBatch->url().toLocalFile());
0278     fOut.open(QIODevice::WriteOnly);
0279     QTextStream ostream(&fOut);
0280 
0281     //Write header
0282     ostream << "# " << i18nc("%1 is a location on earth", "Almanac for %1", geoBatch->fullName())
0283             << QString("  [%1, %2]").arg(geoBatch->lng()->toDMSString(), geoBatch->lat()->toDMSString())
0284             << "\n# " << i18n("computed by KStars")  << Qt::endl
0285             << "# " << "SRise: Sun Rise"  << Qt::endl
0286             << "# " << "STran: Sun Transit"  << Qt::endl
0287             << "# " << "SSet: Sun Set"  << Qt::endl
0288             << "# " << "SRiseAz: Azimuth of Sun Rise"  << Qt::endl
0289             << "# " << "STranAlt: Altitude of Sun Transit"  << Qt::endl
0290             << "# " << "SSetAz: Azimuth of Sun Set"  << Qt::endl
0291             << "# " << "STranAlt: Altitude of Sun Transit"  << Qt::endl
0292             << "# " << "DayLen: Day Duration in hours"  << Qt::endl
0293             << "# " << "MRise: Moon Rise"  << Qt::endl
0294             << "# " << "MTran: Moon Transit"  << Qt::endl
0295             << "# " << "MSet: Moon Set"  << Qt::endl
0296             << "# " << "MRiseAz: Azimuth of Moon Rise"  << Qt::endl
0297             << "# " << "MTranAkt: Altitude of Moon Transit"  << Qt::endl
0298             << "# " << "MSetAz: Azimuth of Moon Set"  << Qt::endl
0299             << "# " << "LunarPhase: Lunar Phase and Illumination Percentage"  << Qt::endl
0300             << "# "  << Qt::endl
0301             << "# Date,SRise,STran,SSet,SRiseAz,STranAlt,SSetAz,DayLen,MRise,MTran,MSet,"
0302             << "MRiseAz,MTranAlt,MSetAz,LunarPhase"  << Qt::endl
0303             << "#" << Qt::endl;
0304 
0305     QString line;
0306     QDate d;
0307 
0308     while (!istream.atEnd())
0309     {
0310         line = istream.readLine();
0311         line = line.trimmed();
0312 
0313         //Parse the line as a date, then compute Almanac values
0314         d = QDate::fromString(line, Qt::ISODate);
0315         if (d.isValid())
0316         {
0317             updateAlmanac(d, geoBatch);
0318             ostream << d.toString(Qt::ISODate) << "," <<
0319                     srTimeString << "," <<
0320                     stTimeString << "," <<
0321                     ssTimeString << "," <<
0322                     srAzString << "," <<
0323                     stAltString << "," <<
0324                     ssAzString << "," <<
0325                     daylengthString << "," <<
0326                     mrTimeString << "," <<
0327                     mtTimeString << "," <<
0328                     msTimeString << "," <<
0329                     mrAzString << "," <<
0330                     mtAltString << "," <<
0331                     msAzString << "," <<
0332                     lunarphaseString << Qt::endl;
0333         }
0334     }
0335 }
0336 
0337 void modCalcDayLength::slotViewBatch()
0338 {
0339     QFile fOut(OutputFileBatch->url().toLocalFile());
0340     fOut.open(QIODevice::ReadOnly);
0341     QTextStream istream(&fOut);
0342     QStringList text;
0343 
0344     while (!istream.atEnd())
0345         text.append(istream.readLine());
0346 
0347     fOut.close();
0348 
0349     KMessageBox::informationList(nullptr, i18n("Results of Almanac calculation"), text, OutputFileBatch->url().toLocalFile());
0350 }