Kstars

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

KDE's Doxygen guidelines are available online.