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

Stellarium / stellarium / 15291801018

28 May 2025 04:52AM UTC coverage: 11.931% (-0.02%) from 11.951%
15291801018

push

github

alex-w
Added new set of navigational stars (XIX century)

0 of 6 new or added lines in 2 files covered. (0.0%)

14124 existing lines in 74 files now uncovered.

14635 of 122664 relevant lines covered (11.93%)

18291.42 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(0),
×
60
          boundariesDisplayed(0),
×
61
          boundariesFadeDuration(1.),
×
62
          linesDisplayed(0),
×
63
          linesFadeDuration(0.),
×
64
          namesDisplayed(0),
×
65
          namesFadeDuration(1.),
×
66
          checkLoadingData(false),
×
67
          constellationLineThickness(1),
×
68
          constellationBoundariesThickness(1)
×
69
{
UNCOV
70
        setObjectName("ConstellationMgr");
×
71
        Q_ASSERT(hipStarMgr);
×
72
}
×
73

UNCOV
74
ConstellationMgr::~ConstellationMgr()
×
75
{
UNCOV
76
        for (auto* constellation : constellations)
×
77
        {
UNCOV
78
                delete constellation;
×
79
        }
80

UNCOV
81
        for (auto* segment : allBoundarySegments)
×
82
        {
UNCOV
83
                delete segment;
×
84
        }
UNCOV
85
}
×
86

UNCOV
87
void ConstellationMgr::init()
×
88
{
UNCOV
89
        QSettings* conf = StelApp::getInstance().getSettings();
×
90
        Q_ASSERT(conf);
×
91

UNCOV
92
        setFontSize(conf->value("viewing/constellation_font_size", 15).toInt());
×
93
        setFlagLines(conf->value("viewing/flag_constellation_drawing", false).toBool());
×
94
        setFlagLabels(conf->value("viewing/flag_constellation_name", false).toBool());
×
95
        setFlagBoundaries(conf->value("viewing/flag_constellation_boundaries", false).toBool());
×
96
        setArtIntensity(conf->value("viewing/constellation_art_intensity", 0.5f).toFloat());
×
97
        setArtFadeDuration(conf->value("viewing/constellation_art_fade_duration",2.f).toFloat());
×
98
        setFlagArt(conf->value("viewing/flag_constellation_art", false).toBool());
×
99
        setFlagIsolateSelected(conf->value("viewing/flag_constellation_isolate_selected", false).toBool());
×
100
        setFlagConstellationPick(conf->value("viewing/flag_constellation_pick", false).toBool());
×
101
        setConstellationLineThickness(conf->value("viewing/constellation_line_thickness", 1).toInt());
×
102
        setConstellationBoundariesThickness(conf->value("viewing/constellation_boundaries_thickness", 1).toInt());
×
103
        setBoundariesFadeDuration(conf->value("viewing/constellation_boundaries_fade_duration", 1.0f).toFloat());
×
104
        setLinesFadeDuration(conf->value("viewing/constellation_lines_fade_duration", 1.0f).toFloat());
×
105
        setLabelsFadeDuration(conf->value("viewing/constellation_labels_fade_duration", 1.0f).toFloat());
×
106
        // The setting for developers
UNCOV
107
        setFlagCheckLoadingData(conf->value("devel/check_loading_constellation_data","false").toBool());
×
108

109
        // Load colors from config file
110
        QString defaultColor = conf->value("color/default_color").toString();
×
111
        setLinesColor(Vec3f(conf->value("color/const_lines_color", defaultColor).toString()));
×
UNCOV
112
        setBoundariesColor(Vec3f(conf->value("color/const_boundary_color", "0.8,0.3,0.3").toString()));
×
113
        setLabelsColor(Vec3f(conf->value("color/const_names_color", defaultColor).toString()));
×
114

UNCOV
115
        StelObjectMgr *objectManager = GETSTELMODULE(StelObjectMgr);
×
116
        objectManager->registerStelObjectMgr(this);
×
UNCOV
117
        connect(objectManager, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
×
118
                        this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
119
        StelApp *app = &StelApp::getInstance();
×
120
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
121
        connect(&app->getSkyCultureMgr(), &StelSkyCultureMgr::currentSkyCultureChanged, this, &ConstellationMgr::updateSkyCulture);
×
122

UNCOV
123
        QString displayGroup = N_("Display Options");
×
124
        addAction("actionShow_Constellation_Lines", displayGroup, N_("Constellation lines"), "linesDisplayed", "C");
×
125
        addAction("actionShow_Constellation_Art", displayGroup, N_("Constellation art"), "artDisplayed", "R");
×
126
        addAction("actionShow_Constellation_Labels", displayGroup, N_("Constellation labels"), "namesDisplayed", "V");
×
UNCOV
127
        addAction("actionShow_Constellation_Boundaries", displayGroup, N_("Constellation boundaries"), "boundariesDisplayed", "B");
×
128
        addAction("actionShow_Constellation_Isolated", displayGroup, N_("Select single constellation"), "isolateSelected"); // no shortcut, sync with GUI
×
129
        addAction("actionShow_Constellation_Deselect", displayGroup, N_("Remove selection of constellations"), this, "deselectConstellations()", "W");
×
130
        addAction("actionShow_Constellation_Select", displayGroup, N_("Select all constellations"), this, "selectAllConstellations()", "Alt+W");
×
131
        // Reload the current sky culture
132
        addAction("actionShow_SkyCulture_Reload", displayGroup, N_("Reload the sky culture"), this, "reloadSkyCulture()", "Ctrl+Alt+I");
×
133
}
×
134

135
/*************************************************************************
136
 Reimplementation of the getCallOrder method
137
*************************************************************************/
138
double ConstellationMgr::getCallOrder(StelModuleActionName actionName) const
×
139
{
UNCOV
140
        if (actionName==StelModule::ActionDraw)
×
141
                return StelApp::getInstance().getModuleMgr().getModule("GridLinesMgr")->getCallOrder(actionName)+10;
×
142
        return 0;
×
143
}
144

UNCOV
145
void ConstellationMgr::reloadSkyCulture()
×
146
{
147
        StelApp::getInstance().getSkyCultureMgr().reloadSkyCulture();
×
UNCOV
148
}
×
149

150
void ConstellationMgr::updateSkyCulture(const StelSkyCulture& skyCulture)
×
151
{
152
        // first of all, remove constellations from the list of selected objects in StelObjectMgr, since we are going to delete them
UNCOV
153
        deselectConstellations();
×
154
        loadLinesNamesAndArt(skyCulture);
×
155

156
        // Translate constellation names for the new sky culture
157
        updateI18n();
×
158

159
        loadBoundaries(skyCulture.boundaries, skyCulture.boundariesEpoch);
×
160

UNCOV
161
        if (getFlagCheckLoadingData())
×
162
        {
163
                int i = 1;
×
164
                for (auto* constellation : constellations)
×
165
                {
166
                        qInfo() << "[Constellation] #" << i << " abbr:" << constellation->abbreviation << " name:" << constellation->getEnglishName() << " segments:" << constellation->numberOfSegments;
×
167
                        i++;
×
168
                }
169
        }
UNCOV
170
}
×
171

UNCOV
172
void ConstellationMgr::selectedObjectChange(StelModule::StelModuleSelectAction action)
×
173
{
UNCOV
174
        StelObjectMgr* omgr = GETSTELMODULE(StelObjectMgr);
×
175
        Q_ASSERT(omgr);
×
UNCOV
176
        const QList<StelObjectP> newSelected = omgr->getSelectedObject();
×
177
        if (newSelected.empty())
×
178
        {
179
                // Even if do not have anything selected, KEEP constellation selection intact
180
                // (allows viewing constellations without distraction from star pointer animation)
181
                // setSelected(nullptr);
182
                return;
×
183
        }
184

UNCOV
185
        const QList<StelObjectP> newSelectedConst = omgr->getSelectedObject("Constellation");
×
186
        if (!newSelectedConst.empty())
×
187
        {
188
                // If removing this selection
UNCOV
189
                if(action == StelModule::RemoveFromSelection)
×
190
                {
191
                        unsetSelectedConst(static_cast<Constellation *>(newSelectedConst[0].data()));
×
192
                }
193
                else
194
                {
195
                        // Add constellation to selected list (do not select a star, just the constellation)
UNCOV
196
                        setSelectedConst(static_cast<Constellation *>(newSelectedConst[0].data()));
×
197
                }
198
        }
199
        else
200
        {
201
                QList<StelObjectP> newSelectedObject;
×
202
                if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
UNCOV
203
                        newSelectedObject = omgr->getSelectedObject();
×
204
                else
205
                        newSelectedObject = omgr->getSelectedObject("Star");
×
206

207
                if (!newSelectedObject.empty())
×
208
                {
UNCOV
209
                        setSelected(newSelectedObject[0].data());
×
210
                }
211
                else
212
                {
UNCOV
213
                        setSelected(nullptr);
×
214
                }
UNCOV
215
        }
×
UNCOV
216
}
×
217

218
void ConstellationMgr::deselectConstellations(void)
×
219
{
UNCOV
220
        static StelObjectMgr* omgr = GETSTELMODULE(StelObjectMgr);
×
221
        Q_ASSERT(omgr);
×
UNCOV
222
        if (getFlagIsolateSelected())
×
223
        {
224
                // The list of selected constellations is empty, but...
225
                if (selected.size()==0)
×
226
                {
227
                        // ...let's unselect all constellations for guarantee
UNCOV
228
                        for (auto* constellation : constellations)
×
229
                        {
UNCOV
230
                                constellation->setFlagLines(false);
×
231
                                constellation->setFlagLabels(false);
×
232
                                constellation->setFlagArt(false);
×
UNCOV
233
                                constellation->setFlagBoundaries(false);
×
234
                        }
235
                }
236

237
                // If any constellation is selected at the moment, then let's do not touch to it!
238
                if (omgr->getWasSelected() && !selected.empty())
×
UNCOV
239
                        selected.pop_back();
×
240

241
                // Let's hide all previously selected constellations
UNCOV
242
                for (auto* constellation : selected)
×
243
                {
244
                        constellation->setFlagLines(false);
×
UNCOV
245
                        constellation->setFlagLabels(false);
×
246
                        constellation->setFlagArt(false);
×
247
                        constellation->setFlagBoundaries(false);
×
248
                }                
249
        }
250
        else
251
        {
UNCOV
252
                const QList<StelObjectP> newSelectedConst = omgr->getSelectedObject("Constellation");
×
UNCOV
253
                if (!newSelectedConst.empty())
×
254
                        omgr->unSelect();
×
255
        }
×
UNCOV
256
        selected.clear();
×
UNCOV
257
}
×
258

UNCOV
259
void ConstellationMgr::selectAllConstellations()
×
260
{
261
        for (auto* constellation : constellations)
×
262
        {
263
                setSelectedConst(constellation);
×
264
        }
UNCOV
265
}
×
266

UNCOV
267
void ConstellationMgr::selectConstellation(const QString &englishName)
×
268
{
269
        if (!getFlagIsolateSelected())
×
270
                setFlagIsolateSelected(true); // Enable isolated selection
×
271

272
        bool found = false;
×
273
        for (auto* constellation : constellations)
×
274
        {
275
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
276
                {
277
                        setSelectedConst(constellation);
×
UNCOV
278
                        found = true;
×
279
                }
280
        }
281
        if (!found)
×
UNCOV
282
                qDebug() << "The constellation" << englishName << "is not found";
×
283
}
×
284

285
void ConstellationMgr::selectConstellationByObjectName(const QString &englishName)
×
286
{
UNCOV
287
        if (!getFlagIsolateSelected())
×
288
                setFlagIsolateSelected(true); // Enable isolated selection
×
289

UNCOV
290
        if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
291
                setSelectedConst(isObjectIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data()));
×
292
        else
293
                setSelectedConst(isStarIn(GETSTELMODULE(StelObjectMgr)->searchByName(englishName).data()));
×
294
}
×
295

UNCOV
296
void ConstellationMgr::deselectConstellation(const QString &englishName)
×
297
{
298
        if (!getFlagIsolateSelected())
×
299
                setFlagIsolateSelected(true); // Enable isolated selection
×
300

301
        bool found = false;
×
UNCOV
302
        for (auto* constellation : constellations)
×
303
        {
304
                if (constellation->getEnglishName().toLower()==englishName.toLower())
×
305
                {
306
                        unsetSelectedConst(constellation);
×
307
                        found = true;
×
308
                }
309
        }
310

UNCOV
311
        if (selected.size()==0 && found)
×
312
        {
313
                // Let's remove the selection for all constellations if the list of selected constellations is empty
314
                for (auto* constellation : constellations)
×
315
                {
UNCOV
316
                        constellation->setFlagLines(false);
×
317
                        constellation->setFlagLabels(false);
×
318
                        constellation->setFlagArt(false);
×
UNCOV
319
                        constellation->setFlagBoundaries(false);
×
320
                }
321
        }
322

323
        if (!found)
×
UNCOV
324
                qDebug() << "The constellation" << englishName << "is not found";
×
UNCOV
325
}
×
326

327
void ConstellationMgr::setLinesColor(const Vec3f& color)
×
328
{
UNCOV
329
        if (color != Constellation::lineColor)
×
330
        {
UNCOV
331
                Constellation::lineColor = color;
×
332
                emit linesColorChanged(color);
×
333
        }
334
}
×
335

UNCOV
336
Vec3f ConstellationMgr::getLinesColor() const
×
337
{
UNCOV
338
        return Constellation::lineColor;
×
339
}
340

341
void ConstellationMgr::setBoundariesColor(const Vec3f& color)
×
342
{
343
        if (Constellation::boundaryColor != color)
×
344
        {
345
                Constellation::boundaryColor = color;
×
UNCOV
346
                emit boundariesColorChanged(color);
×
347
        }
348
}
×
349

350
Vec3f ConstellationMgr::getBoundariesColor() const
×
351
{
352
        return Constellation::boundaryColor;
×
353
}
354

UNCOV
355
void ConstellationMgr::setLabelsColor(const Vec3f& color)
×
356
{
357
        if (Constellation::labelColor != color)
×
358
        {
359
                Constellation::labelColor = color;
×
UNCOV
360
                emit namesColorChanged(color);
×
361
        }
362
}
×
363

364
Vec3f ConstellationMgr::getLabelsColor() const
×
365
{
366
        return Constellation::labelColor;
×
367
}
368

UNCOV
369
void ConstellationMgr::setFontSize(const int newFontSize)
×
370
{
371
        if (asterFont.pixelSize() - newFontSize != 0)
×
372
        {
373
                asterFont.setPixelSize(newFontSize);
×
UNCOV
374
                StelApp::immediateSave("viewing/constellation_font_size", newFontSize);
×
375
                emit fontSizeChanged(newFontSize);
×
376
        }
UNCOV
377
}
×
378

UNCOV
379
int ConstellationMgr::getFontSize() const
×
380
{
UNCOV
381
        return asterFont.pixelSize();
×
382
}
383

UNCOV
384
void ConstellationMgr::setConstellationLineThickness(const int thickness)
×
385
{
UNCOV
386
        if(thickness!=constellationLineThickness)
×
387
        {
UNCOV
388
                constellationLineThickness = thickness;
×
389
                if (constellationLineThickness<=0) // The line can not be negative or zero thickness
×
390
                        constellationLineThickness = 1;
×
391

UNCOV
392
                StelApp::immediateSave("viewing/constellation_line_thickness", thickness);
×
393
                emit constellationLineThicknessChanged(thickness);
×
394
        }
395
}
×
396

397
void ConstellationMgr::setConstellationBoundariesThickness(const int thickness)
×
398
{
UNCOV
399
        if(thickness!=constellationBoundariesThickness)
×
400
        {
UNCOV
401
                constellationBoundariesThickness = qMax(1, thickness); // cannot be 0 or neg.
×
402

403
                StelApp::immediateSave("viewing/constellation_boundaries_thickness", thickness);
×
404
                emit constellationBoundariesThicknessChanged(thickness);
×
405
        }
UNCOV
406
}
×
407

UNCOV
408
void ConstellationMgr::loadLinesNamesAndArt(const StelSkyCulture &culture)
×
409
{
UNCOV
410
        constellations.clear();
×
UNCOV
411
        Constellation::seasonalRuleEnabled = false;
×
412

UNCOV
413
        int readOk = 0;
×
414
        for (const auto& constellationData : culture.constellations)
×
415
        {
UNCOV
416
                Constellation*const cons = new Constellation;
×
417
                const auto consObj = constellationData.toObject();
×
UNCOV
418
                if (!cons->read(consObj, hipStarMgr)) //, preferNativeNames))
×
419
                {
UNCOV
420
                        delete cons;
×
421
                        continue;
×
422
                }
423
                ++readOk;
×
UNCOV
424
                constellations.push_back(cons);
×
425

426
                cons->artOpacity = artIntensity;
×
UNCOV
427
                cons->artFader.setDuration(static_cast<int>(artFadeDuration * 1000.f));
×
428
                cons->lineFader.setDuration(static_cast<int>(linesFadeDuration * 1000.f));
×
UNCOV
429
                cons->boundaryFader.setDuration(static_cast<int>(boundariesFadeDuration * 1000.f));
×
430
                cons->nameFader.setDuration(static_cast<int>(namesFadeDuration * 1000.f));
×
UNCOV
431
                cons->setFlagArt(artDisplayed);
×
432
                cons->setFlagBoundaries(boundariesDisplayed);
×
UNCOV
433
                cons->setFlagLines(linesDisplayed);
×
434
                cons->setFlagLabels(namesDisplayed);
×
435

436
                // Now load constellation art
437

UNCOV
438
                const auto imgVal = consObj["image"];
×
439
                if (imgVal.isUndefined())
×
UNCOV
440
                        continue;
×
441
                const auto imgData = imgVal.toObject();
×
UNCOV
442
                const auto anchors = imgData["anchors"].toArray();
×
443
                if (anchors.size() < 3)
×
444
                {
UNCOV
445
                        qWarning().nospace() << "Bad number of anchors (" << anchors.size() << ") for image in constellation "
×
446
                                             << consObj["id"].toString();
×
447
                        continue;
×
448
                }
449
                const auto anchor1 = anchors[0].toObject();
×
450
                const auto anchor2 = anchors[1].toObject();
×
451
                const auto anchor3 = anchors[2].toObject();
×
UNCOV
452
                const auto xy1 = anchor1["pos"].toArray();
×
453
                const auto xy2 = anchor2["pos"].toArray();
×
454
                const auto xy3 = anchor3["pos"].toArray();
×
455

456
                const int x1 = xy1[0].toInt();
×
457
                const int y1 = xy1[1].toInt();
×
UNCOV
458
                const int x2 = xy2[0].toInt();
×
459
                const int y2 = xy2[1].toInt();
×
460
                const int x3 = xy3[0].toInt();
×
461
                const int y3 = xy3[1].toInt();
×
462
                const int hp1 = StelUtils::getLongLong(anchor1["hip"]);
×
463
                const int hp2 = StelUtils::getLongLong(anchor2["hip"]);
×
464
                const int hp3 = StelUtils::getLongLong(anchor3["hip"]);
×
465

466
                const auto texfile = imgData["file"].toString();
×
467

UNCOV
468
                auto texturePath = culture.path+"/"+texfile;
×
UNCOV
469
                if (!QFileInfo::exists(texturePath))
×
470
                {
471
                        qWarning() << "ERROR: could not find texture" << QDir::toNativeSeparators(texfile);
×
472
                        texturePath.clear();
×
473
                }
474

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

UNCOV
477
                const auto sizeData = imgData["size"].toArray();
×
478
                if (sizeData.size() != 2)
×
479
                {
480
                        qWarning().nospace() << "Bad length of \"size\" array for image in constellation "
×
UNCOV
481
                                             << consObj["id"].toString();
×
482
                        continue;
×
483
                }
484
                const int texSizeX = sizeData[0].toInt(), texSizeY = sizeData[1].toInt();
×
485

486
                StelCore* core = StelApp::getInstance().getCore();
×
487
                StelObjectP s1obj = hipStarMgr->searchHP(static_cast<int>(hp1));
×
UNCOV
488
                StelObjectP s2obj = hipStarMgr->searchHP(static_cast<int>(hp2));
×
489
                StelObjectP s3obj = hipStarMgr->searchHP(static_cast<int>(hp3));
×
490

491
                // check for null pointers
492
                if (s1obj.isNull() || s2obj.isNull() || s3obj.isNull())
×
493
                {
494
                        qWarning() << "ERROR: could not find stars:" << hp1 << hp2 << hp3 << " in constellation" << consObj["id"].toString();
×
495
                        continue;
×
496
                }
497

UNCOV
498
                const Vec3d s1 = s1obj->getJ2000EquatorialPos(core);
×
499
                const Vec3d s2 = s2obj->getJ2000EquatorialPos(core);
×
UNCOV
500
                const Vec3d s3 = s3obj->getJ2000EquatorialPos(core);
×
501

502
                // To transform from texture coordinate to 2d coordinate we need to find X with XA = B
503
                // A formed of 4 points in texture coordinate, B formed with 4 points in 3d coordinate space
504
                // We need 3 stars and the 4th point is deduced from the others to get a normal base
505
                // X = B inv(A)
UNCOV
506
                Vec3d s4 = s1 + ((s2 - s1) ^ (s3 - s1));
×
UNCOV
507
                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);
×
508
                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.);
×
UNCOV
509
                Mat4d X = B * A.inverse();
×
510

511
                // Tessellate on the plane assuming a tangential projection for the image
512
                static const int nbPoints=5;
513
                QVector<Vec2f> texCoords;
×
514
                texCoords.reserve(nbPoints*nbPoints*6);
×
515
                for (int j=0;j<nbPoints;++j)
×
516
                {
517
                        for (int i=0;i<nbPoints;++i)
×
518
                        {
519
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j))/nbPoints);
×
520
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j))/nbPoints);
×
521
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
522
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j))/nbPoints);
×
UNCOV
523
                                texCoords << Vec2f((static_cast<float>(i)+1.f)/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
UNCOV
524
                                texCoords << Vec2f((static_cast<float>(i))/nbPoints, (static_cast<float>(j)+1.f)/nbPoints);
×
525
                        }
526
                }
527

528
                QVector<Vec3d> contour;
×
UNCOV
529
                contour.reserve(texCoords.size());
×
UNCOV
530
                for (const auto& v : std::as_const(texCoords))
×
531
                {
532
                        Vec3d vertex = X * Vec3d(static_cast<double>(v[0]) * texSizeX, static_cast<double>(v[1]) * texSizeY, 0.);
×
533
                        // Originally the projected texture plane remained as tangential plane.
534
                        // The vertices should however be reduced to the sphere for correct aberration:
UNCOV
535
                        vertex.normalize();
×
UNCOV
536
                        contour << vertex;
×
537
                }
538

539
                cons->artPolygon.vertex=contour;
×
540
                cons->artPolygon.texCoords=texCoords;
×
541
                cons->artPolygon.primitiveType=StelVertexArray::Triangles;
×
542

UNCOV
543
                Vec3d tmp(X * Vec3d(0.5*texSizeX, 0.5*texSizeY, 0.));
×
UNCOV
544
                tmp.normalize();
×
UNCOV
545
                Vec3d tmp2(X * Vec3d(0., 0., 0.));
×
546
                tmp2.normalize();
×
547
                cons->boundingCap.n=tmp;
×
548
                cons->boundingCap.d=tmp*tmp2;
×
UNCOV
549
        }
×
550

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

553
        // Set current states
554
        setFlagArt(artDisplayed);
×
555
        setFlagLines(linesDisplayed);
×
556
        setFlagLabels(namesDisplayed);
×
557
        setFlagBoundaries(boundariesDisplayed);
×
UNCOV
558
}
×
559

UNCOV
560
void ConstellationMgr::draw(StelCore* core)
×
561
{
562
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
563
        StelPainter sPainter(prj);
×
UNCOV
564
        sPainter.setFont(asterFont);
×
565
        drawLines(sPainter, core);
×
UNCOV
566
        Vec3d vel(0.);
×
UNCOV
567
        if (core->getUseAberration())
×
568
        {
569
                vel = core->getAberrationVec(core->getJDE());
×
570
        }
UNCOV
571
        drawNames(sPainter, vel);
×
572
        drawArt(sPainter, vel);
×
573
        drawBoundaries(sPainter, vel);
×
574
}
×
575

576
// Draw constellations art textures
577
void ConstellationMgr::drawArt(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
578
{
579
        sPainter.setBlending(true, GL_ONE, GL_ONE);
×
580
        sPainter.setCullFace(true);
×
581

582
        SphericalRegionP region = sPainter.getProjector()->getViewportConvexPolygon();
×
UNCOV
583
        for (auto* constellation : constellations)
×
584
        {
UNCOV
585
                constellation->drawArtOptim(sPainter, *region, obsVelocity);
×
586
        }
587

588
        sPainter.setCullFace(false);
×
589
}
×
590

591
// Draw constellations lines
UNCOV
592
void ConstellationMgr::drawLines(StelPainter& sPainter, const StelCore* core) const
×
593
{
UNCOV
594
        const float scale = sPainter.getProjector()->getScreenScale();
×
595

596
        sPainter.setBlending(true);
×
597
        if (constellationLineThickness>1 || scale>1.f)
×
598
                sPainter.setLineWidth(constellationLineThickness*scale); // set line thickness
×
599
        sPainter.setLineSmooth(true);
×
600

UNCOV
601
        const SphericalCap& viewportHalfspace = sPainter.getProjector()->getBoundingCap();
×
602
        for (auto* constellation : constellations)
×
603
        {
604
                constellation->drawOptim(sPainter, core, viewportHalfspace);
×
605
        }
606
        if (constellationLineThickness>1 || scale>1.f)
×
607
                sPainter.setLineWidth(1); // restore line thickness
×
UNCOV
608
        sPainter.setLineSmooth(false);
×
UNCOV
609
}
×
610

611
// Draw the names of all the constellations
612
void ConstellationMgr::drawNames(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
613
{
UNCOV
614
        sPainter.setBlending(true);
×
615
        for (auto* constellation : constellations)
×
616
        {
UNCOV
617
                Vec3d XYZname=constellation->XYZname;
×
618
                XYZname.normalize();
×
UNCOV
619
                XYZname+=obsVelocity;
×
UNCOV
620
                XYZname.normalize();
×
621

622
                // Check if in the field of view
UNCOV
623
                if (sPainter.getProjector()->projectCheck(XYZname, constellation->XYname))
×
UNCOV
624
                        constellation->drawName(sPainter);
×
625
        }
UNCOV
626
}
×
627

UNCOV
628
Constellation *ConstellationMgr::isStarIn(const StelObject* s) const
×
629
{
630
        for (auto* constellation : constellations)
×
631
        {
632
                // Check if the star is in one of the constellations
UNCOV
633
                if (constellation->isStarIn(s))
×
634
                {
635
                        return constellation;
×
636
                }
637
        }
UNCOV
638
        return nullptr;
×
639
}
640

641
Constellation* ConstellationMgr::findFromAbbreviation(const QString& abbreviation) const
×
642
{
643
        // search in uppercase only
644
        //QString tname = abbreviation.toUpper();
645

UNCOV
646
        for (auto* constellation : constellations)
×
647
        {
648
                //if (constellation->abbreviation.toUpper() == tname)
UNCOV
649
                if (constellation->abbreviation.compare(abbreviation, Qt::CaseInsensitive) == 0)
×
650
                {
651
                        //if (constellation->abbreviation != abbreviation)
652
                        //        qDebug() << "ConstellationMgr::findFromAbbreviation: not a perfect match, but sufficient:" << constellation->abbreviation << "vs." << abbreviation;
653
                        return constellation;
×
654
                }
655
                //else qDebug() << "Comparison mismatch: " << abbreviation << "vs." << constellation->abbreviation;
656
        }
657
        return nullptr;
×
658
}
659

660
// Can't find constellation from a position because it's not well localized
661
// TODO: For modern... SCs, this can just identify IAU constellations.
662
// TODO later: identify from convex hulls.
663
//QList<StelObjectP> ConstellationMgr::searchAround(const Vec3d&, double, const StelCore*) const
664
//{
665
//        return QList<StelObjectP>();
666
//}
667

668
QStringList ConstellationMgr::getConstellationsEnglishNames()
×
669
{
UNCOV
670
        QStringList constellationsEnglishNames;
×
671
        for (auto* constellation : constellations)
×
672
        {
UNCOV
673
                constellationsEnglishNames << constellation->getEnglishName();
×
674
        }
UNCOV
675
        return  constellationsEnglishNames;
×
UNCOV
676
}
×
677

UNCOV
678
void ConstellationMgr::updateI18n()
×
679
{
UNCOV
680
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
681

682
        for (auto* constellation : constellations)
×
683
        {
UNCOV
684
                QString context = constellation->context;
×
UNCOV
685
                constellation->culturalName.translatedI18n = trans.tryQtranslate(constellation->culturalName.translated, context);
×
686
                if (constellation->culturalName.translatedI18n.isEmpty())
×
687
                {
UNCOV
688
                        if (context.isEmpty())
×
UNCOV
689
                                constellation->culturalName.translatedI18n = q_(constellation->culturalName.translated);
×
690
                        else
UNCOV
691
                                constellation->culturalName.translatedI18n = qc_(constellation->culturalName.translated, context);
×
692
                }
UNCOV
693
                constellation->culturalName.pronounceI18n = trans.tryQtranslate(constellation->culturalName.pronounce, context);
×
694
                if (constellation->culturalName.pronounceI18n.isEmpty())
×
695
                {
696
                        if (context.isEmpty())
×
UNCOV
697
                                constellation->culturalName.pronounceI18n = q_(constellation->culturalName.pronounce);
×
698
                        else
699
                                constellation->culturalName.pronounceI18n = qc_(constellation->culturalName.pronounce, context);
×
700
                }
701
                constellation->abbreviationI18n = trans.tryQtranslate(constellation->abbreviation, context).trimmed();
×
UNCOV
702
                if (constellation->abbreviationI18n.isEmpty())
×
703
                {
704
                        if (context.isEmpty())
×
UNCOV
705
                                constellation->abbreviationI18n = q_(constellation->abbreviation).trimmed();
×
706
                        else
UNCOV
707
                                constellation->abbreviationI18n = qc_(constellation->abbreviation, context).trimmed();
×
708
                }
UNCOV
709
        }
×
710
}
×
711

712
// update faders
UNCOV
713
void ConstellationMgr::update(double deltaTime)
×
714
{
715
        //calculate FOV fade value, linear fade between artIntensityMaximumFov and artIntensityMinimumFov
UNCOV
716
        double fov = StelApp::getInstance().getCore()->getMovementMgr()->getCurrentFov();
×
717
        Constellation::artIntensityFovScale = static_cast<float>(qBound(0.0,(fov - artIntensityMinimumFov) / (artIntensityMaximumFov - artIntensityMinimumFov),1.0));
×
718

719
        const int delta = static_cast<int>(deltaTime*1000);
×
720
        for (auto* constellation : constellations)
×
721
        {
UNCOV
722
                constellation->update(delta);
×
723
        }
UNCOV
724
}
×
725

726
void ConstellationMgr::setArtIntensity(const float intensity)
×
727
{
UNCOV
728
        if ((artIntensity - intensity) != 0.0f)
×
729
        {
730
                artIntensity = intensity;
×
731

732
                for (auto* constellation : constellations)
×
733
                {
734
                        constellation->artOpacity = artIntensity;
×
735
                }
736
                StelApp::immediateSave("viewing/constellation_art_intensity", intensity);
×
UNCOV
737
                emit artIntensityChanged(static_cast<double>(intensity));
×
738
        }
UNCOV
739
}
×
740

UNCOV
741
float ConstellationMgr::getArtIntensity() const
×
742
{
UNCOV
743
        return artIntensity;
×
744
}
745

746
void ConstellationMgr::setArtIntensityMinimumFov(const double fov)
×
747
{
UNCOV
748
        artIntensityMinimumFov = fov;
×
749
}
×
750

751
double ConstellationMgr::getArtIntensityMinimumFov() const
×
752
{
753
        return artIntensityMinimumFov;
×
754
}
755

756
void ConstellationMgr::setArtIntensityMaximumFov(const double fov)
×
757
{
758
        artIntensityMaximumFov = fov;
×
759
}
×
760

761
double ConstellationMgr::getArtIntensityMaximumFov() const
×
762
{
763
        return artIntensityMaximumFov;
×
764
}
765

766
void ConstellationMgr::setArtFadeDuration(const float duration)
×
767
{
768
        if (!qFuzzyCompare(artFadeDuration, duration))
×
769
        {
UNCOV
770
                artFadeDuration = duration;
×
771

UNCOV
772
                for (auto* constellation : constellations)
×
773
                {
UNCOV
774
                        constellation->artFader.setDuration(static_cast<int>(duration * 1000.f));
×
775
                }
776
                StelApp::immediateSave("viewing/constellation_art_fade_duration", duration);
×
UNCOV
777
                emit artFadeDurationChanged(duration);
×
778
        }
UNCOV
779
}
×
780

UNCOV
781
float ConstellationMgr::getArtFadeDuration() const
×
782
{
UNCOV
783
        return artFadeDuration;
×
784
}
785

786
void ConstellationMgr::setBoundariesFadeDuration(const float duration)
×
787
{
UNCOV
788
        if (!qFuzzyCompare(boundariesFadeDuration, duration))
×
789
        {
UNCOV
790
                boundariesFadeDuration = duration;
×
791

UNCOV
792
                for (auto* constellation : constellations)
×
793
                {
UNCOV
794
                        constellation->boundaryFader.setDuration(static_cast<int>(duration * 1000.f));
×
795
                }
796
                StelApp::immediateSave("viewing/constellation_boundaries_fade_duration", duration);
×
UNCOV
797
                emit boundariesFadeDurationChanged(duration);
×
798
        }
UNCOV
799
}
×
800

UNCOV
801
float ConstellationMgr::getBoundariesFadeDuration() const
×
802
{
UNCOV
803
        return boundariesFadeDuration;
×
804
}
805

806
void ConstellationMgr::setLinesFadeDuration(const float duration)
×
807
{
UNCOV
808
        if (!qFuzzyCompare(linesFadeDuration, duration))
×
809
        {
UNCOV
810
                linesFadeDuration = duration;
×
811

UNCOV
812
                for (auto* constellation : constellations)
×
813
                {
UNCOV
814
                        constellation->lineFader.setDuration(static_cast<int>(duration * 1000.f));
×
815
                }
816
                StelApp::immediateSave("viewing/constellation_lines_fade_duration", duration);
×
UNCOV
817
                emit linesFadeDurationChanged(duration);
×
818
        }
UNCOV
819
}
×
820

UNCOV
821
float ConstellationMgr::getLinesFadeDuration() const
×
822
{
UNCOV
823
        return linesFadeDuration;
×
824
}
825

826
void ConstellationMgr::setLabelsFadeDuration(const float duration)
×
827
{
UNCOV
828
        if (!qFuzzyCompare(namesFadeDuration, duration))
×
829
        {
UNCOV
830
                namesFadeDuration = duration;
×
831

UNCOV
832
                for (auto* constellation : constellations)
×
833
                {
UNCOV
834
                        constellation->nameFader.setDuration(static_cast<int>(duration * 1000.f));
×
835
                }
836
                StelApp::immediateSave("viewing/constellation_labels_fade_duration", duration);
×
UNCOV
837
                emit namesFadeDurationChanged(duration);
×
838
        }
UNCOV
839
}
×
840

UNCOV
841
float ConstellationMgr::getLabelsFadeDuration() const
×
842
{
UNCOV
843
        return namesFadeDuration;
×
844
}
845

846
void ConstellationMgr::setFlagLines(const bool displayed)
×
847
{
UNCOV
848
        if(linesDisplayed != displayed)
×
849
        {
UNCOV
850
                linesDisplayed = displayed;
×
851
                if (!selected.empty() && isolateSelected)
×
852
                {
853
                        for (auto* constellation : selected)
×
854
                        {
UNCOV
855
                                constellation->setFlagLines(linesDisplayed);
×
856
                        }
857
                }
858
                else
859
                {
860
                        for (auto* constellation : constellations)
×
861
                        {
UNCOV
862
                                constellation->setFlagLines(linesDisplayed);
×
863
                        }
864
                }
865
                StelApp::immediateSave("viewing/flag_constellation_drawing", displayed);
×
UNCOV
866
                emit linesDisplayedChanged(displayed);
×
867
        }
UNCOV
868
}
×
869

870
bool ConstellationMgr::getFlagLines(void) const
×
871
{
872
        return linesDisplayed;
×
873
}
874

875
void ConstellationMgr::setFlagBoundaries(const bool displayed)
×
876
{
UNCOV
877
        if (boundariesDisplayed != displayed)
×
878
        {
UNCOV
879
                boundariesDisplayed = displayed;
×
880
                if (!selected.empty() && isolateSelected)
×
881
                {
882
                        for (auto* constellation : selected)
×
883
                        {
UNCOV
884
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
885
                        }
886
                }
887
                else
888
                {
889
                        for (auto* constellation : constellations)
×
890
                        {
UNCOV
891
                                constellation->setFlagBoundaries(boundariesDisplayed);
×
892
                        }
893
                }
894
                StelApp::immediateSave("viewing/flag_constellation_boundaries", displayed);
×
UNCOV
895
                emit boundariesDisplayedChanged(displayed);
×
896
        }
UNCOV
897
}
×
898

899
bool ConstellationMgr::getFlagBoundaries(void) const
×
900
{
901
        return boundariesDisplayed;
×
902
}
903

904
void ConstellationMgr::setFlagArt(const bool displayed)
×
905
{
UNCOV
906
        if (artDisplayed != displayed)
×
907
        {
UNCOV
908
                artDisplayed = displayed;
×
909
                if (!selected.empty() && isolateSelected)
×
910
                {
911
                        for (auto* constellation : selected)
×
912
                        {
UNCOV
913
                                constellation->setFlagArt(artDisplayed);
×
914
                        }
915
                }
916
                else
917
                {
918
                        for (auto* constellation : constellations)
×
919
                        {
UNCOV
920
                                constellation->setFlagArt(artDisplayed);
×
921
                        }
922
                }
923
                StelApp::immediateSave("viewing/flag_constellation_art", displayed);
×
UNCOV
924
                emit artDisplayedChanged(displayed);
×
925
        }
UNCOV
926
}
×
927

928
bool ConstellationMgr::getFlagArt(void) const
×
929
{
930
        return artDisplayed;
×
931
}
932

933
void ConstellationMgr::setFlagLabels(const bool displayed)
×
934
{
UNCOV
935
        if (namesDisplayed != displayed)
×
936
        {
UNCOV
937
                namesDisplayed = displayed;
×
938
                if (!selected.empty() && isolateSelected)
×
939
                {
940
                        for (auto* constellation : selected)
×
UNCOV
941
                                constellation->setFlagLabels(namesDisplayed);
×
942
                }
943
                else
944
                {
945
                        for (auto* constellation : constellations)
×
UNCOV
946
                                constellation->setFlagLabels(namesDisplayed);
×
947
                }
948
                StelApp::immediateSave("viewing/flag_constellation_name", displayed);
×
UNCOV
949
                emit namesDisplayedChanged(displayed);
×
950
        }
951
}
×
952

UNCOV
953
bool ConstellationMgr::getFlagLabels(void) const
×
954
{
955
        return namesDisplayed;
×
956
}
957

958
void ConstellationMgr::setFlagIsolateSelected(const bool isolate)
×
959
{
UNCOV
960
        if (isolateSelected != isolate)
×
961
        {
UNCOV
962
                isolateSelected = isolate;
×
963

964
                // when turning off isolated selection mode, clear existing isolated selections.
965
                if (!isolateSelected)
×
966
                {
UNCOV
967
                        for (auto* constellation : constellations)
×
968
                        {
UNCOV
969
                                constellation->setFlagLines(getFlagLines());
×
970
                                constellation->setFlagLabels(getFlagLabels());
×
UNCOV
971
                                constellation->setFlagArt(getFlagArt());
×
972
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
973
                        }
974
                }
975
                StelApp::immediateSave("viewing/flag_constellation_isolate_selected", isolate);
×
UNCOV
976
                emit isolateSelectedChanged(isolate);
×
977
        }
UNCOV
978
}
×
979

980
bool ConstellationMgr::getFlagIsolateSelected(void) const
×
981
{
982
        return isolateSelected;
×
983
}
984

985
void ConstellationMgr::setFlagConstellationPick(const bool mode)
×
986
{
UNCOV
987
        StelApp::immediateSave("viewing/flag_constellation_pick", mode);
×
988
        flagConstellationPick = mode;
×
UNCOV
989
        emit flagConstellationPickChanged(mode);
×
990
}
×
991

992
bool ConstellationMgr::getFlagConstellationPick(void) const
×
993
{
UNCOV
994
        return flagConstellationPick;
×
995
}
996

997
StelObject* ConstellationMgr::getSelected(void) const
×
998
{
999
        return *selected.begin();  // TODO return all or just remove this method
×
1000
}
1001

1002
void ConstellationMgr::setSelected(const QString& abbreviation)
×
1003
{
1004
        Constellation * c = findFromAbbreviation(abbreviation);
×
UNCOV
1005
        if(c != nullptr) setSelectedConst(c);
×
UNCOV
1006
}
×
1007

UNCOV
1008
StelObjectP ConstellationMgr::setSelectedStar(const QString& abbreviation)
×
1009
{
UNCOV
1010
        Constellation * c = findFromAbbreviation(abbreviation);
×
UNCOV
1011
        if(c != nullptr)
×
1012
        {
UNCOV
1013
                setSelectedConst(c);
×
1014
                return c->getBrightestStarInConstellation();
×
1015
        }
1016
        return nullptr;
×
1017
}
1018

UNCOV
1019
void ConstellationMgr::setSelectedConst(Constellation * c)
×
1020
{
1021
        // update states for other constellations to fade them out
UNCOV
1022
        if (c != nullptr)
×
1023
        {
1024
                selected.push_back(c);
×
1025

1026
                if (isolateSelected)
×
1027
                {
UNCOV
1028
                        if (!getFlagConstellationPick())
×
1029
                        {
1030
                                // Propagate current settings to newly selected constellation
UNCOV
1031
                                c->setFlagLines(getFlagLines());
×
1032
                                c->setFlagLabels(getFlagLabels());
×
UNCOV
1033
                                c->setFlagArt(getFlagArt());
×
1034
                                c->setFlagBoundaries(getFlagBoundaries());
×
1035

1036
                                for (auto* constellation : constellations)
×
1037
                                {
1038
                                        bool match = false;
×
UNCOV
1039
                                        for (auto* selected_constellation : selected)
×
1040
                                        {
1041
                                                if (constellation == selected_constellation)
×
1042
                                                {
1043
                                                        match=true; // this is a selected constellation
×
1044
                                                        break;
×
1045
                                                }
1046
                                        }
1047

1048
                                        if(!match)
×
1049
                                        {
1050
                                                // Not selected constellation
1051
                                                constellation->setFlagLines(false);
×
UNCOV
1052
                                                constellation->setFlagLabels(false);
×
1053
                                                constellation->setFlagArt(false);
×
1054
                                                constellation->setFlagBoundaries(false);
×
1055
                                        }
1056
                                }
1057
                        }
1058
                        else
1059
                        {
UNCOV
1060
                                for (auto* constellation : constellations)
×
1061
                                {
1062
                                        constellation->setFlagLines(false);
×
1063
                                        constellation->setFlagLabels(false);
×
1064
                                        constellation->setFlagArt(false);
×
UNCOV
1065
                                        constellation->setFlagBoundaries(false);
×
1066
                                }
1067

1068
                                // Propagate current settings to newly selected constellation
UNCOV
1069
                                c->setFlagLines(getFlagLines());
×
1070
                                c->setFlagLabels(getFlagLabels());
×
UNCOV
1071
                                c->setFlagArt(getFlagArt());
×
1072
                                c->setFlagBoundaries(getFlagBoundaries());
×
1073
                        }
1074

1075
                        Constellation::singleSelected = true;  // For boundaries
×
1076
                }
1077
                else
UNCOV
1078
                        Constellation::singleSelected = false; // For boundaries
×
1079
        }
1080
        else
1081
        {
1082
                if (selected.empty()) return;
×
1083

1084
                // Otherwise apply standard flags to all constellations
1085
                for (auto* constellation : constellations)
×
1086
                {
UNCOV
1087
                        constellation->setFlagLines(getFlagLines());
×
1088
                        constellation->setFlagLabels(getFlagLabels());
×
UNCOV
1089
                        constellation->setFlagArt(getFlagArt());
×
UNCOV
1090
                        constellation->setFlagBoundaries(getFlagBoundaries());
×
1091
                }
1092

1093
                // And remove all selections
UNCOV
1094
                selected.clear();
×
1095
        }
1096
}
1097

1098
//! Remove a constellation from the selected constellation list
1099
void ConstellationMgr::unsetSelectedConst(Constellation * c)
×
1100
{
UNCOV
1101
        if (c != nullptr)
×
1102
        {
UNCOV
1103
                for (auto iter = selected.begin(); iter != selected.end();)
×
1104
                {
UNCOV
1105
                        if( (*iter)->getEnglishName() == c->getEnglishName() )
×
1106
                        {
UNCOV
1107
                                iter = selected.erase(iter);
×
1108
                        }
1109
                        else
1110
                        {
1111
                                ++iter;
×
1112
                        }
1113
                }
1114

1115
                // If no longer any selection, restore all flags on all constellations
UNCOV
1116
                if (selected.empty())
×
1117
                {
1118
                        // Otherwise apply standard flags to all constellations
UNCOV
1119
                        for (auto* constellation : constellations)
×
1120
                        {
1121
                                constellation->setFlagLines(getFlagLines());
×
UNCOV
1122
                                constellation->setFlagLabels(getFlagLabels());
×
UNCOV
1123
                                constellation->setFlagArt(getFlagArt());
×
UNCOV
1124
                                constellation->setFlagBoundaries(getFlagBoundaries());
×
1125
                        }
1126

UNCOV
1127
                        Constellation::singleSelected = false; // For boundaries
×
1128
                }
1129
                else if(isolateSelected)
×
1130
                {
1131
                        // No longer selected constellation
1132
                        c->setFlagLines(false);
×
1133
                        c->setFlagLabels(false);
×
1134
                        c->setFlagArt(false);
×
UNCOV
1135
                        c->setFlagBoundaries(false);
×
1136

1137
                        Constellation::singleSelected = true;  // For boundaries
×
1138
                }
1139
        }
UNCOV
1140
}
×
1141

1142
bool ConstellationMgr::loadBoundaries(const QJsonArray& boundaryData, const QString& boundariesEpoch)
×
1143
{
1144
        // delete existing boundaries if any exist
1145
        for (auto* segment : allBoundarySegments)
×
1146
        {
1147
                delete segment;
×
1148
        }
UNCOV
1149
        allBoundarySegments.clear();
×
1150

UNCOV
1151
        bool b1875 = false;
×
1152
        bool customEdgeEpoch = false;
×
UNCOV
1153
        Mat4d matCustomEdgeEpochToJ2000;
×
UNCOV
1154
        if (boundariesEpoch.toUpper() == "B1875")
×
1155
                b1875 = true;
×
UNCOV
1156
        else if (boundariesEpoch.toUpper() != "J2000")
×
1157
        {
UNCOV
1158
                qInfo() << "Custom epoch for boundaries:" << boundariesEpoch;
×
1159
                customEdgeEpoch = true;
×
1160
        }
1161
        if (customEdgeEpoch)
×
1162
        {
1163
                // Allow "Bxxxx.x", "Jxxxx.x", "JDjjjjjjjj.jjj" and pure doubles as JD
1164
                bool ok=false;
×
1165
                double boundariesEpochJD=StelUtils::J2000;
×
1166

UNCOV
1167
                if (boundariesEpoch.startsWith("JD", Qt::CaseInsensitive))
×
1168
                {
1169
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-2);
×
UNCOV
1170
                        boundariesEpochJD=boundariesEpochStrV.toDouble(&ok); // pureJD
×
1171
                }
×
UNCOV
1172
                else if (boundariesEpoch.startsWith("B", Qt::CaseInsensitive))
×
1173
                {
1174
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
UNCOV
1175
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
UNCOV
1176
                        if (ok)
×
1177
                        {
UNCOV
1178
                                boundariesEpochJD=StelUtils::getJDFromBesselianEpoch(boundariesEpochY);
×
1179
                        }
1180
                }
×
1181
                else if (boundariesEpoch.startsWith("J", Qt::CaseInsensitive))
×
1182
                {
UNCOV
1183
                        QString boundariesEpochStrV=boundariesEpoch.right(boundariesEpoch.length()-1);
×
1184
                        double boundariesEpochY=boundariesEpochStrV.toDouble(&ok);
×
1185
                        if (ok)
×
1186
                        {
UNCOV
1187
                                boundariesEpochJD=StelUtils::getJDFromJulianEpoch(boundariesEpochY);
×
1188
                        }
UNCOV
1189
                }
×
1190
                else
1191
                        boundariesEpochJD=boundariesEpoch.toDouble(&ok); // pureJD
×
UNCOV
1192
                if (ok)
×
1193
                {
1194
                        // Create custom precession matrix for transformation of edges to J2000.0
1195
                        double epsEpoch, chiEpoch, omegaEpoch, psiEpoch;
UNCOV
1196
                        getPrecessionAnglesVondrak(boundariesEpochJD, &epsEpoch, &chiEpoch, &omegaEpoch, &psiEpoch);
×
1197
                        matCustomEdgeEpochToJ2000 = Mat4d::xrotation(84381.406*1./3600.*M_PI/180.) * Mat4d::zrotation(-psiEpoch) * Mat4d::xrotation(-omegaEpoch) * Mat4d::zrotation(chiEpoch);
×
1198
                }
1199
                else
1200
                {
1201
                        qWarning() << "SkyCultureMgr: Cannot parse edges_epoch =" << boundariesEpoch << ". Falling back to J2000.0";
×
1202
                        customEdgeEpoch = false;
×
1203
                }
1204
        }
UNCOV
1205
        const StelCore& core = *StelApp::getInstance().getCore();
×
1206
        qInfo().noquote() << "Loading constellation boundary data ... ";
×
1207

UNCOV
1208
        for (int n = 0; n < boundaryData.size(); ++n)
×
1209
        {
UNCOV
1210
                const QByteArray ba = boundaryData[n].toString().toLatin1();
×
1211
                const char *cstr = ba.data();
×
1212
                char edgeType, edgeDir;
1213
                char dec1_sign, dec2_sign;
1214
                int ra1_h, ra1_m, ra1_s, dec1_d, dec1_m, dec1_s;
1215
                int ra2_h, ra2_m, ra2_s, dec2_d, dec2_m, dec2_s;
1216
                char constellationNames[2][8];
UNCOV
1217
                if (sscanf(cstr,
×
1218
                           "%*s %c%c "
1219
                           "%d:%d:%d %c%d:%d:%d "
1220
                           "%d:%d:%d %c%d:%d:%d "
1221
                           "%7s %7s",
1222
                           &edgeType, &edgeDir,
1223
                           &ra1_h, &ra1_m, &ra1_s,
1224
                           &dec1_sign, &dec1_d, &dec1_m, &dec1_s,
1225
                           &ra2_h, &ra2_m, &ra2_s,
1226
                           &dec2_sign, &dec2_d, &dec2_m, &dec2_s,
UNCOV
1227
                           constellationNames[0], constellationNames[1]) != 18)
×
1228
                {
UNCOV
1229
                        qWarning().nospace() << "Failed to parse skyculture boundary line: \"" << cstr << "\"";
×
UNCOV
1230
                        continue;
×
1231
                }
1232

UNCOV
1233
                constexpr double timeSecToRadians = M_PI / (12 * 3600);
×
UNCOV
1234
                double RA1 = (60. * (60. * ra1_h + ra1_m) + ra1_s) * timeSecToRadians;
×
UNCOV
1235
                double RA2 = (60. * (60. * ra2_h + ra2_m) + ra2_s) * timeSecToRadians;
×
1236
                constexpr double angleSecToRad = M_PI / (180 * 3600);
×
UNCOV
1237
                double DE1 = (60. * (60. * dec1_d + dec1_m) + dec1_s) * (dec1_sign=='-' ? -1 : 1) * angleSecToRad;
×
1238
                double DE2 = (60. * (60. * dec2_d + dec2_m) + dec2_s) * (dec2_sign=='-' ? -1 : 1) * angleSecToRad;
×
1239

UNCOV
1240
                Vec3d xyz1;
×
UNCOV
1241
                StelUtils::spheToRect(RA1,DE1,xyz1);
×
1242
                Vec3d xyz2;
×
1243
                StelUtils::spheToRect(RA2,DE2,xyz2);
×
1244

1245
                const auto points = new std::vector<Vec3d>;
×
1246

1247
                const bool edgeTypeDirValid = ((edgeType == 'P' || edgeType == 'M') && (edgeDir == '+' || edgeDir == '-')) ||
×
UNCOV
1248
                                               (edgeType == '_' && edgeDir == '_');
×
1249
                if (!edgeTypeDirValid)
×
1250
                {
1251
                        qWarning().nospace() << "Bad edge type/direction: must be [PM_][-+_], but is " << QString("%1%2").arg(edgeType).arg(edgeDir)
×
1252
                                             << ". Will not interpolate the edges.";
×
UNCOV
1253
                        edgeType = '_';
×
1254
                        edgeDir = '_';
×
1255
                }
1256

1257
                double stepRA = 0, stepDE = 0;
×
1258
                int numPoints = 2;
×
UNCOV
1259
                switch (edgeType)
×
1260
                {
1261
                case 'P': // RA is variable
×
1262
                        if (RA2 > RA1 && edgeDir == '-')
×
1263
                                RA1 += 2*M_PI;
×
UNCOV
1264
                        if (RA2 < RA1 && edgeDir == '+')
×
UNCOV
1265
                                RA1 -= 2*M_PI;
×
1266
                        numPoints = 2 + std::ceil(std::abs(RA1 - RA2) / (M_PI / 64));
×
1267
                        stepRA = (RA2 - RA1) / (numPoints - 1);
×
1268
                        break;
×
UNCOV
1269
                case 'M': // DE is variable
×
1270
                        if (DE2 > DE1 && edgeDir == '-')
×
1271
                                DE1 += 2*M_PI;
×
1272
                        if (DE2 < DE1 && edgeDir == '+')
×
1273
                                DE1 -= 2*M_PI;
×
1274
                        numPoints = 2 + std::ceil(std::abs(DE1 - DE2) / (M_PI / 64));
×
1275
                        stepDE = (DE2 - DE1) / (numPoints - 1);
×
1276
                        break;
×
1277
                default: // No interpolation
×
1278
                        stepRA = RA2 - RA1;
×
1279
                        stepDE = DE2 - DE1;
×
1280
                        break;
×
1281
                }
1282

1283
                for (int n = 0; n < numPoints; ++n)
×
1284
                {
1285
                        const double RA = RA1 + n * stepRA;
×
1286
                        const double DE = DE1 + n * stepDE;
×
1287
                        Vec3d xyz;
×
1288
                        StelUtils::spheToRect(RA,DE,xyz);
×
1289
                        if (b1875) xyz = core.j1875ToJ2000(xyz);
×
UNCOV
1290
                        else if (customEdgeEpoch)
×
UNCOV
1291
                                xyz = matCustomEdgeEpochToJ2000*xyz;
×
1292
                        points->push_back(xyz);
×
1293
                }
1294

1295
                Constellation *cons = nullptr;
×
1296
                for (QString consName : constellationNames)
×
1297
                {
1298
                        // not used?
1299
                        if (consName == "SER1" || consName == "SER2") consName = "SER";
×
1300

1301
                        cons = findFromAbbreviation(consName);
×
UNCOV
1302
                        if (!cons)
×
UNCOV
1303
                                qWarning() << "ERROR while processing boundary file - cannot find constellation:" << consName;
×
1304
                        else
1305
                                cons->isolatedBoundarySegments.push_back(points);
×
UNCOV
1306
                }
×
1307

1308
                if (cons)
×
1309
                {
1310
                        cons->sharedBoundarySegments.push_back(points);
×
1311
                        // this list is for the de-allocation
1312
                        allBoundarySegments.push_back(points);
×
1313
                }
1314
                else
1315
                {
UNCOV
1316
                        delete points;
×
1317
                }
UNCOV
1318
        }
×
1319
        qInfo().noquote() << "Loaded" << boundaryData.size() << "constellation boundary segments";
×
1320

1321
        return true;
×
1322
}
1323

UNCOV
1324
void ConstellationMgr::drawBoundaries(StelPainter& sPainter, const Vec3d &obsVelocity) const
×
1325
{
UNCOV
1326
        const float scale = sPainter.getProjector()->getScreenScale();
×
1327

1328
        sPainter.setBlending(false);
×
UNCOV
1329
        if (constellationBoundariesThickness>1 || scale>1.f)
×
1330
                sPainter.setLineWidth(constellationBoundariesThickness*scale); // set line thickness
×
UNCOV
1331
        sPainter.setLineSmooth(true);
×
UNCOV
1332
        for (auto* constellation : constellations)
×
1333
        {
UNCOV
1334
                constellation->drawBoundaryOptim(sPainter, obsVelocity);
×
1335
        }
UNCOV
1336
        if (constellationBoundariesThickness>1 || scale>1.f)
×
1337
                sPainter.setLineWidth(1); // restore line thickness
×
1338
        sPainter.setLineSmooth(false);
×
1339
}
×
1340

1341
StelObjectP ConstellationMgr::searchByNameI18n(const QString& nameI18n) const
×
1342
{
1343
        QString nameI18nUpper = nameI18n.toUpper();
×
1344

1345
        for (auto* constellation : constellations)
×
1346
        {
1347
                if (constellation->culturalName.translatedI18n.toUpper() == nameI18nUpper) return constellation;
×
1348
                if (constellation->culturalName.pronounceI18n.toUpper()  == nameI18nUpper) return constellation;
×
1349
        }
1350
        return nullptr;
×
UNCOV
1351
}
×
1352

UNCOV
1353
StelObjectP ConstellationMgr::searchByName(const QString& name) const
×
1354
{
UNCOV
1355
        QString nameUpper = name.toUpper();
×
1356
        for (auto* constellation : constellations)
×
1357
        {
1358
                if (constellation->culturalName.translated.toUpper()      == nameUpper) return constellation;
×
1359
                if (constellation->culturalName.native.toUpper()          == nameUpper) return constellation;
×
1360
                if (constellation->culturalName.pronounce.toUpper()       == nameUpper) return constellation;
×
UNCOV
1361
                if (constellation->culturalName.transliteration.toUpper() == nameUpper) return constellation;
×
1362
                if (constellation->abbreviation.toUpper()                 == nameUpper) return constellation;
×
1363
        }
1364
        return nullptr;
×
1365
}
×
1366

1367
StelObjectP ConstellationMgr::searchByID(const QString &id) const
×
1368
{
UNCOV
1369
        for (auto* constellation : constellations)
×
1370
        {
1371
                if (constellation->getID() == id) return constellation;
×
1372
        }
1373
        return nullptr;
×
1374
}
1375

1376
QStringList ConstellationMgr::listAllObjects(bool inEnglish) const
×
1377
{
1378
        // TODO: This is needed for the search dialog.
UNCOV
1379
        QStringList result;
×
1380
        if (inEnglish)
×
1381
        {
1382
                for (auto* constellation : constellations)
×
1383
                {
UNCOV
1384
                        result << constellation->getEnglishName();
×
1385
                        result << constellation->culturalName.pronounce;
×
UNCOV
1386
                        result << constellation->culturalName.transliteration;
×
1387
                        result << constellation->culturalName.native;
×
1388
                }
1389
        }
1390
        else
1391
        {
1392
                for (auto* constellation : constellations)
×
1393
                {
UNCOV
1394
                        result << constellation->getNameI18n();
×
UNCOV
1395
                        result << constellation->culturalName.pronounceI18n;
×
UNCOV
1396
                        result << constellation->culturalName.native;
×
1397
                }
1398
        }
1399
        result.removeDuplicates();
×
UNCOV
1400
        result.removeOne(QString(""));
×
UNCOV
1401
        result.removeOne(QString());
×
1402
        return result;
×
1403
}
×
1404

1405
QString ConstellationMgr::getStelObjectType() const
×
1406
{
1407
        return Constellation::CONSTELLATION_TYPE;
×
1408
}
1409

1410
void ConstellationMgr::setSelected(const StelObject *s)
×
1411
{
1412
        if (!s)
×
1413
                setSelectedConst(nullptr);
×
1414
        else
1415
        {
1416
                if (StelApp::getInstance().getSkyCultureMgr().getCurrentSkyCultureBoundariesType()==StelSkyCulture::BoundariesType::IAU)
×
1417
                        setSelectedConst(isObjectIn(s));
×
1418
                else
1419
                        setSelectedConst(isStarIn(s));
×
1420
        }
1421
}
×
1422

1423
Constellation* ConstellationMgr::isObjectIn(const StelObject *s) const
×
1424
{
1425
        StelCore *core = StelApp::getInstance().getCore();
×
1426
        QString IAUConst = core->getIAUConstellation(s->getEquinoxEquatorialPos(core));
×
1427
        for (auto* constellation : constellations)
×
1428
        {
1429
                // Check if the object is in the constellation
1430
                if (constellation->getShortName().toUpper() == IAUConst.toUpper())
×
1431
                        return constellation;
×
1432
        }
1433
        return nullptr;
×
1434
}
×
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