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

Stellarium / stellarium / 15670918640

16 Jun 2025 02:08AM UTC coverage: 11.775% (-0.2%) from 11.931%
15670918640

push

github

alex-w
Updated data

14700 of 124846 relevant lines covered (11.77%)

18324.52 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
        setSelectedConst(constellations);
×
311
}
×
312

313
void ConstellationMgr::selectConstellation(const QString &englishName)
×
314
{
315
        if (!getFlagIsolateSelected())
×
316
                setFlagIsolateSelected(true); // Enable isolated selection
×
317

318
        bool found = false;
×
319
        QList<Constellation *>cList;
×
320
        for (auto& constellation : constellations)
×
321
        {
322
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
323
                {
324
                        cList.append(constellation);
×
325
                        setSelectedConst(cList);
×
326
                        found = true;
×
327
                }
328
        }
329
        if (!found)
×
330
                qDebug() << "The constellation" << englishName << "was not found";
×
331
}
×
332

333
void ConstellationMgr::selectConstellationByObjectName(const QString &englishName)
×
334
{
335
        if (!getFlagIsolateSelected())
×
336
                setFlagIsolateSelected(true); // Enable isolated selection
×
337

338
        if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
339
                setSelectedConst(isObjectIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data(), false));
×
340
        else
341
                setSelectedConst(isObjectIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data(), true));
×
342
}
×
343

344
void ConstellationMgr::deselectConstellation(const QString &englishName)
×
345
{
346
        if (!getFlagIsolateSelected())
×
347
                setFlagIsolateSelected(true); // Enable isolated selection
×
348

349
        bool found = false;
×
350
        for (auto& constellation : constellations)
×
351
        {
352
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
353
                {
354
                        unsetSelectedConst(constellation);
×
355
                        found = true;
×
356
                }
357
        }
358

359
        if (selected.size()==0 && found)
×
360
        {
361
                // Let's remove the selection for all constellations if the list of selected constellations is empty
362
                for (auto& constellation : constellations)
×
363
                {
364
                        constellation->setFlagLines(false);
×
365
                        constellation->setFlagLabels(false);
×
366
                        constellation->setFlagArt(false);
×
367
                        constellation->setFlagBoundaries(false);
×
368
                        constellation->setFlagHull(false);
×
369
                }
370
        }
371

372
        if (!found)
×
373
                qDebug() << "The constellation" << englishName << "was not found";
×
374
}
×
375

376
void ConstellationMgr::setLinesColor(const Vec3f& color)
×
377
{
378
        if (color != Constellation::lineColor)
×
379
        {
380
                Constellation::lineColor = color;
×
381
                emit linesColorChanged(color);
×
382
        }
383
}
×
384

385
Vec3f ConstellationMgr::getLinesColor() const
×
386
{
387
        return Constellation::lineColor;
×
388
}
389

390
void ConstellationMgr::setBoundariesColor(const Vec3f& color)
×
391
{
392
        if (Constellation::boundaryColor != color)
×
393
        {
394
                Constellation::boundaryColor = color;
×
395
                emit boundariesColorChanged(color);
×
396
        }
397
}
×
398

399
Vec3f ConstellationMgr::getBoundariesColor() const
×
400
{
401
        return Constellation::boundaryColor;
×
402
}
403

404
void ConstellationMgr::setHullsColor(const Vec3f& color)
×
405
{
406
        if (Constellation::hullColor != color)
×
407
        {
408
                Constellation::hullColor = color;
×
409
                emit hullsColorChanged(color);
×
410
        }
411
}
×
412

413
Vec3f ConstellationMgr::getHullsColor() const
×
414
{
415
        return Constellation::hullColor;
×
416
}
417

418
void ConstellationMgr::setZodiacColor(const Vec3f& color)
×
419
{
420
        if (zodiacColor != color)
×
421
        {
422
                zodiacColor = color;
×
423
                emit zodiacColorChanged(color);
×
424
        }
425
}
×
426

427
Vec3f ConstellationMgr::getZodiacColor() const
×
428
{
429
        return zodiacColor;
×
430
}
431

432
void ConstellationMgr::setLunarSystemColor(const Vec3f& color)
×
433
{
434
        if (lunarSystemColor != color)
×
435
        {
436
                lunarSystemColor = color;
×
437
                emit lunarSystemColorChanged(color);
×
438
        }
439
}
×
440

441
Vec3f ConstellationMgr::getLunarSystemColor() const
×
442
{
443
        return lunarSystemColor;
×
444
}
445

446
void ConstellationMgr::setLabelsColor(const Vec3f& color)
×
447
{
448
        if (Constellation::labelColor != color)
×
449
        {
450
                Constellation::labelColor = color;
×
451
                emit namesColorChanged(color);
×
452
        }
453
}
×
454

455
Vec3f ConstellationMgr::getLabelsColor() const
×
456
{
457
        return Constellation::labelColor;
×
458
}
459

460
void ConstellationMgr::setFontSize(const int newFontSize)
×
461
{
462
        if (asterFont.pixelSize() - newFontSize != 0)
×
463
        {
464
                asterFont.setPixelSize(newFontSize);
×
465
                StelApp::immediateSave("viewing/constellation_font_size", newFontSize);
×
466
                emit fontSizeChanged(newFontSize);
×
467
        }
468
}
×
469

470
int ConstellationMgr::getFontSize() const
×
471
{
472
        return asterFont.pixelSize();
×
473
}
474

475
void ConstellationMgr::setConstellationLineThickness(const int thickness)
×
476
{
477
        if(thickness!=constellationLineThickness)
×
478
        {
479
                constellationLineThickness = qMax(1, thickness); // cannot be 0 or neg.
×
480

481
                StelApp::immediateSave("viewing/constellation_line_thickness", thickness);
×
482
                emit constellationLineThicknessChanged(thickness);
×
483
        }
484
}
×
485

486
void ConstellationMgr::setBoundariesThickness(const int thickness)
×
487
{
488
        if(thickness!=boundariesThickness)
×
489
        {
490
                boundariesThickness = qMax(1, thickness); // cannot be 0 or neg.
×
491

492
                StelApp::immediateSave("viewing/constellation_boundaries_thickness", thickness);
×
493
                emit boundariesThicknessChanged(thickness);
×
494
        }
495
}
×
496

497
void ConstellationMgr::setHullsThickness(const int thickness)
×
498
{
499
        if(thickness!=hullsThickness)
×
500
        {
501
                hullsThickness = qMax(1, thickness); // cannot be 0 or neg.
×
502

503
                StelApp::immediateSave("viewing/constellation_hulls_thickness", thickness);
×
504
                emit hullsThicknessChanged(thickness);
×
505
        }
506
}
×
507

508
void ConstellationMgr::setZodiacThickness(const int thickness)
×
509
{
510
        if(thickness!=zodiacThickness)
×
511
        {
512
                zodiacThickness = qMax(1, thickness); // cannot be 0 or neg.
×
513

514
                StelApp::immediateSave("viewing/skyculture_zodiac_thickness", thickness);
×
515
                emit zodiacThicknessChanged(thickness);
×
516
        }
517
}
×
518

519
void ConstellationMgr::setLunarSystemThickness(const int thickness)
×
520
{
521
        if(thickness!=lunarSystemThickness)
×
522
        {
523
                lunarSystemThickness = qMax(1, thickness); // cannot be 0 or neg.
×
524

525
                StelApp::immediateSave("viewing/skyculture_lunar_system_thickness", thickness);
×
526
                emit lunarSystemThicknessChanged(thickness);
×
527
        }
528
}
×
529

530
void ConstellationMgr::loadLinesNamesAndArt(const StelSkyCulture &culture)
×
531
{
532
        constellations.clear();
×
533
        Constellation::seasonalRuleEnabled = false;
×
534

535
        int readOk = 0;
×
536
        for (const auto& constellationData : culture.constellations)
×
537
        {
538
                Constellation*const cons = new Constellation;
×
539
                const auto consObj = constellationData.toObject();
×
540
                if (!cons->read(consObj, hipStarMgr))
×
541
                {
542
                        delete cons;
×
543
                        continue;
×
544
                }
545
                ++readOk;
×
546
                constellations.push_back(cons);
×
547

548
                cons->artOpacity = artIntensity;
×
549
                cons->artFader.setDuration(static_cast<int>(artFadeDuration * 1000.f));
×
550
                cons->lineFader.setDuration(static_cast<int>(linesFadeDuration * 1000.f));
×
551
                cons->boundaryFader.setDuration(static_cast<int>(boundariesFadeDuration * 1000.f));
×
552
                cons->hullFader.setDuration(static_cast<int>(hullsFadeDuration * 1000.f));
×
553
                cons->nameFader.setDuration(static_cast<int>(namesFadeDuration * 1000.f));
×
554
                cons->setFlagArt(artDisplayed);
×
555
                cons->setFlagBoundaries(boundariesDisplayed);
×
556
                cons->setFlagHull(hullsDisplayed);
×
557
                cons->setFlagLines(linesDisplayed);
×
558
                cons->setFlagLabels(namesDisplayed);
×
559

560
                // Now load constellation art
561

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

580
                const int x1 = xy1[0].toInt();
×
581
                const int y1 = xy1[1].toInt();
×
582
                const int x2 = xy2[0].toInt();
×
583
                const int y2 = xy2[1].toInt();
×
584
                const int x3 = xy3[0].toInt();
×
585
                const int y3 = xy3[1].toInt();
×
586
                const int hp1 = StelUtils::getLongLong(anchor1["hip"]);
×
587
                const int hp2 = StelUtils::getLongLong(anchor2["hip"]);
×
588
                const int hp3 = StelUtils::getLongLong(anchor3["hip"]);
×
589

590
                const auto texfile = imgData["file"].toString();
×
591

592
                auto texturePath = culture.path+"/"+texfile;
×
593
                if (!QFileInfo::exists(texturePath))
×
594
                {
595
                        qWarning() << "ERROR: could not find texture" << QDir::toNativeSeparators(texfile);
×
596
                        texturePath.clear();
×
597
                }
598

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

601
                const auto sizeData = imgData["size"].toArray();
×
602
                if (sizeData.size() != 2)
×
603
                {
604
                        qWarning().nospace() << "Bad length of \"size\" array for image in constellation "
×
605
                                             << consObj["id"].toString();
×
606
                        continue;
×
607
                }
608
                const int texSizeX = sizeData[0].toInt(), texSizeY = sizeData[1].toInt();
×
609

610
                StelCore* core = StelApp::getInstance().getCore();
×
611
                StelObjectP s1obj = hipStarMgr->searchHP(static_cast<int>(hp1));
×
612
                StelObjectP s2obj = hipStarMgr->searchHP(static_cast<int>(hp2));
×
613
                StelObjectP s3obj = hipStarMgr->searchHP(static_cast<int>(hp3));
×
614

615
                // check for null pointers
616
                if (s1obj.isNull() || s2obj.isNull() || s3obj.isNull())
×
617
                {
618
                        qWarning() << "ERROR: could not find stars:" << hp1 << hp2 << hp3 << " in constellation" << consObj["id"].toString();
×
619
                        continue;
×
620
                }
621

622
                const Vec3d s1 = s1obj->getJ2000EquatorialPos(core);
×
623
                const Vec3d s2 = s2obj->getJ2000EquatorialPos(core);
×
624
                const Vec3d s3 = s3obj->getJ2000EquatorialPos(core);
×
625

626
                // To transform from texture coordinate to 2d coordinate we need to find X with XA = B
627
                // A formed of 4 points in texture coordinate, B formed with 4 points in 3d coordinate space
628
                // We need 3 stars and the 4th point is deduced from the others to get a normal base
629
                // X = B inv(A)
630
                Vec3d s4 = s1 + ((s2 - s1) ^ (s3 - s1));
×
631
                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);
×
632
                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.);
×
633
                Mat4d X = B * A.inverse();
×
634

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

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

663
                cons->artPolygon.vertex=contour;
×
664
                cons->artPolygon.texCoords=texCoords;
×
665
                cons->artPolygon.primitiveType=StelVertexArray::Triangles;
×
666

667
                Vec3d tmp(X * Vec3d(0.5*texSizeX, 0.5*texSizeY, 0.));
×
668
                tmp.normalize();
×
669
                Vec3d tmp2(X * Vec3d(0., 0., 0.));
×
670
                tmp2.normalize();
×
671
                cons->boundingCap.n=tmp;
×
672
                cons->boundingCap.d=tmp*tmp2;
×
673
        }
×
674

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

677
        // Set current states
678
        setFlagArt(artDisplayed);
×
679
        setFlagLines(linesDisplayed);
×
680
        setFlagLabels(namesDisplayed);
×
681
        setFlagBoundaries(boundariesDisplayed);
×
682
        setFlagHulls(hullsDisplayed);
×
683
}
×
684

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

707
// Draw constellations art textures
708
void ConstellationMgr::drawArt(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
709
{
710
        sPainter.setBlending(true, GL_ONE, GL_ONE);
×
711
        sPainter.setCullFace(true);
×
712

713
        SphericalRegionP region = sPainter.getProjector()->getViewportConvexPolygon();
×
714
        for (auto* constellation : constellations)
×
715
        {
716
                constellation->drawArtOptim(sPainter, *region, obsVelocity);
×
717
        }
718

719
        sPainter.setCullFace(false);
×
720
}
×
721

722
// Draw constellations lines
723
void ConstellationMgr::drawLines(StelPainter& sPainter, const StelCore* core) const
×
724
{
725
        const float scale = sPainter.getProjector()->getScreenScale();
×
726

727
        sPainter.setBlending(true);
×
728
        if (constellationLineThickness>1 || scale>1.f)
×
729
                sPainter.setLineWidth(constellationLineThickness*scale); // set line thickness
×
730
        sPainter.setLineSmooth(true);
×
731

732
        const SphericalCap& viewportHalfspace = sPainter.getProjector()->getBoundingCap();
×
733
        for (auto* constellation : constellations)
×
734
        {
735
                constellation->drawOptim(sPainter, core, viewportHalfspace);
×
736
        }
737
        if (constellationLineThickness>1 || scale>1.f)
×
738
                sPainter.setLineWidth(1); // restore line thickness
×
739
        sPainter.setLineSmooth(false);
×
740
}
×
741

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

755
                        Vec3d xyName;
×
756
                        // Check if in the field of view
757
                        if (sPainter.getProjector()->projectCheck(XYZname, xyName))
×
758
                                constellation->drawName(xyName, sPainter);
×
759
                }
760
        }
761
}
×
762

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

779
QStringList ConstellationMgr::getConstellationsEnglishNames()
×
780
{
781
        QStringList constellationsEnglishNames;
×
782
        for (auto* constellation : std::as_const(constellations))
×
783
        {
784
                constellationsEnglishNames.append(constellation->getEnglishName());
×
785
        }
786
        return  constellationsEnglishNames;
×
787
}
×
788

789
void ConstellationMgr::updateI18n()
×
790
{
791
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
792

793
        for (auto* constellation : std::as_const(constellations))
×
794
        {
795
                QString context = constellation->context;
×
796
                constellation->culturalName.translatedI18n = trans.tryQtranslate(constellation->culturalName.translated, context);
×
797
                if (constellation->culturalName.translatedI18n.isEmpty())
×
798
                {
799
                        if (context.isEmpty())
×
800
                                constellation->culturalName.translatedI18n = q_(constellation->culturalName.translated);
×
801
                        else
802
                                constellation->culturalName.translatedI18n = qc_(constellation->culturalName.translated, context);
×
803
                }
804
                constellation->culturalName.pronounceI18n = trans.tryQtranslate(constellation->culturalName.pronounce, context);
×
805
                if (constellation->culturalName.pronounceI18n.isEmpty())
×
806
                {
807
                        if (context.isEmpty())
×
808
                                constellation->culturalName.pronounceI18n = q_(constellation->culturalName.pronounce);
×
809
                        else
810
                                constellation->culturalName.pronounceI18n = qc_(constellation->culturalName.pronounce, context);
×
811
                }
812
                const QString abbrContext = "abbreviation"; // fixed context for all abbreviations
×
813
                constellation->abbreviationI18n = trans.tryQtranslate(constellation->abbreviation, abbrContext).trimmed();
×
814
                if (constellation->abbreviationI18n.isEmpty())
×
815
                {
816
                        constellation->abbreviationI18n = qc_(constellation->abbreviation, abbrContext).trimmed();
×
817
                }
818
        }
×
819
        if (zodiac)
×
820
                zodiac->updateI18n();
×
821
        if (lunarSystem)
×
822
                lunarSystem->updateI18n();
×
823
}
×
824

825
// update faders
826
void ConstellationMgr::update(double deltaTime)
×
827
{
828
        //calculate FOV fade value, linear fade between artIntensityMaximumFov and artIntensityMinimumFov
829
        static StelCore *core = StelApp::getInstance().getCore();
×
830
        double fov = core->getMovementMgr()->getCurrentFov();
×
831
        Constellation::artIntensityFovScale = static_cast<float>(qBound(0.0,(fov - artIntensityMinimumFov) / (artIntensityMaximumFov - artIntensityMinimumFov),1.0));
×
832

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

836
        const int delta = static_cast<int>(deltaTime*1000);
×
837
        for (auto* constellation : std::as_const(constellations))
×
838
        {
839
                constellation->update(delta);
×
840
        }
841
        zodiacFader.update(delta);
×
842
        lunarSystemFader.update(delta);
×
843
        if (zodiac)
×
844
                zodiac->centerLine->update(deltaTime);
×
845
        if (lunarSystem)
×
846
                lunarSystem->centerLine->update(deltaTime);
×
847
}
×
848

849
void ConstellationMgr::setArtIntensity(const float intensity)
×
850
{
851
        if ((artIntensity - intensity) != 0.0f)
×
852
        {
853
                artIntensity = intensity;
×
854

855
                for (auto* constellation : std::as_const(constellations))
×
856
                {
857
                        constellation->artOpacity = artIntensity;
×
858
                }
859
                StelApp::immediateSave("viewing/constellation_art_intensity", intensity);
×
860
                emit artIntensityChanged(static_cast<double>(intensity));
×
861
        }
862
}
×
863

864
float ConstellationMgr::getArtIntensity() const
×
865
{
866
        return artIntensity;
×
867
}
868

869
void ConstellationMgr::setArtIntensityMinimumFov(const double fov)
×
870
{
871
        artIntensityMinimumFov = fov;
×
872
}
×
873

874
double ConstellationMgr::getArtIntensityMinimumFov() const
×
875
{
876
        return artIntensityMinimumFov;
×
877
}
878

879
void ConstellationMgr::setArtIntensityMaximumFov(const double fov)
×
880
{
881
        artIntensityMaximumFov = fov;
×
882
}
×
883

884
double ConstellationMgr::getArtIntensityMaximumFov() const
×
885
{
886
        return artIntensityMaximumFov;
×
887
}
888

889
void ConstellationMgr::setArtFadeDuration(const float duration)
×
890
{
891
        if (!qFuzzyCompare(artFadeDuration, duration))
×
892
        {
893
                artFadeDuration = duration;
×
894

895
                for (auto &constellation : constellations)
×
896
                {
897
                        constellation->artFader.setDuration(static_cast<int>(duration * 1000.f));
×
898
                }
899
                StelApp::immediateSave("viewing/constellation_art_fade_duration", duration);
×
900
                emit artFadeDurationChanged(duration);
×
901
        }
902
}
×
903

904
float ConstellationMgr::getArtFadeDuration() const
×
905
{
906
        return artFadeDuration;
×
907
}
908

909
void ConstellationMgr::setBoundariesFadeDuration(const float duration)
×
910
{
911
        if (!qFuzzyCompare(boundariesFadeDuration, duration))
×
912
        {
913
                boundariesFadeDuration = duration;
×
914

915
                for (auto& constellation : constellations)
×
916
                {
917
                        constellation->boundaryFader.setDuration(static_cast<int>(duration * 1000.f));
×
918
                }
919
                StelApp::immediateSave("viewing/constellation_boundaries_fade_duration", duration);
×
920
                emit boundariesFadeDurationChanged(duration);
×
921
        }
922
}
×
923

924
float ConstellationMgr::getBoundariesFadeDuration() const
×
925
{
926
        return boundariesFadeDuration;
×
927
}
928

929
void ConstellationMgr::setHullsFadeDuration(const float duration)
×
930
{
931
        if (!qFuzzyCompare(hullsFadeDuration, duration))
×
932
        {
933
                hullsFadeDuration = duration;
×
934

935
                for (auto& constellation : constellations)
×
936
                {
937
                        constellation->hullFader.setDuration(static_cast<int>(duration * 1000.f));
×
938
                }
939
                StelApp::immediateSave("viewing/constellation_hulls_fade_duration", duration);
×
940
                emit hullsFadeDurationChanged(duration);
×
941
        }
942
}
×
943

944
float ConstellationMgr::getHullsFadeDuration() const
×
945
{
946
        return hullsFadeDuration;
×
947
}
948

949
void ConstellationMgr::setZodiacFadeDuration(const float duration)
×
950
{
951
        if (!qFuzzyCompare(zodiacFadeDuration, duration))
×
952
        {
953
                zodiacFadeDuration = duration;
×
954
                zodiacFader.setDuration(static_cast<int>(zodiacFadeDuration * 1000.f));
×
955
                StelApp::immediateSave("viewing/skyculture_zodiac_fade_duration", duration);
×
956
                emit zodiacFadeDurationChanged(duration);
×
957
        }
958
}
×
959

960
float ConstellationMgr::getZodiacFadeDuration() const
×
961
{
962
        return zodiacFadeDuration;
×
963
}
964

965
void ConstellationMgr::setLunarSystemFadeDuration(const float duration)
×
966
{
967
        if (!qFuzzyCompare(lunarSystemFadeDuration, duration))
×
968
        {
969
                lunarSystemFadeDuration=duration;
×
970
                lunarSystemFader.setDuration(static_cast<int>(lunarSystemFadeDuration * 1000.f));
×
971
                StelApp::immediateSave("viewing/skyculture_lunarsystem_fade_duration", duration);
×
972
                emit lunarSystemFadeDurationChanged(duration);
×
973
        }
974
}
×
975

976
float ConstellationMgr::getLunarSystemFadeDuration() const
×
977
{
978
        return lunarSystemFadeDuration;
×
979
}
980

981
void ConstellationMgr::setLinesFadeDuration(const float duration)
×
982
{
983
        if (!qFuzzyCompare(linesFadeDuration, duration))
×
984
        {
985
                linesFadeDuration = duration;
×
986

987
                for (auto& constellation : constellations)
×
988
                {
989
                        constellation->lineFader.setDuration(static_cast<int>(duration * 1000.f));
×
990
                }
991
                StelApp::immediateSave("viewing/constellation_lines_fade_duration", duration);
×
992
                emit linesFadeDurationChanged(duration);
×
993
        }
994
}
×
995

996
float ConstellationMgr::getLinesFadeDuration() const
×
997
{
998
        return linesFadeDuration;
×
999
}
1000

1001
void ConstellationMgr::setLabelsFadeDuration(const float duration)
×
1002
{
1003
        if (!qFuzzyCompare(namesFadeDuration, duration))
×
1004
        {
1005
                namesFadeDuration = duration;
×
1006

1007
                for (auto& constellation : constellations)
×
1008
                {
1009
                        constellation->nameFader.setDuration(static_cast<int>(duration * 1000.f));
×
1010
                }
1011
                StelApp::immediateSave("viewing/constellation_labels_fade_duration", duration);
×
1012
                emit namesFadeDurationChanged(duration);
×
1013
        }
1014
}
×
1015

1016
float ConstellationMgr::getLabelsFadeDuration() const
×
1017
{
1018
        return namesFadeDuration;
×
1019
}
1020

1021
void ConstellationMgr::setFlagLines(const bool displayed)
×
1022
{
1023
        if(linesDisplayed != displayed)
×
1024
        {
1025
                linesDisplayed = displayed;
×
1026
                if (!selected.empty() && isolateSelected)
×
1027
                {
1028
                        for (auto& constellation : selected)
×
1029
                        {
1030
                                constellation->setFlagLines(linesDisplayed);
×
1031
                        }
1032
                }
1033
                else
1034
                {
1035
                        for (auto& constellation : constellations)
×
1036
                        {
1037
                                constellation->setFlagLines(linesDisplayed);
×
1038
                        }
1039
                }
1040
                StelApp::immediateSave("viewing/flag_constellation_drawing", displayed);
×
1041
                emit linesDisplayedChanged(displayed);
×
1042
        }
1043
}
×
1044

1045
bool ConstellationMgr::getFlagLines(void) const
×
1046
{
1047
        return linesDisplayed;
×
1048
}
1049

1050
void ConstellationMgr::setFlagBoundaries(const bool displayed)
×
1051
{
1052
        if (boundariesDisplayed != displayed)
×
1053
        {
1054
                boundariesDisplayed = displayed;
×
1055
                if (!selected.empty() && isolateSelected)
×
1056
                {
1057
                        for (auto& constellation : selected)
×
1058
                        {
1059
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
1060
                        }
1061
                }
1062
                else
1063
                {
1064
                        for (auto& constellation : constellations)
×
1065
                        {
1066
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
1067
                        }
1068
                }
1069
                StelApp::immediateSave("viewing/flag_constellation_boundaries", displayed);
×
1070
                emit boundariesDisplayedChanged(displayed);
×
1071
        }
1072
}
×
1073

1074
bool ConstellationMgr::getFlagBoundaries(void) const
×
1075
{
1076
        return boundariesDisplayed;
×
1077
}
1078

1079
void ConstellationMgr::setFlagHulls(const bool displayed)
×
1080
{
1081
        if (hullsDisplayed != displayed)
×
1082
        {
1083
                hullsDisplayed = displayed;
×
1084
                if (!selected.empty() && isolateSelected)
×
1085
                {
1086
                        for (auto& constellation : selected)
×
1087
                        {
1088
                                constellation->setFlagHull(hullsDisplayed);
×
1089
                        }
1090
                }
1091
                else
1092
                {
1093
                        for (auto& constellation : constellations)
×
1094
                        {
1095
                                constellation->setFlagHull(hullsDisplayed);
×
1096
                        }
1097
                }
1098
                StelApp::immediateSave("viewing/flag_constellation_hulls", displayed);
×
1099
                emit hullsDisplayedChanged(displayed);
×
1100
        }
1101
}
×
1102

1103
bool ConstellationMgr::getFlagHulls(void) const
×
1104
{
1105
        return hullsDisplayed;
×
1106
}
1107

1108
void ConstellationMgr::setFlagZodiac(const bool displayed)
×
1109
{
1110
        if (zodiacFader != displayed)
×
1111
        {
1112
                zodiacFader = displayed;
×
1113
                StelApp::immediateSave("viewing/flag_skyculture_zodiac", displayed);
×
1114
                emit zodiacDisplayedChanged(displayed);
×
1115
        }
1116
}
×
1117

1118
bool ConstellationMgr::getFlagZodiac(void) const
×
1119
{
1120
        return zodiacFader;
×
1121
}
1122

1123
void ConstellationMgr::setFlagLunarSystem(const bool displayed)
×
1124
{
1125
        if (lunarSystemFader != displayed)
×
1126
        {
1127
                lunarSystemFader = displayed;
×
1128
                StelApp::immediateSave("viewing/flag_skyculture_lunarsystem", displayed);
×
1129
                emit lunarSystemDisplayedChanged(displayed);
×
1130
        }
1131
}
×
1132

1133
bool ConstellationMgr::getFlagLunarSystem(void) const
×
1134
{
1135
        return lunarSystemFader;
×
1136
}
1137

1138
void ConstellationMgr::setFlagArt(const bool displayed)
×
1139
{
1140
        if (artDisplayed != displayed)
×
1141
        {
1142
                artDisplayed = displayed;
×
1143
                if (!selected.empty() && isolateSelected)
×
1144
                {
1145
                        for (auto& constellation : selected)
×
1146
                        {
1147
                                constellation->setFlagArt(artDisplayed);
×
1148
                        }
1149
                }
1150
                else
1151
                {
1152
                        for (auto& constellation : constellations)
×
1153
                        {
1154
                                constellation->setFlagArt(artDisplayed);
×
1155
                        }
1156
                }
1157
                StelApp::immediateSave("viewing/flag_constellation_art", displayed);
×
1158
                emit artDisplayedChanged(displayed);
×
1159
        }
1160
}
×
1161

1162
bool ConstellationMgr::getFlagArt(void) const
×
1163
{
1164
        return artDisplayed;
×
1165
}
1166

1167
void ConstellationMgr::setFlagLabels(const bool displayed)
×
1168
{
1169
        if (namesDisplayed != displayed)
×
1170
        {
1171
                namesDisplayed = displayed;
×
1172
                if (!selected.empty() && isolateSelected)
×
1173
                {
1174
                        for (auto& constellation : selected)
×
1175
                                constellation->setFlagLabels(namesDisplayed);
×
1176
                }
1177
                else
1178
                {
1179
                        for (auto& constellation : constellations)
×
1180
                                constellation->setFlagLabels(namesDisplayed);
×
1181
                }
1182
                StelApp::immediateSave("viewing/flag_constellation_name", displayed);
×
1183
                emit namesDisplayedChanged(displayed);
×
1184
        }
1185
}
×
1186

1187
bool ConstellationMgr::getFlagLabels(void) const
×
1188
{
1189
        return namesDisplayed;
×
1190
}
1191

1192
void ConstellationMgr::setFlagIsolateSelected(const bool isolate)
×
1193
{
1194
        if (isolateSelected != isolate)
×
1195
        {
1196
                isolateSelected = isolate;
×
1197

1198
                // when turning off isolated selection mode, clear existing isolated selections.
1199
                if (!isolateSelected)
×
1200
                {
1201
                        for (auto& constellation : constellations)
×
1202
                        {
1203
                                constellation->setFlagLines(getFlagLines());
×
1204
                                constellation->setFlagLabels(getFlagLabels());
×
1205
                                constellation->setFlagArt(getFlagArt());
×
1206
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
1207
                                constellation->setFlagHull(getFlagHulls());
×
1208
                        }
1209
                }
1210
                StelApp::immediateSave("viewing/flag_constellation_isolate_selected", isolate);
×
1211
                emit isolateSelectedChanged(isolate);
×
1212
        }
1213
}
×
1214

1215
bool ConstellationMgr::getFlagIsolateSelected(void) const
×
1216
{
1217
        return isolateSelected;
×
1218
}
1219

1220
void ConstellationMgr::setFlagConstellationPick(const bool mode)
×
1221
{
1222
        StelApp::immediateSave("viewing/flag_constellation_pick", mode);
×
1223
        flagConstellationPick = mode;
×
1224
        emit flagConstellationPickChanged(mode);
×
1225
}
×
1226

1227
bool ConstellationMgr::getFlagConstellationPick(void) const
×
1228
{
1229
        return flagConstellationPick;
×
1230
}
1231

1232
QList<Constellation *> ConstellationMgr::getSelected(void) const
×
1233
{
1234
        return selected;
×
1235
}
1236

1237
void ConstellationMgr::setSelected(const QString& abbreviation)
×
1238
{
1239
        Constellation * c = findFromAbbreviation(abbreviation);
×
1240
        if(c != nullptr)
×
1241
        {
1242
                QList<Constellation *>cList;
×
1243
                cList.append(c);
×
1244
                setSelectedConst(cList);
×
1245
        }
×
1246
}
×
1247

1248
StelObjectP ConstellationMgr::setSelectedStar(const QString& abbreviation)
×
1249
{
1250
        Constellation * c = findFromAbbreviation(abbreviation);
×
1251
        if(c != nullptr)
×
1252
        {
1253
                QList<Constellation *>cList;
×
1254
                cList.append(c);
×
1255
                setSelectedConst(cList);
×
1256
                return c->getBrightestStarInConstellation();
×
1257
        }
×
1258
        return nullptr;
×
1259
}
1260

1261
void ConstellationMgr::setSelectedConst(QList<Constellation *> cList)
×
1262
{
1263
        // update states for other constellations to fade them out
1264
        if (cList.length()>0)
×
1265
        {
1266
                selected.append(cList);
×
1267

1268
                if (isolateSelected)
×
1269
                {
1270
                        if (!getFlagConstellationPick())
×
1271
                        {
1272
                                // Propagate current settings to newly selected constellation
1273
                                cList.at(0)->setFlagLines(getFlagLines());
×
1274
                                cList.at(0)->setFlagLabels(getFlagLabels());
×
1275
                                cList.at(0)->setFlagArt(getFlagArt());
×
1276
                                cList.at(0)->setFlagBoundaries(getFlagBoundaries());
×
1277
                                cList.at(0)->setFlagHull(getFlagHulls());
×
1278

1279
                                for (auto& constellation : constellations)
×
1280
                                {
1281
                                        bool match = false;
×
1282
                                        for (auto& selected_constellation : selected)
×
1283
                                        {
1284
                                                if (constellation == selected_constellation)
×
1285
                                                {
1286
                                                        match=true; // this is a selected constellation
×
1287
                                                        break;
×
1288
                                                }
1289
                                        }
1290

1291
                                        if(!match)
×
1292
                                        {
1293
                                                // Not selected constellation
1294
                                                constellation->setFlagLines(false);
×
1295
                                                constellation->setFlagLabels(false);
×
1296
                                                constellation->setFlagArt(false);
×
1297
                                                constellation->setFlagBoundaries(false);
×
1298
                                                constellation->setFlagHull(false);
×
1299
                                        }
1300
                                }
1301
                        }
1302
                        else
1303
                        {
1304
                                for (auto& constellation : constellations)
×
1305
                                {
1306
                                        constellation->setFlagLines(false);
×
1307
                                        constellation->setFlagLabels(false);
×
1308
                                        constellation->setFlagArt(false);
×
1309
                                        constellation->setFlagBoundaries(false);
×
1310
                                        constellation->setFlagHull(false);
×
1311
                                }
1312

1313
                                // Propagate current settings to newly selected constellation
1314
                                cList.at(0)->setFlagLines(getFlagLines());
×
1315
                                cList.at(0)->setFlagLabels(getFlagLabels());
×
1316
                                cList.at(0)->setFlagArt(getFlagArt());
×
1317
                                cList.at(0)->setFlagBoundaries(getFlagBoundaries());
×
1318
                                cList.at(0)->setFlagHull(getFlagHulls());
×
1319
                        }
1320

1321
                        Constellation::singleSelected = true;  // For boundaries
×
1322
                }
1323
                else
1324
                        Constellation::singleSelected = false; // For boundaries
×
1325
        }
1326
        else
1327
        {
1328
                if (selected.empty()) return;
×
1329

1330
                // Otherwise apply standard flags to all constellations
1331
                for (auto& constellation : constellations)
×
1332
                {
1333
                        constellation->setFlagLines(getFlagLines());
×
1334
                        constellation->setFlagLabels(getFlagLabels());
×
1335
                        constellation->setFlagArt(getFlagArt());
×
1336
                        constellation->setFlagBoundaries(getFlagBoundaries());
×
1337
                        constellation->setFlagHull(getFlagHulls());
×
1338
                }
1339

1340
                // And remove all selections
1341
                selected.clear();
×
1342
        }
1343
}
1344

1345
//! Remove a constellation from the selected constellation list
1346
void ConstellationMgr::unsetSelectedConst(Constellation * c)
×
1347
{
1348
        if (c != nullptr)
×
1349
        {
1350
                for (auto iter = selected.begin(); iter != selected.end();)
×
1351
                {
1352
                        if( (*iter)->getEnglishName() == c->getEnglishName() )
×
1353
                        {
1354
                                iter = selected.erase(iter);
×
1355
                        }
1356
                        else
1357
                        {
1358
                                ++iter;
×
1359
                        }
1360
                }
1361

1362
                // If no longer any selection, restore all flags on all constellations
1363
                if (selected.empty())
×
1364
                {
1365
                        // Otherwise apply standard flags to all constellations
1366
                        for (auto& constellation : constellations)
×
1367
                        {
1368
                                constellation->setFlagLines(getFlagLines());
×
1369
                                constellation->setFlagLabels(getFlagLabels());
×
1370
                                constellation->setFlagArt(getFlagArt());
×
1371
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
1372
                                constellation->setFlagHull(getFlagHulls());
×
1373
                        }
1374

1375
                        Constellation::singleSelected = false; // For boundaries
×
1376
                }
1377
                else if(isolateSelected)
×
1378
                {
1379
                        // No longer selected constellation
1380
                        c->setFlagLines(false);
×
1381
                        c->setFlagLabels(false);
×
1382
                        c->setFlagArt(false);
×
1383
                        c->setFlagBoundaries(false);
×
1384
                        c->setFlagHull(false);
×
1385

1386
                        Constellation::singleSelected = true;  // For boundaries
×
1387
                }
1388
        }
1389
}
×
1390

1391
bool ConstellationMgr::loadBoundaries(const QJsonArray& boundaryData, const QString& boundariesEpoch)
×
1392
{
1393
        // delete existing boundaries if any exist
1394
        for (auto* segment : allBoundarySegments)
×
1395
        {
1396
                delete segment;
×
1397
        }
1398
        allBoundarySegments.clear();
×
1399

1400
        bool b1875 = false;
×
1401
        bool customEdgeEpoch = false;
×
1402
        Mat4d matCustomEdgeEpochToJ2000;
×
1403
        if (boundariesEpoch.toUpper() == "B1875")
×
1404
                b1875 = true;
×
1405
        else if (boundariesEpoch.toUpper() != "J2000")
×
1406
        {
1407
                qInfo() << "Custom epoch for boundaries:" << boundariesEpoch;
×
1408
                customEdgeEpoch = true;
×
1409
        }
1410
        if (customEdgeEpoch)
×
1411
        {
1412
                // Allow "Bxxxx.x", "Jxxxx.x", "JDjjjjjjjj.jjj" and pure doubles as JD
1413
                bool ok=false;
×
1414
                double boundariesEpochJD=StelUtils::J2000;
×
1415

1416
                if (boundariesEpoch.startsWith("JD", Qt::CaseInsensitive))
×
1417
                {
1418
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-2);
×
1419
                        boundariesEpochJD=boundariesEpochStrV.toDouble(&ok); // pureJD
×
1420
                }
×
1421
                else if (boundariesEpoch.startsWith("B", Qt::CaseInsensitive))
×
1422
                {
1423
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
1424
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
1425
                        if (ok)
×
1426
                        {
1427
                                boundariesEpochJD=StelUtils::getJDFromBesselianEpoch(boundariesEpochY);
×
1428
                        }
1429
                }
×
1430
                else if (boundariesEpoch.startsWith("J", Qt::CaseInsensitive))
×
1431
                {
1432
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
1433
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
1434
                        if (ok)
×
1435
                        {
1436
                                boundariesEpochJD=StelUtils::getJDFromJulianEpoch(boundariesEpochY);
×
1437
                        }
1438
                }
×
1439
                else
1440
                        boundariesEpochJD=boundariesEpoch.toDouble(&ok); // pureJD
×
1441
                if (ok)
×
1442
                {
1443
                        // Create custom precession matrix for transformation of edges to J2000.0
1444
                        double epsEpoch, chiEpoch, omegaEpoch, psiEpoch;
1445
                        getPrecessionAnglesVondrak(boundariesEpochJD, &epsEpoch, &chiEpoch, &omegaEpoch, &psiEpoch);
×
1446
                        matCustomEdgeEpochToJ2000 = Mat4d::xrotation(84381.406*1./3600.*M_PI/180.) * Mat4d::zrotation(-psiEpoch) * Mat4d::xrotation(-omegaEpoch) * Mat4d::zrotation(chiEpoch);
×
1447
                }
1448
                else
1449
                {
1450
                        qWarning() << "SkyCultureMgr: Cannot parse edges_epoch =" << boundariesEpoch << ". Falling back to J2000.0";
×
1451
                        customEdgeEpoch = false;
×
1452
                }
1453
        }
1454
        const StelCore& core = *StelApp::getInstance().getCore();
×
1455
        qInfo().noquote() << "Loading constellation boundary data ... ";
×
1456

1457
        for (int n = 0; n < boundaryData.size(); ++n)
×
1458
        {
1459
                const QByteArray ba = boundaryData[n].toString().toLatin1();
×
1460
                const char *cstr = ba.data();
×
1461
                char edgeType, edgeDir;
1462
                char dec1_sign, dec2_sign;
1463
                int ra1_h, ra1_m, ra1_s, dec1_d, dec1_m, dec1_s;
1464
                int ra2_h, ra2_m, ra2_s, dec2_d, dec2_m, dec2_s;
1465
                char constellationNames[2][8];
1466
                if (sscanf(cstr,
×
1467
                           "%*s %c%c "
1468
                           "%d:%d:%d %c%d:%d:%d "
1469
                           "%d:%d:%d %c%d:%d:%d "
1470
                           "%7s %7s",
1471
                           &edgeType, &edgeDir,
1472
                           &ra1_h, &ra1_m, &ra1_s,
1473
                           &dec1_sign, &dec1_d, &dec1_m, &dec1_s,
1474
                           &ra2_h, &ra2_m, &ra2_s,
1475
                           &dec2_sign, &dec2_d, &dec2_m, &dec2_s,
1476
                           constellationNames[0], constellationNames[1]) != 18)
×
1477
                {
1478
                        qWarning().nospace() << "Failed to parse skyculture boundary line: \"" << cstr << "\"";
×
1479
                        continue;
×
1480
                }
1481

1482
                constexpr double timeSecToRadians = M_PI / (12 * 3600);
×
1483
                double RA1 = (60. * (60. * ra1_h + ra1_m) + ra1_s) * timeSecToRadians;
×
1484
                double RA2 = (60. * (60. * ra2_h + ra2_m) + ra2_s) * timeSecToRadians;
×
1485
                constexpr double angleSecToRad = M_PI / (180 * 3600);
×
1486
                double DE1 = (60. * (60. * dec1_d + dec1_m) + dec1_s) * (dec1_sign=='-' ? -1 : 1) * angleSecToRad;
×
1487
                double DE2 = (60. * (60. * dec2_d + dec2_m) + dec2_s) * (dec2_sign=='-' ? -1 : 1) * angleSecToRad;
×
1488

1489
                Vec3d xyz1;
×
1490
                StelUtils::spheToRect(RA1,DE1,xyz1);
×
1491
                Vec3d xyz2;
×
1492
                StelUtils::spheToRect(RA2,DE2,xyz2);
×
1493

1494
                const auto points = new std::vector<Vec3d>;
×
1495

1496
                const bool edgeTypeDirValid = ((edgeType == 'P' || edgeType == 'M') && (edgeDir == '+' || edgeDir == '-')) ||
×
1497
                                               (edgeType == '_' && edgeDir == '_');
×
1498
                if (!edgeTypeDirValid)
×
1499
                {
1500
                        qWarning().nospace() << "Bad edge type/direction: must be [PM_][-+_], but is " << QString("%1%2").arg(edgeType).arg(edgeDir)
×
1501
                                             << ". Will not interpolate the edges.";
×
1502
                        edgeType = '_';
×
1503
                        edgeDir = '_';
×
1504
                }
1505

1506
                double stepRA = 0, stepDE = 0;
×
1507
                int numPoints = 2;
×
1508
                switch (edgeType)
×
1509
                {
1510
                case 'P': // RA is variable
×
1511
                        if (RA2 > RA1 && edgeDir == '-')
×
1512
                                RA1 += 2*M_PI;
×
1513
                        if (RA2 < RA1 && edgeDir == '+')
×
1514
                                RA1 -= 2*M_PI;
×
1515
                        numPoints = 2 + std::ceil(std::abs(RA1 - RA2) / (M_PI / 64));
×
1516
                        stepRA = (RA2 - RA1) / (numPoints - 1);
×
1517
                        break;
×
1518
                case 'M': // DE is variable
×
1519
                        if (DE2 > DE1 && edgeDir == '-')
×
1520
                                DE1 += 2*M_PI;
×
1521
                        if (DE2 < DE1 && edgeDir == '+')
×
1522
                                DE1 -= 2*M_PI;
×
1523
                        numPoints = 2 + std::ceil(std::abs(DE1 - DE2) / (M_PI / 64));
×
1524
                        stepDE = (DE2 - DE1) / (numPoints - 1);
×
1525
                        break;
×
1526
                default: // No interpolation
×
1527
                        stepRA = RA2 - RA1;
×
1528
                        stepDE = DE2 - DE1;
×
1529
                        break;
×
1530
                }
1531

1532
                for (int n = 0; n < numPoints; ++n)
×
1533
                {
1534
                        const double RA = RA1 + n * stepRA;
×
1535
                        const double DE = DE1 + n * stepDE;
×
1536
                        Vec3d xyz;
×
1537
                        StelUtils::spheToRect(RA,DE,xyz);
×
1538
                        if (b1875) xyz = core.j1875ToJ2000(xyz);
×
1539
                        else if (customEdgeEpoch)
×
1540
                                xyz = matCustomEdgeEpochToJ2000*xyz;
×
1541
                        points->push_back(xyz);
×
1542
                }
1543

1544
                Constellation *cons = nullptr;
×
1545
                for (QString consName : constellationNames)
×
1546
                {
1547
                        // not used?
1548
                        if (consName == "SER1" || consName == "SER2") consName = "SER";
×
1549

1550
                        cons = findFromAbbreviation(consName);
×
1551
                        if (!cons)
×
1552
                                qWarning() << "ERROR while processing boundary file - cannot find constellation:" << consName;
×
1553
                        else
1554
                                cons->isolatedBoundarySegments.push_back(points);
×
1555
                }
×
1556

1557
                if (cons)
×
1558
                {
1559
                        cons->sharedBoundarySegments.push_back(points);
×
1560
                        // this list is for the de-allocation
1561
                        allBoundarySegments.push_back(points);
×
1562
                }
1563
                else
1564
                {
1565
                        delete points;
×
1566
                }
1567
        }
×
1568
        qInfo().noquote() << "Loaded" << boundaryData.size() << "constellation boundary segments";
×
1569

1570
        return true;
×
1571
}
1572

1573
void ConstellationMgr::drawBoundaries(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1574
{
1575
        const float scale = sPainter.getProjector()->getScreenScale();
×
1576

1577
        sPainter.setBlending(false);
×
1578
        if (boundariesThickness>1 || scale>1.f)
×
1579
                sPainter.setLineWidth(boundariesThickness*scale); // set line thickness
×
1580
        sPainter.setLineSmooth(true);
×
1581
        for (auto* constellation : constellations)
×
1582
        {
1583
                constellation->drawBoundaryOptim(sPainter, obsVelocity);
×
1584
        }
1585
        if (boundariesThickness>1 || scale>1.f)
×
1586
                sPainter.setLineWidth(1); // restore line thickness
×
1587
        sPainter.setLineSmooth(false);
×
1588
}
×
1589

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

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

1607
// Draw the zodiac, if any is defined in the current skyculture.
1608
// @param obsVelocity is the speed vector of the observer planet to distort zodiac lines by aberration.
1609
void ConstellationMgr::drawZodiac(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1610
{
1611
        if (!zodiac || zodiacFader.getInterstate()==0.)
×
1612
                return;
×
1613

1614
        sPainter.setColor(zodiacColor, zodiacFader.getInterstate());
×
1615
        zodiac->centerLine->setColor(zodiacColor);
×
1616
        zodiac->centerLine->setLineThickness(zodiacThickness);
×
1617
        zodiac->centerLine->setPartThickness(zodiacThickness);
×
1618
        sPainter.setBlending(true);
×
1619
        const float oldLineWidth=sPainter.getLineWidth();
×
1620
        sPainter.setLineWidth(zodiacThickness);
×
1621
        sPainter.setLineSmooth(true);
×
1622
        zodiac->draw(sPainter, obsVelocity);
×
1623
        sPainter.setLineWidth(oldLineWidth); // restore line thickness
×
1624
}
1625
// Draw the lunar system lines, if any is defined in the current skyculture.
1626
// @param obsVelocity is the speed vector of the observer planet to distort lunarSystem lines by aberration.
1627
void ConstellationMgr::drawLunarSystem(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1628
{
1629
        if (!lunarSystem || lunarSystemFader.getInterstate()==0.)
×
1630
                return;
×
1631

1632
        sPainter.setColor(lunarSystemColor, lunarSystemFader.getInterstate());
×
1633
        lunarSystem->centerLine->setColor(lunarSystemColor);
×
1634
        lunarSystem->centerLine->setLineThickness(lunarSystemThickness);
×
1635
        lunarSystem->centerLine->setPartThickness(lunarSystemThickness);
×
1636
        sPainter.setBlending(true);
×
1637
        const float oldLineWidth=sPainter.getLineWidth();
×
1638
        sPainter.setLineWidth(lunarSystemThickness);
×
1639
        sPainter.setLineSmooth(true);
×
1640
        lunarSystem->draw(sPainter, obsVelocity);
×
1641
        sPainter.setLineWidth(oldLineWidth); // restore line thickness
×
1642
}
1643

1644
//! Returns the translated name of the Zodiac system
1645
QString ConstellationMgr::getZodiacSystemName() const
×
1646
{
1647
        if (zodiac)
×
1648
                return zodiac->getCulturalName();
×
1649
        else
1650
                return QString();
×
1651
}
1652
//! Returns the translated name of the Lunar system
1653
QString ConstellationMgr::getLunarSystemName() const
×
1654
{
1655
        if (lunarSystem)
×
1656
                return lunarSystem->getCulturalName();
×
1657
        else
1658
                return QString();
×
1659
}
1660
//! Return longitude in the culture's zodiacal longitudes
1661
QString ConstellationMgr::getZodiacCoordinate(Vec3d eqNow) const
×
1662
{
1663
        if (zodiac)
×
1664
                return zodiac->getLongitudeCoordinate(eqNow);
×
1665
        else
1666
                return QString();
×
1667
}
1668
//! Return lunar station in the culture's Lunar system
1669
QString ConstellationMgr::getLunarSystemCoordinate(Vec3d eqNow) const
×
1670
{
1671
        if (lunarSystem)
×
1672
                return lunarSystem->getLongitudeCoordinate(eqNow);
×
1673
        else
1674
                return QString();
×
1675
}
1676

1677
StelObjectP ConstellationMgr::searchByNameI18n(const QString& nameI18n) const
×
1678
{
1679
        QString nameI18nUpper = nameI18n.toUpper();
×
1680

1681
        for (auto* constellation : constellations)
×
1682
        {
1683
                if (constellation->culturalName.translatedI18n.toUpper() == nameI18nUpper) return constellation;
×
1684
                if (constellation->culturalName.pronounceI18n.toUpper()  == nameI18nUpper) return constellation;
×
1685
        }
1686
        return nullptr;
×
1687
}
×
1688

1689
StelObjectP ConstellationMgr::searchByName(const QString& name) const
×
1690
{
1691
        QString nameUpper = name.toUpper();
×
1692
        for (auto* constellation : constellations)
×
1693
        {
1694
                if (constellation->culturalName.translated.toUpper()      == nameUpper) return constellation;
×
1695
                if (constellation->culturalName.native.toUpper()          == nameUpper) return constellation;
×
1696
                if (constellation->culturalName.pronounce.toUpper()       == nameUpper) return constellation;
×
1697
                if (constellation->culturalName.transliteration.toUpper() == nameUpper) return constellation;
×
1698
                if (constellation->abbreviation.toUpper()                 == nameUpper) return constellation;
×
1699
        }
1700
        return nullptr;
×
1701
}
×
1702

1703
StelObjectP ConstellationMgr::searchByID(const QString &id) const
×
1704
{
1705
        for (auto* constellation : constellations)
×
1706
        {
1707
                if (constellation->getID() == id) return constellation;
×
1708
        }
1709
        return nullptr;
×
1710
}
1711

1712
QStringList ConstellationMgr::listAllObjects(bool inEnglish) const
×
1713
{
1714
        // TODO: This is needed for the search dialog.
1715
        QStringList result;
×
1716
        if (inEnglish)
×
1717
        {
1718
                for (auto* constellation : constellations)
×
1719
                {
1720
                        result << constellation->getEnglishName();
×
1721
                        result << constellation->culturalName.pronounce;
×
1722
                        result << constellation->culturalName.transliteration;
×
1723
                        result << constellation->culturalName.native;
×
1724
                }
1725
        }
1726
        else
1727
        {
1728
                for (auto* constellation : constellations)
×
1729
                {
1730
                        result << constellation->getNameI18n();
×
1731
                        result << constellation->culturalName.pronounceI18n;
×
1732
                        result << constellation->culturalName.native;
×
1733
                }
1734
        }
1735
        result.removeDuplicates();
×
1736
        result.removeOne(QString(""));
×
1737
        result.removeOne(QString());
×
1738
        return result;
×
1739
}
×
1740

1741
QString ConstellationMgr::getStelObjectType() const
×
1742
{
1743
        return Constellation::CONSTELLATION_TYPE;
×
1744
}
1745

1746
// For modern... SCs (with IAU borders), this can just identify IAU constellations.
1747
// For others: identify from convex hulls.
1748
QList<StelObjectP> ConstellationMgr::searchAround(const Vec3d& v, double limitFov, const StelCore* core) const
×
1749
{
1750
        QList<StelObjectP> result;
×
1751

1752
        if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
1753
        {
1754
                QString cName=core->getIAUConstellation(v);
×
1755
                for (auto* constellation : std::as_const(constellations))
×
1756
                {
1757
                        if (constellation->getShortName()==cName)
×
1758
                        {
1759
                                result.append(constellation);
×
1760
                        }
1761
                }
1762
#ifndef NDEBUG
1763
                if (result.isEmpty())
×
1764
                        qDebug() << "ConstellationMgr::searchAround(): The IAU constellation" << cName << "was not found";
×
1765
#endif
1766
        }
×
1767
        else
1768
        {
1769
        for (auto* constellation : constellations)
×
1770
        {
1771
                if (constellation->convexHull && constellation->convexHull->contains(v))
×
1772
                {
1773
#ifndef NDEBUG
1774
                        qDebug() << "ConstellationMgr::searchAround(): point in hull of constellation" << constellation->getID();
×
1775
#endif
1776
                        result.append(constellation);
×
1777
                }
1778
        }
1779
#ifndef NDEBUG
1780
        qDebug() << "Point within hulls of" << result.count() << "constellations";
×
1781
#endif
1782
        }
1783
        return result;
×
1784
}
×
1785

1786
void ConstellationMgr::setSelected(const StelObject *s)
×
1787
{
1788
        if (!s)
×
1789
                setSelectedConst(QList<Constellation*>()); // actually deselect...
×
1790
        else
1791
                setSelectedConst(isObjectIn(s, !(StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)));
×
1792
}
×
1793

1794
// Return a QList<Constellation*>, will allow result from overlapping hulls
1795
QList<Constellation*> ConstellationMgr::isObjectIn(const StelObject *s, bool useHull) const
×
1796
{
1797
        StelCore *core = StelApp::getInstance().getCore();
×
1798
        QList<Constellation*> result;
×
1799
        if (useHull)
×
1800
        {
1801
                for (auto* constellation : constellations)
×
1802
                {
1803
                        if (constellation->convexHull->contains(s->getJ2000EquatorialPos(core)))
×
1804
                                result.append(constellation);
×
1805
                        else foreach(auto &obj, constellation->constellation)
×
1806
                        {
1807
                                // A problem persisted in selecting a star defining the hull which was then found just not to be contained!
1808
                                if (obj->getID() == s->getID())
×
1809
                                {
1810
                                        result.append(constellation);
×
1811
                                        break;
×
1812
                                }
1813
                        }
×
1814
                        // finally also test the hull outliers...
1815
                        foreach(auto &obj, constellation->hullExtension)
×
1816
                        {
1817
                                if (obj->getID() == s->getID())
×
1818
                                {
1819
                                        result.append(constellation);
×
1820
                                        break;
×
1821
                                }
1822
                        }
×
1823
                        // N.B. dark constellations: not forgotten, just not that critically defined around stars!
1824
                }
1825
        }
1826
        else
1827
        {
1828
                QString IAUConstUpper = core->getIAUConstellation(s->getEquinoxEquatorialPos(core)).toUpper();
×
1829
                for (auto* constellation : constellations)
×
1830
                {
1831
                        // Check if the object is in the constellation
1832
                        if (constellation->getShortName().toUpper() == IAUConstUpper)
×
1833
                                result.append(constellation);
×
1834
                }
1835
        }
×
1836
        return result;
×
1837
}
×
1838

1839
void ConstellationMgr::outputHullAreas(const QString &fileNamePrefix) const
×
1840
{
1841
        const QString scName=GETSTELMODULE(StelSkyCultureMgr)->getCurrentSkyCultureEnglishName();
×
1842

1843
        QString fileName=StelFileMgr::getUserDir() + QString("/%1_%2.csv").arg(fileNamePrefix, scName);
×
1844
        QFile file(fileName);
×
1845
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
1846
        if (file.open(QIODevice::Text | QIODevice::WriteOnly))
1847
#else
1848
        if (file.open(QIODeviceBase::Text | QIODeviceBase::WriteOnly))
×
1849
#endif
1850
        {
1851
                qInfo().nospace() << "Writing to:" << fileName;
×
1852
                file.write(QString("ID, Native, English, Translated, Area (sr), Area (sqdeg)\n").toLatin1());
×
1853
                foreach(const Constellation *constellation, constellations)
×
1854
                {
1855
                        double area_sr=constellation->convexHull->getArea();
×
1856
                        file.write(QString("%1, %2, %3, %4, %5, %6\n").arg(constellation->getID(),
×
1857
                                                                           constellation->getNameNative(),
×
1858
                                                                           constellation->getEnglishName(),
×
1859
                                                                           constellation->getNameI18n(),
×
1860
                                                                           QString::number(area_sr, 'f', 6),
×
1861
                                                                           QString::number(area_sr*(M_180_PI*M_180_PI), 'f', 6)).toLatin1());
×
1862
                }
×
1863
        }
1864
        else
1865
        {
1866
                qCritical() << "Cannot open file for writing! Output to logfile:";
×
1867
                foreach(const Constellation *constellation, constellations)
×
1868
                {
1869
                        double area_sr=constellation->convexHull->getArea();
×
1870
                        qInfo().nospace() << constellation->getEnglishName() << ": "
×
1871
                                          <<  area_sr << "sr or " << area_sr*(M_180_PI*M_180_PI) << "°²";
×
1872
                }
×
1873
        }
1874
}
×
1875

1876
//! Create a list of stars within the convex hull of constellation
1877
void ConstellationMgr::starsInHullOf(const QString &englishName, const bool hipOnly, const float maxMag, const QString &fileNamePrefix) const
×
1878
{
1879
        static StelCore *core=StelApp::getInstance().getCore();
×
1880
        StelObjectP constell=searchByName(englishName);
×
1881
        if (!constell)
×
1882
        {
1883
                qWarning() << "Constellation" << englishName << "not found, not creating star list";
×
1884
                return;
×
1885
        }
1886

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

1889
        // Add the actual hull-defining stars, but only if they are not already included. Unfortunately, we need to test via IDs!
1890
        // Results are prepended, so that usually hull-defining HIP stars are in the beginning of the list.
1891
        Constellation* constel=reinterpret_cast<Constellation*>(constell.data());
×
1892
        foreach(auto &star, constel->constellation)
×
1893
        {
1894
                QString id=star->getID();
×
1895
                bool wanted=true;
×
1896
                foreach (auto obj, starList)
×
1897
                        if (obj->getID()==id)
×
1898
                        {
1899
                                wanted=false;
×
1900
                                break;
×
1901
                        }
×
1902
                if (wanted)
×
1903
                        starList.prepend(star);
×
1904
        }
×
1905
        foreach(auto &star, constel->hullExtension)
×
1906
        {
1907
                QString id=star->getID();
×
1908
                bool wanted=true;
×
1909
                foreach (auto obj, starList)
×
1910
                        if (obj->getID()==id)
×
1911
                        {
1912
                                wanted=false;
×
1913
                                break;
×
1914
                        }
×
1915
                if (wanted)
×
1916
                        starList.prepend(star);
×
1917
        }
×
1918

1919
        qInfo().nospace() << starList.length() << " stars within the convex hull (" << constell->getRegion()->getArea()*(M_180_PI*M_180_PI) << " sq degrees) of " << englishName;
×
1920
        int day, month, year;
1921
        StelUtils::getDateFromJulianDay(core->getJD(), &year, &month, &day);
×
1922
        const double yearFraction=StelUtils::yearFraction(year, month, day);
×
1923
        const QString dateString=QString::number(yearFraction, 'f', 1);
×
1924
        const QString scName=GETSTELMODULE(StelSkyCultureMgr)->getCurrentSkyCultureEnglishName();
×
1925

1926
        QString fileName=StelFileMgr::getUserDir() + QString("/%1_%2_%3-%4.csv").arg(fileNamePrefix, scName, englishName, QString::number(maxMag, 'f', 2));
×
1927
        QFile file(fileName);
×
1928
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
1929
        if (file.open(QIODevice::Text | QIODevice::WriteOnly))
1930
#else
1931
        if (file.open(QIODeviceBase::Text | QIODeviceBase::WriteOnly))
×
1932
#endif
1933
        {
1934
                qInfo().nospace() << "Writing to:" << fileName;
×
1935
                file.write(QString("ID, mag, RA_J%1, DE_J%1, RA_J%1(h), DE_J%1(deg)\n").arg(dateString).toLatin1());
×
1936

1937
                foreach(const auto &star, starList)
×
1938
                {
1939
                        double ra, dec;
1940
                        StelUtils::rectToSphe(&ra, &dec, star->getEquinoxEquatorialPos(core));
×
1941
                        file.write(QString("%1, %2, %3, %4, %5, %6\n").arg(star->getID(), QString::number(star->getVMagnitude(core), 'f', 2),
×
1942
                                   StelUtils::radToHmsStr(ra), StelUtils::decDegToDmsStr(dec*M_180_PI),
×
1943
                                   QString::number(ra*M_180_PI / 15., 'f', 6), QString::number(dec*M_180_PI, 'f', 6)).toLatin1());
×
1944
                }
×
1945
                file.close();
×
1946
        }
1947
        else
1948
        {
1949
                qCritical() << "Cannot open file for writing! Dump to logfile:";
×
1950
                foreach(const auto &star, starList)
×
1951
                {
1952
                        double ra, dec;
1953
                        StelUtils::rectToSphe(&ra, &dec, star->getEquinoxEquatorialPos(core));
×
1954
                        qInfo().nospace().noquote() << star->getID() << ", " << star->getVMagnitude(core) << ", " <<
×
1955
                                                       StelUtils::radToHmsStr(ra) << ", " << StelUtils::decDegToDmsStr(dec*M_180_PI) <<
×
1956
                                                       QString::number(ra*M_180_PI / 15., 'f', 6) << ", " << QString::number(dec*M_180_PI, 'f', 6);
×
1957
                }
×
1958
        }
1959
}
×
1960

1961
void ConstellationMgr::recreateHulls()
×
1962
{
1963
        for (auto* constellation : std::as_const(constellations))
×
1964
                constellation->makeConvexHull();
×
1965
}
×
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