• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 9988041738

16 Jul 2024 07:40AM UTC coverage: 12.142%. Remained the same
9988041738

push

github

alex-w
Removed unused code

0 of 1 new or added line in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

14432 of 118861 relevant lines covered (12.14%)

18837.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/modules/StarMgr.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2002 Fabien Chereau
4
 *
5
 * The big star catalogue extension to Stellarium:
6
 * Author and Copyright: Johannes Gajdosik, 2006
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
21
 */
22

23

24
#include "StelProjector.hpp"
25
#include "StarMgr.hpp"
26
#include "StelObject.hpp"
27
#include "StelTexture.hpp"
28

29
#include "StelTranslator.hpp"
30
#include "StelGeodesicGrid.hpp"
31
#include "StelApp.hpp"
32
#include "StelTextureMgr.hpp"
33
#include "StelObjectMgr.hpp"
34
#include "StelLocaleMgr.hpp"
35
#include "StelSkyCultureMgr.hpp"
36
#include "StelFileMgr.hpp"
37
#include "StelModuleMgr.hpp"
38
#include "StelCore.hpp"
39
#include "StelPainter.hpp"
40
#include "StelJsonParser.hpp"
41
#include "ZoneArray.hpp"
42
#include "StelSkyDrawer.hpp"
43
#include "StelModuleMgr.hpp"
44
#include "ConstellationMgr.hpp"
45
#include "Planet.hpp"
46
#include "StelUtils.hpp"
47

48
#include <QTextStream>
49
#include <QFile>
50
#include <QSettings>
51
#include <QString>
52
#include <QRegularExpression>
53
#include <QDebug>
54
#include <QFileInfo>
55
#include <QDir>
56
#include <QCryptographicHash>
57

58
#include <cstdlib>
59

60
static QStringList spectral_array;
61
static QStringList component_array;
62

63
// This number must be incremented each time the content or file format of the stars catalogs change
64
// It can also be incremented when the defaultStarsConfig.json file change.
65
// It should always match the version field of the defaultStarsConfig.json file
66
static const int StarCatalogFormatVersion = 12;
67

68
// Initialise statics
69
bool StarMgr::flagSciNames = true;
70
bool StarMgr::flagAdditionalStarNames = true;
71
bool StarMgr::flagDesignations = false;
72
bool StarMgr::flagDblStarsDesignation = false;
73
bool StarMgr::flagVarStarsDesignation = false;
74
bool StarMgr::flagHIPDesignation = false;
75
QHash<int,QString> StarMgr::commonNamesMap;
76
QHash<int,QString> StarMgr::commonNamesMapI18n;
77
QHash<int,QString> StarMgr::additionalNamesMap;
78
QHash<int,QString> StarMgr::additionalNamesMapI18n;
79
QMap<QString,int> StarMgr::commonNamesIndexI18n;
80
QMap<QString,int> StarMgr::commonNamesIndex;
81
QMap<QString,int> StarMgr::additionalNamesIndex;
82
QMap<QString,int> StarMgr::additionalNamesIndexI18n;
83
QHash<int,QString> StarMgr::sciDesignationsMapI18n;
84
QMap<QString,int> StarMgr::sciDesignationsIndexI18n;
85
QHash<int,QString> StarMgr::sciExtraDesignationsMapI18n;
86
QMap<QString,int> StarMgr::sciExtraDesignationsIndexI18n;
87
QHash<int, varstar> StarMgr::varStarsMapI18n;
88
QMap<QString, int> StarMgr::varStarsIndexI18n;
89
QHash<int, wds> StarMgr::wdsStarsMapI18n;
90
QMap<QString, int> StarMgr::wdsStarsIndexI18n;
91
QMap<QString, crossid> StarMgr::crossIdMap;
92
QMap<int, int> StarMgr::saoStarsIndex;
93
QMap<int, int> StarMgr::hdStarsIndex;
94
QMap<int, int> StarMgr::hrStarsIndex;
95
QHash<int, QString> StarMgr::referenceMap;
96
QHash<int, float> StarMgr::hipParallaxErrors;
97
QHash<int, PMData> StarMgr::hipPMData;
98

99
QStringList initStringListFromFile(const QString& file_name)
×
100
{
101
        QStringList list;
×
102
        QFile f(file_name);
×
103
        if (f.open(QIODevice::ReadOnly | QIODevice::Text))
×
104
        {
105
                while (!f.atEnd())
×
106
                {
107
                        QString s = QString::fromUtf8(f.readLine());
×
108
                        s.chop(1);
×
109
                        list << s;
×
110
                }
×
111
                f.close();
×
112
        }
113
        return list;
×
114
}
×
115

116
QString StarMgr::convertToSpectralType(int index)
×
117
{
118
        if (index < 0 || index >= spectral_array.size())
×
119
        {
120
                qDebug() << "convertToSpectralType: bad index: " << index << ", max: " << spectral_array.size();
×
121
                return "";
×
122
        }
123
        return spectral_array.at(index);
×
124
}
125

126
QString StarMgr::convertToComponentIds(int index)
×
127
{
128
        if (index < 0 || index >= component_array.size())
×
129
        {
130
                qDebug() << "convertToComponentIds: bad index: " << index << ", max: " << component_array.size();
×
131
                return "";
×
132
        }
133
        return component_array.at(index);
×
134
}
135

136

137
void StarMgr::initTriangle(int lev,int index, const Vec3f &c0, const Vec3f &c1, const Vec3f &c2)
×
138
{
139
        gridLevels[lev]->initTriangle(index,c0,c1,c2);
×
140
}
×
141

142

143
StarMgr::StarMgr(void)
×
144
        : StelObjectModule()
145
        , flagStarName(false)
×
146
        , labelsAmount(0.)
×
147
        , gravityLabel(false)
×
148
        , maxGeodesicGridLevel(-1)
×
149
        , lastMaxSearchLevel(-1)
×
150
        , hipIndex(new HipIndexStruct[NR_OF_HIP+1])
×
151
{
152
        setObjectName("StarMgr");
×
153
        objectMgr = GETSTELMODULE(StelObjectMgr);
×
154
        Q_ASSERT(objectMgr);
×
155
}
×
156

157
/*************************************************************************
158
 Reimplementation of the getCallOrder method
159
*************************************************************************/
160
double StarMgr::getCallOrder(StelModuleActionName actionName) const
×
161
{
162
        if (actionName==StelModule::ActionDraw)
×
163
                return StelApp::getInstance().getModuleMgr().getModule("ConstellationMgr")->getCallOrder(actionName)+10;
×
164
        return 0;
×
165
}
166

167

168
StarMgr::~StarMgr(void)
×
169
{
170
        for (auto* z : std::as_const(gridLevels))
×
171
                delete z;
×
172
        gridLevels.clear();
×
173
        if (hipIndex)
×
174
                delete[] hipIndex;
×
175
}
×
176

177
// Allow untranslated name here if set in constellationMgr!
178
QString StarMgr::getCommonName(int hip)
×
179
{
180
        ConstellationMgr* cmgr=GETSTELMODULE(ConstellationMgr);
×
181
        if (cmgr->getConstellationDisplayStyle() == ConstellationMgr::constellationsNative)
×
182
                return getCommonEnglishName(hip);
×
183

184
        auto it = commonNamesMapI18n.find(hip);
×
185
        if (it!=commonNamesMapI18n.end())
×
186
                return it.value();
×
187
        return QString();
×
188
}
189

190
QString StarMgr::getAdditionalNames(int hip)
×
191
{
192
        auto it = additionalNamesMapI18n.find(hip);
×
193
        if (it!=additionalNamesMapI18n.end())
×
194
                return it.value();
×
195
        return QString();
×
196
}
197

198
QString StarMgr::getAdditionalEnglishNames(int hip)
×
199
{
200
        auto it = additionalNamesMap.find(hip);
×
201
        if (it!=additionalNamesMap.end())
×
202
                return it.value();
×
203
        return QString();
×
204
}
205

206
QString StarMgr::getCommonEnglishName(int hip)
×
207
{
208
        auto it = commonNamesMap.find(hip);
×
209
        if (it!=commonNamesMap.end())
×
210
                return it.value();
×
211
        return QString();
×
212
}
213

214

215
QString StarMgr::getSciName(int hip)
×
216
{
217
        auto it = sciDesignationsMapI18n.find(hip);
×
218
        if (it!=sciDesignationsMapI18n.end())
×
219
                return it.value();
×
220
        return QString();
×
221
}
222

223
QString StarMgr::getSciExtraName(int hip)
×
224
{
225
        auto it = sciExtraDesignationsMapI18n.find(hip);
×
226
        if (it!=sciExtraDesignationsMapI18n.end())
×
227
                return it.value();
×
228
        return QString();
×
229
}
230

231
QString StarMgr::getCrossIdentificationDesignations(QString hip)
×
232
{
233
        QStringList designations;
×
234
        auto cr = crossIdMap.find(hip);
×
235
        if (cr==crossIdMap.end() && hip.right(1).toUInt()==0)
×
236
                cr = crossIdMap.find(hip.left(hip.size()-1));
×
237

238
        if (cr!=crossIdMap.end())
×
239
        {
240
                crossid crossIdData = cr.value();
×
241
                if (crossIdData.hr>0)
×
242
                        designations << QString("HR %1").arg(crossIdData.hr);
×
243

244
                if (crossIdData.hd>0)
×
245
                        designations << QString("HD %1").arg(crossIdData.hd);
×
246

247
                if (crossIdData.sao>0)
×
248
                        designations << QString("SAO %1").arg(crossIdData.sao);
×
249
        }
250

251
        return designations.join(" - ");
×
252
}
×
253

254
QString StarMgr::getWdsName(int hip)
×
255
{
256
        auto it = wdsStarsMapI18n.find(hip);
×
257
        if (it!=wdsStarsMapI18n.end())
×
258
                return QString("WDS J%1").arg(it.value().designation);
×
259
        return QString();
×
260
}
261

262
int StarMgr::getWdsLastObservation(int hip)
×
263
{
264
        auto it = wdsStarsMapI18n.find(hip);
×
265
        if (it!=wdsStarsMapI18n.end())
×
266
                return it.value().observation;
×
267
        return 0;
×
268
}
269

270
float StarMgr::getWdsLastPositionAngle(int hip)
×
271
{
272
        auto it = wdsStarsMapI18n.find(hip);
×
273
        if (it!=wdsStarsMapI18n.end())
×
274
                return it.value().positionAngle;
×
275
        return 0;
×
276
}
277

278
float StarMgr::getWdsLastSeparation(int hip)
×
279
{
280
        auto it = wdsStarsMapI18n.find(hip);
×
281
        if (it!=wdsStarsMapI18n.end())
×
282
                return it.value().separation;
×
283
        return 0.f;
×
284
}
285

286
QString StarMgr::getGcvsName(int hip)
×
287
{
288
        auto it = varStarsMapI18n.find(hip);
×
289
        if (it!=varStarsMapI18n.end())
×
290
                return it.value().designation;
×
291
        return QString();
×
292
}
293

294
QString StarMgr::getGcvsVariabilityType(int hip)
×
295
{
296
        auto it = varStarsMapI18n.find(hip);
×
297
        if (it!=varStarsMapI18n.end())
×
298
                return it.value().vtype;
×
299
        return QString();
×
300
}
301

302
float StarMgr::getGcvsMaxMagnitude(int hip)
×
303
{
304
        auto it = varStarsMapI18n.find(hip);
×
305
        if (it!=varStarsMapI18n.end())
×
306
                return it.value().maxmag;
×
307
        return -99.f;
×
308
}
309

310
int StarMgr::getGcvsMagnitudeFlag(int hip)
×
311
{
312
        auto it = varStarsMapI18n.find(hip);
×
313
        if (it!=varStarsMapI18n.end())
×
314
                return it.value().mflag;
×
315
        return 0;
×
316
}
317

318

319
float StarMgr::getGcvsMinMagnitude(int hip, bool firstMinimumFlag)
×
320
{
321
        auto it = varStarsMapI18n.find(hip);
×
322
        if (it!=varStarsMapI18n.end())
×
323
        {
324
                if (firstMinimumFlag)
×
325
                {
326
                        return it.value().min1mag;
×
327
                }
328
                else
329
                {
330
                        return it.value().min2mag;
×
331
                }
332
        }
333
        return -99.f;
×
334
}
335

336
QString StarMgr::getGcvsPhotometricSystem(int hip)
×
337
{
338
        auto it = varStarsMapI18n.find(hip);
×
339
        if (it!=varStarsMapI18n.end())
×
340
                return it.value().photosys;
×
341
        return QString();
×
342
}
343

344
double StarMgr::getGcvsEpoch(int hip)
×
345
{
346
        auto it = varStarsMapI18n.find(hip);
×
347
        if (it!=varStarsMapI18n.end())
×
348
                return it.value().epoch;
×
349
        return -99.;
×
350
}
351

352
double StarMgr::getGcvsPeriod(int hip)
×
353
{
354
        auto it = varStarsMapI18n.find(hip);
×
355
        if (it!=varStarsMapI18n.end())
×
356
                return it.value().period;
×
357
        return -99.;
×
358
}
359

360
int StarMgr::getGcvsMM(int hip)
×
361
{
362
        auto it = varStarsMapI18n.find(hip);
×
363
        if (it!=varStarsMapI18n.end())
×
364
                return it.value().Mm;
×
365
        return -99;
×
366
}
367

368
float StarMgr::getPlxError(int hip)
×
369
{
370
        auto it = hipParallaxErrors.find(hip);
×
371
        if (it!=hipParallaxErrors.end())
×
372
                return it.value();
×
373
        return 0.f;
×
374
}
375

376
PMData StarMgr::getProperMotion(int hip)
×
377
{
378
        auto it = hipPMData.find(hip);
×
379
        if (it!=hipPMData.end())
×
380
                return it.value();
×
381
        return QPair<float, float>(NAN, NAN);
×
382
}
383

384
void StarMgr::copyDefaultConfigFile()
×
385
{
386
        try
387
        {
388
                StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::getUserDir()+"/stars/default");
×
389
                starConfigFileFullPath = StelFileMgr::getUserDir()+"/stars/default/starsConfig.json";
×
390
                qDebug() << "Creates file " << QDir::toNativeSeparators(starConfigFileFullPath);
×
391
                QFile::copy(StelFileMgr::getInstallationDir()+"/stars/default/defaultStarsConfig.json", starConfigFileFullPath);
×
392
                QFile::setPermissions(starConfigFileFullPath, QFile::permissions(starConfigFileFullPath) | QFileDevice::WriteOwner);
×
393
        }
394
        catch (std::runtime_error& e)
×
395
        {
396
                qWarning() << e.what();
×
397
                qFatal("Could not create configuration file stars/default/starsConfig.json");
×
398
        }
×
399
}
×
400

401
void StarMgr::init()
×
402
{
403
        QSettings* conf = StelApp::getInstance().getSettings();
×
404
        Q_ASSERT(conf);
×
405

406
        starConfigFileFullPath = StelFileMgr::findFile("stars/default/starsConfig.json", StelFileMgr::Flags(StelFileMgr::Writable|StelFileMgr::File));
×
407
        if (starConfigFileFullPath.isEmpty())
×
408
        {
409
                qWarning() << "Could not find the starsConfig.json file: will copy the default one.";
×
410
                copyDefaultConfigFile();
×
411
        }
412

413
        QFile fic(starConfigFileFullPath);
×
414
        if(fic.open(QIODevice::ReadOnly))
×
415
        {
416
                starSettings = StelJsonParser::parse(&fic).toMap();
×
417
                fic.close();
×
418
        }
419

420
        // Increment the 1 each time any star catalog file change
421
        if (starSettings.value("version").toInt()!=StarCatalogFormatVersion)
×
422
        {
423
                qWarning() << "Found an old starsConfig.json file, upgrade..";
×
424
                fic.remove();
×
425
                copyDefaultConfigFile();
×
426
                QFile fic2(starConfigFileFullPath);
×
427
                if(fic2.open(QIODevice::ReadOnly))
×
428
                {
429
                        starSettings = StelJsonParser::parse(&fic2).toMap();
×
430
                        fic2.close();
×
431
                }
432
        }
×
433

434
        loadData(starSettings);
×
435

436
        populateStarsDesignations();
×
437
        populateHipparcosLists();
×
438

439
        setFontSize(StelApp::getInstance().getScreenFontSize());
×
440
        connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSize(int)));
×
441

442
        setFlagStars(conf->value("astro/flag_stars", true).toBool());
×
443
        setFlagLabels(conf->value("astro/flag_star_name",true).toBool());
×
444
        setFlagAdditionalNames(conf->value("astro/flag_star_additional_names",true).toBool());
×
445
        setDesignationUsage(conf->value("astro/flag_star_designation_usage", false).toBool());
×
446
        setFlagDblStarsDesignation(conf->value("astro/flag_star_designation_dbl", false).toBool());
×
447
        setFlagVarStarsDesignation(conf->value("astro/flag_star_designation_var", false).toBool());
×
448
        setFlagHIPDesignation(conf->value("astro/flag_star_designation_hip", false).toBool());
×
449
        setLabelsAmount(conf->value("stars/labels_amount",3.).toDouble());
×
450

451
        objectMgr->registerStelObjectMgr(this);
×
452
        texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur2.png");   // Load pointer texture
×
453

454
        StelApp::getInstance().getCore()->getGeodesicGrid(maxGeodesicGridLevel)->visitTriangles(maxGeodesicGridLevel,initTriangleFunc,this);
×
455
        for (auto* z : std::as_const(gridLevels))
×
456
                z->scaleAxis();
×
457
        StelApp *app = &StelApp::getInstance();
×
458
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
459
        connect(&app->getSkyCultureMgr(), &StelSkyCultureMgr::currentSkyCultureIDChanged, this, &StarMgr::updateSkyCulture);
×
460

461
        QString displayGroup = N_("Display Options");
×
462
        addAction("actionShow_Stars", displayGroup, N_("Stars"), "flagStarsDisplayed", "S");
×
463
        addAction("actionShow_Stars_Labels", displayGroup, N_("Stars labels"), "flagLabelsDisplayed", "Alt+S");
×
464
        // Details: https://github.com/Stellarium/stellarium/issues/174
465
        addAction("actionShow_Stars_MagnitudeLimitIncrease", displayGroup, N_("Increase the magnitude limit for stars"), "increaseStarsMagnitudeLimit()");
×
466
        addAction("actionShow_Stars_MagnitudeLimitReduce", displayGroup, N_("Reduce the magnitude limit for stars"), "reduceStarsMagnitudeLimit()");
×
467
}
×
468

469

470
void StarMgr::drawPointer(StelPainter& sPainter, const StelCore* core)
×
471
{
472
        const QList<StelObjectP> newSelected = objectMgr->getSelectedObject("Star");
×
473
        if (!newSelected.empty())
×
474
        {
475
                const StelObjectP obj = newSelected[0];
×
476
                Vec3d pos=obj->getJ2000EquatorialPos(core);
×
477

478
                Vec3f screenpos;
×
479
                // Compute 2D pos and return if outside screen
480
                if (!sPainter.getProjector()->project(pos, screenpos))
×
481
                        return;
×
482

483
                sPainter.setColor(obj->getInfoColor());
×
484
                texPointer->bind();
×
485
                sPainter.setBlending(true);
×
486
                sPainter.drawSprite2dMode(screenpos[0], screenpos[1], 13.f, static_cast<float>(StelApp::getInstance().getAnimationTime())*40.f);
×
487
        }
×
488
}
×
489

490
bool StarMgr::checkAndLoadCatalog(const QVariantMap& catDesc)
×
491
{
492
        const bool checked = catDesc.value("checked").toBool();
×
493
        QString catalogFileName = catDesc.value("fileName").toString();
×
494

495
        // See if it is an absolute path, else prepend default path
496
        if (!(StelFileMgr::isAbsolute(catalogFileName)))
×
497
                catalogFileName = "stars/default/"+catalogFileName;
×
498

499
        QString catalogFilePath = StelFileMgr::findFile(catalogFileName);
×
500
        if (catalogFilePath.isEmpty())
×
501
        {
502
                // The file is supposed to be checked, but we can't find it
503
                if (checked)
×
504
                {
505
                        qWarning() << QString("Warning: could not find star catalog %1").arg(QDir::toNativeSeparators(catalogFileName));
×
506
                        setCheckFlag(catDesc.value("id").toString(), false);
×
507
                }
508
                return false;
×
509
        }
510
        // Possibly fixes crash on Vista
511
        if (!StelFileMgr::isReadable(catalogFilePath))
×
512
        {
513
                qWarning() << QString("Warning: User does not have permissions to read catalog %1").arg(QDir::toNativeSeparators(catalogFilePath));
×
514
                return false;
×
515
        }
516

517
        if (!checked)
×
518
        {
519
                // The file is not checked but we found it, maybe from a previous download/version
520
                qWarning().noquote() << "Found file" << QDir::toNativeSeparators(catalogFilePath) << ", checking md5sum...";
×
521

522
                QFile file(catalogFilePath);
×
523
                if(file.open(QIODevice::ReadOnly | QIODevice::Unbuffered))
×
524
                {
525
                        // Compute the MD5 sum
526
                        QCryptographicHash md5Hash(QCryptographicHash::Md5);
×
527
                        const qint64 cat_sz = file.size();
×
528
                        qint64 maxStarBufMd5 = qMin(cat_sz, 9223372036854775807LL);
×
529
                        uchar *cat = maxStarBufMd5 ? file.map(0, maxStarBufMd5) : Q_NULLPTR;
×
530
                        if (!cat)
×
531
                        {
532
                                // The OS was not able to map the file, revert to slower not mmap based method
533
                                static const qint64 maxStarBufMd5 = 1024*1024*8;
534
                                char* mmd5buf = static_cast<char*>(malloc(maxStarBufMd5));
×
535
                                while (!file.atEnd())
×
536
                                {
537
                                        qint64 sz = file.read(mmd5buf, maxStarBufMd5);
×
538
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
539
                                        md5Hash.addData(QByteArrayView(mmd5buf, static_cast<int>(sz)));
540
#else
541
                                        md5Hash.addData(mmd5buf, static_cast<int>(sz));
×
542
#endif
543
                                }
544
                                free(mmd5buf);
×
545
                        }
546
                        else
547
                        {
548
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
549
                                md5Hash.addData(QByteArrayView(reinterpret_cast<const char*>(cat), static_cast<int>(cat_sz)));
550
#else
551
                                md5Hash.addData(reinterpret_cast<const char*>(cat), static_cast<int>(cat_sz));
×
552
#endif
553
                                file.unmap(cat);
×
554
                        }
555
                        file.close();
×
556
                        if (md5Hash.result().toHex()!=catDesc.value("checksum").toByteArray())
×
557
                        {
558
                                qWarning().noquote() << "Error: File" << QDir::toNativeSeparators(catalogFileName) << "is corrupt, MD5 mismatch! Found" << md5Hash.result().toHex() << "expected" << catDesc.value("checksum").toByteArray();
×
559
                                file.remove();
×
560
                                return false;
×
561
                        }
562
                        qWarning() << "MD5 sum correct!";
×
563
                        setCheckFlag(catDesc.value("id").toString(), true);
×
564
                }
×
565
        }
×
566

567
        ZoneArray* z = ZoneArray::create(catalogFilePath, true);
×
568
        if (z)
×
569
        {
570
                if (z->level<gridLevels.size())
×
571
                {
572
                        qWarning().noquote() << QDir::toNativeSeparators(catalogFileName) << ", " << z->level << ": duplicate level";
×
573
                        delete z;
×
574
                        return true;
×
575
                }
576
                Q_ASSERT(z->level==maxGeodesicGridLevel+1);
×
577
                Q_ASSERT(z->level==gridLevels.size());
×
578
                ++maxGeodesicGridLevel;
×
579
                gridLevels.append(z);
×
580
        }
581
        return true;
×
582
}
×
583

584
void StarMgr::setCheckFlag(const QString& catId, bool b)
×
585
{
586
        // Update the starConfigFileFullPath file to take into account that we now have a new catalog
587
        int idx=0;
×
588
        for (const auto& catV : std::as_const(catalogsDescription))
×
589
        {
590
                ++idx;
×
591
                QVariantMap m = catV.toMap();
×
592
                if (m.value("id").toString()!=catId)
×
593
                        continue;
×
594
                const bool checked = m.value("checked").toBool();
×
595
                if (checked==b)
×
596
                        return;
×
597
                m["checked"]=b;
×
598
                catalogsDescription[idx-1]=m;                
×
599
        }
×
600
        starSettings["catalogs"]=catalogsDescription;
×
601
        QFile tmp(starConfigFileFullPath);
×
602
        if(tmp.open(QIODevice::WriteOnly))
×
603
        {
604
                StelJsonParser::write(starSettings, &tmp);
×
605
                tmp.close();
×
606
        }
607
}
×
608

609
void StarMgr::loadData(QVariantMap starsConfig)
×
610
{
611
        // Please do not init twice:
612
        Q_ASSERT(maxGeodesicGridLevel < 0);
×
613

614
        qDebug() << "Loading star data ...";
×
615

616
        catalogsDescription = starsConfig.value("catalogs").toList();
×
617
        foreach (const QVariant& catV, catalogsDescription)
×
618
        {
619
                QVariantMap m = catV.toMap();
×
620
                checkAndLoadCatalog(m);
×
621
        }
×
622

623
        for (int i=0; i<=NR_OF_HIP; i++)
×
624
        {
625
                hipIndex[i].a = Q_NULLPTR;
×
626
                hipIndex[i].z = Q_NULLPTR;
×
627
                hipIndex[i].s = Q_NULLPTR;
×
628
        }
629
        for (auto* z : std::as_const(gridLevels))
×
630
                z->updateHipIndex(hipIndex);
×
631

632
        const QString cat_hip_sp_file_name = starsConfig.value("hipSpectralFile").toString();
×
633
        if (cat_hip_sp_file_name.isEmpty())
×
634
        {
635
                qWarning() << "ERROR: stars:cat_hip_sp_file_name not found";
×
636
        }
637
        else
638
        {
639
                QString tmpFic = StelFileMgr::findFile("stars/default/" + cat_hip_sp_file_name);
×
640
                if (tmpFic.isEmpty())
×
641
                        qWarning() << "ERROR while loading data from" << QDir::toNativeSeparators(("stars/default/" + cat_hip_sp_file_name));
×
642
                else
643
                        spectral_array = initStringListFromFile(tmpFic);
×
644
        }
×
645

646
        const QString cat_hip_cids_file_name = starsConfig.value("hipComponentsIdsFile").toString();
×
647
        if (cat_hip_cids_file_name.isEmpty())
×
648
        {
649
                qWarning() << "ERROR: stars:cat_hip_cids_file_name not found";
×
650
        }
651
        else
652
        {
653
                QString tmpFic = StelFileMgr::findFile("stars/default/" + cat_hip_cids_file_name);
×
654
                if (tmpFic.isEmpty())
×
655
                        qWarning() << "ERROR while loading data from " << QDir::toNativeSeparators(("stars/default/" + cat_hip_cids_file_name));
×
656
                else
657
                        component_array = initStringListFromFile(tmpFic);
×
658
        }
×
659

660
        lastMaxSearchLevel = maxGeodesicGridLevel;
×
661
        qDebug() << "Finished loading star catalogue data, max_geodesic_level:" << maxGeodesicGridLevel;
×
662
}
×
663

664
void StarMgr::populateHipparcosLists()
×
665
{
666
        hipparcosStars.clear();
×
667
        hipStarsHighPM.clear();
×
668
        doubleHipStars.clear();
×
669
        variableHipStars.clear();
×
670
        algolTypeStars.clear();
×
671
        classicalCepheidsTypeStars.clear();
×
672
        carbonStars.clear();
×
673
        bariumStars.clear();
×
674
        const int pmLimit = 1; // arc-second per year!
×
675
        for (int hip=0; hip<=NR_OF_HIP; hip++)
×
676
        {
677
                const Star1 *const s = hipIndex[hip].s;
×
678
                if (s)
×
679
                {
680
                        const SpecialZoneArray<Star1> *const a = hipIndex[hip].a;
×
681
                        const SpecialZoneData<Star1> *const z = hipIndex[hip].z;
×
682
                        StelObjectP so = s->createStelObject(a,z);
×
683
                        hipparcosStars.push_back(so);
×
684
                        QString spectrum = convertToSpectralType(s->getSpInt());
×
685
                        // Carbon stars have spectral type, which start with C letter
686
                        if (spectrum.startsWith("C", Qt::CaseInsensitive))
×
687
                                carbonStars.push_back(so);
×
688

689
                        // Barium stars have spectral class G to K and contains "Ba" string
690
                        if ((spectrum.startsWith("G", Qt::CaseInsensitive) || spectrum.startsWith("K", Qt::CaseInsensitive)) && spectrum.contains("Ba", Qt::CaseSensitive))
×
691
                                bariumStars.push_back(so);
×
692

693
                        if (!getGcvsVariabilityType(s->getHip()).isEmpty())
×
694
                        {
695
                                QMap<StelObjectP, float> sa;
×
696
                                sa[so] = static_cast<float>(getGcvsPeriod(s->getHip()));
×
697
                                variableHipStars.push_back(sa);
×
698
                                
699
                                auto vartype = getGcvsVariabilityType(s->getHip());
×
700
                                if (vartype.contains("EA"))
×
701
                                {
702
                                        QMap<StelObjectP, float> sal;
×
703
                                        sal[so] = sa[so];
×
704
                                        algolTypeStars.push_back(sal);
×
705
                                }
×
706
                                if (vartype.contains("DCEP") && !vartype.contains("DCEPS"))
×
707
                                {
708
                                        QMap<StelObjectP, float> sacc;
×
709
                                        sacc[so] = sa[so];
×
710
                                        classicalCepheidsTypeStars.push_back(sacc);
×
711
                                }
×
712
                        }
×
713
                        if (!getWdsName(s->getHip()).isEmpty())
×
714
                        {
715
                                QMap<StelObjectP, float> sd;
×
716
                                sd[so] = getWdsLastSeparation(s->getHip());
×
717
                                doubleHipStars.push_back(sd);
×
718
                        }
×
719
                        // use separate variables for avoid the overflow (esp. for Barnard's star)
720
                        PMData properMotion = getProperMotion(s->getHip());
×
721
                        float pmX = properMotion.first;
×
722
                        float pmY = properMotion.second;
×
723
                        float pm = 0.001f * std::sqrt((pmX*pmX) + (pmY*pmY));
×
724
                        if (qAbs(pm)>=pmLimit)
×
725
                        {
726
                                QMap<StelObjectP, float> spm;
×
727
                                spm[so] = pm;
×
728
                                hipStarsHighPM.push_back(spm);
×
729
                        }
×
730
                }
×
731
        }
732
}
×
733

734
// Load common names from file
735
int StarMgr::loadCommonNames(const QString& commonNameFile)
×
736
{
737
        commonNamesMap.clear();
×
738
        commonNamesMapI18n.clear();
×
739
        additionalNamesMap.clear();
×
740
        additionalNamesMapI18n.clear();
×
741
        commonNamesIndexI18n.clear();
×
742
        commonNamesIndex.clear();
×
743
        additionalNamesIndex.clear();
×
744
        additionalNamesIndexI18n.clear();
×
745

746
        qDebug().noquote() << "Loading star names from" << QDir::toNativeSeparators(commonNameFile);
×
747
        QFile cnFile(commonNameFile);
×
748
        if (!cnFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
749
        {
750
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(commonNameFile);
×
751
                return 0;
×
752
        }
753

754
        int readOk=0;
×
755
        int totalRecords=0;
×
756
        int lineNumber=0;
×
757
        QString record;
×
758
        // Allow empty and comment lines where first char (after optional blanks) is #
759
        static const QRegularExpression commentRx("^(\\s*#.*|\\s*)$");
×
760
        // record structure is delimited with a | character.  We will
761
        // use a QRegularExpression to extract the fields. with white-space padding permitted
762
        // (i.e. it will be stripped automatically) Example record strings:
763
        // "   677|_("Alpheratz")"
764
        // "113368|_("Fomalhaut")"
765
        // Note: Stellarium doesn't support sky cultures made prior to version 0.10.6 now!
766
        static const QRegularExpression recordRx("^\\s*(\\d+)\\s*\\|[_]*[(]\"(.*)\"[)]\\s*([\\,\\d\\s]*)");
×
767

768
        while(!cnFile.atEnd())
×
769
        {
770
                record = QString::fromUtf8(cnFile.readLine()).trimmed();
×
771
                lineNumber++;
×
772
                if (commentRx.match(record).hasMatch())
×
773
                        continue;
×
774

775
                totalRecords++;
×
776
                QRegularExpressionMatch recMatch=recordRx.match(record);
×
777
                if (!recMatch.hasMatch())
×
778
                {
779
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(commonNameFile)
×
780
                                   << " - record does not match record pattern";
×
781
                        qWarning().noquote() << "Problematic record:" << record;
×
782
                        continue;
×
783
                }
784
                else
785
                {
786
                        // The record is the right format.  Extract the fields
787
                        bool ok;
788
                        int hip = recMatch.captured(1).toInt(&ok);
×
789
                        if (!ok)
×
790
                        {
791
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(commonNameFile)
×
792
                                           << " - failed to convert " << recMatch.captured(1) << "to a number";
×
793
                                continue;
×
794
                        }
795
                        QString englishCommonName = recMatch.captured(2).trimmed();
×
796
                        if (englishCommonName.isEmpty())
×
797
                        {
798
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(commonNameFile)
×
799
                                           << " - empty name field";
×
800
                                continue;
×
801
                        }
802

803
                        const QString englishNameCap = englishCommonName.toUpper();
×
804
                        if (commonNamesMap.find(hip)!=commonNamesMap.end())
×
805
                        {
806
                                if (additionalNamesMap.find(hip)!=additionalNamesMap.end())
×
807
                                {
808
                                        QString sname = additionalNamesMap[hip].append(" - " + englishCommonName);
×
809
                                        additionalNamesMap[hip] = sname;
×
810
                                        additionalNamesMapI18n[hip] = sname;
×
811
                                        additionalNamesIndex[englishNameCap] = hip;
×
812
                                        additionalNamesIndexI18n[englishNameCap] = hip;
×
813
                                }
×
814
                                else
815
                                {
816
                                        additionalNamesMap[hip] = englishCommonName;
×
817
                                        additionalNamesMapI18n[hip] = englishCommonName;
×
818
                                        additionalNamesIndex[englishNameCap] = hip;
×
819
                                        additionalNamesIndexI18n[englishNameCap] = hip;
×
820
                                }
821
                        }
822
                        else
823
                        {
824
                                commonNamesMap[hip] = englishCommonName;
×
825
                                commonNamesMapI18n[hip] = englishCommonName;
×
826
                                commonNamesIndexI18n[englishNameCap] = hip;
×
827
                                commonNamesIndex[englishNameCap] = hip;
×
828
                        }
829

830
                        QString reference = recMatch.captured(3).trimmed();
×
831
                        if (!reference.isEmpty())
×
832
                        {
833
                                if (referenceMap.find(hip)!=referenceMap.end())
×
834
                                        referenceMap[hip] = referenceMap[hip].append("," + reference);
×
835
                                else
836
                                        referenceMap[hip] = reference;
×
837
                        }
838

839
                        readOk++;
×
840
                }
×
841
        }
×
842
        cnFile.close();
×
843

844
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "common star names";
×
845
        return 1;
×
846
}
×
847

848

849
// Load scientific names from file
850
void StarMgr::loadSciNames(const QString& sciNameFile, const bool extraData)
×
851
{
852
        if (extraData)
×
853
        {
854
                sciExtraDesignationsMapI18n.clear();
×
855
                sciExtraDesignationsIndexI18n.clear();
×
856
                qDebug().noquote() << "Loading scientific star extra names from" << QDir::toNativeSeparators(sciNameFile);
×
857
        }
858
        else
859
        {
860
                sciDesignationsMapI18n.clear();
×
861
                sciDesignationsIndexI18n.clear();
×
862
                qDebug().noquote() << "Loading scientific star names from" << QDir::toNativeSeparators(sciNameFile);
×
863
        }
864

865
        QFile snFile(sciNameFile);
×
866
        if (!snFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
867
        {
868
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(sciNameFile);
×
869
                return;
×
870
        }
871
        const QStringList& allRecords = QString::fromUtf8(snFile.readAll()).split('\n');
×
872
        snFile.close();
×
873

874
        int readOk=0;
×
875
        int totalRecords=0;
×
876
        int lineNumber=0;
×
877
        // record structure is delimited with a | character. Example record strings:
878
        // " 10819|c_And"
879
        // "113726|1_And"
880
        for (const auto& record : allRecords)
×
881
        {
882
                ++lineNumber;
×
883
                // skip comments and empty lines
884
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
885
                        continue;
×
886

887
                ++totalRecords;
×
888
                const QStringList& fields = record.split('|');
×
889
                if (fields.size()!=2)
×
890
                {
891
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(sciNameFile)
×
892
                                   << " - record does not match record pattern";
×
893
                        continue;
×
894
                }
895
                else
896
                {
897
                        // The record is the right format.  Extract the fields
898
                        bool ok;
899
                        int hip = fields.at(0).toInt(&ok);
×
900
                        if (!ok)
×
901
                        {
902
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(sciNameFile)
×
903
                                           << " - failed to convert " << fields.at(0) << "to a number";
×
904
                                continue;
×
905
                        }
906

907
                        QString sci_name = fields.at(1).trimmed();
×
908
                        if (sci_name.isEmpty())
×
909
                        {
910
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(sciNameFile)
×
911
                                           << " - empty name field";
×
912
                                continue;
×
913
                        }
914

915
                        sci_name.replace('_',' ');
×
916
                        if (extraData)
×
917
                        {
918
                                // Don't set the main sci name if it's already set - it's additional sci name
919
                                if (sciExtraDesignationsMapI18n.find(hip)!=sciExtraDesignationsMapI18n.end())
×
920
                                {
921
                                        QString sname = sciExtraDesignationsMapI18n[hip].append(" - " + sci_name);
×
922
                                        sciExtraDesignationsMapI18n[hip] = sname;
×
923
                                }
×
924
                                else
925
                                        sciExtraDesignationsMapI18n[hip] = sci_name;
×
926
                                sciExtraDesignationsIndexI18n[sci_name] = hip;
×
927
                        }
928
                        else
929
                        {
930
                                // Don't set the main sci name if it's already set - it's additional sci name
931
                                if (sciDesignationsMapI18n.find(hip)!=sciDesignationsMapI18n.end())
×
932
                                {
933
                                        QString sname = sciDesignationsMapI18n[hip].append(" - " + sci_name);
×
934
                                        sciDesignationsMapI18n[hip] = sname;
×
935
                                }
×
936
                                else
937
                                        sciDesignationsMapI18n[hip] = sci_name;
×
938
                                sciDesignationsIndexI18n[sci_name] = hip;
×
939
                        }
940
                        ++readOk;
×
941
                }
×
942
        }
×
943

944
        if (extraData)
×
945
                qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "scientific star extra names";
×
946
        else
947
                qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "scientific star names";
×
948
}
×
949

950
// Load GCVS from file
951
void StarMgr::loadGcvs(const QString& GcvsFile)
×
952
{
953
        varStarsMapI18n.clear();
×
954
        varStarsIndexI18n.clear();
×
955

956
        qDebug().noquote() << "Loading variable stars from" << QDir::toNativeSeparators(GcvsFile);
×
957
        QFile vsFile(GcvsFile);
×
958
        if (!vsFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
959
        {
960
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(GcvsFile);
×
961
                return;
×
962
        }
963
        const QStringList& allRecords = QString::fromUtf8(vsFile.readAll()).split('\n');
×
964
        vsFile.close();
×
965

966
        int readOk=0;
×
967
        int totalRecords=0;
×
968
        int lineNumber=0;
×
969

970
        // record structure is delimited with a tab character.
971
        for (const auto& record : allRecords)
×
972
        {
973
                ++lineNumber;
×
974
                // skip comments and empty lines
975
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
976
                        continue;
×
977

978
                ++totalRecords;
×
979
                const QStringList& fields = record.split('\t');
×
980

981
                bool ok;
982
                int hip = fields.at(0).toInt(&ok);
×
983
                if (!ok)
×
984
                {
985
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(GcvsFile)
×
986
                                   << " - failed to convert " << fields.at(0) << "to a number";
×
987
                        continue;
×
988
                }
989

990
                // Don't set the star if it's already set
991
                if (varStarsMapI18n.find(hip)!=varStarsMapI18n.end())
×
992
                        continue;
×
993

994
                varstar variableStar;
×
995

996
                variableStar.designation = fields.at(1).trimmed();
×
997
                variableStar.vtype = fields.at(2).trimmed();
×
998
                if (fields.at(3).isEmpty())
×
999
                        variableStar.maxmag = 99.f;
×
1000
                else
1001
                        variableStar.maxmag = fields.at(3).toFloat();
×
1002
                variableStar.mflag = fields.at(4).toInt();
×
1003
                if (fields.at(5).isEmpty())
×
1004
                        variableStar.min1mag = 99.f;
×
1005
                else
1006
                        variableStar.min1mag = fields.at(5).toFloat();
×
1007
                if (fields.at(6).isEmpty())
×
1008
                        variableStar.min2mag = 99.f;
×
1009
                else
1010
                        variableStar.min2mag = fields.at(6).toFloat();
×
1011
                variableStar.photosys = fields.at(7).trimmed();
×
1012
                variableStar.epoch = fields.at(8).toDouble();
×
1013
                variableStar.period = fields.at(9).toDouble();
×
1014
                variableStar.Mm = fields.at(10).toInt();
×
1015
                variableStar.stype = fields.at(11).trimmed();
×
1016

1017
                varStarsMapI18n[hip] = variableStar;
×
1018
                varStarsIndexI18n[variableStar.designation.toUpper()] = hip;
×
1019
                ++readOk;
×
1020
        }
×
1021

1022
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "variable stars";
×
1023
}
×
1024

1025
// Load WDS from file
1026
void StarMgr::loadWds(const QString& WdsFile)
×
1027
{
1028
        wdsStarsMapI18n.clear();
×
1029
        wdsStarsIndexI18n.clear();
×
1030

1031
        qDebug().noquote() << "Loading double stars from" << QDir::toNativeSeparators(WdsFile);
×
1032
        QFile dsFile(WdsFile);
×
1033
        if (!dsFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
1034
        {
1035
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(WdsFile);
×
1036
                return;
×
1037
        }
1038
        const QStringList& allRecords = QString::fromUtf8(dsFile.readAll()).split('\n');
×
1039
        dsFile.close();
×
1040

1041
        int readOk=0;
×
1042
        int totalRecords=0;
×
1043
        int lineNumber=0;
×
1044

1045
        // record structure is delimited with a tab character.
1046
        for (const auto& record : allRecords)
×
1047
        {
1048
                ++lineNumber;
×
1049
                // skip comments and empty lines
1050
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
1051
                        continue;
×
1052

1053
                ++totalRecords;
×
1054
                const QStringList& fields = record.split('\t');
×
1055

1056
                bool ok;
1057
                int hip = fields.at(0).toInt(&ok);
×
1058
                if (!ok)
×
1059
                {
1060
                        qWarning() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(WdsFile)
×
1061
                                   << " - failed to convert " << fields.at(0) << "to a number";
×
1062
                        continue;
×
1063
                }
1064

1065
                // Don't set the star if it's already set
1066
                if (wdsStarsMapI18n.find(hip)!=wdsStarsMapI18n.end())
×
1067
                        continue;
×
1068

1069
                wds doubleStar;
×
1070

1071
                doubleStar.designation = fields.at(1).trimmed();
×
1072
                doubleStar.observation = fields.at(2).toInt();
×
1073
                doubleStar.positionAngle = fields.at(3).toFloat();
×
1074
                doubleStar.separation = fields.at(4).toFloat();
×
1075

1076
                wdsStarsMapI18n[hip] = doubleStar;
×
1077
                wdsStarsIndexI18n[QString("WDS J%1").arg(doubleStar.designation.toUpper())] = hip;
×
1078
                ++readOk;
×
1079
        }
×
1080

1081
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "double stars";
×
1082
}
×
1083

1084
// Load cross-identification data from file
1085
void StarMgr::loadCrossIdentificationData(const QString& crossIdFile)
×
1086
{
1087
        crossIdMap.clear();
×
1088
        saoStarsIndex.clear();        
×
1089
        hdStarsIndex.clear();        
×
1090
        hrStarsIndex.clear();
×
1091

1092
        qDebug().noquote() << "Loading cross-identification data from" << QDir::toNativeSeparators(crossIdFile);
×
1093
        QFile ciFile(crossIdFile);
×
1094
        if (!ciFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
1095
        {
1096
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(crossIdFile);
×
1097
                return;
×
1098
        }
1099
        const QStringList& allRecords = QString::fromUtf8(ciFile.readAll()).split('\n');
×
1100
        ciFile.close();
×
1101

1102
        crossid crossIdData;
1103

1104
        int readOk=0;
×
1105
        int totalRecords=0;
×
1106
        int lineNumber=0;
×
1107
        // record structure is delimited with a 'tab' character. Example record strings:
1108
        // "1        128522        224700"
1109
        // "2        165988        224690"
1110
        for (const auto& record : allRecords)
×
1111
        {
1112
                ++lineNumber;
×
1113
                // skip comments and empty lines
1114
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
1115
                        continue;
×
1116

1117
                ++totalRecords;
×
1118
                const QStringList& fields = record.split('\t');
×
1119
                if (fields.size()!=5)
×
1120
                {
1121
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(crossIdFile)
×
1122
                                   << " - record does not match record pattern";
×
1123
                        continue;
×
1124
                }
1125
                else
1126
                {
1127
                        // The record is the right format.  Extract the fields
1128
                        bool ok;
1129
                        int hip = fields.at(0).toInt(&ok);
×
1130
                        if (!ok)
×
1131
                        {
1132
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(crossIdFile)
×
1133
                                           << " - failed to convert " << fields.at(0) << "to a number";
×
1134
                                continue;
×
1135
                        }
1136

1137
                        QString hipstar = QString("%1%2").arg(hip).arg(fields.at(1).trimmed());
×
1138
                        crossIdData.sao = fields.at(2).toInt(&ok);
×
1139
                        crossIdData.hd = fields.at(3).toInt(&ok);
×
1140
                        crossIdData.hr = fields.at(4).toInt(&ok);
×
1141

1142
                        crossIdMap[hipstar] = crossIdData;
×
1143
                        if (crossIdData.sao>0)
×
1144
                                saoStarsIndex[crossIdData.sao] = hip;
×
1145
                        if (crossIdData.hd>0)
×
1146
                                hdStarsIndex[crossIdData.hd] = hip;
×
1147
                        if (crossIdData.hr>0)
×
1148
                                hrStarsIndex[crossIdData.hr] = hip;
×
1149

1150
                        ++readOk;
×
1151
                }
×
1152
        }
×
1153

1154
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "cross-identification data records for stars";
×
1155
}
×
1156

1157
void StarMgr::loadPlxErr(const QString& plxErrFile)
×
1158
{
1159
        // TODO: This is temporary solution for display parallax errors until format of stars catalogs will not be changed!
1160
        hipParallaxErrors.clear();
×
1161

1162
        qDebug().noquote() << "Loading parallax errors data from" << QDir::toNativeSeparators(plxErrFile);
×
1163
        QFile ciFile(plxErrFile);
×
1164
        if (!ciFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
1165
        {
1166
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(plxErrFile);
×
1167
                return;
×
1168
        }
1169
        const QStringList& allRecords = QString::fromUtf8(ciFile.readAll()).split('\n');
×
1170
        ciFile.close();
×
1171

1172
        int readOk=0;
×
1173
        int totalRecords=0;
×
1174
        int lineNumber=0;
×
1175
        // record structure is delimited with a 'tab' character. Example record strings:
1176
        // "1        0.0606"
1177
        // "2        0.3193"
1178
        for (const auto& record : allRecords)
×
1179
        {
1180
                ++lineNumber;
×
1181
                // skip comments and empty lines
1182
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
1183
                        continue;
×
1184

1185
                ++totalRecords;
×
1186
                const QStringList& fields = record.split('\t');
×
1187
                if (fields.size()!=2)
×
1188
                {
1189
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(plxErrFile)
×
1190
                                   << " - record does not match record pattern";
×
1191
                        continue;
×
1192
                }
1193
                else
1194
                {
1195
                        // The record is the right format.  Extract the fields
1196
                        bool ok;
1197
                        int hip = fields.at(0).toInt(&ok);
×
1198
                        if (!ok)
×
1199
                        {
1200
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(plxErrFile)
×
1201
                                           << " - failed to convert " << fields.at(0) << "to a number";
×
1202
                                continue;
×
1203
                        }
1204
                        hipParallaxErrors[hip] = fields.at(1).toFloat(&ok);
×
1205

1206
                        ++readOk;
×
1207
                }
1208
        }
×
1209

1210
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "parallax error data records for stars";
×
1211
}
×
1212

1213
void StarMgr::loadPMData(const QString &pmDataFile)
×
1214
{
1215
        // TODO: This is temporary solution for display parallax errors until format of stars catalogs will not be changed!
1216
        hipPMData.clear();
×
1217

1218
        qDebug().noquote() << "Loading proper motion data from" << QDir::toNativeSeparators(pmDataFile);
×
1219
        QFile ciFile(pmDataFile);
×
1220
        if (!ciFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
1221
        {
1222
                qWarning().noquote() << "WARNING - could not open" << QDir::toNativeSeparators(pmDataFile);
×
1223
                return;
×
1224
        }
1225
        const QStringList& allRecords = QString::fromUtf8(ciFile.readAll()).split('\n');
×
1226
        ciFile.close();
×
1227

1228
        int readOk=0;
×
1229
        int totalRecords=0;
×
1230
        int lineNumber=0;
×
1231
        // record structure is delimited with a 'tab' character. Example record strings:
1232
        // "1        -4.58        -1.61"
1233
        // "2        179.70        1.40"
1234
        for (const auto& record : allRecords)
×
1235
        {
1236
                ++lineNumber;
×
1237
                // skip comments and empty lines
1238
                if (record.startsWith("//") || record.startsWith("#") || record.isEmpty())
×
1239
                        continue;
×
1240

1241
                ++totalRecords;
×
1242
                const QStringList& fields = record.split('\t');
×
1243
                if (fields.size()!=3)
×
1244
                {
1245
                        qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(pmDataFile)
×
1246
                                   << " - record does not match record pattern";
×
1247
                        continue;
×
1248
                }
1249
                else
1250
                {
1251
                        // The record is the right format.  Extract the fields
1252
                        bool ok;
1253
                        int hip = fields.at(0).toInt(&ok);
×
1254
                        if (!ok)
×
1255
                        {
1256
                                qWarning().noquote() << "WARNING - parse error at line" << lineNumber << "in" << QDir::toNativeSeparators(pmDataFile)
×
1257
                                           << " - failed to convert " << fields.at(0) << "to a number";
×
1258
                                continue;
×
1259
                        }
1260
                        PMData properMotion;
×
1261
                        properMotion.first = fields.at(1).toFloat(&ok);
×
1262
                        properMotion.second = fields.at(2).toFloat(&ok);
×
1263
                        hipPMData[hip] = properMotion;
×
1264

1265
                        ++readOk;
×
1266
                }
1267
        }
×
1268

1269
        qDebug().noquote() << "Loaded" << readOk << "/" << totalRecords << "proper motion data records for stars";
×
1270
}
×
1271

1272
int StarMgr::getMaxSearchLevel() const
×
1273
{
1274
        int rval = -1;
×
1275
        for (const auto* z : gridLevels)
×
1276
        {
1277
                const float mag_min = 0.001f*z->mag_min;
×
1278
                RCMag rcmag;
1279
                if (StelApp::getInstance().getCore()->getSkyDrawer()->computeRCMag(mag_min, &rcmag)==false)
×
1280
                        break;
×
1281
                rval = z->level;
×
1282
        }
1283
        return rval;
×
1284
}
1285

1286

1287
// Draw all the stars
1288
void StarMgr::draw(StelCore* core)
×
1289
{
1290
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
1291
        StelSkyDrawer* skyDrawer = core->getSkyDrawer();
×
1292
        // If stars are turned off don't waste time below
1293
        // projecting all stars just to draw disembodied labels
1294
        if (!static_cast<bool>(starsFader.getInterstate()))
×
1295
                return;
×
1296

1297
        int maxSearchLevel = getMaxSearchLevel();
×
1298
        QVector<SphericalCap> viewportCaps = prj->getViewportConvexPolygon()->getBoundingSphericalCaps();
×
1299
        viewportCaps.append(core->getVisibleSkyArea());
×
1300
        const GeodesicSearchResult* geodesic_search_result = core->getGeodesicGrid(maxSearchLevel)->search(viewportCaps,maxSearchLevel);
×
1301

1302
        // Set temporary static variable for optimization
1303
        const float names_brightness = labelsFader.getInterstate() * starsFader.getInterstate();
×
1304

1305
        // prepare for aberration: Explan. Suppl. 2013, (7.38)
1306
        const bool withAberration=core->getUseAberration();
×
1307
        Vec3d vel(0.);
×
1308
        if (withAberration)
×
1309
        {
1310
                vel=core->getCurrentPlanet()->getHeliocentricEclipticVelocity();
×
1311
                StelCore::matVsop87ToJ2000.transfo(vel);
×
1312
                vel*=core->getAberrationFactor()*(AU/(86400.0*SPEED_OF_LIGHT));
×
1313
        }
1314
        const Vec3f velf=vel.toVec3f();
×
1315

1316
        // Prepare openGL for drawing many stars
1317
        StelPainter sPainter(prj);
×
1318
        sPainter.setFont(starFont);
×
1319
        skyDrawer->preDrawPointSource(&sPainter);
×
1320

1321
        // Prepare a table for storing precomputed RCMag for all ZoneArrays
1322
        RCMag rcmag_table[RCMAG_TABLE_SIZE];
1323
        
1324
        // Draw all the stars of all the selected zones
1325
        for (const auto* z : std::as_const(gridLevels))
×
1326
        {
1327
                int limitMagIndex=RCMAG_TABLE_SIZE;
×
1328
                const float mag_min = 0.001f*z->mag_min;
×
1329
                const float k = (0.001f*z->mag_range)/z->mag_steps; // MagStepIncrement
×
1330
                for (int i=0;i<RCMAG_TABLE_SIZE;++i)
×
1331
                {
1332
                        const float mag = mag_min+k*i;
×
1333
                        if (skyDrawer->computeRCMag(mag, &rcmag_table[i])==false)
×
1334
                        {
1335
                                if (i==0)
×
1336
                                        goto exit_loop;
×
1337
                                
1338
                                // The last magnitude at which the star is visible
1339
                                limitMagIndex = i-1;
×
1340
                                
1341
                                // We reached the point where stars are not visible anymore
1342
                                // Fill the rest of the table with zero and leave.
1343
                                for (;i<RCMAG_TABLE_SIZE;++i)
×
1344
                                {
1345
                                        rcmag_table[i].luminance=0;
×
1346
                                        rcmag_table[i].radius=0;
×
1347
                                }
1348
                                break;
×
1349
                        }
1350
                        rcmag_table[i].radius *= starsFader.getInterstate();
×
1351
                }
1352
                lastMaxSearchLevel = z->level;
×
1353

1354
                int maxMagStarName = 0;
×
1355
                if (labelsFader.getInterstate()>0.f)
×
1356
                {
1357
                        // Adapt magnitude limit of the stars labels according to FOV and labelsAmount
1358
                        float maxMag = (skyDrawer->getLimitMagnitude()-6.5f)*0.7f+(static_cast<float>(labelsAmount)*1.2f)-2.f;
×
1359
                        int x = static_cast<int>((maxMag-mag_min)/k);
×
1360
                        if (x > 0)
×
1361
                                maxMagStarName = x;
×
1362
                }
1363
                int zone;
1364
                
1365
                for (GeodesicSearchInsideIterator it1(*geodesic_search_result,z->level);(zone = it1.next()) >= 0;)
×
1366
                        z->draw(&sPainter, zone, true, rcmag_table, limitMagIndex, core, maxMagStarName, names_brightness, viewportCaps, withAberration, velf);
×
1367
                for (GeodesicSearchBorderIterator it1(*geodesic_search_result,z->level);(zone = it1.next()) >= 0;)
×
1368
                        z->draw(&sPainter, zone, false, rcmag_table, limitMagIndex, core, maxMagStarName,names_brightness, viewportCaps, withAberration, velf);
×
1369
        }
1370
        exit_loop:
×
1371

1372
        // Finish drawing many stars
1373
        skyDrawer->postDrawPointSource(&sPainter);
×
1374

1375
        if (objectMgr->getFlagSelectedObjectPointer())
×
1376
                drawPointer(sPainter, core);
×
1377
}
×
1378

1379

1380
// Return a QList containing the stars located
1381
// inside the limFov circle around position vv (in J2000 frame without aberration)
1382
QList<StelObjectP > StarMgr::searchAround(const Vec3d& vv, double limFov, const StelCore* core) const
×
1383
{
1384
        QList<StelObjectP > result;
×
1385
        if (!getFlagStars())
×
1386
                return result;
×
1387

1388
        Vec3d v(vv);
×
1389
        v.normalize();
×
1390

1391
        // find any vectors h0 and h1 (length 1), so that h0*v=h1*v=h0*h1=0
1392
        int i;
1393
        {
1394
                const double a0 = fabs(v[0]);
×
1395
                const double a1 = fabs(v[1]);
×
1396
                const double a2 = fabs(v[2]);
×
1397
                if (a0 <= a1)
×
1398
                {
1399
                        if (a0 <= a2) i = 0;
×
1400
                        else i = 2;
×
1401
                } else
1402
                {
1403
                        if (a1 <= a2) i = 1;
×
1404
                        else i = 2;
×
1405
                }
1406
        }
1407
        Vec3d h0(0.0,0.0,0.0);
×
1408
        h0[i] = 1.0;
×
1409
        Vec3d h1 = h0 ^ v;
×
1410
        h1.normalize();
×
1411
        h0 = h1 ^ v;
×
1412
        h0.normalize();
×
1413

1414
        // Now we have h0*v=h1*v=h0*h1=0.
1415
        // Construct a region with 4 corners e0,e1,e2,e3 inside which all desired stars must be:
1416
        double f = 1.4142136 * tan(limFov * M_PI/180.0);
×
1417
        h0 *= f;
×
1418
        h1 *= f;
×
1419
        Vec3d e0 = v + h0;
×
1420
        Vec3d e1 = v + h1;
×
1421
        Vec3d e2 = v - h0;
×
1422
        Vec3d e3 = v - h1;
×
1423
        f = 1.0/e0.norm();
×
1424
        e0 *= f;
×
1425
        e1 *= f;
×
1426
        e2 *= f;
×
1427
        e3 *= f;
×
1428
        // Search the triangles
1429
        SphericalConvexPolygon c(e3, e2, e2, e0);
×
1430
        const GeodesicSearchResult* geodesic_search_result = core->getGeodesicGrid(lastMaxSearchLevel)->search(c.getBoundingSphericalCaps(),lastMaxSearchLevel);
×
1431

1432
        // Iterate over the stars inside the triangles
1433
        f = cos(limFov * M_PI/180.);
×
1434
        for (auto* z : gridLevels)
×
1435
        {
1436
                //qDebug() << "search inside(" << it->first << "):";
1437
                int zone;
1438
                for (GeodesicSearchInsideIterator it1(*geodesic_search_result,z->level);(zone = it1.next()) >= 0;)
×
1439
                {
1440
                        z->searchAround(core, zone,v,f,result);
×
1441
                        //qDebug() << " " << zone;
1442
                }
1443
                //qDebug() << StelUtils::getEndLineChar() << "search border(" << it->first << "):";
1444
                for (GeodesicSearchBorderIterator it1(*geodesic_search_result,z->level); (zone = it1.next()) >= 0;)
×
1445
                {
1446
                        z->searchAround(core, zone,v,f,result);
×
1447
                        //qDebug() << " " << zone;
1448
                }
1449
        }
1450
        return result;
×
1451
}
×
1452

1453

1454
//! Update i18 names from english names according to passed translator.
1455
//! The translation is done using gettext with translated strings defined in translations.h
1456
void StarMgr::updateI18n()
×
1457
{
1458
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
1459
        commonNamesMapI18n.clear();
×
1460
        commonNamesIndexI18n.clear();
×
1461
        additionalNamesMapI18n.clear();
×
1462
        additionalNamesIndexI18n.clear();
×
1463
        for (QHash<int,QString>::ConstIterator it(commonNamesMap.constBegin());it!=commonNamesMap.constEnd();it++)
×
1464
        {
1465
                const int i = it.key();
×
1466
                const QString t(trans.qtranslate(it.value()));
×
1467
                commonNamesMapI18n[i] = t;
×
1468
                commonNamesIndexI18n[t.toUpper()] = i;
×
1469
        }
×
1470
        for (QHash<int,QString>::ConstIterator ita(additionalNamesMap.constBegin());ita!=additionalNamesMap.constEnd();ita++)
×
1471
        {
1472
                const int i = ita.key();
×
1473
                QStringList a = ita.value().split(" - ");
×
1474
                QStringList tn;
×
1475
                for (const auto& str : a)
×
1476
                {
1477
                        QString tns = trans.qtranslate(str);
×
1478
                        tn << tns;
×
1479
                        additionalNamesIndexI18n[tns.toUpper()] = i;
×
1480
                }
×
1481
                const QString r = tn.join(" - ");
×
1482
                additionalNamesMapI18n[i] = r;
×
1483
        }
×
1484
}
×
1485

1486
// Search the star by HP number
1487
StelObjectP StarMgr::searchHP(int hp) const
×
1488
{
1489
        if (0 < hp && hp <= NR_OF_HIP)
×
1490
        {
1491
                const Star1 *const s = hipIndex[hp].s;
×
1492
                if (s)
×
1493
                {
1494
                        const SpecialZoneArray<Star1> *const a = hipIndex[hp].a;
×
1495
                        const SpecialZoneData<Star1> *const z = hipIndex[hp].z;
×
1496
                        return s->createStelObject(a,z);
×
1497
                }
1498
        }
1499
        return StelObjectP();
×
1500
}
1501

1502
StelObjectP StarMgr::searchByNameI18n(const QString& nameI18n) const
×
1503
{
1504
        QString objw = nameI18n.toUpper();
×
1505

1506
        // Search by I18n common name
1507
        auto it = commonNamesIndexI18n.find(objw);
×
1508
        if (it!=commonNamesIndexI18n.end())
×
1509
                return searchHP(it.value());
×
1510

1511
        if (getFlagAdditionalNames())
×
1512
        {
1513
                // Search by I18n additional common names
1514
                auto ita = additionalNamesIndexI18n.find(objw);
×
1515
                if (ita!=additionalNamesIndexI18n.end())
×
1516
                        return searchHP(ita.value());
×
1517
        }
1518

1519
        return searchByName(nameI18n);
×
1520
}
×
1521

1522

1523
StelObjectP StarMgr::searchByName(const QString& name) const
×
1524
{
1525
        QString objw = name.toUpper();
×
1526

1527
        // Search by HP number if it's an HP formatted number. The final part (A/B/...) is ignored
1528
        static const QRegularExpression rx("^\\s*(HP|HIP)\\s*(\\d+)\\s*.*$", QRegularExpression::CaseInsensitiveOption);
×
1529
        QRegularExpressionMatch match=rx.match(objw);
×
1530
        if (match.hasMatch())
×
1531
                return searchHP(match.captured(2).toInt());
×
1532

1533
        // Search by SAO number if it's an SAO formatted number
1534
        static const QRegularExpression rx2("^\\s*(SAO)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1535
        match=rx2.match(objw);
×
1536
        if (match.hasMatch())
×
1537
        {
1538
                auto sao = saoStarsIndex.find(match.captured(2).toInt());
×
1539
                if (sao!=saoStarsIndex.end())
×
1540
                        return searchHP(sao.value());
×
1541
        }
1542

1543
        // Search by HD number if it's an HD formatted number
1544
        static const QRegularExpression rx3("^\\s*(HD)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1545
        match=rx3.match(objw);
×
1546
        if (match.hasMatch())
×
1547
        {
1548
                auto hd = hdStarsIndex.find(match.captured(2).toInt());
×
1549
                if (hd!=hdStarsIndex.end())
×
1550
                        return searchHP(hd.value());
×
1551
        }
1552

1553
        // Search by HR number if it's an HR formatted number
1554
        static const QRegularExpression rx4("^\\s*(HR)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1555
        match=rx4.match(objw);
×
1556
        if (match.hasMatch())
×
1557
        {
1558
                auto hr = hrStarsIndex.find(match.captured(2).toInt());
×
1559
                if (hr!=hrStarsIndex.end())
×
1560
                        return searchHP(hr.value());
×
1561
        }
1562

1563
        // Search by English common name
1564
        auto it = commonNamesIndex.find(objw);
×
1565
        if (it!=commonNamesIndex.end())
×
1566
                return searchHP(it.value());
×
1567

1568
        if (getFlagAdditionalNames())
×
1569
        {
1570
                // Search by English additional common names
1571
                auto ita = additionalNamesIndex.find(objw);
×
1572
                if (ita!=additionalNamesIndex.end())
×
1573
                        return searchHP(ita.value());
×
1574
        }
1575

1576
        // Search by scientific name
1577
        auto itd = sciDesignationsIndexI18n.find(name); // case sensitive!
×
1578
        if (itd!=sciDesignationsIndexI18n.end())
×
1579
                return searchHP(itd.value());
×
1580
        auto itdi = sciDesignationsIndexI18n.find(objw); // case insensitive!
×
1581
        if (itdi!=sciDesignationsIndexI18n.end())
×
1582
                return searchHP(itdi.value());
×
1583

1584
        // Search by scientific name
1585
        auto eitd = sciExtraDesignationsIndexI18n.find(name); // case sensitive!
×
1586
        if (eitd!=sciExtraDesignationsIndexI18n.end())
×
1587
                return searchHP(eitd.value());
×
1588
        auto eitdi = sciExtraDesignationsIndexI18n.find(objw); // case insensitive!
×
1589
        if (eitdi!=sciExtraDesignationsIndexI18n.end())
×
1590
                return searchHP(eitdi.value());
×
1591

1592
        // Search by GCVS name
1593
        auto it4 = varStarsIndexI18n.find(objw);
×
1594
        if (it4!=varStarsIndexI18n.end())
×
1595
                return searchHP(it4.value());
×
1596

1597
        // Search by WDS name
1598
        auto wdsIt = wdsStarsIndexI18n.find(objw);
×
1599
        if (wdsIt!=wdsStarsIndexI18n.end())
×
1600
                return searchHP(wdsIt.value());
×
1601

1602
        return StelObjectP();
×
1603
}
×
1604

1605
StelObjectP StarMgr::searchByID(const QString &id) const
×
1606
{
1607
        return searchByName(id);
×
1608
}
1609

1610
//! Find and return the list of at most maxNbItem objects auto-completing the passed object name.
1611
QStringList StarMgr::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
1612
{
1613
        QStringList result;
×
1614
        if (maxNbItem <= 0 || !getFlagStars())
×
1615
                return result;
×
1616

1617
        QString objw = objPrefix.toUpper();
×
1618
        bool found;
1619

1620
        // Search for common names
1621
        QMapIterator<QString, int> i(commonNamesIndexI18n);
×
1622
        while (i.hasNext())
×
1623
        {
1624
                i.next();
×
1625
                if (useStartOfWords && i.key().startsWith(objw))
×
1626
                        found = true;
×
1627
                else if (!useStartOfWords && i.key().contains(objw))
×
1628
                        found = true;
×
1629
                else
1630
                        found = false;
×
1631

1632
                if (found)
×
1633
                {
1634
                        if (maxNbItem<=0)
×
1635
                                break;
×
1636
                        result.append(getCommonName(i.value()));
×
1637
                        --maxNbItem;
×
1638
                }
1639
        }
1640

1641
        QMapIterator<QString, int> j(commonNamesIndex);
×
1642
        while (j.hasNext())
×
1643
        {
1644
                j.next();
×
1645
                if (useStartOfWords && j.key().startsWith(objw))
×
1646
                        found = true;
×
1647
                else if (!useStartOfWords && j.key().contains(objw))
×
1648
                        found = true;
×
1649
                else
1650
                        found = false;
×
1651

1652
                if (found)
×
1653
                {
1654
                        if (maxNbItem<=0)
×
1655
                                break;
×
1656
                        result.append(getCommonEnglishName(j.value()));
×
1657
                        --maxNbItem;
×
1658
                }
1659
        }
1660

1661
        if (getFlagAdditionalNames())
×
1662
        {
1663
                QMapIterator<QString, int> k(additionalNamesIndexI18n);
×
1664
                while (k.hasNext())
×
1665
                {
1666
                        k.next();
×
1667
                        QStringList names = getAdditionalNames(k.value()).split(" - ");
×
1668
                        for (const auto &name : std::as_const(names))
×
1669
                        {
1670
                                if (useStartOfWords && name.startsWith(objw, Qt::CaseInsensitive))
×
1671
                                        found = true;
×
1672
                                else if (!useStartOfWords && name.contains(objw, Qt::CaseInsensitive))
×
1673
                                        found = true;
×
1674
                                else
1675
                                        found = false;
×
1676

1677
                                if (found)
×
1678
                                {
1679
                                        if (maxNbItem<=0)
×
1680
                                                break;
×
1681
                                        result.append(name);
×
1682
                                        --maxNbItem;
×
1683
                                }
1684
                        }
1685
                }
×
1686

1687
                QMapIterator<QString, int> l(additionalNamesIndex);
×
1688
                while (l.hasNext())
×
1689
                {
1690
                        l.next();
×
1691
                        QStringList names = getAdditionalEnglishNames(l.value()).split(" - ");
×
1692
                        for (const auto &name : std::as_const(names))
×
1693
                        {
1694
                                if (useStartOfWords && name.startsWith(objw, Qt::CaseInsensitive))
×
1695
                                        found = true;
×
1696
                                else if (!useStartOfWords && name.contains(objw, Qt::CaseInsensitive))
×
1697
                                        found = true;
×
1698
                                else
1699
                                        found = false;
×
1700

1701
                                if (found)
×
1702
                                {
1703
                                        if (maxNbItem<=0)
×
1704
                                                break;
×
1705
                                        result.append(name);
×
1706
                                        --maxNbItem;
×
1707
                                }
1708
                        }
1709
                }
×
1710
        }
×
1711

1712
        // Search for sci names
1713
        QString bayerPattern = objPrefix;
×
1714
        QRegularExpression bayerRegEx(bayerPattern);
×
1715
        QString bayerPatternCI = objw;
×
1716
        QRegularExpression bayerRegExCI(bayerPatternCI);
×
1717

1718
        // if the first character is a Greek letter, check if there's an index
1719
        // after it, such as "alpha1 Cen".
1720
        if (objPrefix.at(0).unicode() >= 0x0391 && objPrefix.at(0).unicode() <= 0x03A9)
×
1721
                bayerRegEx.setPattern(bayerPattern.insert(1,"\\d?"));        
×
1722
        if (objw.at(0).unicode() >= 0x0391 && objw.at(0).unicode() <= 0x03A9)
×
1723
                bayerRegExCI.setPattern(bayerPatternCI.insert(1,"\\d?"));
×
1724

1725
        for (auto it = sciDesignationsIndexI18n.lowerBound(objPrefix); it != sciDesignationsIndexI18n.end(); ++it)
×
1726
        {
1727
                if (it.key().indexOf(bayerRegEx)==0 || it.key().indexOf(objPrefix)==0)
×
1728
                {
1729
                        if (maxNbItem<=0)
×
1730
                                break;
×
1731
                        QStringList names = getSciName(it.value()).split(" - ");
×
1732
                        for (const auto &name : std::as_const(names))
×
1733
                        {
1734
                                if (useStartOfWords && name.startsWith(objPrefix, Qt::CaseInsensitive))
×
1735
                                        found = true;
×
1736
                                else if (!useStartOfWords && name.contains(objPrefix, Qt::CaseInsensitive))
×
1737
                                        found = true;
×
1738
                                else
1739
                                        found = false;
×
1740

1741
                                if (found)
×
1742
                                {
1743
                                        if (maxNbItem<=0)
×
1744
                                                break;
×
1745
                                        result.append(name);
×
1746
                                        --maxNbItem;
×
1747
                                }
1748
                        }
1749
                }
×
1750
                else if (it.key().at(0) != objPrefix.at(0))
×
1751
                        break;
×
1752
        }
1753

1754
        for (auto it = sciDesignationsIndexI18n.lowerBound(objw); it != sciDesignationsIndexI18n.end(); ++it)
×
1755
        {
1756
                if (it.key().indexOf(bayerRegExCI)==0 || it.key().indexOf(objw)==0)
×
1757
                {
1758
                        if (maxNbItem<=0)
×
1759
                                break;
×
1760
                        QStringList names = getSciName(it.value()).split(" - ");
×
1761
                        for (const auto &name : std::as_const(names))
×
1762
                        {
1763
                                if (useStartOfWords && name.startsWith(objPrefix, Qt::CaseInsensitive))
×
1764
                                        found = true;
×
1765
                                else if (!useStartOfWords && name.contains(objPrefix, Qt::CaseInsensitive))
×
1766
                                        found = true;
×
1767
                                else
1768
                                        found = false;
×
1769

1770
                                if (found)
×
1771
                                {
1772
                                        if (maxNbItem<=0)
×
1773
                                                break;
×
1774
                                        result.append(name);
×
1775
                                        --maxNbItem;
×
1776
                                }
1777
                        }
1778
                }
×
1779
                else if (it.key().at(0) != objw.at(0))
×
1780
                        break;
×
1781
        }
1782

1783
        for (auto it = sciExtraDesignationsIndexI18n.lowerBound(objPrefix); it != sciExtraDesignationsIndexI18n.end(); ++it)
×
1784
        {
1785
                if (it.key().indexOf(bayerRegEx)==0 || it.key().indexOf(objPrefix)==0)
×
1786
                {
1787
                        if (maxNbItem<=0)
×
1788
                                break;
×
1789
                        QStringList names = getSciExtraName(it.value()).split(" - ");
×
1790
                        for (const auto &name : std::as_const(names))
×
1791
                        {
1792
                                if (useStartOfWords && name.startsWith(objPrefix, Qt::CaseInsensitive))
×
1793
                                        found = true;
×
1794
                                else if (!useStartOfWords && name.contains(objPrefix, Qt::CaseInsensitive))
×
1795
                                        found = true;
×
1796
                                else
1797
                                        found = false;
×
1798

1799
                                if (found)
×
1800
                                {
1801
                                        if (maxNbItem<=0)
×
1802
                                                break;
×
1803
                                        result.append(name);
×
1804
                                        --maxNbItem;
×
1805
                                }
1806
                        }
1807
                }
×
1808
                else if (it.key().at(0) != objPrefix.at(0))
×
1809
                        break;
×
1810
        }
1811

1812
        for (auto it = sciExtraDesignationsIndexI18n.lowerBound(objw); it != sciExtraDesignationsIndexI18n.end(); ++it)
×
1813
        {
1814
                if (it.key().indexOf(bayerRegExCI)==0 || it.key().indexOf(objw)==0)
×
1815
                {
1816
                        if (maxNbItem<=0)
×
1817
                                break;
×
1818
                        QStringList names = getSciExtraName(it.value()).split(" - ");
×
1819
                        for (const auto &name : std::as_const(names))
×
1820
                        {
1821
                                if (useStartOfWords && name.startsWith(objPrefix, Qt::CaseInsensitive))
×
1822
                                        found = true;
×
1823
                                else if (!useStartOfWords && name.contains(objPrefix, Qt::CaseInsensitive))
×
1824
                                        found = true;
×
1825
                                else
1826
                                        found = false;
×
1827

1828
                                if (found)
×
1829
                                {
1830
                                        if (maxNbItem<=0)
×
1831
                                                break;
×
1832
                                        result.append(name);
×
1833
                                        --maxNbItem;
×
1834
                                }
1835
                        }
1836
                }
×
1837
                else if (it.key().at(0) != objw.at(0))
×
1838
                        break;
×
1839
        }
1840

1841
        // Search for sci names for var stars
1842
        for (auto it = varStarsIndexI18n.lowerBound(objw); it != varStarsIndexI18n.end(); ++it)
×
1843
        {
1844
                if (it.key().startsWith(objw))
×
1845
                {
1846
                        if (maxNbItem<=0)
×
1847
                                break;
×
1848
                        result << getGcvsName(it.value());
×
1849
                        --maxNbItem;
×
1850
                }
1851
                else
1852
                        break;
×
1853
        }
1854

1855
        // Add exact Hp catalogue numbers. The final part (A/B/...) is ignored
1856
        static const QRegularExpression hpRx("^(HIP|HP)\\s*(\\d+)\\s*.*$", QRegularExpression::CaseInsensitiveOption);
×
1857
        QRegularExpressionMatch match=hpRx.match(objw);
×
1858
        if (match.hasMatch())
×
1859
        {
1860
                bool ok;
1861
                int hpNum = match.captured(2).toInt(&ok);
×
1862
                if (ok)
×
1863
                {
1864
                        StelObjectP s = searchHP(hpNum);
×
1865
                        if (s && maxNbItem>0)
×
1866
                        {
1867
                                result << QString("HIP%1").arg(hpNum);
×
1868
                                maxNbItem--;
×
1869
                        }
1870
                }
×
1871
        }
1872

1873
        // Add exact SAO catalogue numbers
1874
        static const QRegularExpression saoRx("^(SAO)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1875
        match=saoRx.match(objw);
×
1876
        if (match.hasMatch())
×
1877
        {
1878
                int saoNum = match.captured(2).toInt();
×
1879
                auto sao = saoStarsIndex.find(saoNum);
×
1880
                if (sao!=saoStarsIndex.end())
×
1881
                {
1882
                        StelObjectP s = searchHP(sao.value());
×
1883
                        if (s && maxNbItem>0)
×
1884
                        {
1885
                                result << QString("SAO%1").arg(saoNum);
×
1886
                                maxNbItem--;
×
1887
                        }
1888
                }
×
1889
        }
1890

1891
        // Add exact HD catalogue numbers
1892
        static const QRegularExpression hdRx("^(HD)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1893
        match=hdRx.match(objw);
×
1894
        if (match.hasMatch())
×
1895
        {
1896
                int hdNum = match.captured(2).toInt();
×
1897
                auto hd = hdStarsIndex.find(hdNum);
×
1898
                if (hd!=hdStarsIndex.end())
×
1899
                {
1900
                        StelObjectP s = searchHP(hd.value());
×
1901
                        if (s && maxNbItem>0)
×
1902
                        {
1903
                                result << QString("HD%1").arg(hdNum);
×
1904
                                maxNbItem--;
×
1905
                        }
1906
                }
×
1907
        }
1908

1909
        // Add exact HR catalogue numbers
1910
        static const QRegularExpression hrRx("^(HR)\\s*(\\d+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1911
        match=hrRx.match(objw);
×
1912
        if (match.hasMatch())
×
1913
        {
1914
                int hrNum = match.captured(2).toInt();
×
1915
                auto hr = hrStarsIndex.find(hrNum);
×
1916
                if (hr!=hrStarsIndex.end())
×
1917
                {
1918
                        StelObjectP s = searchHP(hr.value());
×
1919
                        if (s && maxNbItem>0)
×
1920
                        {
1921
                                result << QString("HR%1").arg(hrNum);
×
1922
                                maxNbItem--;
×
1923
                        }
1924
                }
×
1925
        }
1926

1927
        // Add exact WDS catalogue numbers
1928
        static const QRegularExpression wdsRx("^(WDS)\\s*(\\S+)\\s*$", QRegularExpression::CaseInsensitiveOption);
×
1929
        if (wdsRx.match(objw).hasMatch())
×
1930
        {
1931
                for (auto wds = wdsStarsIndexI18n.lowerBound(objw); wds != wdsStarsIndexI18n.end(); ++wds)
×
1932
                {
1933
                        if (wds.key().startsWith(objw))
×
1934
                        {
1935
                                if (maxNbItem==0)
×
1936
                                        break;
×
1937
                                result << getWdsName(wds.value());
×
1938
                                --maxNbItem;
×
1939
                        }
1940
                        else
1941
                                break;
×
1942
                }
1943
        }
1944

1945
        result.sort();        
×
1946
        return result;
×
1947
}
×
1948

1949
//! Define font file name and size to use for star names display
1950
void StarMgr::setFontSize(int newFontSize)
×
1951
{
1952
        starFont.setPixelSize(newFontSize);
×
1953
}
×
1954

1955
void StarMgr::updateSkyCulture(const QString& skyCultureDir)
×
1956
{
1957
        // Load culture star names in english
1958
        QString fic = StelFileMgr::findFile("skycultures/" + skyCultureDir + "/star_names.fab");
×
1959
        if (fic.isEmpty())
×
1960
                qDebug() << "Could not load star_names.fab for sky culture " << QDir::toNativeSeparators(skyCultureDir);
×
1961
        else
1962
                loadCommonNames(fic);
×
1963

1964
        // Turn on sci names/catalog names for modern cultures only
1965
        setFlagSciNames(skyCultureDir.contains("modern", Qt::CaseInsensitive));
×
1966
        updateI18n();
×
1967
}
×
1968

1969
void StarMgr::increaseStarsMagnitudeLimit()
×
1970
{
1971
        StelCore* core = StelApp::getInstance().getCore();
×
1972
        core->getSkyDrawer()->setCustomStarMagnitudeLimit(core->getSkyDrawer()->getCustomStarMagnitudeLimit() + 0.1);
×
1973
}
×
1974

1975
void StarMgr::reduceStarsMagnitudeLimit()
×
1976
{
1977
        StelCore* core = StelApp::getInstance().getCore();
×
1978
        core->getSkyDrawer()->setCustomStarMagnitudeLimit(core->getSkyDrawer()->getCustomStarMagnitudeLimit() - 0.1);
×
1979
}
×
1980

1981
void StarMgr::populateStarsDesignations()
×
1982
{
1983
        QString fic;
×
1984
        fic = StelFileMgr::findFile("stars/default/name.fab");
×
1985
        if (fic.isEmpty())
×
1986
                qWarning() << "WARNING: could not load scientific star names file: stars/default/name.fab";
×
1987
        else
1988
                loadSciNames(fic, false);
×
1989

1990
        fic = StelFileMgr::findFile("stars/default/extra_name.fab");
×
1991
        if (fic.isEmpty())
×
1992
                qWarning() << "WARNING: could not load scientific star extra names file: stars/default/extra_name.fab";
×
1993
        else
1994
                loadSciNames(fic, true);
×
1995

1996
        fic = StelFileMgr::findFile("stars/default/gcvs_hip_part.dat");
×
1997
        if (fic.isEmpty())
×
1998
                qWarning() << "WARNING: could not load variable stars file: stars/default/gcvs_hip_part.dat";
×
1999
        else
2000
                loadGcvs(fic);
×
2001

2002
        fic = StelFileMgr::findFile("stars/default/wds_hip_part.dat");
×
2003
        if (fic.isEmpty())
×
2004
                qWarning() << "WARNING: could not load double stars file: stars/default/wds_hip_part.dat";
×
2005
        else
2006
                loadWds(fic);
×
2007

2008
        fic = StelFileMgr::findFile("stars/default/cross-id.dat");
×
2009
        if (fic.isEmpty())
×
2010
                qWarning() << "WARNING: could not load cross-identification data file: stars/default/cross-id.dat";
×
2011
        else
2012
                loadCrossIdentificationData(fic);
×
2013

2014
        fic = StelFileMgr::findFile("stars/default/hip_plx_err.dat");
×
2015
        if (fic.isEmpty())
×
2016
                qWarning() << "WARNING: could not load parallax errors data file: stars/default/hip_plx_err.dat";
×
2017
        else
2018
                loadPlxErr(fic);
×
2019

2020
        fic = StelFileMgr::findFile("stars/default/hip_pm.dat");
×
2021
        if (fic.isEmpty())
×
2022
                qWarning() << "WARNING: could not load proper motion data file: stars/default/hip_pm.dat";
×
2023
        else
2024
                loadPMData(fic);
×
2025
}
×
2026

2027
QStringList StarMgr::listAllObjects(bool inEnglish) const
×
2028
{
2029
        QStringList result;
×
2030
        if (inEnglish)
×
2031
        {
2032
                QMapIterator<QString, int> i(commonNamesIndex);
×
2033
                while (i.hasNext())
×
2034
                {
2035
                        i.next();
×
2036
                        result << getCommonEnglishName(i.value());
×
2037
                }
2038
        }
×
2039
        else
2040
        {
2041
                QMapIterator<QString, int> i(commonNamesIndexI18n);
×
2042
                while (i.hasNext())
×
2043
                {
2044
                        i.next();
×
2045
                        result << getCommonName(i.value());
×
2046
                }
2047
        }
×
2048
        return result;
×
2049
}
×
2050

2051
QStringList StarMgr::listAllObjectsByType(const QString &objType, bool inEnglish) const
×
2052
{
2053
        QStringList result;        
×
2054
        // type 1
2055
        bool isStarT1 = false;
×
2056
        QList<StelObjectP> starsT1;
×
2057
        // type 2
2058
        bool isStarT2 = false;
×
2059
        QList<QMap<StelObjectP, float>> starsT2;
×
NEW
2060
        int type = objType.toInt();        
×
UNCOV
2061
        switch (type)
×
2062
        {
2063
                case 0: // Interesting double stars
×
2064
                {
2065
                        static const QStringList doubleStars = {
2066
                                "21 Tau", "27 Tau", "77 Tau", "δ1 Tau", "V1016 Ori",
2067
                                "42 Ori", "ι Ori", "ζ Crv", "ζ UMa", "α2 Lib", "α1 Cru",
2068
                                "ω1 Sco", "λ Sco", "μ1 Sco", "ζ1 Sco", "ε1 Lyr", "ε2 Lyr",
2069
                                "δ1 Lyr",         "ν1 Sgr", "ο1 Cyg", "ο2 Cyg", "α2 Cap", "β1 Cyg",
2070
                                "β Ori", "γ1 And", "ξ Boo", "α1 Her", "T Dra", "ν1 Dra",
2071
                                "70 Oph", "α Gem", "ζ Her", "ο2 Eri", "γ1 Ari", "γ Vir",
2072
                                "γ1 Leo", "β Mon", "ε Boo", "44 Boo", "β1 Sco", "ζ1 Cnc",
2073
                                "φ2 Cnc", "α Leo", "α2 CVn", "ι Cas", "ε Ari", "κ Vel", "γ1 Del",
2074
                                "61 Cyg B", "55 Aqr", "σ Cas", "η Cas", "α UMi", "36 Oph",
2075
                                "α1 Cen",  "65 UMa", "σ2 UMa", "55 Cnc", "16 Cyg A",
2076
                                "HIP 28393", "HIP 84709"};
×
2077
                        result = doubleStars;
×
2078
                        break;
×
2079
                }
2080
                case 1: // Interesting variable stars
×
2081
                {
2082
                        static const QStringList variableStars = {
2083
                                "δ Cep", "β Per", "ο Cet", "λ Tau", "β Lyr", "ζ Gem", "μ Cep",
2084
                                "α1 Her", "η Gem", "η Aql", "γ Cas", "α Ori", "R And",
2085
                                "U Ant", "θ Aps", "R Aql", "V Aql", "R Aqr", "ε Aur", "R Aur",
2086
                                "AE Aur", "W Boo", "VZ Cam", "l Car", "WZ Cas",        "S Cen",
2087
                                "α Cen C", "T Cep", "U Cep", "R CMa", "VY CMa",
2088
                                "S Cnc", "α CrB", "R CrB", "T CrB", "U CrB", "R Cru",
2089
                                "SU Cyg", "EU Del", "β Dor", "R Gem", "30 Her", "68 Her",
2090
                                "R Hor", "R Lep", "R Leo", "RR Lyr", "U Mon", "R Hya", "χ Cyg",
2091
                                "δ Ori", "VV Ori", "κ Pav", "β Peg", "ε Peg", "ζ Phe", "R Sct",
2092
                                "U Sgr", "RY Sgr", "W UMa", "α UMi"};
×
2093
                        result = variableStars;
×
2094
                        break;
×
2095
                }
2096
                case 2: // Bright double stars
×
2097
                {
2098
                        starsT2 = doubleHipStars;
×
2099
                        isStarT2 = true;
×
2100
                        break;
×
2101
                }
2102
                case 3: // Bright variable stars
×
2103
                {
2104
                        starsT2 = variableHipStars;
×
2105
                        isStarT2 = true;
×
2106
                        break;
×
2107
                }
2108
                case 4:
×
2109
                {
2110
                        starsT2 = hipStarsHighPM;
×
2111
                        isStarT2 = true;
×
2112
                        break;
×
2113
                }
2114
                case 5: // Variable stars: Algol-type eclipsing systems
×
2115
                {
2116
                        starsT2 = algolTypeStars;
×
2117
                        isStarT2 = true;
×
2118
                        break;
×
2119
                }
2120
                case 6: // Variable stars: the classical cepheids
×
2121
                {
2122
                        starsT2 = classicalCepheidsTypeStars;
×
2123
                        isStarT2 = true;
×
2124
                        break;
×
2125
                }
2126
                case 7: // Bright carbon stars
×
2127
                {
2128
                        starsT1 = carbonStars;
×
2129
                        isStarT1 = true;
×
2130
                        break;
×
2131
                }
2132
                case 8: // Bright barium stars
×
2133
                {
2134
                        starsT1 = bariumStars;
×
2135
                        isStarT1 = true;
×
2136
                        break;
×
2137
                }
2138
                default:
×
2139
                {
2140
                        // No stars yet?
2141
                        break;
×
2142
                }
2143
        }
2144

2145
        QString starName;
×
2146
        if (isStarT1)
×
2147
        {
2148
                for (const auto& star : std::as_const(starsT1))
×
2149
                {
2150
                        starName = inEnglish ? star->getEnglishName() : star->getNameI18n();
×
2151
                        if (!starName.isEmpty())
×
2152
                                result << starName;
×
2153
                        else
2154
                                result << star->getID();
×
2155
                }
2156
        }
2157

2158
        if (isStarT2)
×
2159
        {
2160
                for (const auto& star : std::as_const(starsT2))
×
2161
                {
2162
                        starName = inEnglish ? star.firstKey()->getEnglishName() : star.firstKey()->getNameI18n();
×
2163
                        if (!starName.isEmpty())
×
2164
                                result << starName;
×
2165
                        else
2166
                                result << star.firstKey()->getID();
×
2167
                }
2168
        }
2169

2170
        result.removeDuplicates();
×
2171
        return result;
×
2172
}
×
2173

2174
QString StarMgr::getStelObjectType() const
×
2175
{
2176
        return STAR_TYPE;
×
2177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc