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

Stellarium / stellarium / 17068063291

19 Aug 2025 11:22AM UTC coverage: 11.766%. Remained the same
17068063291

push

github

alex-w
Reformatting

14706 of 124990 relevant lines covered (11.77%)

18303.49 hits per line

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

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

21

22
#include "ConstellationMgr.hpp"
23
#include "Constellation.hpp"
24
#include "StarMgr.hpp"
25
#include "StelUtils.hpp"
26
#include "StelApp.hpp"
27
#include "StelTextureMgr.hpp"
28
#include "StelProjector.hpp"
29
#include "StelObjectMgr.hpp"
30
#include "StelLocaleMgr.hpp"
31
#include "StelSkyCultureMgr.hpp"
32
#include "StelModuleMgr.hpp"
33
#include "StelMovementMgr.hpp"
34
#include "StelFileMgr.hpp"
35
#include "StelCore.hpp"
36
#include "StelPainter.hpp"
37
#include "Planet.hpp"
38
#include "StelUtils.hpp"
39
#include "precession.h"
40

41
#include <vector>
42
#include <QDebug>
43
#include <QFile>
44
#include <QSettings>
45
#include <QRegularExpression>
46
#include <QString>
47
#include <QStringList>
48
#include <QDir>
49

50
// constructor which loads all data from appropriate files
51
ConstellationMgr::ConstellationMgr(StarMgr *_hip_stars)
×
52
        : hipStarMgr(_hip_stars),
×
53
          isolateSelected(false),
×
54
          flagConstellationPick(false),
×
55
          artFadeDuration(2.),
×
56
          artIntensity(0),
×
57
          artIntensityMinimumFov(1.0),
×
58
          artIntensityMaximumFov(2.0),
×
59
          artDisplayed(false),
×
60
          boundariesDisplayed(false),
×
61
          boundariesFadeDuration(1.),
×
62
          linesDisplayed(false),
×
63
          linesFadeDuration(0.),
×
64
          namesDisplayed(false),
×
65
          namesFadeDuration(1.),
×
66
          hullsDisplayed(false),
×
67
          hullsFadeDuration(1.),
×
68
          zodiacFadeDuration(1.),
×
69
          lunarSystemFadeDuration(1.),
×
70
          checkLoadingData(false),
×
71
          constellationLineThickness(1),
×
72
          boundariesThickness(1),
×
73
          hullsThickness(1),
×
74
          zodiacThickness(1),
×
75
          lunarSystemThickness(1),
×
76
          zodiacColor(1.,1.,0.),
×
77
          lunarSystemColor(0., 1., 0.5)
×
78
{
79
        setObjectName("ConstellationMgr");
×
80
        Q_ASSERT(hipStarMgr);
×
81
}
×
82

83
ConstellationMgr::~ConstellationMgr()
×
84
{
85
        for (auto* constellation : constellations)
×
86
        {
87
                delete constellation;
×
88
        }
89

90
        for (auto* segment : allBoundarySegments)
×
91
        {
92
                delete segment;
×
93
        }
94
}
×
95

96
void ConstellationMgr::init()
×
97
{
98
        QSettings* conf = StelApp::getInstance().getSettings();
×
99
        Q_ASSERT(conf);
×
100

101
        setFontSize(conf->value("viewing/constellation_font_size", 15).toInt());
×
102
        setFlagLines(conf->value("viewing/flag_constellation_drawing", false).toBool());
×
103
        setFlagLabels(conf->value("viewing/flag_constellation_name", false).toBool());
×
104
        setFlagBoundaries(conf->value("viewing/flag_constellation_boundaries", false).toBool());
×
105
        setFlagHulls(conf->value("viewing/flag_constellation_hulls", false).toBool());
×
106
        setFlagZodiac(conf->value("viewing/flag_skyculture_zodiac", false).toBool());
×
107
        setFlagLunarSystem(conf->value("viewing/flag_skyculture_lunarsystem", false).toBool());
×
108
        setArtIntensity(conf->value("viewing/constellation_art_intensity", 0.5f).toFloat());
×
109
        setArtFadeDuration(conf->value("viewing/constellation_art_fade_duration",2.f).toFloat());
×
110
        setFlagArt(conf->value("viewing/flag_constellation_art", false).toBool());
×
111
        setFlagIsolateSelected(conf->value("viewing/flag_constellation_isolate_selected", false).toBool());
×
112
        setFlagConstellationPick(conf->value("viewing/flag_constellation_pick", false).toBool());
×
113
        setConstellationLineThickness(conf->value("viewing/constellation_line_thickness", 1).toInt());
×
114
        setBoundariesThickness(conf->value("viewing/constellation_boundaries_thickness", 1).toInt());
×
115
        setBoundariesFadeDuration(conf->value("viewing/constellation_boundaries_fade_duration", 1.0f).toFloat());
×
116
        setHullsThickness(conf->value("viewing/constellation_hulls_thickness", 1).toInt());
×
117
        setHullsFadeDuration(conf->value("viewing/constellation_hulls_fade_duration", 1.0f).toFloat());
×
118
        setZodiacThickness(conf->value("viewing/skyculture_zodiac_thickness", 1).toInt());
×
119
        setZodiacFadeDuration(conf->value("viewing/skyculture_zodiac_fade_duration", 1.0f).toFloat());
×
120
        setHullsThickness(conf->value("viewing/skyculture_lunarsystem_thickness", 1).toInt());
×
121
        setLunarSystemFadeDuration(conf->value("viewing/skyculture_lunarsystem_fade_duration", 1.0f).toFloat());
×
122

123
        setLinesFadeDuration(conf->value("viewing/constellation_lines_fade_duration", 1.0f).toFloat());
×
124
        setLabelsFadeDuration(conf->value("viewing/constellation_labels_fade_duration", 1.0f).toFloat());
×
125
        // The setting for developers
126
        setFlagCheckLoadingData(conf->value("devel/check_loading_constellation_data","false").toBool());
×
127

128
        // Load colors from config file
129
        QString defaultColor = conf->value("color/default_color").toString();
×
130
        setLinesColor(Vec3f(conf->value("color/const_lines_color", defaultColor).toString()));
×
131
        setBoundariesColor(Vec3f(conf->value("color/const_boundary_color", "0.8,0.3,0.3").toString()));
×
132
        setHullsColor(Vec3f(conf->value("color/const_hull_color", "0.6,0.2,0.2").toString()));
×
133
        setZodiacColor(Vec3f(conf->value("color/skyculture_zodiac_color", "1.0,1.0,0.0").toString()));
×
134
        setLunarSystemColor(Vec3f(conf->value("color/skyculture_lunarsystem_color", "0.0,1.0,0.5").toString()));
×
135
        setLabelsColor(Vec3f(conf->value("color/const_names_color", defaultColor).toString()));
×
136

137
        StelObjectMgr *objectManager = GETSTELMODULE(StelObjectMgr);
×
138
        objectManager->registerStelObjectMgr(this);
×
139
        connect(objectManager, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
×
140
                        this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
141
        StelApp *app = &StelApp::getInstance();
×
142
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
143
        connect(&app->getSkyCultureMgr(), &StelSkyCultureMgr::currentSkyCultureChanged, this, &ConstellationMgr::updateSkyCulture);
×
144

145
        QString displayGroup = N_("Display Options");
×
146
        addAction("actionShow_Constellation_Lines", displayGroup, N_("Constellation lines"), "linesDisplayed", "C");
×
147
        addAction("actionShow_Constellation_Art", displayGroup, N_("Constellation art"), "artDisplayed", "R");
×
148
        addAction("actionShow_Constellation_Labels", displayGroup, N_("Constellation labels"), "namesDisplayed", "V");
×
149
        addAction("actionShow_Constellation_Boundaries", displayGroup, N_("Constellation boundaries"), "boundariesDisplayed", "B");
×
150
        addAction("actionShow_Zodiac", displayGroup, N_("Zodiac (if defined in skyculture)"), "zodiacDisplayed");
×
151
        addAction("actionShow_LunarSystem", displayGroup, N_("Lunar stations/mansions (if defined in skyculture)"), "lunarSystemDisplayed");
×
152

153
        if (conf->value("gui/skyculture_enable_hulls", "false").toBool())
×
154
                addAction("actionShow_Constellation_Hulls", displayGroup, N_("Constellation areas (hulls)"), "hullsDisplayed", "Shift+B");
×
155
        addAction("actionShow_Constellation_Isolated", displayGroup, N_("Select single constellation"), "isolateSelected"); // no shortcut, sync with GUI
×
156
        addAction("actionShow_Constellation_Deselect", displayGroup, N_("Remove selection of constellations"), this, "deselectConstellations()", "W");
×
157
        addAction("actionShow_Constellation_Select", displayGroup, N_("Select all constellations"), this, "selectAllConstellations()", "Alt+W");
×
158
        // Reload the current sky culture
159
        addAction("actionShow_SkyCulture_Reload", displayGroup, N_("Reload the sky culture"), this, "reloadSkyCulture()", "Ctrl+Alt+I");
×
160
}
×
161

162
/*************************************************************************
163
 Reimplementation of the getCallOrder method
164
*************************************************************************/
165
double ConstellationMgr::getCallOrder(StelModuleActionName actionName) const
×
166
{
167
        if (actionName==StelModule::ActionDraw)
×
168
                return StelApp::getInstance().getModuleMgr().getModule("GridLinesMgr")->getCallOrder(actionName)+10;
×
169
        return 0;
×
170
}
171

172
void ConstellationMgr::reloadSkyCulture()
×
173
{
174
        StelApp::getInstance().getSkyCultureMgr().reloadSkyCulture();
×
175
}
×
176

177
void ConstellationMgr::updateSkyCulture(const StelSkyCulture& skyCulture)
×
178
{
179
        // first of all, remove constellations from the list of selected objects in StelObjectMgr, since we are going to delete them
180
        deselectConstellations();
×
181
        loadLinesNamesAndArt(skyCulture);
×
182

183
        // Load optional StelSkyCultureSkyPartitions, or delete obsolete ones. [PRELIMINARY]
184
        if (skyCulture.zodiac.count()>1)
×
185
        {
186
                zodiac = StelSkyCultureSkyPartitionP(new StelSkyCultureSkyPartition(skyCulture.zodiac));
×
187
                zodiac->centerLine->setDisplayed(true);
×
188
        }
189
        else if (zodiac) zodiac.clear();
×
190

191
        if (skyCulture.lunarSystem.count()>1)
×
192
        {
193
                lunarSystem = StelSkyCultureSkyPartitionP(new StelSkyCultureSkyPartition(skyCulture.lunarSystem));
×
194
                lunarSystem->centerLine->setDisplayed(true);
×
195
        }
196
        else if (lunarSystem) lunarSystem.clear();
×
197

198
        // Translate constellation names for the new sky culture
199
        updateI18n();
×
200

201
        loadBoundaries(skyCulture.boundaries, skyCulture.boundariesEpoch);
×
202

203
        if (getFlagCheckLoadingData())
×
204
        {
205
                int i = 1;
×
206
                for (auto* constellation : std::as_const(constellations))
×
207
                {
208
                        qInfo() << "[Constellation] #" << i << " abbr:" << constellation->abbreviation << " name:" << constellation->getEnglishName() << " segments:" << constellation->numberOfSegments;
×
209
                        i++;
×
210
                }
211
        }
212
}
×
213

214
void ConstellationMgr::selectedObjectChange(StelModule::StelModuleSelectAction action)
×
215
{
216
        StelObjectMgr* omgr = GETSTELMODULE(StelObjectMgr);
×
217
        Q_ASSERT(omgr);
×
218
        const QList<StelObjectP> newSelected = omgr->getSelectedObject();
×
219
        if (newSelected.empty())
×
220
        {
221
                // Even if do not have anything selected, KEEP constellation selection intact
222
                // (allows viewing constellations without distraction from star pointer animation)
223
                // setSelected(nullptr);
224
                return;
×
225
        }
226
#ifndef NDEBUG
227
        else
228
        {
229
                qDebug() << "ConstellationMgr::selectedObjectChange(): selected objects:";
×
230
                foreach (StelObjectP obj, newSelected)
×
231
                        qDebug() << "   " << obj->getID();
×
232
        }
233
#endif
234

235
        const QList<StelObjectP> newSelectedConst = omgr->getSelectedObject("Constellation");
×
236
        if (!newSelectedConst.empty())
×
237
        {
238
                // If removing this selection
239
                if(action == StelModule::RemoveFromSelection)
×
240
                {
241
                        unsetSelectedConst(static_cast<Constellation *>(newSelectedConst[0].data()));
×
242
                }
243
                else
244
                {
245
                        // Add constellation to selected list (do not select a star, just the constellation)
246
                        QList<Constellation*>cList;
×
247
                        cList.append(static_cast<Constellation *>(newSelectedConst[0].data()));
×
248
                        setSelectedConst(cList);
×
249
                }
×
250
        }
251
        else
252
        {
253
                QList<StelObjectP> newSelectedObject = omgr->getSelectedObject();
×
254
                if (!newSelectedObject.empty())
×
255
                {
256
                        setSelected(newSelectedObject[0].data());
×
257
                }
258
                else
259
                {
260
                        setSelected(nullptr);
×
261
                }
262
        }
×
263
}
×
264

265
void ConstellationMgr::deselectConstellations(void)
×
266
{
267
        static StelObjectMgr* omgr = GETSTELMODULE(StelObjectMgr);
×
268
        Q_ASSERT(omgr);
×
269
        if (getFlagIsolateSelected())
×
270
        {
271
                // The list of selected constellations is empty, but...
272
                if (selected.size()==0)
×
273
                {
274
                        // ...let's unselect all constellations for guarantee
275
                        for (auto& constellation : constellations)
×
276
                        {
277
                                constellation->setFlagLines(false);
×
278
                                constellation->setFlagLabels(false);
×
279
                                constellation->setFlagArt(false);
×
280
                                constellation->setFlagBoundaries(false);
×
281
                                constellation->setFlagHull(false);
×
282
                        }
283
                }
284

285
                // If any constellation is selected at the moment, then let's do not touch to it!
286
                if (omgr->getWasSelected() && !selected.empty())
×
287
                        selected.pop_back();
×
288

289
                // Let's hide all previously selected constellations
290
                for (auto& constellation : selected)
×
291
                {
292
                        constellation->setFlagLines(false);
×
293
                        constellation->setFlagLabels(false);
×
294
                        constellation->setFlagArt(false);
×
295
                        constellation->setFlagBoundaries(false);
×
296
                        constellation->setFlagHull(false);
×
297
                }
298
        }
299
        else
300
        {
301
                const QList<StelObjectP> newSelectedConst = omgr->getSelectedObject("Constellation");
×
302
                if (!newSelectedConst.empty())
×
303
                        omgr->unSelect();
×
304
        }
×
305
        selected.clear();
×
306
}
×
307

308
void ConstellationMgr::selectAllConstellations()
×
309
{
310
        // We really must select in a loop! (GH:#4415)
311
        for (auto* constellation : qAsConst(constellations))
×
312
        {
313
                QList<Constellation *>cList;
×
314
                cList.append(constellation);
×
315
                setSelectedConst(cList);
×
316
        }
×
317
}
×
318

319
void ConstellationMgr::selectConstellation(const QString &englishName)
×
320
{
321
        if (!getFlagIsolateSelected())
×
322
                setFlagIsolateSelected(true); // Enable isolated selection
×
323

324
        bool found = false;
×
325
        QList<Constellation *>cList;
×
326
        for (auto& constellation : constellations)
×
327
        {
328
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
329
                {
330
                        cList.append(constellation);
×
331
                        setSelectedConst(cList);
×
332
                        found = true;
×
333
                }
334
        }
335
        if (!found)
×
336
                qDebug() << "The constellation" << englishName << "was not found";
×
337
}
×
338

339
void ConstellationMgr::selectConstellationByObjectName(const QString &englishName)
×
340
{
341
        if (!getFlagIsolateSelected())
×
342
                setFlagIsolateSelected(true); // Enable isolated selection
×
343

344
        if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
345
                setSelectedConst(isObjectIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data(), false));
×
346
        else
347
                setSelectedConst(isObjectIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data(), true));
×
348
}
×
349

350
void ConstellationMgr::deselectConstellation(const QString &englishName)
×
351
{
352
        if (!getFlagIsolateSelected())
×
353
                setFlagIsolateSelected(true); // Enable isolated selection
×
354

355
        bool found = false;
×
356
        for (auto& constellation : constellations)
×
357
        {
358
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
359
                {
360
                        unsetSelectedConst(constellation);
×
361
                        found = true;
×
362
                }
363
        }
364

365
        if (selected.size()==0 && found)
×
366
        {
367
                // Let's remove the selection for all constellations if the list of selected constellations is empty
368
                for (auto& constellation : constellations)
×
369
                {
370
                        constellation->setFlagLines(false);
×
371
                        constellation->setFlagLabels(false);
×
372
                        constellation->setFlagArt(false);
×
373
                        constellation->setFlagBoundaries(false);
×
374
                        constellation->setFlagHull(false);
×
375
                }
376
        }
377

378
        if (!found)
×
379
                qDebug() << "The constellation" << englishName << "was not found";
×
380
}
×
381

382
void ConstellationMgr::setLinesColor(const Vec3f& color)
×
383
{
384
        if (color != Constellation::lineColor)
×
385
        {
386
                Constellation::lineColor = color;
×
387
                emit linesColorChanged(color);
×
388
        }
389
}
×
390

391
Vec3f ConstellationMgr::getLinesColor() const
×
392
{
393
        return Constellation::lineColor;
×
394
}
395

396
void ConstellationMgr::setBoundariesColor(const Vec3f& color)
×
397
{
398
        if (Constellation::boundaryColor != color)
×
399
        {
400
                Constellation::boundaryColor = color;
×
401
                emit boundariesColorChanged(color);
×
402
        }
403
}
×
404

405
Vec3f ConstellationMgr::getBoundariesColor() const
×
406
{
407
        return Constellation::boundaryColor;
×
408
}
409

410
void ConstellationMgr::setHullsColor(const Vec3f& color)
×
411
{
412
        if (Constellation::hullColor != color)
×
413
        {
414
                Constellation::hullColor = color;
×
415
                emit hullsColorChanged(color);
×
416
        }
417
}
×
418

419
Vec3f ConstellationMgr::getHullsColor() const
×
420
{
421
        return Constellation::hullColor;
×
422
}
423

424
void ConstellationMgr::setZodiacColor(const Vec3f& color)
×
425
{
426
        if (zodiacColor != color)
×
427
        {
428
                zodiacColor = color;
×
429
                emit zodiacColorChanged(color);
×
430
        }
431
}
×
432

433
Vec3f ConstellationMgr::getZodiacColor() const
×
434
{
435
        return zodiacColor;
×
436
}
437

438
void ConstellationMgr::setLunarSystemColor(const Vec3f& color)
×
439
{
440
        if (lunarSystemColor != color)
×
441
        {
442
                lunarSystemColor = color;
×
443
                emit lunarSystemColorChanged(color);
×
444
        }
445
}
×
446

447
Vec3f ConstellationMgr::getLunarSystemColor() const
×
448
{
449
        return lunarSystemColor;
×
450
}
451

452
void ConstellationMgr::setLabelsColor(const Vec3f& color)
×
453
{
454
        if (Constellation::labelColor != color)
×
455
        {
456
                Constellation::labelColor = color;
×
457
                emit namesColorChanged(color);
×
458
        }
459
}
×
460

461
Vec3f ConstellationMgr::getLabelsColor() const
×
462
{
463
        return Constellation::labelColor;
×
464
}
465

466
void ConstellationMgr::setFontSize(const int newFontSize)
×
467
{
468
        if (asterFont.pixelSize() - newFontSize != 0)
×
469
        {
470
                asterFont.setPixelSize(newFontSize);
×
471
                StelApp::immediateSave("viewing/constellation_font_size", newFontSize);
×
472
                emit fontSizeChanged(newFontSize);
×
473
        }
474
}
×
475

476
int ConstellationMgr::getFontSize() const
×
477
{
478
        return asterFont.pixelSize();
×
479
}
480

481
void ConstellationMgr::setConstellationLineThickness(const int thickness)
×
482
{
483
        if(thickness!=constellationLineThickness)
×
484
        {
485
                constellationLineThickness = qMax(1, thickness); // cannot be 0 or neg.
×
486

487
                StelApp::immediateSave("viewing/constellation_line_thickness", thickness);
×
488
                emit constellationLineThicknessChanged(thickness);
×
489
        }
490
}
×
491

492
void ConstellationMgr::setBoundariesThickness(const int thickness)
×
493
{
494
        if(thickness!=boundariesThickness)
×
495
        {
496
                boundariesThickness = qMax(1, thickness); // cannot be 0 or neg.
×
497

498
                StelApp::immediateSave("viewing/constellation_boundaries_thickness", thickness);
×
499
                emit boundariesThicknessChanged(thickness);
×
500
        }
501
}
×
502

503
void ConstellationMgr::setHullsThickness(const int thickness)
×
504
{
505
        if(thickness!=hullsThickness)
×
506
        {
507
                hullsThickness = qMax(1, thickness); // cannot be 0 or neg.
×
508

509
                StelApp::immediateSave("viewing/constellation_hulls_thickness", thickness);
×
510
                emit hullsThicknessChanged(thickness);
×
511
        }
512
}
×
513

514
void ConstellationMgr::setZodiacThickness(const int thickness)
×
515
{
516
        if(thickness!=zodiacThickness)
×
517
        {
518
                zodiacThickness = qMax(1, thickness); // cannot be 0 or neg.
×
519

520
                StelApp::immediateSave("viewing/skyculture_zodiac_thickness", thickness);
×
521
                emit zodiacThicknessChanged(thickness);
×
522
        }
523
}
×
524

525
void ConstellationMgr::setLunarSystemThickness(const int thickness)
×
526
{
527
        if(thickness!=lunarSystemThickness)
×
528
        {
529
                lunarSystemThickness = qMax(1, thickness); // cannot be 0 or neg.
×
530

531
                StelApp::immediateSave("viewing/skyculture_lunar_system_thickness", thickness);
×
532
                emit lunarSystemThicknessChanged(thickness);
×
533
        }
534
}
×
535

536
void ConstellationMgr::loadLinesNamesAndArt(const StelSkyCulture &culture)
×
537
{
538
        constellations.clear();
×
539
        Constellation::seasonalRuleEnabled = false;
×
540

541
        int readOk = 0;
×
542
        for (const auto& constellationData : culture.constellations)
×
543
        {
544
                Constellation*const cons = new Constellation;
×
545
                const auto consObj = constellationData.toObject();
×
546
                if (!cons->read(consObj, hipStarMgr))
×
547
                {
548
                        delete cons;
×
549
                        continue;
×
550
                }
551
                ++readOk;
×
552
                constellations.push_back(cons);
×
553

554
                cons->artOpacity = artIntensity;
×
555
                cons->artFader.setDuration(static_cast<int>(artFadeDuration * 1000.f));
×
556
                cons->lineFader.setDuration(static_cast<int>(linesFadeDuration * 1000.f));
×
557
                cons->boundaryFader.setDuration(static_cast<int>(boundariesFadeDuration * 1000.f));
×
558
                cons->hullFader.setDuration(static_cast<int>(hullsFadeDuration * 1000.f));
×
559
                cons->nameFader.setDuration(static_cast<int>(namesFadeDuration * 1000.f));
×
560
                cons->setFlagArt(artDisplayed);
×
561
                cons->setFlagBoundaries(boundariesDisplayed);
×
562
                cons->setFlagHull(hullsDisplayed);
×
563
                cons->setFlagLines(linesDisplayed);
×
564
                cons->setFlagLabels(namesDisplayed);
×
565

566
                // Now load constellation art
567

568
                const auto imgVal = consObj["image"];
×
569
                if (imgVal.isUndefined())
×
570
                        continue;
×
571
                const auto imgData = imgVal.toObject();
×
572
                const auto anchors = imgData["anchors"].toArray();
×
573
                if (anchors.size() < 3)
×
574
                {
575
                        qWarning().nospace() << "Bad number of anchors (" << anchors.size() << ") for image in constellation "
×
576
                                             << consObj["id"].toString();
×
577
                        continue;
×
578
                }
579
                const auto anchor1 = anchors[0].toObject();
×
580
                const auto anchor2 = anchors[1].toObject();
×
581
                const auto anchor3 = anchors[2].toObject();
×
582
                const auto xy1 = anchor1["pos"].toArray();
×
583
                const auto xy2 = anchor2["pos"].toArray();
×
584
                const auto xy3 = anchor3["pos"].toArray();
×
585

586
                const int x1 = xy1[0].toInt();
×
587
                const int y1 = xy1[1].toInt();
×
588
                const int x2 = xy2[0].toInt();
×
589
                const int y2 = xy2[1].toInt();
×
590
                const int x3 = xy3[0].toInt();
×
591
                const int y3 = xy3[1].toInt();
×
592
                const int hp1 = StelUtils::getLongLong(anchor1["hip"]);
×
593
                const int hp2 = StelUtils::getLongLong(anchor2["hip"]);
×
594
                const int hp3 = StelUtils::getLongLong(anchor3["hip"]);
×
595

596
                const auto texfile = imgData["file"].toString();
×
597

598
                auto texturePath = culture.path+"/"+texfile;
×
599
                if (!QFileInfo::exists(texturePath))
×
600
                {
601
                        qWarning() << "ERROR: could not find texture" << QDir::toNativeSeparators(texfile);
×
602
                        texturePath.clear();
×
603
                }
604

605
                cons->artTexture = StelApp::getInstance().getTextureManager().createTextureThread(texturePath, StelTexture::StelTextureParams(true));
×
606

607
                const auto sizeData = imgData["size"].toArray();
×
608
                if (sizeData.size() != 2)
×
609
                {
610
                        qWarning().nospace() << "Bad length of \"size\" array for image in constellation "
×
611
                                             << consObj["id"].toString();
×
612
                        continue;
×
613
                }
614
                const int texSizeX = sizeData[0].toInt(), texSizeY = sizeData[1].toInt();
×
615

616
                StelCore* core = StelApp::getInstance().getCore();
×
617
                StelObjectP s1obj = hipStarMgr->searchHP(static_cast<int>(hp1));
×
618
                StelObjectP s2obj = hipStarMgr->searchHP(static_cast<int>(hp2));
×
619
                StelObjectP s3obj = hipStarMgr->searchHP(static_cast<int>(hp3));
×
620

621
                // check for null pointers
622
                if (s1obj.isNull() || s2obj.isNull() || s3obj.isNull())
×
623
                {
624
                        qWarning() << "ERROR: could not find stars:" << hp1 << hp2 << hp3 << " in constellation" << consObj["id"].toString();
×
625
                        continue;
×
626
                }
627

628
                const Vec3d s1 = s1obj->getJ2000EquatorialPos(core);
×
629
                const Vec3d s2 = s2obj->getJ2000EquatorialPos(core);
×
630
                const Vec3d s3 = s3obj->getJ2000EquatorialPos(core);
×
631

632
                // To transform from texture coordinate to 2d coordinate we need to find X with XA = B
633
                // A formed of 4 points in texture coordinate, B formed with 4 points in 3d coordinate space
634
                // We need 3 stars and the 4th point is deduced from the others to get a normal base
635
                // X = B inv(A)
636
                Vec3d s4 = s1 + ((s2 - s1) ^ (s3 - s1));
×
637
                Mat4d B(s1[0], s1[1], s1[2], 1, s2[0], s2[1], s2[2], 1, s3[0], s3[1], s3[2], 1, s4[0], s4[1], s4[2], 1);
×
638
                Mat4d A(x1, texSizeY - static_cast<int>(y1), 0., 1., x2, texSizeY - static_cast<int>(y2), 0., 1., x3, texSizeY - static_cast<int>(y3), 0., 1., x1, texSizeY - static_cast<int>(y1), texSizeX, 1.);
×
639
                Mat4d X = B * A.inverse();
×
640

641
                // Tessellate on the plane assuming a tangential projection for the image
642
                static const int nbPoints=5;
643
                QVector<Vec2f> texCoords;
×
644
                texCoords.reserve(nbPoints*nbPoints*6);
×
645
                for (int j=0;j<nbPoints;++j)
×
646
                {
647
                        for (int i=0;i<nbPoints;++i)
×
648
                        {
649
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j))/nbPoints);
×
650
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j))/nbPoints);
×
651
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
652
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j))/nbPoints);
×
653
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
654
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
655
                        }
656
                }
657

658
                QVector<Vec3d> contour;
×
659
                contour.reserve(texCoords.size());
×
660
                for (const auto& v : std::as_const(texCoords))
×
661
                {
662
                        Vec3d vertex = X * Vec3d(static_cast<double>(v[0]) * texSizeX, static_cast<double>(v[1]) * texSizeY, 0.);
×
663
                        // Originally the projected texture plane remained as tangential plane.
664
                        // The vertices should however be reduced to the sphere for correct aberration:
665
                        vertex.normalize();
×
666
                        contour << vertex;
×
667
                }
668

669
                cons->artPolygon.vertex=contour;
×
670
                cons->artPolygon.texCoords=texCoords;
×
671
                cons->artPolygon.primitiveType=StelVertexArray::Triangles;
×
672

673
                Vec3d tmp(X * Vec3d(0.5*texSizeX, 0.5*texSizeY, 0.));
×
674
                tmp.normalize();
×
675
                Vec3d tmp2(X * Vec3d(0., 0., 0.));
×
676
                tmp2.normalize();
×
677
                cons->boundingCap.n=tmp;
×
678
                cons->boundingCap.d=tmp*tmp2;
×
679
        }
×
680

681
        qInfo().noquote() << "Loaded" << readOk << "/" << constellations.size() << "constellation records successfully for culture" << culture.id;
×
682

683
        // Set current states
684
        setFlagArt(artDisplayed);
×
685
        setFlagLines(linesDisplayed);
×
686
        setFlagLabels(namesDisplayed);
×
687
        setFlagBoundaries(boundariesDisplayed);
×
688
        setFlagHulls(hullsDisplayed);
×
689
}
×
690

691
void ConstellationMgr::draw(StelCore* core)
×
692
{
693
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
694
        StelPainter sPainter(prj);
×
695
        sPainter.setFont(asterFont);
×
696
        drawLines(sPainter, core);
×
697
        Vec3d vel(0.);
×
698
        if (core->getUseAberration())
×
699
        {
700
                vel = core->getAberrationVec(core->getJDE());
×
701
        }
702
        drawNames(sPainter, vel);
×
703
        drawArt(sPainter, vel);
×
704
        drawBoundaries(sPainter, vel);
×
705
        drawHulls(sPainter, vel);
×
706
        if (core->getCurrentPlanet()->getEnglishName()=="Earth")
×
707
        {
708
                drawZodiac(sPainter, vel);
×
709
                drawLunarSystem(sPainter, vel);
×
710
        }
711
}
×
712

713
// Draw constellations art textures
714
void ConstellationMgr::drawArt(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
715
{
716
        sPainter.setBlending(true, GL_ONE, GL_ONE);
×
717
        sPainter.setCullFace(true);
×
718

719
        SphericalRegionP region = sPainter.getProjector()->getViewportConvexPolygon();
×
720
        for (auto* constellation : constellations)
×
721
        {
722
                constellation->drawArtOptim(sPainter, *region, obsVelocity);
×
723
        }
724

725
        sPainter.setCullFace(false);
×
726
}
×
727

728
// Draw constellations lines
729
void ConstellationMgr::drawLines(StelPainter& sPainter, const StelCore* core) const
×
730
{
731
        const float scale = sPainter.getProjector()->getScreenScale();
×
732

733
        sPainter.setBlending(true);
×
734
        if (constellationLineThickness>1 || scale>1.f)
×
735
                sPainter.setLineWidth(constellationLineThickness*scale); // set line thickness
×
736
        sPainter.setLineSmooth(true);
×
737

738
        const SphericalCap& viewportHalfspace = sPainter.getProjector()->getBoundingCap();
×
739
        for (auto* constellation : constellations)
×
740
        {
741
                constellation->drawOptim(sPainter, core, viewportHalfspace);
×
742
        }
743
        if (constellationLineThickness>1 || scale>1.f)
×
744
                sPainter.setLineWidth(1); // restore line thickness
×
745
        sPainter.setLineSmooth(false);
×
746
}
×
747

748
// Draw the names of all the constellations
749
void ConstellationMgr::drawNames(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
750
{
751
        sPainter.setBlending(true);
×
752
        for (auto* constellation : constellations)
×
753
        {
754
                for (int i=0; i<constellation->XYZname.size(); ++i)
×
755
                {
756
                        Vec3d XYZname=constellation->XYZname.at(i);
×
757
                        XYZname.normalize();
×
758
                        XYZname+=obsVelocity;
×
759
                        XYZname.normalize();
×
760

761
                        Vec3d xyName;
×
762
                        // Check if in the field of view
763
                        if (sPainter.getProjector()->projectCheck(XYZname, xyName))
×
764
                                constellation->drawName(xyName, sPainter);
×
765
                }
766
        }
767
}
×
768

769
Constellation* ConstellationMgr::findFromAbbreviation(const QString& abbreviation) const
×
770
{
771
        for (auto* constellation : constellations)
×
772
        {
773
                if (constellation->abbreviation.compare(abbreviation, Qt::CaseInsensitive) == 0)
×
774
                {
775
#ifndef NDEBUG
776
                        if (constellation->abbreviation != abbreviation)
×
777
                                qDebug() << "ConstellationMgr::findFromAbbreviation: not a perfect match, but sufficient:" << constellation->abbreviation << "vs." << abbreviation;
×
778
#endif
779
                        return constellation;
×
780
                }
781
        }
782
        return nullptr;
×
783
}
784

785
QStringList ConstellationMgr::getConstellationsEnglishNames()
×
786
{
787
        QStringList constellationsEnglishNames;
×
788
        for (auto* constellation : std::as_const(constellations))
×
789
        {
790
                constellationsEnglishNames.append(constellation->getEnglishName());
×
791
        }
792
        return  constellationsEnglishNames;
×
793
}
×
794

795
void ConstellationMgr::updateI18n()
×
796
{
797
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
798

799
        for (auto* constellation : std::as_const(constellations))
×
800
        {
801
                QString context = constellation->context;
×
802

803
                constellation->culturalName.translatedI18n = trans.tryQtranslate(constellation->culturalName.translated, context);
×
804
                if (constellation->culturalName.translatedI18n.isEmpty())
×
805
                {
806
                        if (context.isEmpty())
×
807
                                constellation->culturalName.translatedI18n = q_(constellation->culturalName.translated);
×
808
                        else
809
                                constellation->culturalName.translatedI18n = qc_(constellation->culturalName.translated, context);
×
810
                }
811

812
                constellation->culturalName.pronounceI18n = trans.tryQtranslate(constellation->culturalName.pronounce, context);
×
813
                if (constellation->culturalName.pronounceI18n.isEmpty())
×
814
                {
815
                        if (context.isEmpty())
×
816
                                constellation->culturalName.pronounceI18n = q_(constellation->culturalName.pronounce);
×
817
                        else
818
                                constellation->culturalName.pronounceI18n = qc_(constellation->culturalName.pronounce, context);
×
819
                }
820

821
                constellation->culturalName.bynameI18n = trans.tryQtranslate(constellation->culturalName.byname, context);
×
822
                if (constellation->culturalName.bynameI18n.isEmpty())
×
823
                {
824
                        if (context.isEmpty())
×
825
                                constellation->culturalName.bynameI18n = q_(constellation->culturalName.byname);
×
826
                        else
827
                                constellation->culturalName.bynameI18n = qc_(constellation->culturalName.byname, context);
×
828
                }
829

830
                const QString abbrContext = "abbreviation"; // fixed context for all abbreviations
×
831
                constellation->abbreviationI18n = trans.tryQtranslate(constellation->abbreviation, abbrContext).trimmed();
×
832
                if (constellation->abbreviationI18n.isEmpty())
×
833
                {
834
                        constellation->abbreviationI18n = qc_(constellation->abbreviation, abbrContext).trimmed();
×
835
                }
836
        }
×
837
        if (zodiac)
×
838
                zodiac->updateI18n();
×
839
        if (lunarSystem)
×
840
                lunarSystem->updateI18n();
×
841
}
×
842

843
// update faders
844
void ConstellationMgr::update(double deltaTime)
×
845
{
846
        //calculate FOV fade value, linear fade between artIntensityMaximumFov and artIntensityMinimumFov
847
        static StelCore *core = StelApp::getInstance().getCore();
×
848
        double fov = core->getMovementMgr()->getCurrentFov();
×
849
        Constellation::artIntensityFovScale = static_cast<float>(qBound(0.0,(fov - artIntensityMinimumFov) / (artIntensityMaximumFov - artIntensityMinimumFov),1.0));
×
850

851
        if (hullsDisplayed) // Computational cost is fortunately negligible, but at least by rapid aberration changes we really need dense interval. So, basically, every frame...
×
852
                recreateHulls();
×
853

854
        const int delta = static_cast<int>(deltaTime*1000);
×
855
        for (auto* constellation : std::as_const(constellations))
×
856
        {
857
                constellation->update(delta);
×
858
        }
859
        zodiacFader.update(delta);
×
860
        lunarSystemFader.update(delta);
×
861
        if (zodiac)
×
862
                zodiac->centerLine->update(deltaTime);
×
863
        if (lunarSystem)
×
864
                lunarSystem->centerLine->update(deltaTime);
×
865
}
×
866

867
void ConstellationMgr::setArtIntensity(const float intensity)
×
868
{
869
        if ((artIntensity - intensity) != 0.0f)
×
870
        {
871
                artIntensity = intensity;
×
872

873
                for (auto* constellation : std::as_const(constellations))
×
874
                {
875
                        constellation->artOpacity = artIntensity;
×
876
                }
877
                StelApp::immediateSave("viewing/constellation_art_intensity", intensity);
×
878
                emit artIntensityChanged(static_cast<double>(intensity));
×
879
        }
880
}
×
881

882
float ConstellationMgr::getArtIntensity() const
×
883
{
884
        return artIntensity;
×
885
}
886

887
void ConstellationMgr::setArtIntensityMinimumFov(const double fov)
×
888
{
889
        artIntensityMinimumFov = fov;
×
890
}
×
891

892
double ConstellationMgr::getArtIntensityMinimumFov() const
×
893
{
894
        return artIntensityMinimumFov;
×
895
}
896

897
void ConstellationMgr::setArtIntensityMaximumFov(const double fov)
×
898
{
899
        artIntensityMaximumFov = fov;
×
900
}
×
901

902
double ConstellationMgr::getArtIntensityMaximumFov() const
×
903
{
904
        return artIntensityMaximumFov;
×
905
}
906

907
void ConstellationMgr::setArtFadeDuration(const float duration)
×
908
{
909
        if (!qFuzzyCompare(artFadeDuration, duration))
×
910
        {
911
                artFadeDuration = duration;
×
912

913
                for (auto &constellation : constellations)
×
914
                {
915
                        constellation->artFader.setDuration(static_cast<int>(duration * 1000.f));
×
916
                }
917
                StelApp::immediateSave("viewing/constellation_art_fade_duration", duration);
×
918
                emit artFadeDurationChanged(duration);
×
919
        }
920
}
×
921

922
float ConstellationMgr::getArtFadeDuration() const
×
923
{
924
        return artFadeDuration;
×
925
}
926

927
void ConstellationMgr::setBoundariesFadeDuration(const float duration)
×
928
{
929
        if (!qFuzzyCompare(boundariesFadeDuration, duration))
×
930
        {
931
                boundariesFadeDuration = duration;
×
932

933
                for (auto& constellation : constellations)
×
934
                {
935
                        constellation->boundaryFader.setDuration(static_cast<int>(duration * 1000.f));
×
936
                }
937
                StelApp::immediateSave("viewing/constellation_boundaries_fade_duration", duration);
×
938
                emit boundariesFadeDurationChanged(duration);
×
939
        }
940
}
×
941

942
float ConstellationMgr::getBoundariesFadeDuration() const
×
943
{
944
        return boundariesFadeDuration;
×
945
}
946

947
void ConstellationMgr::setHullsFadeDuration(const float duration)
×
948
{
949
        if (!qFuzzyCompare(hullsFadeDuration, duration))
×
950
        {
951
                hullsFadeDuration = duration;
×
952

953
                for (auto& constellation : constellations)
×
954
                {
955
                        constellation->hullFader.setDuration(static_cast<int>(duration * 1000.f));
×
956
                }
957
                StelApp::immediateSave("viewing/constellation_hulls_fade_duration", duration);
×
958
                emit hullsFadeDurationChanged(duration);
×
959
        }
960
}
×
961

962
float ConstellationMgr::getHullsFadeDuration() const
×
963
{
964
        return hullsFadeDuration;
×
965
}
966

967
void ConstellationMgr::setZodiacFadeDuration(const float duration)
×
968
{
969
        if (!qFuzzyCompare(zodiacFadeDuration, duration))
×
970
        {
971
                zodiacFadeDuration = duration;
×
972
                zodiacFader.setDuration(static_cast<int>(zodiacFadeDuration * 1000.f));
×
973
                StelApp::immediateSave("viewing/skyculture_zodiac_fade_duration", duration);
×
974
                emit zodiacFadeDurationChanged(duration);
×
975
        }
976
}
×
977

978
float ConstellationMgr::getZodiacFadeDuration() const
×
979
{
980
        return zodiacFadeDuration;
×
981
}
982

983
void ConstellationMgr::setLunarSystemFadeDuration(const float duration)
×
984
{
985
        if (!qFuzzyCompare(lunarSystemFadeDuration, duration))
×
986
        {
987
                lunarSystemFadeDuration=duration;
×
988
                lunarSystemFader.setDuration(static_cast<int>(lunarSystemFadeDuration * 1000.f));
×
989
                StelApp::immediateSave("viewing/skyculture_lunarsystem_fade_duration", duration);
×
990
                emit lunarSystemFadeDurationChanged(duration);
×
991
        }
992
}
×
993

994
float ConstellationMgr::getLunarSystemFadeDuration() const
×
995
{
996
        return lunarSystemFadeDuration;
×
997
}
998

999
void ConstellationMgr::setLinesFadeDuration(const float duration)
×
1000
{
1001
        if (!qFuzzyCompare(linesFadeDuration, duration))
×
1002
        {
1003
                linesFadeDuration = duration;
×
1004

1005
                for (auto& constellation : constellations)
×
1006
                {
1007
                        constellation->lineFader.setDuration(static_cast<int>(duration * 1000.f));
×
1008
                }
1009
                StelApp::immediateSave("viewing/constellation_lines_fade_duration", duration);
×
1010
                emit linesFadeDurationChanged(duration);
×
1011
        }
1012
}
×
1013

1014
float ConstellationMgr::getLinesFadeDuration() const
×
1015
{
1016
        return linesFadeDuration;
×
1017
}
1018

1019
void ConstellationMgr::setLabelsFadeDuration(const float duration)
×
1020
{
1021
        if (!qFuzzyCompare(namesFadeDuration, duration))
×
1022
        {
1023
                namesFadeDuration = duration;
×
1024

1025
                for (auto& constellation : constellations)
×
1026
                {
1027
                        constellation->nameFader.setDuration(static_cast<int>(duration * 1000.f));
×
1028
                }
1029
                StelApp::immediateSave("viewing/constellation_labels_fade_duration", duration);
×
1030
                emit namesFadeDurationChanged(duration);
×
1031
        }
1032
}
×
1033

1034
float ConstellationMgr::getLabelsFadeDuration() const
×
1035
{
1036
        return namesFadeDuration;
×
1037
}
1038

1039
void ConstellationMgr::setFlagLines(const bool displayed)
×
1040
{
1041
        if(linesDisplayed != displayed)
×
1042
        {
1043
                linesDisplayed = displayed;
×
1044
                if (!selected.empty() && isolateSelected)
×
1045
                {
1046
                        for (auto& constellation : selected)
×
1047
                        {
1048
                                constellation->setFlagLines(linesDisplayed);
×
1049
                        }
1050
                }
1051
                else
1052
                {
1053
                        for (auto& constellation : constellations)
×
1054
                        {
1055
                                constellation->setFlagLines(linesDisplayed);
×
1056
                        }
1057
                }
1058
                StelApp::immediateSave("viewing/flag_constellation_drawing", displayed);
×
1059
                emit linesDisplayedChanged(displayed);
×
1060
        }
1061
}
×
1062

1063
bool ConstellationMgr::getFlagLines(void) const
×
1064
{
1065
        return linesDisplayed;
×
1066
}
1067

1068
void ConstellationMgr::setFlagBoundaries(const bool displayed)
×
1069
{
1070
        if (boundariesDisplayed != displayed)
×
1071
        {
1072
                boundariesDisplayed = displayed;
×
1073
                if (!selected.empty() && isolateSelected)
×
1074
                {
1075
                        for (auto& constellation : selected)
×
1076
                        {
1077
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
1078
                        }
1079
                }
1080
                else
1081
                {
1082
                        for (auto& constellation : constellations)
×
1083
                        {
1084
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
1085
                        }
1086
                }
1087
                StelApp::immediateSave("viewing/flag_constellation_boundaries", displayed);
×
1088
                emit boundariesDisplayedChanged(displayed);
×
1089
        }
1090
}
×
1091

1092
bool ConstellationMgr::getFlagBoundaries(void) const
×
1093
{
1094
        return boundariesDisplayed;
×
1095
}
1096

1097
void ConstellationMgr::setFlagHulls(const bool displayed)
×
1098
{
1099
        if (hullsDisplayed != displayed)
×
1100
        {
1101
                hullsDisplayed = displayed;
×
1102
                if (!selected.empty() && isolateSelected)
×
1103
                {
1104
                        for (auto& constellation : selected)
×
1105
                        {
1106
                                constellation->setFlagHull(hullsDisplayed);
×
1107
                        }
1108
                }
1109
                else
1110
                {
1111
                        for (auto& constellation : constellations)
×
1112
                        {
1113
                                constellation->setFlagHull(hullsDisplayed);
×
1114
                        }
1115
                }
1116
                StelApp::immediateSave("viewing/flag_constellation_hulls", displayed);
×
1117
                emit hullsDisplayedChanged(displayed);
×
1118
        }
1119
}
×
1120

1121
bool ConstellationMgr::getFlagHulls(void) const
×
1122
{
1123
        return hullsDisplayed;
×
1124
}
1125

1126
void ConstellationMgr::setFlagZodiac(const bool displayed)
×
1127
{
1128
        if (zodiacFader != displayed)
×
1129
        {
1130
                zodiacFader = displayed;
×
1131
                StelApp::immediateSave("viewing/flag_skyculture_zodiac", displayed);
×
1132
                emit zodiacDisplayedChanged(displayed);
×
1133
        }
1134
}
×
1135

1136
bool ConstellationMgr::getFlagZodiac(void) const
×
1137
{
1138
        return zodiacFader;
×
1139
}
1140

1141
void ConstellationMgr::setFlagLunarSystem(const bool displayed)
×
1142
{
1143
        if (lunarSystemFader != displayed)
×
1144
        {
1145
                lunarSystemFader = displayed;
×
1146
                StelApp::immediateSave("viewing/flag_skyculture_lunarsystem", displayed);
×
1147
                emit lunarSystemDisplayedChanged(displayed);
×
1148
        }
1149
}
×
1150

1151
bool ConstellationMgr::getFlagLunarSystem(void) const
×
1152
{
1153
        return lunarSystemFader;
×
1154
}
1155

1156
void ConstellationMgr::setFlagArt(const bool displayed)
×
1157
{
1158
        if (artDisplayed != displayed)
×
1159
        {
1160
                artDisplayed = displayed;
×
1161
                if (!selected.empty() && isolateSelected)
×
1162
                {
1163
                        for (auto& constellation : selected)
×
1164
                        {
1165
                                constellation->setFlagArt(artDisplayed);
×
1166
                        }
1167
                }
1168
                else
1169
                {
1170
                        for (auto& constellation : constellations)
×
1171
                        {
1172
                                constellation->setFlagArt(artDisplayed);
×
1173
                        }
1174
                }
1175
                StelApp::immediateSave("viewing/flag_constellation_art", displayed);
×
1176
                emit artDisplayedChanged(displayed);
×
1177
        }
1178
}
×
1179

1180
bool ConstellationMgr::getFlagArt(void) const
×
1181
{
1182
        return artDisplayed;
×
1183
}
1184

1185
void ConstellationMgr::setFlagLabels(const bool displayed)
×
1186
{
1187
        if (namesDisplayed != displayed)
×
1188
        {
1189
                namesDisplayed = displayed;
×
1190
                if (!selected.empty() && isolateSelected)
×
1191
                {
1192
                        for (auto& constellation : selected)
×
1193
                                constellation->setFlagLabels(namesDisplayed);
×
1194
                }
1195
                else
1196
                {
1197
                        for (auto& constellation : constellations)
×
1198
                                constellation->setFlagLabels(namesDisplayed);
×
1199
                }
1200
                StelApp::immediateSave("viewing/flag_constellation_name", displayed);
×
1201
                emit namesDisplayedChanged(displayed);
×
1202
        }
1203
}
×
1204

1205
bool ConstellationMgr::getFlagLabels(void) const
×
1206
{
1207
        return namesDisplayed;
×
1208
}
1209

1210
void ConstellationMgr::setFlagIsolateSelected(const bool isolate)
×
1211
{
1212
        if (isolateSelected != isolate)
×
1213
        {
1214
                isolateSelected = isolate;
×
1215

1216
                // when turning off isolated selection mode, clear existing isolated selections.
1217
                if (!isolateSelected)
×
1218
                {
1219
                        for (auto& constellation : constellations)
×
1220
                        {
1221
                                constellation->setFlagLines(getFlagLines());
×
1222
                                constellation->setFlagLabels(getFlagLabels());
×
1223
                                constellation->setFlagArt(getFlagArt());
×
1224
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
1225
                                constellation->setFlagHull(getFlagHulls());
×
1226
                        }
1227
                }
1228
                StelApp::immediateSave("viewing/flag_constellation_isolate_selected", isolate);
×
1229
                emit isolateSelectedChanged(isolate);
×
1230
        }
1231
}
×
1232

1233
bool ConstellationMgr::getFlagIsolateSelected(void) const
×
1234
{
1235
        return isolateSelected;
×
1236
}
1237

1238
void ConstellationMgr::setFlagConstellationPick(const bool mode)
×
1239
{
1240
        StelApp::immediateSave("viewing/flag_constellation_pick", mode);
×
1241
        flagConstellationPick = mode;
×
1242
        emit flagConstellationPickChanged(mode);
×
1243
}
×
1244

1245
bool ConstellationMgr::getFlagConstellationPick(void) const
×
1246
{
1247
        return flagConstellationPick;
×
1248
}
1249

1250
QList<Constellation *> ConstellationMgr::getSelected(void) const
×
1251
{
1252
        return selected;
×
1253
}
1254

1255
void ConstellationMgr::setSelected(const QString& abbreviation)
×
1256
{
1257
        Constellation * c = findFromAbbreviation(abbreviation);
×
1258
        if(c != nullptr)
×
1259
        {
1260
                QList<Constellation *>cList;
×
1261
                cList.append(c);
×
1262
                setSelectedConst(cList);
×
1263
        }
×
1264
}
×
1265

1266
StelObjectP ConstellationMgr::setSelectedStar(const QString& abbreviation)
×
1267
{
1268
        Constellation * c = findFromAbbreviation(abbreviation);
×
1269
        if(c != nullptr)
×
1270
        {
1271
                QList<Constellation *>cList;
×
1272
                cList.append(c);
×
1273
                setSelectedConst(cList);
×
1274
                return c->getBrightestStarInConstellation();
×
1275
        }
×
1276
        return nullptr;
×
1277
}
1278

1279
void ConstellationMgr::setSelectedConst(QList<Constellation *> cList)
×
1280
{
1281
        // update states for other constellations to fade them out
1282
        if (cList.length()>0)
×
1283
        {
1284
                selected.append(cList);
×
1285

1286
                if (isolateSelected)
×
1287
                {
1288
                        if (!getFlagConstellationPick())
×
1289
                        {
1290
                                // Propagate current settings to newly selected constellation
1291
                                cList.at(0)->setFlagLines(getFlagLines());
×
1292
                                cList.at(0)->setFlagLabels(getFlagLabels());
×
1293
                                cList.at(0)->setFlagArt(getFlagArt());
×
1294
                                cList.at(0)->setFlagBoundaries(getFlagBoundaries());
×
1295
                                cList.at(0)->setFlagHull(getFlagHulls());
×
1296

1297
                                for (auto& constellation : constellations)
×
1298
                                {
1299
                                        bool match = false;
×
1300
                                        for (auto& selected_constellation : selected)
×
1301
                                        {
1302
                                                if (constellation == selected_constellation)
×
1303
                                                {
1304
                                                        match=true; // this is a selected constellation
×
1305
                                                        break;
×
1306
                                                }
1307
                                        }
1308

1309
                                        if(!match)
×
1310
                                        {
1311
                                                // Not selected constellation
1312
                                                constellation->setFlagLines(false);
×
1313
                                                constellation->setFlagLabels(false);
×
1314
                                                constellation->setFlagArt(false);
×
1315
                                                constellation->setFlagBoundaries(false);
×
1316
                                                constellation->setFlagHull(false);
×
1317
                                        }
1318
                                }
1319
                        }
1320
                        else
1321
                        {
1322
                                for (auto& constellation : constellations)
×
1323
                                {
1324
                                        constellation->setFlagLines(false);
×
1325
                                        constellation->setFlagLabels(false);
×
1326
                                        constellation->setFlagArt(false);
×
1327
                                        constellation->setFlagBoundaries(false);
×
1328
                                        constellation->setFlagHull(false);
×
1329
                                }
1330

1331
                                // Propagate current settings to newly selected constellation
1332
                                cList.at(0)->setFlagLines(getFlagLines());
×
1333
                                cList.at(0)->setFlagLabels(getFlagLabels());
×
1334
                                cList.at(0)->setFlagArt(getFlagArt());
×
1335
                                cList.at(0)->setFlagBoundaries(getFlagBoundaries());
×
1336
                                cList.at(0)->setFlagHull(getFlagHulls());
×
1337
                        }
1338

1339
                        Constellation::singleSelected = true;  // For boundaries
×
1340
                }
1341
                else
1342
                        Constellation::singleSelected = false; // For boundaries
×
1343
        }
1344
        else
1345
        {
1346
                if (selected.empty()) return;
×
1347

1348
                // Otherwise apply standard flags to all constellations
1349
                for (auto& constellation : constellations)
×
1350
                {
1351
                        constellation->setFlagLines(getFlagLines());
×
1352
                        constellation->setFlagLabels(getFlagLabels());
×
1353
                        constellation->setFlagArt(getFlagArt());
×
1354
                        constellation->setFlagBoundaries(getFlagBoundaries());
×
1355
                        constellation->setFlagHull(getFlagHulls());
×
1356
                }
1357

1358
                // And remove all selections
1359
                selected.clear();
×
1360
        }
1361
}
1362

1363
//! Remove a constellation from the selected constellation list
1364
void ConstellationMgr::unsetSelectedConst(Constellation * c)
×
1365
{
1366
        if (c != nullptr)
×
1367
        {
1368
                for (auto iter = selected.begin(); iter != selected.end();)
×
1369
                {
1370
                        if( (*iter)->getEnglishName() == c->getEnglishName() )
×
1371
                        {
1372
                                iter = selected.erase(iter);
×
1373
                        }
1374
                        else
1375
                        {
1376
                                ++iter;
×
1377
                        }
1378
                }
1379

1380
                // If no longer any selection, restore all flags on all constellations
1381
                if (selected.empty())
×
1382
                {
1383
                        // Otherwise apply standard flags to all constellations
1384
                        for (auto& constellation : constellations)
×
1385
                        {
1386
                                constellation->setFlagLines(getFlagLines());
×
1387
                                constellation->setFlagLabels(getFlagLabels());
×
1388
                                constellation->setFlagArt(getFlagArt());
×
1389
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
1390
                                constellation->setFlagHull(getFlagHulls());
×
1391
                        }
1392

1393
                        Constellation::singleSelected = false; // For boundaries
×
1394
                }
1395
                else if(isolateSelected)
×
1396
                {
1397
                        // No longer selected constellation
1398
                        c->setFlagLines(false);
×
1399
                        c->setFlagLabels(false);
×
1400
                        c->setFlagArt(false);
×
1401
                        c->setFlagBoundaries(false);
×
1402
                        c->setFlagHull(false);
×
1403

1404
                        Constellation::singleSelected = true;  // For boundaries
×
1405
                }
1406
        }
1407
}
×
1408

1409
bool ConstellationMgr::loadBoundaries(const QJsonArray& boundaryData, const QString& boundariesEpoch)
×
1410
{
1411
        // delete existing boundaries if any exist
1412
        for (auto* segment : allBoundarySegments)
×
1413
        {
1414
                delete segment;
×
1415
        }
1416
        allBoundarySegments.clear();
×
1417

1418
        bool b1875 = false;
×
1419
        bool customEdgeEpoch = false;
×
1420
        Mat4d matCustomEdgeEpochToJ2000;
×
1421
        if (boundariesEpoch.toUpper() == "B1875")
×
1422
                b1875 = true;
×
1423
        else if (boundariesEpoch.toUpper() != "J2000")
×
1424
        {
1425
                qInfo() << "Custom epoch for boundaries:" << boundariesEpoch;
×
1426
                customEdgeEpoch = true;
×
1427
        }
1428
        if (customEdgeEpoch)
×
1429
        {
1430
                // Allow "Bxxxx.x", "Jxxxx.x", "JDjjjjjjjj.jjj" and pure doubles as JD
1431
                bool ok=false;
×
1432
                double boundariesEpochJD=StelUtils::J2000;
×
1433

1434
                if (boundariesEpoch.startsWith("JD", Qt::CaseInsensitive))
×
1435
                {
1436
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-2);
×
1437
                        boundariesEpochJD=boundariesEpochStrV.toDouble(&ok); // pureJD
×
1438
                }
×
1439
                else if (boundariesEpoch.startsWith("B", Qt::CaseInsensitive))
×
1440
                {
1441
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
1442
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
1443
                        if (ok)
×
1444
                        {
1445
                                boundariesEpochJD=StelUtils::getJDFromBesselianEpoch(boundariesEpochY);
×
1446
                        }
1447
                }
×
1448
                else if (boundariesEpoch.startsWith("J", Qt::CaseInsensitive))
×
1449
                {
1450
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
1451
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
1452
                        if (ok)
×
1453
                        {
1454
                                boundariesEpochJD=StelUtils::getJDFromJulianEpoch(boundariesEpochY);
×
1455
                        }
1456
                }
×
1457
                else
1458
                        boundariesEpochJD=boundariesEpoch.toDouble(&ok); // pureJD
×
1459
                if (ok)
×
1460
                {
1461
                        // Create custom precession matrix for transformation of edges to J2000.0
1462
                        double epsEpoch, chiEpoch, omegaEpoch, psiEpoch;
1463
                        getPrecessionAnglesVondrak(boundariesEpochJD, &epsEpoch, &chiEpoch, &omegaEpoch, &psiEpoch);
×
1464
                        matCustomEdgeEpochToJ2000 = Mat4d::xrotation(84381.406*1./3600.*M_PI/180.) * Mat4d::zrotation(-psiEpoch) * Mat4d::xrotation(-omegaEpoch) * Mat4d::zrotation(chiEpoch);
×
1465
                }
1466
                else
1467
                {
1468
                        qWarning() << "SkyCultureMgr: Cannot parse edges_epoch =" << boundariesEpoch << ". Falling back to J2000.0";
×
1469
                        customEdgeEpoch = false;
×
1470
                }
1471
        }
1472
        const StelCore& core = *StelApp::getInstance().getCore();
×
1473
        qInfo().noquote() << "Loading constellation boundary data ... ";
×
1474

1475
        for (int n = 0; n < boundaryData.size(); ++n)
×
1476
        {
1477
                const QByteArray ba = boundaryData[n].toString().toLatin1();
×
1478
                const char *cstr = ba.data();
×
1479
                char edgeType, edgeDir;
1480
                char dec1_sign, dec2_sign;
1481
                int ra1_h, ra1_m, ra1_s, dec1_d, dec1_m, dec1_s;
1482
                int ra2_h, ra2_m, ra2_s, dec2_d, dec2_m, dec2_s;
1483
                char constellationNames[2][8];
1484
                if (sscanf(cstr,
×
1485
                           "%*s %c%c "
1486
                           "%d:%d:%d %c%d:%d:%d "
1487
                           "%d:%d:%d %c%d:%d:%d "
1488
                           "%7s %7s",
1489
                           &edgeType, &edgeDir,
1490
                           &ra1_h, &ra1_m, &ra1_s,
1491
                           &dec1_sign, &dec1_d, &dec1_m, &dec1_s,
1492
                           &ra2_h, &ra2_m, &ra2_s,
1493
                           &dec2_sign, &dec2_d, &dec2_m, &dec2_s,
1494
                           constellationNames[0], constellationNames[1]) != 18)
×
1495
                {
1496
                        qWarning().nospace() << "Failed to parse skyculture boundary line: \"" << cstr << "\"";
×
1497
                        continue;
×
1498
                }
1499

1500
                constexpr double timeSecToRadians = M_PI / (12 * 3600);
×
1501
                double RA1 = (60. * (60. * ra1_h + ra1_m) + ra1_s) * timeSecToRadians;
×
1502
                double RA2 = (60. * (60. * ra2_h + ra2_m) + ra2_s) * timeSecToRadians;
×
1503
                constexpr double angleSecToRad = M_PI / (180 * 3600);
×
1504
                double DE1 = (60. * (60. * dec1_d + dec1_m) + dec1_s) * (dec1_sign=='-' ? -1 : 1) * angleSecToRad;
×
1505
                double DE2 = (60. * (60. * dec2_d + dec2_m) + dec2_s) * (dec2_sign=='-' ? -1 : 1) * angleSecToRad;
×
1506

1507
                Vec3d xyz1;
×
1508
                StelUtils::spheToRect(RA1,DE1,xyz1);
×
1509
                Vec3d xyz2;
×
1510
                StelUtils::spheToRect(RA2,DE2,xyz2);
×
1511

1512
                const auto points = new std::vector<Vec3d>;
×
1513

1514
                const bool edgeTypeDirValid = ((edgeType == 'P' || edgeType == 'M') && (edgeDir == '+' || edgeDir == '-')) ||
×
1515
                                               (edgeType == '_' && edgeDir == '_');
×
1516
                if (!edgeTypeDirValid)
×
1517
                {
1518
                        qWarning().nospace() << "Bad edge type/direction: must be [PM_][-+_], but is " << QString("%1%2").arg(edgeType).arg(edgeDir)
×
1519
                                             << ". Will not interpolate the edges.";
×
1520
                        edgeType = '_';
×
1521
                        edgeDir = '_';
×
1522
                }
1523

1524
                double stepRA = 0, stepDE = 0;
×
1525
                int numPoints = 2;
×
1526
                switch (edgeType)
×
1527
                {
1528
                case 'P': // RA is variable
×
1529
                        if (RA2 > RA1 && edgeDir == '-')
×
1530
                                RA1 += 2*M_PI;
×
1531
                        if (RA2 < RA1 && edgeDir == '+')
×
1532
                                RA1 -= 2*M_PI;
×
1533
                        numPoints = 2 + std::ceil(std::abs(RA1 - RA2) / (M_PI / 64));
×
1534
                        stepRA = (RA2 - RA1) / (numPoints - 1);
×
1535
                        break;
×
1536
                case 'M': // DE is variable
×
1537
                        if (DE2 > DE1 && edgeDir == '-')
×
1538
                                DE1 += 2*M_PI;
×
1539
                        if (DE2 < DE1 && edgeDir == '+')
×
1540
                                DE1 -= 2*M_PI;
×
1541
                        numPoints = 2 + std::ceil(std::abs(DE1 - DE2) / (M_PI / 64));
×
1542
                        stepDE = (DE2 - DE1) / (numPoints - 1);
×
1543
                        break;
×
1544
                default: // No interpolation
×
1545
                        stepRA = RA2 - RA1;
×
1546
                        stepDE = DE2 - DE1;
×
1547
                        break;
×
1548
                }
1549

1550
                for (int n = 0; n < numPoints; ++n)
×
1551
                {
1552
                        const double RA = RA1 + n * stepRA;
×
1553
                        const double DE = DE1 + n * stepDE;
×
1554
                        Vec3d xyz;
×
1555
                        StelUtils::spheToRect(RA,DE,xyz);
×
1556
                        if (b1875) xyz = core.j1875ToJ2000(xyz);
×
1557
                        else if (customEdgeEpoch)
×
1558
                                xyz = matCustomEdgeEpochToJ2000*xyz;
×
1559
                        points->push_back(xyz);
×
1560
                }
1561

1562
                Constellation *cons = nullptr;
×
1563
                for (QString consName : constellationNames)
×
1564
                {
1565
                        // not used?
1566
                        if (consName == "SER1" || consName == "SER2") consName = "SER";
×
1567

1568
                        cons = findFromAbbreviation(consName);
×
1569
                        if (!cons)
×
1570
                                qWarning() << "ERROR while processing boundary file - cannot find constellation:" << consName;
×
1571
                        else
1572
                                cons->isolatedBoundarySegments.push_back(points);
×
1573
                }
×
1574

1575
                if (cons)
×
1576
                {
1577
                        cons->sharedBoundarySegments.push_back(points);
×
1578
                        // this list is for the de-allocation
1579
                        allBoundarySegments.push_back(points);
×
1580
                }
1581
                else
1582
                {
1583
                        delete points;
×
1584
                }
1585
        }
×
1586
        qInfo().noquote() << "Loaded" << boundaryData.size() << "constellation boundary segments";
×
1587

1588
        return true;
×
1589
}
1590

1591
void ConstellationMgr::drawBoundaries(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1592
{
1593
        const float scale = sPainter.getProjector()->getScreenScale();
×
1594

1595
        sPainter.setBlending(false);
×
1596
        if (boundariesThickness>1 || scale>1.f)
×
1597
                sPainter.setLineWidth(boundariesThickness*scale); // set line thickness
×
1598
        sPainter.setLineSmooth(true);
×
1599
        for (auto* constellation : constellations)
×
1600
        {
1601
                constellation->drawBoundaryOptim(sPainter, obsVelocity);
×
1602
        }
1603
        if (boundariesThickness>1 || scale>1.f)
×
1604
                sPainter.setLineWidth(1); // restore line thickness
×
1605
        sPainter.setLineSmooth(false);
×
1606
}
×
1607

1608
void ConstellationMgr::drawHulls(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1609
{
1610
        const float scale = sPainter.getProjector()->getScreenScale();
×
1611

1612
        sPainter.setBlending(false);
×
1613
        if (hullsThickness>1 || scale>1.f)
×
1614
                sPainter.setLineWidth(hullsThickness*scale); // set line thickness
×
1615
        sPainter.setLineSmooth(true);
×
1616
        for (auto* constellation : constellations)
×
1617
        {
1618
                constellation->drawHullOptim(sPainter, obsVelocity);
×
1619
        }
1620
        if (hullsThickness>1 || scale>1.f)
×
1621
                sPainter.setLineWidth(1); // restore line thickness
×
1622
        sPainter.setLineSmooth(false);
×
1623
}
×
1624

1625
// Draw the zodiac, if any is defined in the current skyculture.
1626
// @param obsVelocity is the speed vector of the observer planet to distort zodiac lines by aberration.
1627
void ConstellationMgr::drawZodiac(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1628
{
1629
        if (!zodiac || zodiacFader.getInterstate()==0.)
×
1630
                return;
×
1631

1632
        sPainter.setColor(zodiacColor, zodiacFader.getInterstate());
×
1633
        zodiac->centerLine->setColor(zodiacColor);
×
1634
        zodiac->centerLine->setLineThickness(zodiacThickness);
×
1635
        zodiac->centerLine->setPartThickness(zodiacThickness);
×
1636
        sPainter.setBlending(true);
×
1637
        const float oldLineWidth=sPainter.getLineWidth();
×
1638
        sPainter.setLineWidth(zodiacThickness);
×
1639
        sPainter.setLineSmooth(true);
×
1640
        zodiac->draw(sPainter, obsVelocity);
×
1641
        sPainter.setLineWidth(oldLineWidth); // restore line thickness
×
1642
}
1643
// Draw the lunar system lines, if any is defined in the current skyculture.
1644
// @param obsVelocity is the speed vector of the observer planet to distort lunarSystem lines by aberration.
1645
void ConstellationMgr::drawLunarSystem(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1646
{
1647
        if (!lunarSystem || lunarSystemFader.getInterstate()==0.)
×
1648
                return;
×
1649

1650
        sPainter.setColor(lunarSystemColor, lunarSystemFader.getInterstate());
×
1651
        lunarSystem->centerLine->setColor(lunarSystemColor);
×
1652
        lunarSystem->centerLine->setLineThickness(lunarSystemThickness);
×
1653
        lunarSystem->centerLine->setPartThickness(lunarSystemThickness);
×
1654
        sPainter.setBlending(true);
×
1655
        const float oldLineWidth=sPainter.getLineWidth();
×
1656
        sPainter.setLineWidth(lunarSystemThickness);
×
1657
        sPainter.setLineSmooth(true);
×
1658
        lunarSystem->draw(sPainter, obsVelocity);
×
1659
        sPainter.setLineWidth(oldLineWidth); // restore line thickness
×
1660
}
1661

1662
//! Returns the translated name of the Zodiac system
1663
QString ConstellationMgr::getZodiacSystemName() const
×
1664
{
1665
        if (zodiac)
×
1666
                return zodiac->getCulturalName();
×
1667
        else
1668
                return QString();
×
1669
}
1670
//! Returns the translated name of the Lunar system
1671
QString ConstellationMgr::getLunarSystemName() const
×
1672
{
1673
        if (lunarSystem)
×
1674
                return lunarSystem->getCulturalName();
×
1675
        else
1676
                return QString();
×
1677
}
1678
//! Return longitude in the culture's zodiacal longitudes
1679
QString ConstellationMgr::getZodiacCoordinate(Vec3d eqNow) const
×
1680
{
1681
        if (zodiac)
×
1682
                return zodiac->getLongitudeCoordinate(eqNow);
×
1683
        else
1684
                return QString();
×
1685
}
1686
//! Return lunar station in the culture's Lunar system
1687
QString ConstellationMgr::getLunarSystemCoordinate(Vec3d eqNow) const
×
1688
{
1689
        if (lunarSystem)
×
1690
                return lunarSystem->getLongitudeCoordinate(eqNow);
×
1691
        else
1692
                return QString();
×
1693
}
1694

1695
StelObjectP ConstellationMgr::searchByNameI18n(const QString& nameI18n) const
×
1696
{
1697
        QString nameI18nUpper = nameI18n.toUpper();
×
1698

1699
        for (auto* constellation : constellations)
×
1700
        {
1701
                if (constellation->culturalName.translatedI18n.toUpper() == nameI18nUpper) return constellation;
×
1702
                if (constellation->culturalName.pronounceI18n.toUpper()  == nameI18nUpper) return constellation;
×
1703
        }
1704
        return nullptr;
×
1705
}
×
1706

1707
StelObjectP ConstellationMgr::searchByName(const QString& name) const
×
1708
{
1709
        QString nameUpper = name.toUpper();
×
1710
        for (auto* constellation : constellations)
×
1711
        {
1712
                if (constellation->culturalName.translated.toUpper()      == nameUpper) return constellation;
×
1713
                if (constellation->culturalName.native.toUpper()          == nameUpper) return constellation;
×
1714
                if (constellation->culturalName.pronounce.toUpper()       == nameUpper) return constellation;
×
1715
                if (constellation->culturalName.transliteration.toUpper() == nameUpper) return constellation;
×
1716
                if (constellation->abbreviation.toUpper()                 == nameUpper) return constellation;
×
1717
        }
1718
        return nullptr;
×
1719
}
×
1720

1721
StelObjectP ConstellationMgr::searchByID(const QString &id) const
×
1722
{
1723
        for (auto* constellation : constellations)
×
1724
        {
1725
                if (constellation->getID() == id) return constellation;
×
1726
        }
1727
        return nullptr;
×
1728
}
1729

1730
QStringList ConstellationMgr::listAllObjects(bool inEnglish) const
×
1731
{
1732
        // TODO: This is needed for the search dialog.
1733
        QStringList result;
×
1734
        if (inEnglish)
×
1735
        {
1736
                for (auto* constellation : constellations)
×
1737
                {
1738
                        result << constellation->getEnglishName();
×
1739
                        result << constellation->culturalName.pronounce;
×
1740
                        result << constellation->culturalName.transliteration;
×
1741
                        result << constellation->culturalName.native;
×
1742
                }
1743
        }
1744
        else
1745
        {
1746
                for (auto* constellation : constellations)
×
1747
                {
1748
                        result << constellation->getNameI18n();
×
1749
                        result << constellation->culturalName.pronounceI18n;
×
1750
                        result << constellation->culturalName.native;
×
1751
                }
1752
        }
1753
        result.removeDuplicates();
×
1754
        result.removeOne(QString(""));
×
1755
        result.removeOne(QString());
×
1756
        return result;
×
1757
}
×
1758

1759
QString ConstellationMgr::getStelObjectType() const
×
1760
{
1761
        return Constellation::CONSTELLATION_TYPE;
×
1762
}
1763

1764
// For modern... SCs (with IAU borders), this can just identify IAU constellations.
1765
// For others: identify from convex hulls.
1766
QList<StelObjectP> ConstellationMgr::searchAround(const Vec3d& v, double limitFov, const StelCore* core) const
×
1767
{
1768
        QList<StelObjectP> result;
×
1769

1770
        if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
1771
        {
1772
                QString cName=core->getIAUConstellation(v);
×
1773
                for (auto* constellation : std::as_const(constellations))
×
1774
                {
1775
                        if (constellation->getShortName()==cName)
×
1776
                        {
1777
                                result.append(constellation);
×
1778
                        }
1779
                }
1780
#ifndef NDEBUG
1781
                if (result.isEmpty())
×
1782
                        qDebug() << "ConstellationMgr::searchAround(): The IAU constellation" << cName << "was not found";
×
1783
#endif
1784
        }
×
1785
        else
1786
        {
1787
        for (auto* constellation : constellations)
×
1788
        {
1789
                if (constellation->convexHull && constellation->convexHull->contains(v))
×
1790
                {
1791
#ifndef NDEBUG
1792
                        qDebug() << "ConstellationMgr::searchAround(): point in hull of constellation" << constellation->getID();
×
1793
#endif
1794
                        result.append(constellation);
×
1795
                }
1796
        }
1797
#ifndef NDEBUG
1798
        qDebug() << "Point within hulls of" << result.count() << "constellations";
×
1799
#endif
1800
        }
1801
        return result;
×
1802
}
×
1803

1804
void ConstellationMgr::setSelected(const StelObject *s)
×
1805
{
1806
        if (!s)
×
1807
                setSelectedConst(QList<Constellation*>()); // actually deselect...
×
1808
        else
1809
                setSelectedConst(isObjectIn(s, !(StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)));
×
1810
}
×
1811

1812
// Return a QList<Constellation*>, will allow result from overlapping hulls
1813
QList<Constellation*> ConstellationMgr::isObjectIn(const StelObject *s, bool useHull) const
×
1814
{
1815
        StelCore *core = StelApp::getInstance().getCore();
×
1816
        QList<Constellation*> result;
×
1817
        if (useHull)
×
1818
        {
1819
                for (auto* constellation : constellations)
×
1820
                {
1821
                        if (constellation->convexHull->contains(s->getJ2000EquatorialPos(core)))
×
1822
                                result.append(constellation);
×
1823
                        else foreach(auto &obj, constellation->constellation)
×
1824
                        {
1825
                                // A problem persisted in selecting a star defining the hull which was then found just not to be contained!
1826
                                if (obj->getID() == s->getID())
×
1827
                                {
1828
                                        result.append(constellation);
×
1829
                                        break;
×
1830
                                }
1831
                        }
×
1832
                        // finally also test the hull outliers...
1833
                        foreach(auto &obj, constellation->hullExtension)
×
1834
                        {
1835
                                if (obj->getID() == s->getID())
×
1836
                                {
1837
                                        result.append(constellation);
×
1838
                                        break;
×
1839
                                }
1840
                        }
×
1841
                        // N.B. dark constellations: not forgotten, just not that critically defined around stars!
1842
                }
1843
        }
1844
        else
1845
        {
1846
                QString IAUConstUpper = core->getIAUConstellation(s->getEquinoxEquatorialPos(core)).toUpper();
×
1847
                for (auto* constellation : constellations)
×
1848
                {
1849
                        // Check if the object is in the constellation
1850
                        if (constellation->getShortName().toUpper() == IAUConstUpper)
×
1851
                                result.append(constellation);
×
1852
                }
1853
        }
×
1854
        return result;
×
1855
}
×
1856

1857
void ConstellationMgr::outputHullAreas(const QString &fileNamePrefix) const
×
1858
{
1859
        const QString scName=GETSTELMODULE(StelSkyCultureMgr)->getCurrentSkyCultureEnglishName();
×
1860

1861
        QString fileName=StelFileMgr::getUserDir() + QString("/%1_%2.csv").arg(fileNamePrefix, scName);
×
1862
        QFile file(fileName);
×
1863
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
1864
        if (file.open(QIODevice::Text | QIODevice::WriteOnly))
1865
#else
1866
        if (file.open(QIODeviceBase::Text | QIODeviceBase::WriteOnly))
×
1867
#endif
1868
        {
1869
                qInfo().nospace() << "Writing to:" << fileName;
×
1870
                file.write(QString("ID, Native, English, Translated, Area (sr), Area (sqdeg)\n").toLatin1());
×
1871
                foreach(const Constellation *constellation, constellations)
×
1872
                {
1873
                        double area_sr=constellation->convexHull->getArea();
×
1874
                        file.write(QString("%1, %2, %3, %4, %5, %6\n").arg(constellation->getID(),
×
1875
                                                                           constellation->getNameNative(),
×
1876
                                                                           constellation->getEnglishName(),
×
1877
                                                                           constellation->getNameI18n(),
×
1878
                                                                           QString::number(area_sr, 'f', 6),
×
1879
                                                                           QString::number(area_sr*(M_180_PI*M_180_PI), 'f', 6)).toLatin1());
×
1880
                }
×
1881
        }
1882
        else
1883
        {
1884
                qCritical() << "Cannot open file for writing! Output to logfile:";
×
1885
                foreach(const Constellation *constellation, constellations)
×
1886
                {
1887
                        double area_sr=constellation->convexHull->getArea();
×
1888
                        qInfo().nospace() << constellation->getEnglishName() << ": "
×
1889
                                          <<  area_sr << "sr or " << area_sr*(M_180_PI*M_180_PI) << "°²";
×
1890
                }
×
1891
        }
1892
}
×
1893

1894
//! Create a list of stars within the convex hull of constellation
1895
void ConstellationMgr::starsInHullOf(const QString &englishName, const bool hipOnly, const float maxMag, const QString &fileNamePrefix) const
×
1896
{
1897
        static StelCore *core=StelApp::getInstance().getCore();
×
1898
        StelObjectP constell=searchByName(englishName);
×
1899
        if (!constell)
×
1900
        {
1901
                qWarning() << "Constellation" << englishName << "not found, not creating star list";
×
1902
                return;
×
1903
        }
1904

1905
        QList<StelObjectP> starList=GETSTELMODULE(StarMgr)->searchWithin(constell->getRegion(), core, hipOnly, maxMag);
×
1906

1907
        // Add the actual hull-defining stars, but only if they are not already included. Unfortunately, we need to test via IDs!
1908
        // Results are prepended, so that usually hull-defining HIP stars are in the beginning of the list.
1909
        Constellation* constel=reinterpret_cast<Constellation*>(constell.data());
×
1910
        foreach(auto &star, constel->constellation)
×
1911
        {
1912
                QString id=star->getID();
×
1913
                bool wanted=true;
×
1914
                foreach (auto obj, starList)
×
1915
                        if (obj->getID()==id)
×
1916
                        {
1917
                                wanted=false;
×
1918
                                break;
×
1919
                        }
×
1920
                if (wanted)
×
1921
                        starList.prepend(star);
×
1922
        }
×
1923
        foreach(auto &star, constel->hullExtension)
×
1924
        {
1925
                QString id=star->getID();
×
1926
                bool wanted=true;
×
1927
                foreach (auto obj, starList)
×
1928
                        if (obj->getID()==id)
×
1929
                        {
1930
                                wanted=false;
×
1931
                                break;
×
1932
                        }
×
1933
                if (wanted)
×
1934
                        starList.prepend(star);
×
1935
        }
×
1936

1937
        qInfo().nospace() << starList.length() << " stars within the convex hull (" << constell->getRegion()->getArea()*(M_180_PI*M_180_PI) << " sq degrees) of " << englishName;
×
1938
        int day, month, year;
1939
        StelUtils::getDateFromJulianDay(core->getJD(), &year, &month, &day);
×
1940
        const double yearFraction=StelUtils::yearFraction(year, month, day);
×
1941
        const QString dateString=QString::number(yearFraction, 'f', 1);
×
1942
        const QString scName=GETSTELMODULE(StelSkyCultureMgr)->getCurrentSkyCultureEnglishName();
×
1943

1944
        QString fileName=StelFileMgr::getUserDir() + QString("/%1_%2_%3-%4.csv").arg(fileNamePrefix, scName, englishName, QString::number(maxMag, 'f', 2));
×
1945
        QFile file(fileName);
×
1946
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
1947
        if (file.open(QIODevice::Text | QIODevice::WriteOnly))
1948
#else
1949
        if (file.open(QIODeviceBase::Text | QIODeviceBase::WriteOnly))
×
1950
#endif
1951
        {
1952
                qInfo().nospace() << "Writing to:" << fileName;
×
1953
                file.write(QString("ID, mag, RA_J%1, DE_J%1, RA_J%1(h), DE_J%1(deg)\n").arg(dateString).toLatin1());
×
1954

1955
                foreach(const auto &star, starList)
×
1956
                {
1957
                        double ra, dec;
1958
                        StelUtils::rectToSphe(&ra, &dec, star->getEquinoxEquatorialPos(core));
×
1959
                        file.write(QString("%1, %2, %3, %4, %5, %6\n").arg(star->getID(), QString::number(star->getVMagnitude(core), 'f', 2),
×
1960
                                   StelUtils::radToHmsStr(ra), StelUtils::decDegToDmsStr(dec*M_180_PI),
×
1961
                                   QString::number(ra*M_180_PI / 15., 'f', 6), QString::number(dec*M_180_PI, 'f', 6)).toLatin1());
×
1962
                }
×
1963
                file.close();
×
1964
        }
1965
        else
1966
        {
1967
                qCritical() << "Cannot open file for writing! Dump to logfile:";
×
1968
                foreach(const auto &star, starList)
×
1969
                {
1970
                        double ra, dec;
1971
                        StelUtils::rectToSphe(&ra, &dec, star->getEquinoxEquatorialPos(core));
×
1972
                        qInfo().nospace().noquote() << star->getID() << ", " << star->getVMagnitude(core) << ", " <<
×
1973
                                                       StelUtils::radToHmsStr(ra) << ", " << StelUtils::decDegToDmsStr(dec*M_180_PI) <<
×
1974
                                                       QString::number(ra*M_180_PI / 15., 'f', 6) << ", " << QString::number(dec*M_180_PI, 'f', 6);
×
1975
                }
×
1976
        }
1977
}
×
1978

1979
void ConstellationMgr::recreateHulls()
×
1980
{
1981
        for (auto* constellation : std::as_const(constellations))
×
1982
                constellation->makeConvexHull();
×
1983
}
×
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