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
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
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 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
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
188QList<SkyObject *> *castStarObjListToSkyObjList(QList<StarObject *> *starObjList)
189{
191
192 foreach (StarObject *so, *starObjList)
193 {
194 skyObjList->append(so);
195 }
196 return skyObjList;
197}
198
199QString 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
380QString 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
561QString 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
743QString 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
925QString Logging::_filename;
926
928{
929 if (_filename.isEmpty())
930 {
931 QDir dir;
932 QString path =
933 QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
934 .filePath("logs" + QDir::separator() + 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 + QDir::separator() + name;
939
940 // Clear file contents
941 QFile file(_filename);
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}");
951}
952
953void Logging::File(QtMsgType type, const QMessageLogContext &context, const QString &msg)
954{
955 QFile file(_filename);
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}");
970}
971
972void Logging::Stdout(QtMsgType type, const QMessageLogContext &context,
973 const QString &msg)
974{
976 Write(stream, type, context, msg);
977}
978
980{
982}
983
984void Logging::Stderr(QtMsgType type, const QMessageLogContext &context,
985 const QString &msg)
986{
988 Write(stream, type, context, msg);
989}
990
991void 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
1034void 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
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
1084 for (int i = 0; i < rules.size(); i += 2)
1085 formattedRules.append(QString("%1=%2\n").arg(rules[i], rules[i + 1]));
1086
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
1097QString 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 {
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 == "PlaceholderFormat")
1135 {
1136#if defined(Q_OS_WIN)
1137 return "\\%t\\%T\\%F\\%t_%T_%F";
1138#else
1139 return "/%t/%T/%F/%t_%T_%F";
1140#endif
1141 }
1142 else if (option == "INDIHubAgent")
1143 {
1144#if defined(INDI_PREFIX)
1145 return QString(INDI_PREFIX "/bin/indihub-agent");
1146#elif defined(Q_OS_OSX)
1147 return "/usr/local/bin/indihub-agent";
1148#endif
1149 return prefix + "/bin/indihub-agent";
1150 }
1151 else if (option == "indiDriversDir")
1152 {
1153#if defined(INDI_PREFIX)
1154 return QString(INDI_PREFIX "/share/indi");
1155#elif defined(Q_OS_OSX)
1156 return "/usr/local/share/indi";
1157#elif defined(Q_OS_LINUX)
1158 return prefix + "/share/indi";
1159#else
1162#endif
1163 }
1164 else if (option == "AstrometrySolverBinary")
1165 {
1166#if defined(ASTROMETRY_PREFIX)
1167 return QString(ASTROMETRY_PREFIX "/bin/solve-field");
1168#elif defined(Q_OS_OSX)
1169 return "/usr/local/bin/solve-field";
1170#elif defined(Q_OS_WIN)
1171 return QDir::homePath() +
1172 "/AppData/Local/cygwin_ansvr/lib/astrometry/bin/solve-field.exe";
1173#endif
1174 return prefix + "/bin/solve-field";
1175 }
1176 else if (option == "WatneyBinary")
1177 {
1178#if defined(ASTROMETRY_PREFIX)
1179 return QString(ASTROMETRY_PREFIX "/opt/watney/watney-solve");
1180#elif defined(Q_OS_OSX)
1181 return "/usr/local/bin/watney-solve";
1182#elif defined(Q_OS_WIN)
1183 return "C:/watney/watney-solve.exe";
1184#endif
1185 return prefix + "/opt/watney/watney-solve";
1186 }
1187 else if (option == "SextractorBinary")
1188 {
1189#if defined(SEXTRACTOR_PREFIX)
1190 return QString(SEXTRACTOR_PREFIX "/bin/sextractor");
1191#elif defined(Q_OS_OSX)
1192 return "/usr/local/bin/sex";
1193#endif
1194 return prefix + "/bin/sextractor";
1195 }
1196 else if (option == "AstrometryWCSInfo")
1197 {
1198#if defined(ASTROMETRY_PREFIX)
1199 return QString(ASTROMETRY_PREFIX "/bin/wcsinfo");
1200#elif defined(Q_OS_OSX)
1201 return "/usr/local/bin/wcsinfo";
1202#elif defined(Q_OS_WIN)
1203 return QDir::homePath() +
1204 "/AppData/Local/cygwin_ansvr/lib/astrometry/bin/wcsinfo.exe";
1205#endif
1206 return prefix + "/bin/wcsinfo";
1207 }
1208 else if (option == "AstrometryConfFile")
1209 {
1210#if defined(ASTROMETRY_CONF_IN_PREFIX) && defined(ASTROMETRY_PREFIX)
1211 return QString(ASTROMETRY_PREFIX "/etc/astrometry.cfg");
1212#elif defined(Q_OS_OSX)
1213 return "/usr/local/etc/astrometry.cfg";
1214#elif defined(Q_OS_WIN)
1215 return QDir::homePath() +
1216 "/AppData/Local/cygwin_ansvr/etc/astrometry/backend.cfg";
1217#endif
1218 // We move /usr
1219 prefix.remove(userPrefix);
1220 return prefix + "/etc/astrometry.cfg";
1221 }
1222 else if (option == "AstrometryIndexFileLocation")
1223 {
1224#if defined(ASTROMETRY_PREFIX)
1225 return QString(ASTROMETRY_PREFIX "/share/astrometry");
1226#elif defined(Q_OS_OSX)
1228 .filePath("Astrometry/");
1229#endif
1230 return prefix + "/share/astrometry/";
1231 }
1232 else if (option == "AstrometryLogFilepath")
1233 {
1234 return QDir::tempPath() + "/astrometryLog.txt";
1235 }
1236 else if (option == "XplanetPath")
1237 {
1238#if defined(XPLANET_PREFIX)
1239 return QString(XPLANET_PREFIX "/bin/xplanet");
1240#elif defined(Q_OS_OSX)
1241 return "/usr/local/bin/xplanet";
1242#endif
1243 return prefix + "/bin/xplanet";
1244 }
1245 else if (option == "ASTAP")
1246 {
1247#if defined(Q_OS_OSX)
1248 return "/Applications/ASTAP.app/Contents/MacOS/astap";
1249#elif defined(Q_OS_WIN)
1250 return "C:/Program Files/astap/astap.exe";
1251#endif
1252 return "/opt/astap/astap";
1253 }
1254
1255 return QString();
1256}
1257
1258QStringList getAstrometryDefaultIndexFolderPaths()
1259{
1261 const QString confDir =
1262 QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
1263 .filePath(QLatin1String("astrometry"));
1265 // Check if directory already exists, if it doesn't create one
1267 if (writableDir.exists() == false)
1268 {
1269 if (writableDir.mkdir(confDir) == false)
1270 {
1271 qCCritical(KSTARS) << "Failed to create local astrometry directory";
1272 folderPaths.clear();
1273 }
1274 }
1275
1276#ifdef HAVE_STELLARSOLVER
1278#endif
1279 return folderPaths;
1280}
1281
1282#if defined(Q_OS_OSX)
1283//Note that this will copy and will not overwrite, so that the user's changes in the files are preserved.
1285{
1289 if (folder == "kstars")
1291 QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars")
1292 .absolutePath();
1293 else
1295 QDir(QCoreApplication::applicationDirPath() + "/../Resources/" + folder)
1296 .absolutePath();
1297 if (folderSourceDir.exists())
1298 {
1301 folder;
1305 }
1306}
1307
1308bool setupMacKStarsIfNeeded() // This method will return false if the KStars data directory doesn't exist when it's done
1309{
1310 //This will copy the locale folder, the notifications folder, and the sounds folder and any missing files in them to Application Support if needed.
1312 copyResourcesFolderFromAppBundle("knotifications5");
1314
1315 //This will copy the KStars data directory
1317 copyResourcesFolderFromAppBundle("kstars/xplanet");
1318
1319 if (Options::kStarsFirstRun())
1320 {
1321 //This sets some important OS X options.
1322 Options::setIndiServerIsInternal(true);
1323 Options::setIndiServer("*Internal INDI Server*");
1324 Options::setIndiDriversAreInternal(true);
1325 Options::setIndiDriversDir("*Internal INDI Drivers*");
1326 Options::setXplanetIsInternal(true);
1327 Options::setXplanetPath("*Internal XPlanet*");
1328 }
1329
1332 if (dataLocation.isEmpty()) //If there is no kstars user data directory
1333 return false;
1334
1335 return true;
1336}
1337
1339{
1340 QStringList astrometryDataDirs = getAstrometryDataDirs();
1341 if (astrometryDataDirs.count() == 0)
1342 return false;
1343 QString defaultAstrometryDataDir = getDefaultPath("AstrometryIndexFileLocation");
1344 if (astrometryDataDirs.contains("IndexFileLocationNotYetSet"))
1346 if (QDir(defaultAstrometryDataDir).exists() == false)
1347 {
1348 if (KMessageBox::warningYesNo(
1349 nullptr,
1350 i18n("The selected Astrometry Index File Location:\n %1 \n does not "
1351 "exist. Do you want to make the directory?",
1353 i18n("Make Astrometry Index File Directory?")) == KMessageBox::Yes)
1354 {
1356 {
1357 KSNotification::info(
1358 i18n("The Default Astrometry Index File Location was created."));
1359 }
1360 else
1361 {
1362 KSNotification::sorry(
1363 i18n("The Default Astrometry Index File Directory does not exist and "
1364 "was not able to be created."));
1365 }
1366 }
1367 else
1368 {
1369 return false;
1370 }
1371 }
1372
1373 return true;
1374}
1375
1377{
1378 QString confPath = KSUtils::getAstrometryConfFilePath();
1379
1381 QString contents;
1382 if (confFile.open(QIODevice::ReadOnly) == false)
1383 {
1384 KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1385 return false;
1386 }
1387 else
1388 {
1389 QByteArray fileContent = confFile.readAll();
1390 confFile.close();
1392 contents.replace("IndexFileLocationNotYetSet",
1393 getDefaultPath("AstrometryIndexFileLocation"));
1394
1395 if (confFile.open(QIODevice::WriteOnly) == false)
1396 {
1397 KSNotification::error(
1398 i18n("Internal Astrometry Configuration File Write Error."));
1399 return false;
1400 }
1401 else
1402 {
1404 out << contents;
1405 confFile.close();
1406 }
1407 }
1408 return true;
1409}
1410
1412{
1414
1415 if (!sourceDir.exists())
1416 return false;
1417
1419 if (!destDir.exists())
1420 destDir.mkdir(destFolder);
1421
1422 QStringList files = sourceDir.entryList(QDir::Files);
1423 for (int i = 0; i < files.count(); i++)
1424 {
1426 QString destName = destFolder + QDir::separator() + files[i];
1427 QFile::copy(srcName, destName); //Note this does not overwrite files
1428 }
1429
1430 files.clear();
1431 files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
1432 for (int i = 0; i < files.count(); i++)
1433 {
1435 QString destName = destFolder + QDir::separator() + files[i];
1437 }
1438
1439 return true;
1440}
1441#endif
1442
1443QString getAstrometryConfFilePath()
1444{
1445 return Options::astrometryConfFile();
1446}
1447
1448QStringList getAstrometryDataDirs()
1449{
1450 QStringList optionsDataDirs = Options::astrometryIndexFolderList();
1451
1452 bool updated = false;
1453
1454 // Cleaning up the list of directories in options.
1455 for (int dir = 0; dir < optionsDataDirs.count(); dir++)
1456 {
1459 if (optionsDataDir.exists())
1460 {
1461 //This will replace directory names that aren't the absolute path
1462 if (optionsDataDir.absolutePath() != optionsDataDirName)
1463 {
1464 optionsDataDirs.replace(dir, optionsDataDir.absolutePath());
1465 updated = true;
1466 }
1467 }
1468 else
1469 {
1470 //This removes directories that do not exist from the list.
1471 optionsDataDirs.removeAt(dir);
1472 dir--;
1473 updated = true;
1474 }
1475 }
1476
1477 //This will load the conf file if it exists
1478 QFile confFile(KSUtils::getAstrometryConfFilePath());
1479 if (confFile.open(QIODevice::ReadOnly))
1480 {
1482 QTextStream in(&confFile);
1483 QString line;
1484
1485 //This will find the index file paths in the conf file
1486 while (!in.atEnd())
1487 {
1488 line = in.readLine();
1489 if (line.isEmpty() || line.startsWith('#'))
1490 continue;
1491
1492 line = line.trimmed();
1493 if (line.startsWith(QLatin1String("add_path")))
1494 {
1495 confDataDirs << line.mid(9).trimmed();
1496 }
1497 }
1498
1499 //This will search through the paths and compare them to the index folder list
1500 //It will add them if they aren't in there.
1502 {
1504 //This rejects any that do not exist
1505 if (!astrometryDataDir.exists())
1506 continue;
1509 {
1511 updated = true;
1512 }
1513 }
1514 }
1515
1516 //This will remove any duplicate entries.
1517 if (optionsDataDirs.removeDuplicates() != 0)
1518 updated = true;
1519
1520 //This updates the list in Options if it changed.
1521 if (updated)
1522 Options::setAstrometryIndexFolderList(optionsDataDirs);
1523
1524 return optionsDataDirs;
1525}
1526
1527bool addAstrometryDataDir(const QString &dataDir)
1528{
1529 //This will need to be fixed!
1530 //if(Options::astrometryIndexFileLocation() != dataDir)
1531 // Options::setAstrometryIndexFileLocation(dataDir);
1532
1533 QString confPath = KSUtils::getAstrometryConfFilePath();
1534 QStringList astrometryDataDirs = getAstrometryDataDirs();
1535
1537 QString contents;
1538 if (confFile.open(QIODevice::ReadOnly) == false)
1539 {
1540 KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1541 return false;
1542 }
1543 else
1544 {
1545 QTextStream in(&confFile);
1546 QString line;
1547 bool foundSpot = false;
1548 while (!in.atEnd())
1549 {
1550 line = in.readLine();
1551
1552 if (line.trimmed().startsWith(QLatin1String("add_path")))
1553 {
1554 if (!foundSpot)
1555 {
1556 foundSpot = true;
1558 contents += "add_path " + astrometryDataDir + '\n';
1559 contents += "add_path " + dataDir + '\n';
1560 }
1561 else
1562 {
1563 //Do not keep adding the other add_paths because they just got added in the seciton above.
1564 }
1565 }
1566 else
1567 {
1568 contents += line + '\n';
1569 }
1570 }
1571 if (!foundSpot)
1572 {
1574 contents += "add_path " + astrometryDataDir + '\n';
1575 contents += "add_path " + dataDir + '\n';
1576 }
1577
1578 confFile.close();
1579
1580 if (confFile.open(QIODevice::WriteOnly) == false)
1581 {
1582 KSNotification::error(
1583 i18n("Internal Astrometry Configuration File Write Error."));
1584 return false;
1585 }
1586 else
1587 {
1589 out << contents;
1590 confFile.close();
1591 }
1592 }
1593 return true;
1594}
1595
1596bool removeAstrometryDataDir(const QString &dataDir)
1597{
1598 QString confPath = KSUtils::getAstrometryConfFilePath();
1599 QStringList astrometryDataDirs = getAstrometryDataDirs();
1600
1602 QString contents;
1603 if (confFile.open(QIODevice::ReadOnly) == false)
1604 {
1605 KSNotification::error(i18n("Astrometry Configuration File Read Error."));
1606 return false;
1607 }
1608 else
1609 {
1610 QTextStream in(&confFile);
1611 QString line;
1612 while (!in.atEnd())
1613 {
1614 line = in.readLine();
1615 if (line.mid(9).trimmed() != dataDir)
1616 {
1617 contents += line + '\n';
1618 }
1619 }
1620 confFile.close();
1621
1622 if (confFile.open(QIODevice::WriteOnly) == false)
1623 {
1624 KSNotification::error(
1625 i18n("Internal Astrometry Configuration File Write Error."));
1626 return false;
1627 }
1628 else
1629 {
1631 out << contents;
1632 confFile.close();
1633 }
1634 }
1635 return true;
1636}
1637
1638QByteArray getJPLQueryString(const QByteArray &kind, const QByteArray &dataFields,
1639 const QVector<JPLFilter> &filters)
1640{
1641 /* For example:
1642 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
1643 */
1644
1645 QByteArray query("sb-kind=" + kind + "&full-prec=true");
1646
1647 // Apply filters:
1648 if (filters.size() > 0)
1649 {
1650 QByteArray filter_string("{\"AND\":[");
1651 for (const auto &item : filters)
1652 {
1653 filter_string += "\"" + item.item + "|" + item.op + "|" + item.value + "\",";
1654 }
1655
1656 filter_string.chop(1);
1657 filter_string += "]}";
1658
1659 query += "&sb-cdata=" + filter_string;
1660 }
1661
1662 // Apply query data fields...
1663 query += "&fields=" + dataFields;
1664
1665 return query;
1666}
1667
1668bool RAWToJPEG(const QString &rawImage, const QString &output, QString &errorMessage)
1669{
1670#ifndef HAVE_LIBRAW
1671 errorMessage = i18n("Unable to find dcraw and cjpeg. Please install the required "
1672 "tools to convert CR2/NEF to JPEG.");
1673 return false;
1674#else
1675 int ret = 0;
1676 // Creation of image processing object
1678
1679 // Let us open the file
1680 if ((ret = RawProcessor.open_file(rawImage.toLatin1().data())) != LIBRAW_SUCCESS)
1681 {
1682 errorMessage = i18n("Cannot open %1: %2", rawImage, libraw_strerror(ret));
1683 RawProcessor.recycle();
1684 return false;
1685 }
1686
1687 // Let us unpack the thumbnail
1688 if ((ret = RawProcessor.unpack_thumb()) != LIBRAW_SUCCESS)
1689 {
1690 errorMessage = i18n("Cannot unpack_thumb %1: %2", rawImage, libraw_strerror(ret));
1691 RawProcessor.recycle();
1692 return false;
1693 }
1694 else
1695 // We have successfully unpacked the thumbnail, now let us write it to a file
1696 {
1697 //snprintf(thumbfn,sizeof(thumbfn),"%s.%s",av[i],T.tformat == LIBRAW_THUMBNAIL_JPEG ? "thumb.jpg" : "thumb.ppm");
1698 if (LIBRAW_SUCCESS !=
1699 (ret = RawProcessor.dcraw_thumb_writer(output.toLatin1().data())))
1700 {
1701 errorMessage = i18n("Cannot write %s %1: %2", output, libraw_strerror(ret));
1702 RawProcessor.recycle();
1703 return false;
1704 }
1705 }
1706 return true;
1707#endif
1708}
1709
1710double getAvailableRAM()
1711{
1712#if defined(Q_OS_OSX)
1713 int mib[] = { CTL_HW, HW_MEMSIZE };
1714 size_t length;
1715 length = sizeof(int64_t);
1716 int64_t RAMcheck;
1717 if (sysctl(mib, 2, &RAMcheck, &length, NULL, 0))
1718 return false; // On Error
1719 //Until I can figure out how to get free RAM on Mac
1720 return RAMcheck;
1721#elif defined(Q_OS_LINUX)
1722 QProcess p;
1723 p.start("awk", QStringList() << "/MemAvailable/ { print $2 }"
1724 << "/proc/meminfo");
1725 p.waitForFinished();
1727 p.close();
1728 //kB to bytes
1729 return (memory.toLong() * 1024.0);
1730#elif defined(Q_OS_WIN32)
1733 memory_status.dwLength = sizeof(MEMORYSTATUSEX);
1735 {
1736 return memory_status.ullAvailPhys;
1737 }
1738 else
1739 {
1740 return 0;
1741 }
1742#endif
1743 return 0;
1744}
1745
1746JPLParser::JPLParser(const QString &path)
1747{
1748 QFile jpl_file(path);
1749 if (!jpl_file.open(QIODevice::ReadOnly))
1750 {
1751 throw std::runtime_error("Could not open file.");
1752 }
1753
1754 const auto &ast_json = QJsonDocument::fromJson(jpl_file.readAll());
1755 const auto &fields = ast_json["fields"].toArray();
1756 m_data = ast_json["data"].toArray();
1757
1758 {
1759 int i = 0;
1760 for (const auto &field : fields)
1761 {
1762 m_field_map[field.toString()] = i++;
1763 }
1764 }
1765}
1766
1767MPCParser::MPCParser(const QString &path)
1768{
1769 QFile mpc_file(path);
1770 if (!mpc_file.open(QIODevice::ReadOnly))
1771 {
1772 throw std::runtime_error("Could not open file.");
1773 }
1774
1775 gzFile file = gzopen(path.toLatin1().constData(), "r");
1776 if (file)
1777 {
1778
1779 QByteArray data;
1780 const uint32_t len = 32768;
1781
1782 while (!gzeof(file))
1783 {
1784 char buffer[len] = {0};
1785 int bytes_read = gzread(file, buffer, len - 1);
1786 if (bytes_read < 0)
1787 break;
1788 buffer[bytes_read] = 0;
1789 data.append(buffer);
1790 }
1791
1792 gzclose(file);
1793 const auto &ast_json = QJsonDocument::fromJson(data);
1794 m_data = ast_json.array();
1795 }
1796 else
1797 qCritical(KSTARS) << "Failed to read MPC comets data file" << path;
1798}
1799
1800void setGlobalSettings(const QVariantMap &settings)
1801{
1802 for (auto &key : settings.keys())
1803 {
1804 auto property = key;
1805 // Anything starting with kcfg_ must be processed to remove the
1806 // prefix and ensure first letter is lower case.
1807 if (property.startsWith("kcfg_"))
1808 {
1809 property.remove("kcfg_");
1810 property.replace(0, 1, property.at(0).toLower());
1811 }
1812 Options::self()->setProperty(property.toLatin1(), settings[key]);
1813 }
1814
1815 Options::self()->save();
1816}
1817
1818QString sanitize(const QString &text)
1819{
1820 static const QRegularExpression re1("\\s|/|\\(|\\)|:|\\*|\\+|~|\"" );
1821 static const QRegularExpression re2("_{2,}");
1822 static const QRegularExpression re3("_$");
1823
1824 QString sanitized = text;
1825 if (sanitized != i18n("unnamed"))
1826 {
1827 // Remove illegal characters that can be problematic
1828 sanitized = sanitized.replace(re1, "_" )
1829 // Remove any two or more __
1830 .replace( re2, "_")
1831 // Remove any _ at the end
1832 .replace( re3, "");
1833 }
1834 return sanitized;
1835}
1836
1837double rangePA(double pa)
1838{
1839 while (pa > 180)
1840 pa -= 360;
1841 while (pa < -180)
1842 pa += 360;
1843 return pa;
1844}
1845
1846double range360(double r)
1847{
1848 double res = r;
1849 while (res < 0.00)
1850 res += 360.00;
1851 while (res > 359.99) // uniqueness of angle (360 = 0)
1852 res -= 360.00;
1853 return res;
1854}
1855
1856double rotationToPositionAngle(double value)
1857{
1858 double pa = value + 180;
1859 while (pa > 180)
1860 pa -= 360;
1861 while (pa < -180)
1862 pa += 360;
1863 return pa;
1864}
1865
1866double positionAngleToRotation(double value)
1867{
1868 double rotation = value - 180;
1869 while (rotation > 180)
1870 rotation -= 360;
1871 while (rotation < -180)
1872 rotation += 360;
1873 return rotation;
1874}
1875
1876
1877} // namespace KSUtils
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
static void UseDefault()
Use the default logging mechanism.
Definition ksutils.cpp:1024
static void UseStdout()
Output logs to stdout.
Definition ksutils.cpp:963
static void SyncFilterRules()
SyncFilterRules Sync QtLogging filter rules from Options.
Definition ksutils.cpp:1036
static void Disable()
Disable logging.
Definition ksutils.cpp:1029
static void UseFile()
Store all logs into the specified file.
Definition ksutils.cpp:927
static void UseStderr()
Output logs to stderr.
Definition ksutils.cpp:979
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
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
QString i18nc(const char *context, const char *text, const TYPE &arg...)
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
QString filePath(const QString &fileName) const const
QString homePath()
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 clear()
qsizetype count() 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 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
QString trimmed() const const
QTextStream & dec(QTextStream &stream)
void flush()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:01 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.