1 /*
2     SPDX-FileCopyrightText: 2005 Pablo de Vicente <p.devicente@wanadoo.es>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "modcalcvlsr.h"
8 
9 #include "dms.h"
10 #include "geolocation.h"
11 #include "ksnumbers.h"
12 #include "kstars.h"
13 #include "ksnotification.h"
14 #include "kstarsdata.h"
15 #include "kstarsdatetime.h"
16 #include "dialogs/locationdialog.h"
17 #include "dialogs/finddialog.h"
18 #include "skyobjects/skypoint.h"
19 #include "widgets/dmsbox.h"
20 
21 #include <KLocalizedString>
22 
23 #include <QPointer>
24 #include <QFileDialog>
25 
modCalcVlsr(QWidget * parentSplit)26 modCalcVlsr::modCalcVlsr(QWidget *parentSplit) : QFrame(parentSplit), velocityFlag(0)
27 {
28     setupUi(this);
29     RA->setDegType(false);
30 
31     Date->setDateTime(KStarsDateTime::currentDateTime());
32     initGeo();
33 
34     VLSR->setValidator(new QDoubleValidator(VLSR));
35     VHelio->setValidator(new QDoubleValidator(VHelio));
36     VGeo->setValidator(new QDoubleValidator(VGeo));
37     VTopo->setValidator(new QDoubleValidator(VTopo));
38 
39     // signals and slots connections
40     connect(Date, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(slotCompute()));
41     connect(NowButton, SIGNAL(clicked()), this, SLOT(slotNow()));
42     connect(LocationButton, SIGNAL(clicked()), this, SLOT(slotLocation()));
43     connect(ObjectButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
44     connect(RA, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
45     connect(Dec, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
46     connect(VLSR, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
47     connect(VHelio, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
48     connect(VGeo, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
49     connect(VTopo, SIGNAL(editingFinished()), this, SLOT(slotCompute()));
50 
51     connect(RunButtonBatch, SIGNAL(clicked()), this, SLOT(slotRunBatch()));
52 
53     show();
54 }
55 
initGeo(void)56 void modCalcVlsr::initGeo(void)
57 {
58     geoPlace = KStarsData::Instance()->geo();
59     LocationButton->setText(geoPlace->fullName());
60 }
61 
slotNow()62 void modCalcVlsr::slotNow()
63 {
64     Date->setDateTime(KStarsDateTime::currentDateTime());
65     slotCompute();
66 }
67 
slotFindObject()68 void modCalcVlsr::slotFindObject()
69 {
70     if (FindDialog::Instance()->exec() == QDialog::Accepted)
71     {
72         SkyObject *o = FindDialog::Instance()->targetObject();
73         RA->showInHours(o->ra0());
74         Dec->showInDegrees(o->dec0());
75     }
76 }
77 
slotLocation()78 void modCalcVlsr::slotLocation()
79 {
80     QPointer<LocationDialog> ld(new LocationDialog(this));
81 
82     if (ld->exec() == QDialog::Accepted && ld)
83     {
84         GeoLocation *newGeo = ld->selectedCity();
85         if (newGeo)
86         {
87             geoPlace = newGeo;
88             LocationButton->setText(geoPlace->fullName());
89         }
90     }
91     delete ld;
92 
93     slotCompute();
94 }
95 
slotCompute()96 void modCalcVlsr::slotCompute()
97 {
98     bool ok1(false), ok2(false);
99     SkyPoint sp(RA->createDms(false, &ok1), Dec->createDms(true, &ok2));
100     if (!ok1 || !ok2)
101         return;
102 
103     KStarsDateTime dt(Date->dateTime());
104     double vst[3];
105 
106     geoPlace->TopocentricVelocity(vst, dt.gst());
107 
108     if (sender()->objectName() == "VLSR")
109         velocityFlag = 0;
110     if (sender()->objectName() == "VHelio")
111         velocityFlag = 1;
112     if (sender()->objectName() == "VGeo")
113         velocityFlag = 2;
114     if (sender()->objectName() == "VTopo")
115         velocityFlag = 3;
116 
117     switch (velocityFlag)
118     {
119         case 0: //Hold VLSR constant, compute the others
120         {
121             double vlsr   = VLSR->text().toDouble();
122             double vhelio = sp.vHeliocentric(vlsr, dt.djd());
123             double vgeo   = sp.vGeocentric(vhelio, dt.djd());
124 
125             VHelio->setText(QString::number(vhelio));
126             VGeo->setText(QString::number(vgeo));
127             VTopo->setText(QString::number(sp.vTopocentric(vgeo, vst)));
128             break;
129         }
130 
131         case 1: //Hold VHelio constant, compute the others
132         {
133             double vhelio = VHelio->text().toDouble();
134             double vlsr   = sp.vHelioToVlsr(vhelio, dt.djd());
135             double vgeo   = sp.vGeocentric(vhelio, dt.djd());
136 
137             VLSR->setText(QString::number(vlsr));
138             VGeo->setText(QString::number(vgeo));
139             VTopo->setText(QString::number(sp.vTopocentric(vgeo, vst)));
140             break;
141         }
142 
143         case 2: //Hold VGeo constant, compute the others
144         {
145             double vgeo   = VGeo->text().toDouble();
146             double vhelio = sp.vGeoToVHelio(vgeo, dt.djd());
147             double vlsr   = sp.vHelioToVlsr(vhelio, dt.djd());
148 
149             VLSR->setText(QString::number(vlsr));
150             VHelio->setText(QString::number(vhelio));
151             VTopo->setText(QString::number(sp.vTopocentric(vgeo, vst)));
152             break;
153         }
154 
155         case 3: //Hold VTopo constant, compute the others
156         {
157             double vtopo  = VTopo->text().toDouble();
158             double vgeo   = sp.vTopoToVGeo(vtopo, vst);
159             double vhelio = sp.vGeoToVHelio(vgeo, dt.djd());
160             double vlsr   = sp.vHelioToVlsr(vhelio, dt.djd());
161 
162             VLSR->setText(QString::number(vlsr));
163             VHelio->setText(QString::number(vhelio));
164             VGeo->setText(QString::number(vgeo));
165             break;
166         }
167 
168         default: //oops
169             qDebug() << "Error: do not know which velocity to use for input.";
170             break;
171     }
172 }
173 
slotUtChecked()174 void modCalcVlsr::slotUtChecked()
175 {
176     if (UTCheckBatch->isChecked())
177         UTBoxBatch->setEnabled(false);
178     else
179     {
180         UTBoxBatch->setEnabled(true);
181     }
182 }
183 
slotDateChecked()184 void modCalcVlsr::slotDateChecked()
185 {
186     if (DateCheckBatch->isChecked())
187         DateBoxBatch->setEnabled(false);
188     else
189     {
190         DateBoxBatch->setEnabled(true);
191     }
192 }
193 
slotRaChecked()194 void modCalcVlsr::slotRaChecked()
195 {
196     if (RACheckBatch->isChecked())
197     {
198         RABoxBatch->setEnabled(false);
199     }
200     else
201     {
202         RABoxBatch->setEnabled(true);
203     }
204 }
205 
slotDecChecked()206 void modCalcVlsr::slotDecChecked()
207 {
208     if (DecCheckBatch->isChecked())
209     {
210         DecBoxBatch->setEnabled(false);
211     }
212     else
213     {
214         DecBoxBatch->setEnabled(true);
215     }
216 }
217 
slotEpochChecked()218 void modCalcVlsr::slotEpochChecked()
219 {
220     if (EpochCheckBatch->isChecked())
221         EpochBoxBatch->setEnabled(false);
222     else
223         EpochBoxBatch->setEnabled(true);
224 }
225 
slotLongChecked()226 void modCalcVlsr::slotLongChecked()
227 {
228     if (LongCheckBatch->isChecked())
229         LongitudeBoxBatch->setEnabled(false);
230     else
231         LongitudeBoxBatch->setEnabled(true);
232 }
233 
slotLatChecked()234 void modCalcVlsr::slotLatChecked()
235 {
236     if (LatCheckBatch->isChecked())
237         LatitudeBoxBatch->setEnabled(false);
238     else
239     {
240         LatitudeBoxBatch->setEnabled(true);
241     }
242 }
243 
slotHeightChecked()244 void modCalcVlsr::slotHeightChecked()
245 {
246     if (ElevationCheckBatch->isChecked())
247         ElevationBoxBatch->setEnabled(false);
248     else
249     {
250         ElevationBoxBatch->setEnabled(true);
251     }
252 }
253 
slotVlsrChecked()254 void modCalcVlsr::slotVlsrChecked()
255 {
256     if (InputVelocityCheckBatch->isChecked())
257         InputVelocityBoxBatch->setEnabled(false);
258     else
259     {
260         InputVelocityBoxBatch->setEnabled(true);
261     }
262 }
263 
slotInputFile()264 void modCalcVlsr::slotInputFile()
265 {
266     const QString inputFileName = QFileDialog::getOpenFileName(KStars::Instance(), QString(), QString());
267     if (!inputFileName.isEmpty())
268         InputFileBoxBatch->setUrl(QUrl::fromLocalFile(inputFileName));
269 }
270 
slotOutputFile()271 void modCalcVlsr::slotOutputFile()
272 {
273     const QString outputFileName = QFileDialog::getSaveFileName();
274     if (!outputFileName.isEmpty())
275         OutputFileBoxBatch->setUrl(QUrl::fromLocalFile(outputFileName));
276 }
277 
slotRunBatch()278 void modCalcVlsr::slotRunBatch()
279 {
280     const QString inputFileName = InputFileBoxBatch->url().toLocalFile();
281 
282     // We open the input file and read its content
283 
284     if (QFile::exists(inputFileName))
285     {
286         QFile f(inputFileName);
287         if (!f.open(QIODevice::ReadOnly))
288         {
289             KSNotification::sorry(i18n("Could not open file %1.", f.fileName()), i18n("Could Not Open File"));
290             return;
291         }
292 
293         //		processLines(&f);
294         QTextStream istream(&f);
295         processLines(istream);
296         //		readFile( istream );
297         f.close();
298     }
299     else
300     {
301         KSNotification::sorry(i18n("Invalid file: %1", inputFileName), i18n("Invalid file"));
302         InputFileBoxBatch->setUrl(QUrl());
303     }
304 }
305 
processLines(QTextStream & istream)306 void modCalcVlsr::processLines(QTextStream &istream)
307 {
308     // we open the output file
309 
310     //	QTextStream istream(&fIn);
311     QString outputFileName;
312     outputFileName = OutputFileBoxBatch->url().toLocalFile();
313     QFile fOut(outputFileName);
314     fOut.open(QIODevice::WriteOnly);
315     QTextStream ostream(&fOut);
316 
317     QString line;
318     QChar space = ' ';
319     int i       = 0;
320     long double jd0;
321     SkyPoint spB;
322     double sra, cra, sdc, cdc;
323     dms raB, decB, latB, longB;
324     QString epoch0B;
325     double vhB, vgB, vtB, vlsrB, heightB;
326     double vtopo[3];
327     QTime utB;
328     QDate dtB;
329     KStarsDateTime dt0B;
330 
331     while (!istream.atEnd())
332     {
333         line = istream.readLine();
334         line = line.trimmed();
335 
336         //Go through the line, looking for parameters
337 
338         QStringList fields = line.split(' ');
339 
340         i = 0;
341 
342         // Read Ut and write in ostream if corresponds
343 
344         if (UTCheckBatch->isChecked())
345         {
346             utB = QTime::fromString(fields[i]);
347             i++;
348         }
349         else
350             utB = UTBoxBatch->time();
351 
352         if (AllRadioBatch->isChecked())
353             ostream << QLocale().toString(utB) << space;
354         else if (UTCheckBatch->isChecked())
355             ostream << QLocale().toString(utB) << space;
356 
357         // Read date and write in ostream if corresponds
358 
359         if (DateCheckBatch->isChecked())
360         {
361             dtB = QDate::fromString(fields[i]);
362             i++;
363         }
364         else
365             dtB = DateBoxBatch->date();
366         if (AllRadioBatch->isChecked())
367             ostream << QLocale().toString(dtB, QLocale::LongFormat).append(space);
368         else if (DateCheckBatch->isChecked())
369             ostream << QLocale().toString(dtB, QLocale::LongFormat).append(space);
370 
371         // Read RA and write in ostream if corresponds
372 
373         if (RACheckBatch->isChecked())
374         {
375             raB = dms::fromString(fields[i], false);
376             i++;
377         }
378         else
379             raB = RABoxBatch->createDms(false);
380 
381         if (AllRadioBatch->isChecked())
382             ostream << raB.toHMSString() << space;
383         else if (RACheckBatch->isChecked())
384             ostream << raB.toHMSString() << space;
385 
386         // Read DEC and write in ostream if corresponds
387 
388         if (DecCheckBatch->isChecked())
389         {
390             decB = dms::fromString(fields[i], true);
391             i++;
392         }
393         else
394             decB = DecBoxBatch->createDms();
395 
396         if (AllRadioBatch->isChecked())
397             ostream << decB.toDMSString() << space;
398         else if (DecCheckBatch->isChecked())
399             ostream << decB.toDMSString() << space;
400 
401         // Read Epoch and write in ostream if corresponds
402 
403         if (EpochCheckBatch->isChecked())
404         {
405             epoch0B = fields[i];
406             i++;
407         }
408         else
409             epoch0B = EpochBoxBatch->text();
410 
411         if (AllRadioBatch->isChecked())
412             ostream << epoch0B << space;
413         else if (EpochCheckBatch->isChecked())
414             ostream << epoch0B << space;
415 
416         // Read vlsr and write in ostream if corresponds
417 
418         if (InputVelocityCheckBatch->isChecked())
419         {
420             vlsrB = fields[i].toDouble();
421             i++;
422         }
423         else
424             vlsrB = InputVelocityComboBatch->currentText().toDouble();
425 
426         if (AllRadioBatch->isChecked())
427             ostream << vlsrB << space;
428         else if (InputVelocityCheckBatch->isChecked())
429             ostream << vlsrB << space;
430 
431         // Read Longitude and write in ostream if corresponds
432 
433         if (LongCheckBatch->isChecked())
434         {
435             longB = dms::fromString(fields[i], true);
436             i++;
437         }
438         else
439             longB = LongitudeBoxBatch->createDms(true);
440 
441         if (AllRadioBatch->isChecked())
442             ostream << longB.toDMSString() << space;
443         else if (LongCheckBatch->isChecked())
444             ostream << longB.toDMSString() << space;
445 
446         // Read Latitude
447 
448         if (LatCheckBatch->isChecked())
449         {
450             latB = dms::fromString(fields[i], true);
451             i++;
452         }
453         else
454             latB = LatitudeBoxBatch->createDms(true);
455         if (AllRadioBatch->isChecked())
456             ostream << latB.toDMSString() << space;
457         else if (LatCheckBatch->isChecked())
458             ostream << latB.toDMSString() << space;
459 
460         // Read height and write in ostream if corresponds
461 
462         if (ElevationCheckBatch->isChecked())
463         {
464             heightB = fields[i].toDouble();
465             i++;
466         }
467         else
468             heightB = ElevationBoxBatch->text().toDouble();
469 
470         if (AllRadioBatch->isChecked())
471             ostream << heightB << space;
472         else if (ElevationCheckBatch->isChecked())
473             ostream << heightB << space;
474 
475         // We make the first calculations
476 
477         spB = SkyPoint(raB, decB);
478         dt0B.setFromEpoch(epoch0B);
479         vhB = spB.vHeliocentric(vlsrB, dt0B.djd());
480         jd0 = KStarsDateTime(dtB, utB).djd();
481         vgB = spB.vGeocentric(vlsrB, jd0);
482         geoPlace->setLong(longB);
483         geoPlace->setLat(latB);
484         geoPlace->setElevation(heightB);
485         dms gsidt = KStarsDateTime(dtB, utB).gst();
486         geoPlace->TopocentricVelocity(vtopo, gsidt);
487         spB.ra().SinCos(sra, cra);
488         spB.dec().SinCos(sdc, cdc);
489         vtB = vgB - (vtopo[0] * cdc * cra + vtopo[1] * cdc * sra + vtopo[2] * sdc);
490 
491         ostream << vhB << space << vgB << space << vtB << '\n';
492     }
493 
494     fOut.close();
495 }
496