Kstars

ksutils.cpp
1 /*
2  SPDX-FileCopyrightText: 2002 Mark Hollomon <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "ksutils.h"
8 #include "config-kstars.h"
9 #include "ksnotification.h"
10 #include "kstars_debug.h"
11 
12 #include "catalogobject.h"
13 #ifndef KSTARS_LITE
14 #include "kswizard.h"
15 #endif
16 #include "Options.h"
17 #include "starobject.h"
18 #include "auxiliary/kspaths.h"
19 
20 #ifndef KSTARS_LITE
21 #include <KMessageBox>
22 #include <zlib.h>
23 #endif
24 
25 #ifdef HAVE_LIBRAW
26 #include <libraw/libraw.h>
27 #endif
28 
29 #if defined(__APPLE__)
30 #include <sys/sysctl.h>
31 #elif defined(_WIN32)
32 #include "windows.h"
33 #else //Linux
34 #include <QProcess>
35 #endif
36 
37 #include <QPointer>
38 #include <QProcessEnvironment>
39 #include <QLoggingCategory>
40 
41 #ifdef HAVE_STELLARSOLVER
42 #include <stellarsolver.h>
43 #endif
44 
45 namespace KSUtils
46 {
47 bool isHardwareLimited()
48 {
49 #ifdef __arm__
50  return true;
51 #else
52  return false;
53 #endif
54 }
55 
56 bool openDataFile(QFile &file, const QString &s)
57 {
58  QString FileName = KSPaths::locate(QStandardPaths::AppLocalDataLocation, s);
59  if (!FileName.isNull())
60  {
61  file.setFileName(FileName);
62  return file.open(QIODevice::ReadOnly);
63  }
64  return false;
65 }
66 
67 QString getDSSURL(const SkyPoint *const p)
68 {
69  double height, width;
70  double dss_default_size = Options::defaultDSSImageSize();
71  double dss_padding = Options::dSSPadding();
72 
73  Q_ASSERT(p);
74  Q_ASSERT(dss_default_size > 0.0 && dss_padding >= 0.0);
75 
76  const auto *dso = dynamic_cast<const CatalogObject *>(p);
77 
78  // Decide what to do about the height and width
79  if (dso)
80  {
81  // For deep-sky objects, use their height and width information
82  double a, b, pa;
83  a = dso->a();
84  b = dso->a() *
85  dso->e(); // Use a * e instead of b, since e() returns 1 whenever one of the dimensions is zero. This is important for circular objects
86  pa = dso->pa() * dms::DegToRad;
87 
88  // We now want to convert a, b, and pa into an image
89  // height and width -- i.e. a dRA and dDec.
90  // DSS uses dDec for height and dRA for width. (i.e. "top" is north in the DSS images, AFAICT)
91  // From some trigonometry, assuming we have a rectangular object (worst case), we need:
92  width = a * sin(pa) + b * cos(pa);
93  height = a * cos(pa) + b * sin(pa);
94  // 'a' and 'b' are in arcminutes, so height and width are in arcminutes
95 
96  // Pad the RA and Dec, so that we show more of the sky than just the object.
97  height += dss_padding;
98  width += dss_padding;
99  }
100  else
101  {
102  // For a generic sky object, we don't know what to do. So
103  // we just assume the default size.
104  height = width = dss_default_size;
105  }
106  // There's no point in tiny DSS images that are smaller than dss_default_size
107  if (height < dss_default_size)
108  height = dss_default_size;
109  if (width < dss_default_size)
110  width = dss_default_size;
111 
112  return getDSSURL(p->ra0(), p->dec0(), width, height);
113 }
114 
115 QString getDSSURL(const dms &ra, const dms &dec, float width, float height,
116  const QString &type)
117 {
118  const QString URLprefix("https://archive.stsci.edu/cgi-bin/dss_search?");
119  QString URLsuffix = QString("&e=J2000&f=%1&c=none&fov=NONE").arg(type);
120  const double dss_default_size = Options::defaultDSSImageSize();
121 
122  char decsgn = (dec.Degrees() < 0.0) ? '-' : '+';
123  int dd = abs(dec.degree());
124  int dm = abs(dec.arcmin());
125  int ds = abs(dec.arcsec());
126 
127  // Infinite and NaN sizes are replaced by the default size and tiny DSS images are resized to default size
128  if (!qIsFinite(height) || height <= 0.0)
129  height = dss_default_size;
130  if (!qIsFinite(width) || width <= 0.0)
131  width = dss_default_size;
132 
133  // DSS accepts images that are no larger than 75 arcminutes
134  if (height > 75.0)
135  height = 75.0;
136  if (width > 75.0)
137  width = 75.0;
138 
139  QString RAString, DecString, SizeString;
140  DecString = QString::asprintf("&d=%c%02d+%02d+%02d", decsgn, dd, dm, ds);
141  RAString = QString::asprintf("r=%02d+%02d+%02d", ra.hour(), ra.minute(), ra.second());
142  SizeString = QString::asprintf("&h=%02.1f&w=%02.1f", height, width);
143 
144  return (URLprefix + RAString + DecString + SizeString + URLsuffix);
145 }
146 
147 QString toDirectionString(dms angle)
148 {
149  // TODO: Instead of doing it this way, it would be nicer to
150  // compute the string to arbitrary precision. Although that will
151  // not be easy to localize. (Consider, for instance, Indian
152  // languages that have special names for the intercardinal points)
153  // -- asimha
154 
155  static const char *directions[] =
156  {
157  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "N"),
158  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "NNE"),
159  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "NE"),
160  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "ENE"),
161  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "E"),
162  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "ESE"),
163  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "SE"),
164  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "SSE"),
165  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "S"),
166  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "SSW"),
167  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "SW"),
168  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "WSW"),
169  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "W"),
170  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "WNW"),
171  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "NW"),
172  I18N_NOOP2("Abbreviated cardinal / intercardinal etc. direction", "NNW"),
173  I18N_NOOP2("Unknown cardinal / intercardinal direction", "???")
174  };
175 
176  int index = (int)((angle.reduce().Degrees() + 11.25) /
177  22.5); // A number between 0 and 16 (inclusive) is expected
178 
179  if (index < 0 || index > 16)
180  index = 16; // Something went wrong.
181  else
182  index = (index == 16 ? 0 : index);
183 
184  return i18nc("Abbreviated cardinal / intercardinal etc. direction",
185  directions[index]);
186 }
187 
188 QList<SkyObject *> *castStarObjListToSkyObjList(QList<StarObject *> *starObjList)
189 {
190  QList<SkyObject *> *skyObjList = new QList<SkyObject *>();
191 
192  foreach (StarObject *so, *starObjList)
193  {
194  skyObjList->append(so);
195  }
196  return skyObjList;
197 }
198 
199 QString constGenetiveFromAbbrev(const QString &code)
200 {
201  if (code == "And")
202  return QString("Andromedae");
203  if (code == "Ant")
204  return QString("Antliae");
205  if (code == "Aps")
206  return QString("Apodis");
207  if (code == "Aqr")
208  return QString("Aquarii");
209  if (code == "Aql")
210  return QString("Aquilae");
211  if (code == "Ara")
212  return QString("Arae");
213  if (code == "Ari")
214  return QString("Arietis");
215  if (code == "Aur")
216  return QString("Aurigae");
217  if (code == "Boo")
218  return QString("Bootis");
219  if (code == "Cae")
220  return QString("Caeli");
221  if (code == "Cam")
222  return QString("Camelopardalis");
223  if (code == "Cnc")
224  return QString("Cancri");
225  if (code == "CVn")
226  return QString("Canum Venaticorum");
227  if (code == "CMa")
228  return QString("Canis Majoris");
229  if (code == "CMi")
230  return QString("Canis Minoris");
231  if (code == "Cap")
232  return QString("Capricorni");
233  if (code == "Car")
234  return QString("Carinae");
235  if (code == "Cas")
236  return QString("Cassiopeiae");
237  if (code == "Cen")
238  return QString("Centauri");
239  if (code == "Cep")
240  return QString("Cephei");
241  if (code == "Cet")
242  return QString("Ceti");
243  if (code == "Cha")
244  return QString("Chamaeleontis");
245  if (code == "Cir")
246  return QString("Circini");
247  if (code == "Col")
248  return QString("Columbae");
249  if (code == "Com")
250  return QString("Comae Berenices");
251  if (code == "CrA")
252  return QString("Coronae Austrinae");
253  if (code == "CrB")
254  return QString("Coronae Borealis");
255  if (code == "Crv")
256  return QString("Corvi");
257  if (code == "Crt")
258  return QString("Crateris");
259  if (code == "Cru")
260  return QString("Crucis");
261  if (code == "Cyg")
262  return QString("Cygni");
263  if (code == "Del")
264  return QString("Delphini");
265  if (code == "Dor")
266  return QString("Doradus");
267  if (code == "Dra")
268  return QString("Draconis");
269  if (code == "Equ")
270  return QString("Equulei");
271  if (code == "Eri")
272  return QString("Eridani");
273  if (code == "For")
274  return QString("Fornacis");
275  if (code == "Gem")
276  return QString("Geminorum");
277  if (code == "Gru")
278  return QString("Gruis");
279  if (code == "Her")
280  return QString("Herculis");
281  if (code == "Hor")
282  return QString("Horologii");
283  if (code == "Hya")
284  return QString("Hydrae");
285  if (code == "Hyi")
286  return QString("Hydri");
287  if (code == "Ind")
288  return QString("Indi");
289  if (code == "Lac")
290  return QString("Lacertae");
291  if (code == "Leo")
292  return QString("Leonis");
293  if (code == "LMi")
294  return QString("Leonis Minoris");
295  if (code == "Lep")
296  return QString("Leporis");
297  if (code == "Lib")
298  return QString("Librae");
299  if (code == "Lup")
300  return QString("Lupi");
301  if (code == "Lyn")
302  return QString("Lyncis");
303  if (code == "Lyr")
304  return QString("Lyrae");
305  if (code == "Men")
306  return QString("Mensae");
307  if (code == "Mic")
308  return QString("Microscopii");
309  if (code == "Mon")
310  return QString("Monocerotis");
311  if (code == "Mus")
312  return QString("Muscae");
313  if (code == "Nor")
314  return QString("Normae");
315  if (code == "Oct")
316  return QString("Octantis");
317  if (code == "Oph")
318  return QString("Ophiuchi");
319  if (code == "Ori")
320  return QString("Orionis");
321  if (code == "Pav")
322  return QString("Pavonis");
323  if (code == "Peg")
324  return QString("Pegasi");
325  if (code == "Per")
326  return QString("Persei");
327  if (code == "Phe")
328  return QString("Phoenicis");
329  if (code == "Pic")
330  return QString("Pictoris");
331  if (code == "Psc")
332  return QString("Piscium");
333  if (code == "PsA")
334  return QString("Piscis Austrini");
335  if (code == "Pup")
336  return QString("Puppis");
337  if (code == "Pyx")
338  return QString("Pyxidis");
339  if (code == "Ret")
340  return QString("Reticuli");
341  if (code == "Sge")
342  return QString("Sagittae");
343  if (code == "Sgr")
344  return QString("Sagittarii");
345  if (code == "Sco")
346  return QString("Scorpii");
347  if (code == "Scl")
348  return QString("Sculptoris");
349  if (code == "Sct")
350  return QString("Scuti");
351  if (code == "Ser")
352  return QString("Serpentis");
353  if (code == "Sex")
354  return QString("Sextantis");
355  if (code == "Tau")
356  return QString("Tauri");
357  if (code == "Tel")
358  return QString("Telescopii");
359  if (code == "Tri")
360  return QString("Trianguli");
361  if (code == "TrA")
362  return QString("Trianguli Australis");
363  if (code == "Tuc")
364  return QString("Tucanae");
365  if (code == "UMa")
366  return QString("Ursae Majoris");
367  if (code == "UMi")
368  return QString("Ursae Minoris");
369  if (code == "Vel")
370  return QString("Velorum");
371  if (code == "Vir")
372  return QString("Virginis");
373  if (code == "Vol")
374  return QString("Volantis");
375  if (code == "Vul")
376  return QString("Vulpeculae");
377  return code;
378 }
379 
380 QString constNameFromAbbrev(const QString &code)
381 {
382  if (code == "And")
383  return QString("Andromeda");
384  if (code == "Ant")
385  return QString("Antlia");
386  if (code == "Aps")
387  return QString("Apus");
388  if (code == "Aqr")
389  return QString("Aquarius");
390  if (code == "Aql")
391  return QString("Aquila");
392  if (code == "Ara")
393  return QString("Ara");
394  if (code == "Ari")
395  return QString("Aries");
396  if (code == "Aur")
397  return QString("Auriga");
398  if (code == "Boo")
399  return QString("Bootes");
400  if (code == "Cae")
401  return QString("Caelum");
402  if (code == "Cam")
403  return QString("Camelopardalis");
404  if (code == "Cnc")
405  return QString("Cancer");
406  if (code == "CVn")
407  return QString("Canes Venatici");
408  if (code == "CMa")
409  return QString("Canis Major");
410  if (code == "CMi")
411  return QString("Canis Minor");
412  if (code == "Cap")
413  return QString("Capricornus");
414  if (code == "Car")
415  return QString("Carina");
416  if (code == "Cas")
417  return QString("Cassiopeia");
418  if (code == "Cen")
419  return QString("Centaurus");
420  if (code == "Cep")
421  return QString("Cepheus");
422  if (code == "Cet")
423  return QString("Cetus");
424  if (code == "Cha")
425  return QString("Chamaeleon");
426  if (code == "Cir")
427  return QString("Circinus");
428  if (code == "Col")
429  return QString("Columba");
430  if (code == "Com")
431  return QString("Coma Berenices");
432  if (code == "CrA")
433  return QString("Corona Australis");
434  if (code == "CrB")
435  return QString("Corona Borealis");
436  if (code == "Crv")
437  return QString("Corvus");
438  if (code == "Crt")
439  return QString("Crater");
440  if (code == "Cru")
441  return QString("Crux");
442  if (code == "Cyg")
443  return QString("Cygnus");
444  if (code == "Del")
445  return QString("Delphinus");
446  if (code == "Dor")
447  return QString("Doradus");
448  if (code == "Dra")
449  return QString("Draco");
450  if (code == "Equ")
451  return QString("Equuleus");
452  if (code == "Eri")
453  return QString("Eridanus");
454  if (code == "For")
455  return QString("Fornax");
456  if (code == "Gem")
457  return QString("Gemini");
458  if (code == "Gru")
459  return QString("Grus");
460  if (code == "Her")
461  return QString("Hercules");
462  if (code == "Hor")
463  return QString("Horologium");
464  if (code == "Hya")
465  return QString("Hydra");
466  if (code == "Hyi")
467  return QString("Hydrus");
468  if (code == "Ind")
469  return QString("Indus");
470  if (code == "Lac")
471  return QString("Lacerta");
472  if (code == "Leo")
473  return QString("Leo");
474  if (code == "LMi")
475  return QString("Leo Minor");
476  if (code == "Lep")
477  return QString("Lepus");
478  if (code == "Lib")
479  return QString("Libra");
480  if (code == "Lup")
481  return QString("Lupus");
482  if (code == "Lyn")
483  return QString("Lynx");
484  if (code == "Lyr")
485  return QString("Lyra");
486  if (code == "Men")
487  return QString("Mensa");
488  if (code == "Mic")
489  return QString("Microscopium");
490  if (code == "Mon")
491  return QString("Monoceros");
492  if (code == "Mus")
493  return QString("Musca");
494  if (code == "Nor")
495  return QString("Norma");
496  if (code == "Oct")
497  return QString("Octans");
498  if (code == "Oph")
499  return QString("Ophiuchus");
500  if (code == "Ori")
501  return QString("Orion");
502  if (code == "Pav")
503  return QString("Pavo");
504  if (code == "Peg")
505  return QString("Pegasus");
506  if (code == "Per")
507  return QString("Perseus");
508  if (code == "Phe")
509  return QString("Phoenix");
510  if (code == "Pic")
511  return QString("Pictor");
512  if (code == "Psc")
513  return QString("Pisces");
514  if (code == "PsA")
515  return QString("Piscis Austrinus");
516  if (code == "Pup")
517  return QString("Puppis");
518  if (code == "Pyx")
519  return QString("Pyxis");
520  if (code == "Ret")
521  return QString("Reticulum");
522  if (code == "Sge")
523  return QString("Sagitta");
524  if (code == "Sgr")
525  return QString("Sagittarius");
526  if (code == "Sco")
527  return QString("Scorpius");
528  if (code == "Scl")
529  return QString("Sculptor");
530  if (code == "Sct")
531  return QString("Scutum");
532  if (code == "Ser")
533  return QString("Serpens");
534  if (code == "Sex")
535  return QString("Sextans");
536  if (code == "Tau")
537  return QString("Taurus");
538  if (code == "Tel")
539  return QString("Telescopium");
540  if (code == "Tri")
541  return QString("Triangulum");
542  if (code == "TrA")
543  return QString("Triangulum Australe");
544  if (code == "Tuc")
545  return QString("Tucana");
546  if (code == "UMa")
547  return QString("Ursa Major");
548  if (code == "UMi")
549  return QString("Ursa Minor");
550  if (code == "Vel")
551  return QString("Vela");
552  if (code == "Vir")
553  return QString("Virgo");
554  if (code == "Vol")
555  return QString("Volans");
556  if (code == "Vul")
557  return QString("Vulpecula");
558  return code;
559 }
560 
561 QString constNameToAbbrev(const QString &fullName_)
562 {
563  QString fullName = fullName_.toLower();
564  if (fullName == "andromeda")
565  return QString("And");
566  if (fullName == "antlia")
567  return QString("Ant");
568  if (fullName == "apus")
569  return QString("Aps");
570  if (fullName == "aquarius")
571  return QString("Aqr");
572  if (fullName == "aquila")
573  return QString("Aql");
574  if (fullName == "ara")
575  return QString("Ara");
576  if (fullName == "aries")
577  return QString("Ari");
578  if (fullName == "auriga")
579  return QString("Aur");
580  if (fullName == "bootes")
581  return QString("Boo");
582  if (fullName == "caelum")
583  return QString("Cae");
584  if (fullName == "camelopardalis")
585  return QString("Cam");
586  if (fullName == "cancer")
587  return QString("Cnc");
588  if (fullName == "canes venatici")
589  return QString("CVn");
590  if (fullName == "canis major")
591  return QString("CMa");
592  if (fullName == "canis minor")
593  return QString("CMi");
594  if (fullName == "capricornus")
595  return QString("Cap");
596  if (fullName == "carina")
597  return QString("Car");
598  if (fullName == "cassiopeia")
599  return QString("Cas");
600  if (fullName == "centaurus")
601  return QString("Cen");
602  if (fullName == "cepheus")
603  return QString("Cep");
604  if (fullName == "cetus")
605  return QString("Cet");
606  if (fullName == "chamaeleon")
607  return QString("Cha");
608  if (fullName == "circinus")
609  return QString("Cir");
610  if (fullName == "columba")
611  return QString("Col");
612  if (fullName == "coma berenices")
613  return QString("Com");
614  if (fullName == "corona australis")
615  return QString("CrA");
616  if (fullName == "corona borealis")
617  return QString("CrB");
618  if (fullName == "corvus")
619  return QString("Crv");
620  if (fullName == "crater")
621  return QString("Crt");
622  if (fullName == "crux")
623  return QString("Cru");
624  if (fullName == "cygnus")
625  return QString("Cyg");
626  if (fullName == "delphinus")
627  return QString("Del");
628  if (fullName == "doradus")
629  return QString("Dor");
630  if (fullName == "draco")
631  return QString("Dra");
632  if (fullName == "equuleus")
633  return QString("Equ");
634  if (fullName == "eridanus")
635  return QString("Eri");
636  if (fullName == "fornax")
637  return QString("For");
638  if (fullName == "gemini")
639  return QString("Gem");
640  if (fullName == "grus")
641  return QString("Gru");
642  if (fullName == "hercules")
643  return QString("Her");
644  if (fullName == "horologium")
645  return QString("Hor");
646  if (fullName == "hydra")
647  return QString("Hya");
648  if (fullName == "hydrus")
649  return QString("Hyi");
650  if (fullName == "indus")
651  return QString("Ind");
652  if (fullName == "lacerta")
653  return QString("Lac");
654  if (fullName == "leo")
655  return QString("Leo");
656  if (fullName == "leo minor")
657  return QString("LMi");
658  if (fullName == "lepus")
659  return QString("Lep");
660  if (fullName == "libra")
661  return QString("Lib");
662  if (fullName == "lupus")
663  return QString("Lup");
664  if (fullName == "lynx")
665  return QString("Lyn");
666  if (fullName == "lyra")
667  return QString("Lyr");
668  if (fullName == "mensa")
669  return QString("Men");
670  if (fullName == "microscopium")
671  return QString("Mic");
672  if (fullName == "monoceros")
673  return QString("Mon");
674  if (fullName == "musca")
675  return QString("Mus");
676  if (fullName == "norma")
677  return QString("Nor");
678  if (fullName == "octans")
679  return QString("Oct");
680  if (fullName == "ophiuchus")
681  return QString("Oph");
682  if (fullName == "orion")
683  return QString("Ori");
684  if (fullName == "pavo")
685  return QString("Pav");
686  if (fullName == "pegasus")
687  return QString("Peg");
688  if (fullName == "perseus")
689  return QString("Per");
690  if (fullName == "phoenix")
691  return QString("Phe");
692  if (fullName == "pictor")
693  return QString("Pic");
694  if (fullName == "pisces")
695  return QString("Psc");
696  if (fullName == "piscis austrinus")
697  return QString("PsA");
698  if (fullName == "puppis")
699  return QString("Pup");
700  if (fullName == "pyxis")
701  return QString("Pyx");
702  if (fullName == "reticulum")
703  return QString("Ret");
704  if (fullName == "sagitta")
705  return QString("Sge");
706  if (fullName == "sagittarius")
707  return QString("Sgr");
708  if (fullName == "scorpius")
709  return QString("Sco");
710  if (fullName == "sculptor")
711  return QString("Scl");
712  if (fullName == "scutum")
713  return QString("Sct");
714  if (fullName == "serpens")
715  return QString("Ser");
716  if (fullName == "sextans")
717  return QString("Sex");
718  if (fullName == "taurus")
719  return QString("Tau");
720  if (fullName == "telescopium")
721  return QString("Tel");
722  if (fullName == "triangulum")
723  return QString("Tri");
724  if (fullName == "triangulum australe")
725  return QString("TrA");
726  if (fullName == "tucana")
727  return QString("Tuc");
728  if (fullName == "ursa major")
729  return QString("UMa");
730  if (fullName == "ursa minor")
731  return QString("UMi");
732  if (fullName == "vela")
733  return QString("Vel");
734  if (fullName == "virgo")
735  return QString("Vir");
736  if (fullName == "volans")
737  return QString("Vol");
738  if (fullName == "vulpecula")
739  return QString("Vul");
740  return fullName_;
741 }
742 
743 QString constGenetiveToAbbrev(const QString &genetive_)
744 {
745  QString genetive = genetive_.toLower();
746  if (genetive == "andromedae")
747  return QString("And");
748  if (genetive == "antliae")
749  return QString("Ant");
750  if (genetive == "apodis")
751  return QString("Aps");
752  if (genetive == "aquarii")
753  return QString("Aqr");
754  if (genetive == "aquilae")
755  return QString("Aql");
756  if (genetive == "arae")
757  return QString("Ara");
758  if (genetive == "arietis")
759  return QString("Ari");
760  if (genetive == "aurigae")
761  return QString("Aur");
762  if (genetive == "bootis")
763  return QString("Boo");
764  if (genetive == "caeli")
765  return QString("Cae");
766  if (genetive == "camelopardalis")
767  return QString("Cam");
768  if (genetive == "cancri")
769  return QString("Cnc");
770  if (genetive == "canum venaticorum")
771  return QString("CVn");
772  if (genetive == "canis majoris")
773  return QString("CMa");
774  if (genetive == "canis minoris")
775  return QString("CMi");
776  if (genetive == "capricorni")
777  return QString("Cap");
778  if (genetive == "carinae")
779  return QString("Car");
780  if (genetive == "cassiopeiae")
781  return QString("Cas");
782  if (genetive == "centauri")
783  return QString("Cen");
784  if (genetive == "cephei")
785  return QString("Cep");
786  if (genetive == "ceti")
787  return QString("Cet");
788  if (genetive == "chamaeleontis")
789  return QString("Cha");
790  if (genetive == "circini")
791  return QString("Cir");
792  if (genetive == "columbae")
793  return QString("Col");
794  if (genetive == "comae berenices")
795  return QString("Com");
796  if (genetive == "coronae austrinae")
797  return QString("CrA");
798  if (genetive == "coronae borealis")
799  return QString("CrB");
800  if (genetive == "corvi")
801  return QString("Crv");
802  if (genetive == "crateris")
803  return QString("Crt");
804  if (genetive == "crucis")
805  return QString("Cru");
806  if (genetive == "cygni")
807  return QString("Cyg");
808  if (genetive == "delphini")
809  return QString("Del");
810  if (genetive == "doradus")
811  return QString("Dor");
812  if (genetive == "draconis")
813  return QString("Dra");
814  if (genetive == "equulei")
815  return QString("Equ");
816  if (genetive == "eridani")
817  return QString("Eri");
818  if (genetive == "fornacis")
819  return QString("For");
820  if (genetive == "geminorum")
821  return QString("Gem");
822  if (genetive == "gruis")
823  return QString("Gru");
824  if (genetive == "herculis")
825  return QString("Her");
826  if (genetive == "horologii")
827  return QString("Hor");
828  if (genetive == "hydrae")
829  return QString("Hya");
830  if (genetive == "hydri")
831  return QString("Hyi");
832  if (genetive == "indi")
833  return QString("Ind");
834  if (genetive == "lacertae")
835  return QString("Lac");
836  if (genetive == "leonis")
837  return QString("Leo");
838  if (genetive == "leonis minoris")
839  return QString("LMi");
840  if (genetive == "leporis")
841  return QString("Lep");
842  if (genetive == "librae")
843  return QString("Lib");
844  if (genetive == "lupi")
845  return QString("Lup");
846  if (genetive == "lyncis")
847  return QString("Lyn");
848  if (genetive == "lyrae")
849  return QString("Lyr");
850  if (genetive == "mensae")
851  return QString("Men");
852  if (genetive == "microscopii")
853  return QString("Mic");
854  if (genetive == "monocerotis")
855  return QString("Mon");
856  if (genetive == "muscae")
857  return QString("Mus");
858  if (genetive == "normae")
859  return QString("Nor");
860  if (genetive == "octantis")
861  return QString("Oct");
862  if (genetive == "ophiuchi")
863  return QString("Oph");
864  if (genetive == "orionis")
865  return QString("Ori");
866  if (genetive == "pavonis")
867  return QString("Pav");
868  if (genetive == "pegasi")
869  return QString("Peg");
870  if (genetive == "persei")
871  return QString("Per");
872  if (genetive == "phoenicis")
873  return QString("Phe");
874  if (genetive == "pictoris")
875  return QString("Pic");
876  if (genetive == "piscium")
877  return QString("Psc");
878  if (genetive == "piscis austrini")
879  return QString("PsA");
880  if (genetive == "puppis")
881  return QString("Pup");
882  if (genetive == "pyxidis")
883  return QString("Pyx");
884  if (genetive == "reticuli")
885  return QString("Ret");
886  if (genetive == "sagittae")
887  return QString("Sge");
888  if (genetive == "sagittarii")
889  return QString("Sgr");
890  if (genetive == "scorpii")
891  return QString("Sco");
892  if (genetive == "sculptoris")
893  return QString("Scl");
894  if (genetive == "scuti")
895  return QString("Sct");
896  if (genetive == "serpentis")
897  return QString("Ser");
898  if (genetive == "sextantis")
899  return QString("Sex");
900  if (genetive == "tauri")
901  return QString("Tau");
902  if (genetive == "telescopii")
903  return QString("Tel");
904  if (genetive == "trianguli")
905  return QString("Tri");
906  if (genetive == "trianguli australis")
907  return QString("TrA");
908  if (genetive == "tucanae")
909  return QString("Tuc");
910  if (genetive == "ursae majoris")
911  return QString("UMa");
912  if (genetive == "ursae minoris")
913  return QString("UMi");
914  if (genetive == "velorum")
915  return QString("Vel");
916  if (genetive == "virginis")
917  return QString("Vir");
918  if (genetive == "volantis")
919  return QString("Vol");
920  if (genetive == "vulpeculae")
921  return QString("Vul");
922  return genetive_;
923 }
924 
925 QString Logging::_filename;
926 
928 {
929  if (_filename.isEmpty())
930  {
931  QDir dir;
932  QString path =
933  QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
934  .filePath("logs/" + QDateTime::currentDateTime().toString("yyyy-MM-dd"));
935  dir.mkpath(path);
936  QString name =
937  "log_" + QDateTime::currentDateTime().toString("HH-mm-ss") + ".txt";
938  _filename = path + QStringLiteral("/") + name;
939 
940  // Clear file contents
941  QFile file(_filename);
942  file.open(QFile::WriteOnly);
943  file.close();
944  }
945 
946  qSetMessagePattern("[%{time yyyy-MM-dd h:mm:ss.zzz t} "
947  "%{if-debug}DEBG%{endif}%{if-info}INFO%{endif}%{if-warning}WARN%{"
948  "endif}%{if-critical}CRIT%{endif}%{if-fatal}FATL%{endif}] "
949  "%{if-category}[%{category}]%{endif} - %{message}");
950  qInstallMessageHandler(File);
951 }
952 
953 void Logging::File(QtMsgType type, const QMessageLogContext &context, const QString &msg)
954 {
955  QFile file(_filename);
956  if (file.open(QFile::Append | QIODevice::Text))
957  {
958  QTextStream stream(&file);
959  Write(stream, type, context, msg);
960  }
961 }
962 
964 {
965  qSetMessagePattern("[%{time yyyy-MM-dd h:mm:ss.zzz t} "
966  "%{if-debug}DEBG%{endif}%{if-info}INFO%{endif}%{if-warning}WARN%{"
967  "endif}%{if-critical}CRIT%{endif}%{if-fatal}FATL%{endif}] "
968  "%{if-category}[%{category}]%{endif} - %{message}");
969  qInstallMessageHandler(Stdout);
970 }
971 
972 void Logging::Stdout(QtMsgType type, const QMessageLogContext &context,
973  const QString &msg)
974 {
975  QTextStream stream(stdout, QIODevice::WriteOnly);
976  Write(stream, type, context, msg);
977 }
978 
980 {
981  qInstallMessageHandler(Stderr);
982 }
983 
984 void Logging::Stderr(QtMsgType type, const QMessageLogContext &context,
985  const QString &msg)
986 {
987  QTextStream stream(stderr, QIODevice::WriteOnly);
988  Write(stream, type, context, msg);
989 }
990 
991 void Logging::Write(QTextStream &stream, QtMsgType type,
992  const QMessageLogContext &context, const QString &msg)
993 {
994  stream << QDateTime::currentDateTime().toString("[yyyy-MM-ddThh:mm:ss.zzz t ");
995 
996  switch (type)
997  {
998  case QtInfoMsg:
999  stream << "INFO ]";
1000  break;
1001  case QtDebugMsg:
1002  stream << "DEBG ]";
1003  break;
1004  case QtWarningMsg:
1005  stream << "WARN ]";
1006  break;
1007  case QtCriticalMsg:
1008  stream << "CRIT ]";
1009  break;
1010  case QtFatalMsg:
1011  stream << "FATL ]";
1012  break;
1013  default:
1014  stream << "UNKN ]";
1015  }
1016 
1017  stream << "[" << qSetFieldWidth(30) << context.category << qSetFieldWidth(0)
1018  << "] - ";
1019  stream << msg << '\n';
1020  stream.flush();
1021  //stream << qFormatLogMessage(type, context, msg) << Qt::endl;
1022 }
1023 
1025 {
1026  qInstallMessageHandler(nullptr);
1027 }
1028 
1030 {
1031  qInstallMessageHandler(Disabled);
1032 }
1033 
1034 void Logging::Disabled(QtMsgType, const QMessageLogContext &, const QString &) {}
1035 
1037 {
1038  // QString rules = QString("org.kde.kstars.ekos.debug=%1\n"
1039  // "org.kde.kstars.indi.debug=%2\n"
1040  // "org.kde.kstars.fits.debug=%3\n"
1041  // "org.kde.kstars.ekos.capture.debug=%4\n"
1042  // "org.kde.kstars.ekos.focus.debug=%5\n"
1043  // "org.kde.kstars.ekos.guide.debug=%6\n"
1044  // "org.kde.kstars.ekos.align.debug=%7\n"
1045  // "org.kde.kstars.ekos.mount.debug=%8\n"
1046  // "org.kde.kstars.ekos.scheduler.debug=%9\n").arg(
1047  // Options::verboseLogging() ? "true" : "false",
1048  // Options::iNDILogging() ? "true" : "false",
1049  // Options::fITSLogging() ? "true" : "false",
1050  // Options::captureLogging() ? "true" : "false",
1051  // Options::focusLogging() ? "true" : "false",
1052  // Options::guideLogging() ? "true" : "false",
1053  // Options::alignmentLogging() ? "true" : "false",
1054  // Options::mountLogging() ? "true" : "false",
1055  // Options::schedulerLogging() ? "true" : "false")
1056  // .append(QString("org.kde.kstars.ekos.observatory.debug=%2\n"
1057  // "org.kde.kstars.debug=%1").arg(
1058  // Options::verboseLogging() ? "true" : "false",
1059  // Options::observatoryLogging() ? "true" : "false"));
1060 
1061  QStringList rules;
1062 
1063  rules << "org.kde.kstars.ekos.debug"
1064  << (Options::verboseLogging() ? "true" : "false");
1065  rules << "org.kde.kstars.indi.debug" << (Options::iNDILogging() ? "true" : "false");
1066  rules << "org.kde.kstars.fits.debug" << (Options::fITSLogging() ? "true" : "false");
1067  rules << "org.kde.kstars.ekos.capture.debug"
1068  << (Options::captureLogging() ? "true" : "false");
1069  rules << "org.kde.kstars.ekos.focus.debug"
1070  << (Options::focusLogging() ? "true" : "false");
1071  rules << "org.kde.kstars.ekos.guide.debug"
1072  << (Options::guideLogging() ? "true" : "false");
1073  rules << "org.kde.kstars.ekos.align.debug"
1074  << (Options::alignmentLogging() ? "true" : "false");
1075  rules << "org.kde.kstars.ekos.mount.debug"
1076  << (Options::mountLogging() ? "true" : "false");
1077  rules << "org.kde.kstars.ekos.scheduler.debug"
1078  << (Options::schedulerLogging() ? "true" : "false");
1079  rules << "org.kde.kstars.ekos.observatory.debug"
1080  << (Options::observatoryLogging() ? "true" : "false");
1081  rules << "org.kde.kstars.debug" << (Options::verboseLogging() ? "true" : "false");
1082 
1083  QString formattedRules;
1084  for (int i = 0; i < rules.size(); i += 2)
1085  formattedRules.append(QString("%1=%2\n").arg(rules[i], rules[i + 1]));
1086 
1087  QLoggingCategory::setFilterRules(formattedRules);
1088 }
1089 
1090 /**
1091  This method provides a centralized location for the default paths to important external files used in the Options
1092  on different operating systems. Note that on OS X, if the user builds the app without indi, astrometry, and xplanet internally
1093  then the options below will be used. If the user drags the app from a dmg and has to install the KStars data directory,
1094  then most of these paths will be overwritten since it is preferred to use the internal versions.
1095 **/
1096 
1097 QString getDefaultPath(const QString &option)
1098 {
1099  // We support running within Snaps, Flatpaks, and AppImage
1100  // The path should accomodate the differences between the different
1101  // packaging solutions
1103  QString flat = QProcessEnvironment::systemEnvironment().value("FLATPAK_DEST");
1105 
1106  // User prefix is the primary mounting point
1107  QString userPrefix = "/usr";
1108  // By default /usr is the prefix
1109  QString prefix = userPrefix;
1110  // Detect if we are within an App Image
1111  if (QProcessEnvironment::systemEnvironment().value("APPIMAGE").isEmpty() == false &&
1112  appimg.isEmpty() == false)
1113  prefix = appimg + userPrefix;
1114  else if (flat.isEmpty() == false)
1115  // Detect if we are within a Flatpak
1116  prefix = flat;
1117  // Detect if we are within a snap
1118  else if (snap.isEmpty() == false)
1119  prefix = snap + userPrefix;
1120 
1121  if (option == "fitsDir")
1122  {
1123  return QDir::homePath();
1124  }
1125  else if (option == "indiServer")
1126  {
1127 #if defined(INDI_PREFIX)
1128  return QString(INDI_PREFIX "/bin/indiserver");
1129 #elif defined(Q_OS_OSX)
1130  return "/usr/local/bin/indiserver";
1131 #endif
1132  return prefix + "/bin/indiserver";
1133  }
1134  else if (option == "INDIHubAgent")
1135  {
1136 #if defined(INDI_PREFIX)
1137  return QString(INDI_PREFIX "/bin/indihub-agent");
1138 #elif defined(Q_OS_OSX)
1139  return "/usr/local/bin/indihub-agent";
1140 #endif
1141  return prefix + "/bin/indihub-agent";
1142  }
1143  else if (option == "indiDriversDir")
1144  {
1145 #if defined(INDI_PREFIX)
1146  return QString(INDI_PREFIX "/share/indi");
1147 #elif defined(Q_OS_OSX)
1148  return "/usr/local/share/indi";
1149 #elif defined(Q_OS_LINUX)
1150  return prefix + "/share/indi";
1151 #else
1154 #endif
1155  }
1156  else if (option == "AstrometrySolverBinary")
1157  {
1158 #if defined(ASTROMETRY_PREFIX)
1159  return QString(ASTROMETRY_PREFIX "/bin/solve-field");
1160 #elif defined(Q_OS_OSX)
1161  return "/usr/local/bin/solve-field";
1162 #elif defined(Q_OS_WIN)
1163  return QDir::homePath() +
1164  "/AppData/Local/cygwin_ansvr/lib/astrometry/bin/solve-field.exe";
1165 #endif
1166  return prefix + "/bin/solve-field";
1167  }
1168  else if (option == "WatneyBinary")
1169  {
1170 #if defined(ASTROMETRY_PREFIX)
1171  return QString(ASTROMETRY_PREFIX "/opt/watney/watney-solve");
1172 #elif defined(Q_OS_OSX)
1173  return "/usr/local/bin/watney-solve";
1174 #elif defined(Q_OS_WIN)
1175  return "C:/watney/watney-solve.exe";
1176 #endif
1177  return prefix + "/opt/watney/watney-solve";
1178  }
1179  else if (option == "SextractorBinary")
1180  {
1181 #if defined(SEXTRACTOR_PREFIX)
1182  return QString(SEXTRACTOR_PREFIX "/bin/sextractor");
1183 #elif defined(Q_OS_OSX)
1184  return "/usr/local/bin/sex";
1185 #endif
1186  return prefix + "/bin/sextractor";
1187  }
1188  else if (option == "AstrometryWCSInfo")
1189  {
1190 #if defined(ASTROMETRY_PREFIX)
1191  return QString(ASTROMETRY_PREFIX "/bin/wcsinfo");
1192 #elif defined(Q_OS_OSX)
1193  return "/usr/local/bin/wcsinfo";
1194 #elif defined(Q_OS_WIN)
1195  return QDir::homePath() +
1196  "/AppData/Local/cygwin_ansvr/lib/astrometry/bin/wcsinfo.exe";
1197 #endif
1198  return prefix + "/bin/wcsinfo";
1199  }
1200  else if (option == "AstrometryConfFile")
1201  {
1202 #if defined(ASTROMETRY_CONF_IN_PREFIX) && defined(ASTROMETRY_PREFIX)
1203  return QString(ASTROMETRY_PREFIX "/etc/astrometry.cfg");
1204 #elif defined(Q_OS_OSX)
1205  return "/usr/local/etc/astrometry.cfg";
1206 #elif defined(Q_OS_WIN)
1207  return QDir::homePath() +
1208  "/AppData/Local/cygwin_ansvr/etc/astrometry/backend.cfg";
1209 #endif
1210  // We move /usr
1211  prefix.remove(userPrefix);
1212  return prefix + "/etc/astrometry.cfg";
1213  }
1214  else if (option == "AstrometryIndexFileLocation")
1215  {
1216 #if defined(ASTROMETRY_PREFIX)
1217  return QString(ASTROMETRY_PREFIX "/share/astrometry");
1218 #elif defined(Q_OS_OSX)
1220  .filePath("Astrometry/");
1221 #endif
1222  return prefix + "/share/astrometry/";
1223  }
1224  else if (option == "AstrometryLogFilepath")
1225  {
1226  return QDir::tempPath() + "/astrometryLog.txt";
1227  }
1228  else if (option == "XplanetPath")
1229  {
1230 #if defined(XPLANET_PREFIX)
1231  return QString(XPLANET_PREFIX "/bin/xplanet");
1232 #elif defined(Q_OS_OSX)
1233  return "/usr/local/bin/xplanet";
1234 #endif
1235  return prefix + "/bin/xplanet";
1236  }
1237  else if (option == "ASTAP")
1238  {
1239 #if defined(Q_OS_OSX)
1240  return "/Applications/ASTAP.app/Contents/MacOS/astap";
1241 #elif defined(Q_OS_WIN)
1242  return "C:/Program Files/astap/astap.exe";
1243 #endif
1244  return "/opt/astap/astap";
1245  }
1246 
1247  return QString();
1248 }
1249 
1250 QStringList getAstrometryDefaultIndexFolderPaths()
1251 {
1252  QStringList folderPaths;
1253  const QString confDir =
1254  QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
1255  .filePath(QLatin1String("astrometry"));
1256  folderPaths << confDir;
1257  // Check if directory already exists, if it doesn't create one
1258  QDir writableDir(confDir);
1259  if (writableDir.exists() == false)
1260  {
1261  if (writableDir.mkdir(confDir) == false)
1262  {
1263  qCCritical(KSTARS) << "Failed to create local astrometry directory";
1264  folderPaths.clear();
1265  }
1266  }
1267 
1268 #ifdef HAVE_STELLARSOLVER
1269  folderPaths.append(StellarSolver::getDefaultIndexFolderPaths());
1270 #endif
1271  return folderPaths;
1272 }
1273 
1274 #if defined(Q_OS_OSX)
1275 //Note that this will copy and will not overwrite, so that the user's changes in the files are preserved.
1276 void copyResourcesFolderFromAppBundle(QString folder)
1277 {
1278  QString folderLocation = QStandardPaths::locate(
1280  QDir folderSourceDir;
1281  if (folder == "kstars")
1282  folderSourceDir =
1283  QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars")
1284  .absolutePath();
1285  else
1286  folderSourceDir =
1287  QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + folder)
1288  .absolutePath();
1289  if (folderSourceDir.exists())
1290  {
1291  folderLocation =
1293  folder;
1294  QDir writableDir;
1295  writableDir.mkdir(folderLocation);
1296  copyRecursively(folderSourceDir.absolutePath(), folderLocation);
1297  }
1298 }
1299 
1300 bool setupMacKStarsIfNeeded() // This method will return false if the KStars data directory doesn't exist when it's done
1301 {
1302  //This will copy the locale folder, the notifications folder, and the sounds folder and any missing files in them to Application Support if needed.
1303  copyResourcesFolderFromAppBundle("locale");
1304  copyResourcesFolderFromAppBundle("knotifications5");
1305  copyResourcesFolderFromAppBundle("sounds");
1306 
1307  //This will copy the KStars data directory
1308  copyResourcesFolderFromAppBundle("kstars");
1309  copyResourcesFolderFromAppBundle("kstars/xplanet");
1310 
1311  if (Options::kStarsFirstRun())
1312  {
1313  //This sets some important OS X options.
1314  Options::setIndiServerIsInternal(true);
1315  Options::setIndiServer("*Internal INDI Server*");
1316  Options::setIndiDriversAreInternal(true);
1317  Options::setIndiDriversDir("*Internal INDI Drivers*");
1318  Options::setXplanetIsInternal(true);
1319  Options::setXplanetPath("*Internal XPlanet*");
1320  }
1321 
1322  QString dataLocation = QStandardPaths::locate(
1324  if (dataLocation.isEmpty()) //If there is no kstars user data directory
1325  return false;
1326 
1327  return true;
1328 }
1329 
1330 bool configureAstrometry()
1331 {
1332  QStringList astrometryDataDirs = getAstrometryDataDirs();
1333  if (astrometryDataDirs.count() == 0)
1334  return false;
1335  QString defaultAstrometryDataDir = getDefaultPath("AstrometryIndexFileLocation");
1336  if (astrometryDataDirs.contains("IndexFileLocationNotYetSet"))
1337  replaceIndexFileNotYetSet();
1338  if (QDir(defaultAstrometryDataDir).exists() == false)
1339  {
1341  nullptr,
1342  i18n("The selected Astrometry Index File Location:\n %1 \n does not "
1343  "exist. Do you want to make the directory?",
1344  defaultAstrometryDataDir),
1345  i18n("Make Astrometry Index File Directory?")) == KMessageBox::Yes)
1346  {
1347  if (QDir(defaultAstrometryDataDir).mkdir(defaultAstrometryDataDir))
1348  {
1349  KSNotification::info(
1350  i18n("The Default Astrometry Index File Location was created."));
1351  }
1352  else
1353  {
1354  KSNotification::sorry(
1355  i18n("The Default Astrometry Index File Directory does not exist and "
1356  "was not able to be created."));
1357  }
1358  }
1359  else
1360  {
1361  return false;
1362  }
1363  }
1364 
1365  return true;
1366 }
1367 
1368 bool replaceIndexFileNotYetSet()
1369 {
1370  QString confPath = KSUtils::getAstrometryConfFilePath();
1371 
1372  QFile confFile(confPath);
1373  QString contents;
1374  if (confFile.open(QIODevice::ReadOnly) == false)
1375  {
1376  KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1377  return false;
1378  }
1379  else
1380  {
1381  QByteArray fileContent = confFile.readAll();
1382  confFile.close();
1383  QString contents = QString::fromLatin1(fileContent);
1384  contents.replace("IndexFileLocationNotYetSet",
1385  getDefaultPath("AstrometryIndexFileLocation"));
1386 
1387  if (confFile.open(QIODevice::WriteOnly) == false)
1388  {
1389  KSNotification::error(
1390  i18n("Internal Astrometry Configuration File Write Error."));
1391  return false;
1392  }
1393  else
1394  {
1395  QTextStream out(&confFile);
1396  out << contents;
1397  confFile.close();
1398  }
1399  }
1400  return true;
1401 }
1402 
1403 bool copyRecursively(QString sourceFolder, QString destFolder)
1404 {
1405  QDir sourceDir(sourceFolder);
1406 
1407  if (!sourceDir.exists())
1408  return false;
1409 
1410  QDir destDir(destFolder);
1411  if (!destDir.exists())
1412  destDir.mkdir(destFolder);
1413 
1414  QStringList files = sourceDir.entryList(QDir::Files);
1415  for (int i = 0; i < files.count(); i++)
1416  {
1417  QString srcName = sourceFolder + QDir::separator() + files[i];
1418  QString destName = destFolder + QDir::separator() + files[i];
1419  QFile::copy(srcName, destName); //Note this does not overwrite files
1420  }
1421 
1422  files.clear();
1423  files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
1424  for (int i = 0; i < files.count(); i++)
1425  {
1426  QString srcName = sourceFolder + QDir::separator() + files[i];
1427  QString destName = destFolder + QDir::separator() + files[i];
1428  copyRecursively(srcName, destName);
1429  }
1430 
1431  return true;
1432 }
1433 #endif
1434 
1435 QString getAstrometryConfFilePath()
1436 {
1437  return Options::astrometryConfFile();
1438 }
1439 
1440 QStringList getAstrometryDataDirs()
1441 {
1442  QStringList optionsDataDirs = Options::astrometryIndexFolderList();
1443 
1444  bool updated = false;
1445 
1446  // Cleaning up the list of directories in options.
1447  for (int dir = 0; dir < optionsDataDirs.count(); dir++)
1448  {
1449  QString optionsDataDirName = optionsDataDirs.at(dir);
1450  QDir optionsDataDir(optionsDataDirName);
1451  if (optionsDataDir.exists())
1452  {
1453  //This will replace directory names that aren't the absolute path
1454  if (optionsDataDir.absolutePath() != optionsDataDirName)
1455  {
1456  optionsDataDirs.replace(dir, optionsDataDir.absolutePath());
1457  updated = true;
1458  }
1459  }
1460  else
1461  {
1462  //This removes directories that do not exist from the list.
1463  optionsDataDirs.removeAt(dir);
1464  dir--;
1465  updated = true;
1466  }
1467  }
1468 
1469  //This will load the conf file if it exists
1470  QFile confFile(KSUtils::getAstrometryConfFilePath());
1471  if (confFile.open(QIODevice::ReadOnly))
1472  {
1473  QStringList confDataDirs;
1474  QTextStream in(&confFile);
1475  QString line;
1476 
1477  //This will find the index file paths in the conf file
1478  while (!in.atEnd())
1479  {
1480  line = in.readLine();
1481  if (line.isEmpty() || line.startsWith('#'))
1482  continue;
1483 
1484  line = line.trimmed();
1485  if (line.startsWith(QLatin1String("add_path")))
1486  {
1487  confDataDirs << line.mid(9).trimmed();
1488  }
1489  }
1490 
1491  //This will search through the paths and compare them to the index folder list
1492  //It will add them if they aren't in there.
1493  for (QString astrometryDataDirName : confDataDirs)
1494  {
1495  QDir astrometryDataDir(astrometryDataDirName);
1496  //This rejects any that do not exist
1497  if (!astrometryDataDir.exists())
1498  continue;
1499  QString astrometryDataDirPath = astrometryDataDir.absolutePath();
1500  if (!optionsDataDirs.contains(astrometryDataDirPath))
1501  {
1502  optionsDataDirs.append(astrometryDataDirPath);
1503  updated = true;
1504  }
1505  }
1506  }
1507 
1508  //This will remove any duplicate entries.
1509  if (optionsDataDirs.removeDuplicates() != 0)
1510  updated = true;
1511 
1512  //This updates the list in Options if it changed.
1513  if (updated)
1514  Options::setAstrometryIndexFolderList(optionsDataDirs);
1515 
1516  return optionsDataDirs;
1517 }
1518 
1519 bool addAstrometryDataDir(const QString &dataDir)
1520 {
1521  //This will need to be fixed!
1522  //if(Options::astrometryIndexFileLocation() != dataDir)
1523  // Options::setAstrometryIndexFileLocation(dataDir);
1524 
1525  QString confPath = KSUtils::getAstrometryConfFilePath();
1526  QStringList astrometryDataDirs = getAstrometryDataDirs();
1527 
1528  QFile confFile(confPath);
1529  QString contents;
1530  if (confFile.open(QIODevice::ReadOnly) == false)
1531  {
1532  KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1533  return false;
1534  }
1535  else
1536  {
1537  QTextStream in(&confFile);
1538  QString line;
1539  bool foundSpot = false;
1540  while (!in.atEnd())
1541  {
1542  line = in.readLine();
1543 
1544  if (line.trimmed().startsWith(QLatin1String("add_path")))
1545  {
1546  if (!foundSpot)
1547  {
1548  foundSpot = true;
1549  for (QString astrometryDataDir : astrometryDataDirs)
1550  contents += "add_path " + astrometryDataDir + '\n';
1551  contents += "add_path " + dataDir + '\n';
1552  }
1553  else
1554  {
1555  //Do not keep adding the other add_paths because they just got added in the seciton above.
1556  }
1557  }
1558  else
1559  {
1560  contents += line + '\n';
1561  }
1562  }
1563  if (!foundSpot)
1564  {
1565  for (QString astrometryDataDir : astrometryDataDirs)
1566  contents += "add_path " + astrometryDataDir + '\n';
1567  contents += "add_path " + dataDir + '\n';
1568  }
1569 
1570  confFile.close();
1571 
1572  if (confFile.open(QIODevice::WriteOnly) == false)
1573  {
1574  KSNotification::error(
1575  i18n("Internal Astrometry Configuration File Write Error."));
1576  return false;
1577  }
1578  else
1579  {
1580  QTextStream out(&confFile);
1581  out << contents;
1582  confFile.close();
1583  }
1584  }
1585  return true;
1586 }
1587 
1588 bool removeAstrometryDataDir(const QString &dataDir)
1589 {
1590  QString confPath = KSUtils::getAstrometryConfFilePath();
1591  QStringList astrometryDataDirs = getAstrometryDataDirs();
1592 
1593  QFile confFile(confPath);
1594  QString contents;
1595  if (confFile.open(QIODevice::ReadOnly) == false)
1596  {
1597  KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1598  return false;
1599  }
1600  else
1601  {
1602  QTextStream in(&confFile);
1603  QString line;
1604  while (!in.atEnd())
1605  {
1606  line = in.readLine();
1607  if (line.mid(9).trimmed() != dataDir)
1608  {
1609  contents += line + '\n';
1610  }
1611  }
1612  confFile.close();
1613 
1614  if (confFile.open(QIODevice::WriteOnly) == false)
1615  {
1616  KSNotification::error(
1617  i18n("Internal Astrometry Configuration File Write Error."));
1618  return false;
1619  }
1620  else
1621  {
1622  QTextStream out(&confFile);
1623  out << contents;
1624  confFile.close();
1625  }
1626  }
1627  return true;
1628 }
1629 
1630 QByteArray getJPLQueryString(const QByteArray &kind, const QByteArray &dataFields,
1631  const QVector<JPLFilter> &filters)
1632 {
1633  /* For example:
1634  https://ssd-api.jpl.nasa.gov/sbdb_query.api?fields=full_name,neo,H,G,diameter,extent,albedo,rot_per,orbit_id,epoch.mjd,e,a,q,i,om,w,ma,per.y,moid,class&full-prec=false&sb-cdata=%7B%22AND%22:%5B%22H%7CLT%7C10%22%5D%7D&sb-kind=a&sb-ns=n&www=1
1635  */
1636 
1637  QByteArray query("sb-kind=" + kind + "&full-prec=true");
1638 
1639  // Apply filters:
1640  if (filters.size() > 0)
1641  {
1642  QByteArray filter_string("{\"AND\":[");
1643  for (const auto &item : filters)
1644  {
1645  filter_string += "\"" + item.item + "|" + item.op + "|" + item.value + "\",";
1646  }
1647 
1648  filter_string.chop(1);
1649  filter_string += "]}";
1650 
1651  query += "&sb-cdata=" + filter_string;
1652  }
1653 
1654  // Apply query data fields...
1655  query += "&fields=" + dataFields;
1656 
1657  return query;
1658 }
1659 
1660 bool RAWToJPEG(const QString &rawImage, const QString &output, QString &errorMessage)
1661 {
1662 #ifndef HAVE_LIBRAW
1663  errorMessage = i18n("Unable to find dcraw and cjpeg. Please install the required "
1664  "tools to convert CR2/NEF to JPEG.");
1665  return false;
1666 #else
1667  int ret = 0;
1668  // Creation of image processing object
1669  LibRaw RawProcessor;
1670 
1671  // Let us open the file
1672  if ((ret = RawProcessor.open_file(rawImage.toLatin1().data())) != LIBRAW_SUCCESS)
1673  {
1674  errorMessage = i18n("Cannot open %1: %2", rawImage, libraw_strerror(ret));
1675  RawProcessor.recycle();
1676  return false;
1677  }
1678 
1679  // Let us unpack the thumbnail
1680  if ((ret = RawProcessor.unpack_thumb()) != LIBRAW_SUCCESS)
1681  {
1682  errorMessage = i18n("Cannot unpack_thumb %1: %2", rawImage, libraw_strerror(ret));
1683  RawProcessor.recycle();
1684  return false;
1685  }
1686  else
1687  // We have successfully unpacked the thumbnail, now let us write it to a file
1688  {
1689  //snprintf(thumbfn,sizeof(thumbfn),"%s.%s",av[i],T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" : "thumb.ppm");
1690  if (LIBRAW_SUCCESS !=
1691  (ret = RawProcessor.dcraw_thumb_writer(output.toLatin1().data())))
1692  {
1693  errorMessage = i18n("Cannot write %s %1: %2", output, libraw_strerror(ret));
1694  RawProcessor.recycle();
1695  return false;
1696  }
1697  }
1698  return true;
1699 #endif
1700 }
1701 
1702 double getAvailableRAM()
1703 {
1704 #if defined(Q_OS_OSX)
1705  int mib[] = { CTL_HW, HW_MEMSIZE };
1706  size_t length;
1707  length = sizeof(int64_t);
1708  int64_t RAMcheck;
1709  if (sysctl(mib, 2, &RAMcheck, &length, NULL, 0))
1710  return false; // On Error
1711  //Until I can figure out how to get free RAM on Mac
1712  return RAMcheck;
1713 #elif defined(Q_OS_LINUX)
1714  QProcess p;
1715  p.start("awk", QStringList() << "/MemAvailable/ { print $2 }"
1716  << "/proc/meminfo");
1717  p.waitForFinished();
1718  QString memory = p.readAllStandardOutput();
1719  p.close();
1720  //kB to bytes
1721  return (memory.toLong() * 1024.0);
1722 #elif defined(Q_OS_WIN32)
1723  MEMORYSTATUSEX memory_status;
1724  ZeroMemory(&memory_status, sizeof(MEMORYSTATUSEX));
1725  memory_status.dwLength = sizeof(MEMORYSTATUSEX);
1726  if (GlobalMemoryStatusEx(&memory_status))
1727  {
1728  return memory_status.ullAvailPhys;
1729  }
1730  else
1731  {
1732  return 0;
1733  }
1734 #endif
1735  return 0;
1736 }
1737 
1738 JPLParser::JPLParser(const QString &path)
1739 {
1740  QFile jpl_file(path);
1741  if (!jpl_file.open(QIODevice::ReadOnly))
1742  {
1743  throw std::runtime_error("Could not open file.");
1744  }
1745 
1746  const auto &ast_json = QJsonDocument::fromJson(jpl_file.readAll());
1747 #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
1748  const auto &fields = ast_json["fields"].toArray();
1749  m_data = ast_json["data"].toArray();
1750 #else
1751  const auto &fields = ast_json.object().value("fields").toArray();
1752  m_data = ast_json.object().value("data").toArray();
1753 #endif
1754 
1755  {
1756  int i = 0;
1757  for (const auto &field : fields)
1758  {
1759  m_field_map[field.toString()] = i++;
1760  }
1761  }
1762 }
1763 
1764 MPCParser::MPCParser(const QString &path)
1765 {
1766  QFile mpc_file(path);
1767  if (!mpc_file.open(QIODevice::ReadOnly))
1768  {
1769  throw std::runtime_error("Could not open file.");
1770  }
1771 
1772  gzFile file = gzopen(path.toLatin1().constData(), "r");
1773  if (file)
1774  {
1775 
1776  QByteArray data;
1777  const uint32_t len = 32768;
1778 
1779  while (!gzeof(file))
1780  {
1781  char buffer[len] = {0};
1782  int bytes_read = gzread(file, buffer, len - 1);
1783  if (bytes_read < 0)
1784  break;
1785  buffer[bytes_read] = 0;
1786  data.append(buffer);
1787  }
1788 
1789  gzclose(file);
1790  const auto &ast_json = QJsonDocument::fromJson(data);
1791  m_data = ast_json.array();
1792  }
1793  else
1794  qCritical(KSTARS) << "Failed to read MPC comets data file" << path;
1795 }
1796 
1797 } // namespace KSUtils
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
void append(const T &value)
bool isNull() const const
bool exists() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool waitForFinished(int msecs)
QByteArray & append(char ch)
virtual bool open(QIODevice::OpenMode mode) override
QDateTime currentDateTime()
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
bool copy(const QString &newName)
int count(const T &value) const const
QChar separator()
static constexpr double DegToRad
DegToRad is a const static member equal to the number of radians in one degree (dms::PI/180....
Definition: dms.h:385
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QString trimmed() const const
QProcessEnvironment systemEnvironment()
bool mkdir(const QString &dirName) const const
QByteArray readAllStandardOutput()
QString applicationDirPath()
QString writableLocation(QStandardPaths::StandardLocation type)
QByteArray toLatin1() const const
QString homePath()
static void UseStderr()
Output logs to stderr.
Definition: ksutils.cpp:979
static void UseStdout()
Output logs to stdout.
Definition: ksutils.cpp:963
void replace(int i, const T &value)
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
ButtonCode warningYesNo(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous))
void removeAt(int i)
QString tempPath()
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
float a() const
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
#define I18N_NOOP2(context, text)
void flush()
int size() const const
static void UseFile()
Store all logs into the specified file.
Definition: ksutils.cpp:927
QString i18n(const char *text, const TYPE &arg...)
int mkdir(const QString &pathname, mode_t mode)
subclass of SkyObject specialized for stars.
Definition: starobject.h:32
static void SyncFilterRules()
SyncFilterRules Sync QtLogging filter rules from Options.
Definition: ksutils.cpp:1036
bool isEmpty() const const
const T & at(int i) const const
void setFileName(const QString &name)
virtual void close() override
QTextStream & dec(QTextStream &stream)
virtual void close() override
KStars utility functions.
QString absolutePath() const const
int second() const
Definition: dms.cpp:231
QString & replace(int position, int n, QChar after)
QString & remove(int position, int n)
static void Disable()
Disable logging.
Definition: ksutils.cpp:1029
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
int removeDuplicates()
QString toLower() const const
KIOFILEWIDGETS_EXPORT QString dir(const QString &fileClass)
const char * constData() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const CachingDms & dec0() const
Definition: skypoint.h:257
QString fromLatin1(const char *str, int size)
const double & Degrees() const
Definition: dms.h:141
static void UseDefault()
Use the default logging mechanism.
Definition: ksutils.cpp:1024
QString filePath(const QString &fileName) const const
const CachingDms & ra0() const
Definition: skypoint.h:251
int hour() const
Definition: dms.h:147
void clear()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
int size() const const
const dms reduce() const
return the equivalent angle between 0 and 360 degrees.
Definition: dms.cpp:251
QString asprintf(const char *cformat,...)
QString toString(Qt::DateFormat format) const const
int minute() const
Definition: dms.cpp:221
QString mid(int position, int n) const const
A simple container object to hold the minimum information for a Deeb Sky Object to be drawn on the sk...
Definition: catalogobject.h:40
void setFilterRules(const QString &rules)
QString fullName(const PartType &type)
QString & append(QChar ch)
QString value(const QString &name, const QString &defaultValue) const const
char * data()
long toLong(bool *ok, int base) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Aug 13 2022 04:01:55 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.