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

Stellarium / stellarium / 11525764947

25 Oct 2024 09:38PM UTC coverage: 12.071%. Remained the same
11525764947

push

github

gzotti
More Cleanup

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

1 existing line in 1 file now uncovered.

14434 of 119576 relevant lines covered (12.07%)

18720.3 hits per line

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

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

23
#include "StelActionMgr.hpp"
24
#include "LandscapeMgr.hpp"
25
#include "Landscape.hpp"
26
#include "AtmospherePreetham.hpp"
27
#include "AtmosphereShowMySky.hpp"
28
#include "StelApp.hpp"
29
#include "SolarSystem.hpp"
30
#include "StelCore.hpp"
31
#include "StelLocaleMgr.hpp"
32
#include "StelModuleMgr.hpp"
33
#include "StelFileMgr.hpp"
34
#include "Planet.hpp"
35
#include "StelIniParser.hpp"
36
#include "StelSkyDrawer.hpp"
37
#include "StelPainter.hpp"
38
#include "StelPropertyMgr.hpp"
39
#include "StelUtils.hpp"
40

41
#if USE_BUNDLED_QTCOMPRESS
42
#include "external/qtcompress/qzipreader.h"
43
#else
44
#include <private/qzipreader_p.h>
45
#endif
46
#include <QTimer>
47
#include <QDebug>
48
#include <QSettings>
49
#include <QString>
50
#include <QDir>
51
#include <QDirIterator>
52
#include <QFile>
53
#include <QTemporaryFile>
54
#include <QMouseEvent>
55
#include <QPainter>
56
#include <QElapsedTimer>
57
#include <QOpenGLPaintDevice>
58

59
#include <stdexcept>
60

61
namespace
62
{
63
constexpr char ATMOSPHERE_MODEL_CONFIG_KEY[]="landscape/atmosphere_model";
64
constexpr char ATMOSPHERE_MODEL_PATH_CONFIG_KEY[]="landscape/atmosphere_model_path";
65
constexpr char ATMOSPHERE_ECLIPSE_SIM_QUALITY_CONFIG_KEY[]="landscape/atmosphere_eclipse_simulation_quality";
66
constexpr char ATMOSPHERE_MODEL_CONF_VAL_PREETHAM[]="preetham";
67
constexpr char ATMOSPHERE_MODEL_CONF_VAL_SHOWMYSKY[]="showmysky";
68
constexpr char ATMOSPHERE_MODEL_CONF_VAL_DEFAULT[]="preetham";
69
}
70

71
Cardinals::Cardinals()
×
72
        : color(0.6f,0.2f,0.2f)
×
73
{
74
        QSettings* conf = StelApp::getInstance().getSettings();
×
75
        Q_ASSERT(conf);
×
76
        screenFontSize = StelApp::getInstance().getScreenFontSize();
×
77
        propMgr = StelApp::getInstance().getStelPropertyManager();
×
78
        // Default font size is 24
79
        font4WCR.setPixelSize(conf->value("viewing/cardinal_font_size", screenFontSize+11).toInt());
×
80
        // Default font size is 18
81
        font8WCR.setPixelSize(conf->value("viewing/ordinal_font_size", screenFontSize+5).toInt());
×
82
        // Draw the principal wind points even smaller.
83
        font16WCR.setPixelSize(conf->value("viewing/16wcr_font_size", screenFontSize+2).toInt());
×
84
        font32WCR.setPixelSize(conf->value("viewing/32wcr_font_size", screenFontSize).toInt());
×
85

86
        // English names for cardinals
87
        labels = {
88
                {   dN,  "N" }, {   dS,  "S" }, {   dE,  "E" }, {   dW,  "W" },
×
89
                {  dNE, "NE" }, {  dSE, "SE" }, {  dSW, "SW" }, {  dNW, "NW" },
×
90
                { dNNE,"NNE" }, { dENE,"ENE" }, { dESE,"ESE" }, { dSSE,"SSE" },
×
91
                { dSSW,"SSW" }, { dWSW,"WSW" }, { dWNW,"WNW" }, { dNNW,"NNW" },
×
92
                { dNbE,"NbE" }, {dNEbN,"NEbN"}, {dNEbE,"NEbE"}, { dEbN,"EbN" },
×
93
                { dEbS,"EbS" }, {dSEbE,"SEbE"}, {dSEbS,"SEbS"}, { dSbE,"SbE" },
×
94
                { dSbW,"SbW" }, {dSWbS,"SWbS"}, {dSWbW,"SWbW"}, { dWbS,"WbS" },
×
95
                { dWbN,"WbN" }, {dNWbW,"NWbW"}, {dNWbN,"NWbN"}, { dNbW,"NbW" }
×
96
        };
×
97
}
×
98

99
Cardinals::~Cardinals()
×
100
{
101
}
×
102

103
const float Cardinals::sp8 = sin(M_PIf/8.f); // dimension for intercardinals
104
const float Cardinals::cp8 = cos(M_PIf/8.f); // dimension for intercardinals
105
const float Cardinals::s1p16 = sin(M_PIf/16.f);     // dimension for rose32
106
const float Cardinals::c1p16 = cos(M_PIf/16.f);     // dimension for rose32
107
const float Cardinals::s3p16 = sin(3.f*M_PIf/16.f); // dimension for rose32
108
const float Cardinals::c3p16 = cos(3.f*M_PIf/16.f); // dimension for rose32
109

110
const QMap<Cardinals::CompassDirection, Vec3f> Cardinals::rose4winds = {
111
        { Cardinals::dN, Vec3f(-1.f, 0.f, 0.f) }, { Cardinals::dS, Vec3f(1.f,  0.f, 0.f) },
112
        { Cardinals::dE, Vec3f( 0.f, 1.f, 0.f) }, { Cardinals::dW, Vec3f(0.f, -1.f, 0.f) }
113
};
114
const QMap<Cardinals::CompassDirection, Vec3f> Cardinals::rose8winds = {
115
        { Cardinals::dNE, Vec3f(-q8,  q8, 0.f) }, { Cardinals::dSE, Vec3f( q8,  q8, 0.f) },
116
        { Cardinals::dSW, Vec3f( q8, -q8, 0.f) }, { Cardinals::dNW, Vec3f(-q8, -q8, 0.f) }
117
};
118
const QMap<Cardinals::CompassDirection, Vec3f> Cardinals::rose16winds = {
119
        { Cardinals::dNNE, Vec3f(-cp8,  sp8, 0.f) }, { Cardinals::dENE, Vec3f(-sp8,  cp8, 0.f) },
120
        { Cardinals::dESE, Vec3f( sp8,  cp8, 0.f) }, { Cardinals::dSSE, Vec3f( cp8,  sp8, 0.f) },
121
        { Cardinals::dSSW, Vec3f( cp8, -sp8, 0.f) }, { Cardinals::dWSW, Vec3f( sp8, -cp8, 0.f) },
122
        { Cardinals::dWNW, Vec3f(-sp8, -cp8, 0.f) }, { Cardinals::dNNW, Vec3f(-cp8, -sp8, 0.f) }
123
};
124
const QMap<Cardinals::CompassDirection, Vec3f> Cardinals::rose32winds = {
125
        { Cardinals::dNbE,  Vec3f(-c1p16, s1p16, 0.f) }, { Cardinals::dNbW,  Vec3f(-c1p16, -s1p16, 0.f) },
126
        { Cardinals::dSbE,  Vec3f( c1p16, s1p16, 0.f) }, { Cardinals::dSbW,  Vec3f( c1p16, -s1p16, 0.f) },
127
        { Cardinals::dEbS,  Vec3f( s1p16, c1p16, 0.f) }, { Cardinals::dEbN,  Vec3f(-s1p16,  c1p16, 0.f) },
128
        { Cardinals::dWbN,  Vec3f(-s1p16,-c1p16, 0.f) }, { Cardinals::dWbS,  Vec3f( s1p16, -c1p16, 0.f) },
129
        { Cardinals::dNEbN, Vec3f(-c3p16, s3p16, 0.f) }, { Cardinals::dNWbN, Vec3f(-c3p16, -s3p16, 0.f) },
130
        { Cardinals::dSEbS, Vec3f( c3p16, s3p16, 0.f) }, { Cardinals::dSWbS, Vec3f( c3p16, -s3p16, 0.f) },
131
        { Cardinals::dSEbE, Vec3f( s3p16, c3p16, 0.f) }, { Cardinals::dNEbE, Vec3f(-s3p16,  c3p16, 0.f) },
132
        { Cardinals::dNWbW, Vec3f(-s3p16,-c3p16, 0.f) }, { Cardinals::dSWbW, Vec3f( s3p16, -c3p16, 0.f) }
133
};
134

135
void Cardinals::update(double deltaTime)
×
136
{
137
        fader4WCR.update(static_cast<int>(deltaTime*1000));
×
138
        fader8WCR.update(static_cast<int>(deltaTime*1000));
×
139
        fader16WCR.update(static_cast<int>(deltaTime*1000));
×
140
        fader32WCR.update(static_cast<int>(deltaTime*1000));
×
141
}
×
142

143
void Cardinals::setFadeDuration(float duration)
×
144
{
145
        fader4WCR.setDuration(static_cast<int>(duration*1000.f));
×
146
        fader8WCR.setDuration(static_cast<int>(duration*1000.f));
×
147
        fader16WCR.setDuration(static_cast<int>(duration*1000.f));
×
148
        fader32WCR.setDuration(static_cast<int>(duration*1000.f));
×
149
}
×
150

151
// Draw the cardinals points : N S E W and the subcardinal and sub-subcardinal.
152
// Handles special cases at poles
153
void Cardinals::draw(const StelCore* core, double latitude) const
×
154
{
155
        // fun polar special cases: no cardinals!
156
        if ((fabs(latitude - 90.0) < 1e-10) || (fabs(latitude + 90.0) < 1e-10))
×
157
                return;
×
158

159
        if (fader4WCR.getInterstate()>0.f)
×
160
        {
161
                const StelProjectorP prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
162
                const float ppx = static_cast<float>(core->getCurrentStelProjectorParams().devicePixelsPerPixel);
×
163
                StelPainter sPainter(prj);
×
164
                sPainter.setFont(font4WCR);
×
165
                float sshift=0.f, bshift=0.f, cshift=0.f, dshift=0.f, vshift=1.f;
×
166
                bool flagMask = (core->getProjection(StelCore::FrameJ2000)->getMaskType() != StelProjector::MaskDisk);
×
167
                if (propMgr->getProperty("SpecialMarkersMgr.compassMarksDisplayed")->getValue().toBool())
×
168
                        vshift = static_cast<float>(screenFontSize + 12)*ppx;
×
169

170
                Vec3f xy;
×
171
                sPainter.setColor(color, fader4WCR.getInterstate());
×
172
                sPainter.setBlending(true);
×
173
                QMapIterator<Cardinals::CompassDirection, Vec3f> it4w(rose4winds);
×
174
                while(it4w.hasNext())
×
175
                {
176
                        it4w.next();
×
177
                        QString directionLabel = labels.value(it4w.key(), "");
×
178

179
                        if (flagMask)
×
180
                                sshift = ppx*static_cast<float>(sPainter.getFontMetrics().boundingRect(directionLabel).width())*0.5f;
×
181

182
                        if (prj->project(it4w.value(), xy))
×
183
                        {
184
                                Vec3f up(it4w.value()[0], it4w.value()[1], 1.f*M_PI_180f);
×
185
                                Vec3f upPrj;
×
186
                                prj->project(up, upPrj);
×
187
                                float dx=upPrj[0]-xy[0];
×
188
                                float dy=upPrj[1]-xy[1];
×
189
                                float textAngle=atan2(dx, dy);
×
190
                                sPainter.drawText(xy[0], xy[1], directionLabel, -textAngle*M_180_PIf, -sshift, vshift, true);
×
191
                        }
192
                }
×
193

194
                if (fader8WCR.getInterstate()>0.f)
×
195
                {
196
                        float minFader = qMin(fader4WCR.getInterstate(), fader8WCR.getInterstate());
×
197
                        sPainter.setColor(color, minFader);
×
198
                        sPainter.setFont(font8WCR);
×
199

200
                        QMapIterator<Cardinals::CompassDirection, Vec3f> it8w(rose8winds);
×
201
                        while(it8w.hasNext())
×
202
                        {
203
                                it8w.next();
×
204
                                QString directionLabel = labels.value(it8w.key(), "");
×
205

206
                                if (flagMask)
×
207
                                        bshift = ppx*static_cast<float>(sPainter.getFontMetrics().boundingRect(directionLabel).width())*0.5f;
×
208

209
                                if (prj->project(it8w.value(), xy))
×
210
                                {
211
                                        Vec3f up(it8w.value()[0], it8w.value()[1], 1.f*M_PI_180f);
×
212
                                        Vec3f upPrj;
×
213
                                        prj->project(up, upPrj);
×
214
                                        float dx=upPrj[0]-xy[0];
×
215
                                        float dy=upPrj[1]-xy[1];
×
216
                                        float textAngle=atan2(dx, dy);
×
217
                                        sPainter.drawText(xy[0], xy[1], directionLabel, -textAngle*M_180_PIf, -bshift, vshift, true);
×
218
                                }
219
                        }
×
220

221
                        if (fader16WCR.getInterstate()>0.f)
×
222
                        {
223
                                sPainter.setColor(color, qMin(minFader, fader16WCR.getInterstate()));
×
224
                                sPainter.setFont(font16WCR);
×
225

226
                                QMapIterator<Cardinals::CompassDirection, Vec3f> it16w(rose16winds);
×
227
                                while(it16w.hasNext())
×
228
                                {
229
                                        it16w.next();
×
230
                                        QString directionLabel = labels.value(it16w.key(), "");
×
231

232
                                        if (flagMask)
×
233
                                                cshift = ppx*static_cast<float>(sPainter.getFontMetrics().boundingRect(directionLabel).width())*0.5f;
×
234

235
                                        if (prj->project(it16w.value(), xy))
×
236
                                        {
237
                                                Vec3f up(it16w.value()[0], it16w.value()[1], 1.f*M_PI_180f);
×
238
                                                Vec3f upPrj;
×
239
                                                prj->project(up, upPrj);
×
240
                                                float dx=upPrj[0]-xy[0];
×
241
                                                float dy=upPrj[1]-xy[1];
×
242
                                                float textAngle=atan2(dx, dy);
×
243
                                                sPainter.drawText(xy[0], xy[1], directionLabel, -textAngle*M_180_PIf, -cshift, vshift, true);
×
244
                                        }
245
                                }
×
246

247
                                if (fader32WCR.getInterstate()>0.f)
×
248
                                {
249
                                        sPainter.setColor(color, qMin(minFader, fader32WCR.getInterstate()));
×
250
                                        sPainter.setFont(font32WCR);
×
251

252
                                        QMapIterator<Cardinals::CompassDirection, Vec3f> it32w(rose32winds);
×
253
                                        while(it32w.hasNext())
×
254
                                        {
255
                                                it32w.next();
×
256
                                                QString directionLabel = labels.value(it32w.key(), "");
×
257

258
                                                if (flagMask)
×
259
                                                        dshift = ppx*static_cast<float>(sPainter.getFontMetrics().boundingRect(directionLabel).width())*0.5f;
×
260

261
                                                if (prj->project(it32w.value(), xy))
×
262
                                                {
263
                                                        Vec3f up(it32w.value()[0], it32w.value()[1], 1.f*M_PI_180f);
×
264
                                                        Vec3f upPrj;
×
265
                                                        prj->project(up, upPrj);
×
266
                                                        float dx=upPrj[0]-xy[0];
×
267
                                                        float dy=upPrj[1]-xy[1];
×
268
                                                        float textAngle=atan2(dx, dy);
×
269
                                                        sPainter.drawText(xy[0], xy[1], directionLabel, -textAngle*M_180_PIf, -dshift, vshift, true);
×
270
                                                }
271
                                        }
×
272
                                }
×
273
                        }
×
274
                }
×
275
        }
×
276
}
277

278
// Translate cardinal labels with gettext to current sky language and update font for the language
279
void Cardinals::updateI18n()
×
280
{
281
        labels = {
282
                // TRANSLATORS: North
283
                { dN,        qc_("N",   "compass direction") },
×
284
                // TRANSLATORS: South
285
                { dS,        qc_("S",   "compass direction") },
×
286
                // TRANSLATORS: East
287
                { dE,        qc_("E",   "compass direction") },
×
288
                // TRANSLATORS: West
289
                { dW,        qc_("W",   "compass direction") },
×
290
                // TRANSLATORS: Northeast
291
                { dNE,        qc_("NE",  "compass direction") },
×
292
                // TRANSLATORS: Southeast
293
                { dSE,        qc_("SE",  "compass direction") },
×
294
                // TRANSLATORS: Southwest
295
                { dSW,        qc_("SW",  "compass direction") },
×
296
                // TRANSLATORS: Northwest
297
                { dNW,        qc_("NW",  "compass direction") },
×
298
                // TRANSLATORS: North-northeast
299
                { dNNE,        qc_("NNE", "compass direction") },
×
300
                // TRANSLATORS: East-northeast
301
                { dENE,        qc_("ENE", "compass direction") },
×
302
                // TRANSLATORS: East-southeast
303
                { dESE,        qc_("ESE", "compass direction") },
×
304
                // TRANSLATORS: South-southeast
305
                { dSSE,        qc_("SSE", "compass direction") },
×
306
                // TRANSLATORS: South-southwest
307
                { dSSW,        qc_("SSW", "compass direction") },
×
308
                // TRANSLATORS: West-southwest
309
                { dWSW,        qc_("WSW", "compass direction") },
×
310
                // TRANSLATORS: West-northwest
311
                { dWNW, qc_("WNW", "compass direction") },
×
312
                // TRANSLATORS: North-northwest
313
                { dNNW,        qc_("NNW", "compass direction") },
×
314
                // TRANSLATORS: North by east
315
                { dNbE, qc_("NbE", "compass direction") },
×
316
                // TRANSLATORS: Northeast by north
317
                {dNEbN, qc_("NEbN","compass direction") },
×
318
                // TRANSLATORS: Northeast by east
319
                {dNEbE, qc_("NEbE","compass direction") },
×
320
                // TRANSLATORS: East by north
321
                { dEbN, qc_("EbN", "compass direction") },
×
322
                // TRANSLATORS: East by south
323
                { dEbS, qc_("EbS", "compass direction") },
×
324
                // TRANSLATORS: Southeast by east
325
                {dSEbE, qc_("SEbE","compass direction") },
×
326
                // TRANSLATORS: Southeast by south
327
                {dSEbS, qc_("SEbS","compass direction") },
×
328
                // TRANSLATORS: South by east
329
                { dSbE, qc_("SbE", "compass direction") },
×
330
                // TRANSLATORS: South by west
331
                { dSbW, qc_("SbW", "compass direction") },
×
332
                // TRANSLATORS: Southwest by south
333
                {dSWbS, qc_("SWbS","compass direction") },
×
334
                // TRANSLATORS: Southwest by west
335
                {dSWbW, qc_("SWbW","compass direction") },
×
336
                // TRANSLATORS: West by south
337
                { dWbS, qc_("WbS", "compass direction") },
×
338
                // TRANSLATORS: West by north
339
                { dWbN, qc_("WbN", "compass direction") },
×
340
                // TRANSLATORS: Northwest by west
341
                {dNWbW, qc_("NWbW","compass direction") },
×
342
                // TRANSLATORS: Northwest by north
343
                {dNWbN, qc_("NWbN","compass direction") },
×
344
                // TRANSLATORS: North by west
345
                { dNbW, qc_("NbW", "compass direction") }
×
346
        };
×
347
}
×
348

349
LandscapeMgr::LandscapeMgr()
×
350
        : StelModule()
351
        , atmosphere(Q_NULLPTR)
×
352
        , cardinalPoints(Q_NULLPTR)
×
353
        , landscape(Q_NULLPTR)
×
354
        , oldLandscape(Q_NULLPTR)
×
355
        , messageTimer(new QTimer(this))
×
356
        , flagLandscapeSetsLocation(false)
×
357
        , flagLandscapeAutoSelection(false)
×
358
        , flagLightPollutionFromDatabase(false)
×
359
        , atmosphereNoScatter(false)
×
360
        , flagPolyLineDisplayedOnly(false)
×
361
        , flagLandscapeUseMinimalBrightness(false)
×
362
        , defaultMinimalBrightness(0.01)
×
363
        , flagLandscapeSetsMinimalBrightness(false)
×
364
        , flagEnvironmentAutoEnabling(false)
×
365
        , flagLandscapeUseTransparency(false)
×
366
        , landscapeTransparency(0.)
×
367
        , landscapeTint(1.f, 1.f, 1.f)
×
368
{
369
        setObjectName("LandscapeMgr"); // should be done by StelModule's constructor.
×
370

371
        //Note: The first entry in the list is used as the default 'default landscape' in removeLandscape().
372
        packagedLandscapeIDs = (QStringList() << "guereins");
×
373
        QDirIterator directories(StelFileMgr::getInstallationDir()+"/landscapes/", QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
×
374
        while(directories.hasNext())
×
375
        {
376
                directories.next();
×
377
                packagedLandscapeIDs << directories.fileName();
×
378
        }
379
        packagedLandscapeIDs.removeDuplicates();
×
380
        landscapeCache.clear();
×
381

382
        messageTimer->setInterval(5000);
×
383
        messageTimer->setSingleShot(true);
×
384
        connect(messageTimer, &QTimer::timeout, this, &LandscapeMgr::clearMessage);
×
385
}
×
386

387
LandscapeMgr::~LandscapeMgr()
×
388
{
389
        delete cardinalPoints;
×
390
        if (oldLandscape)
×
391
        {
392
                delete oldLandscape;
×
393
                oldLandscape=Q_NULLPTR;
×
394
        }
395
        delete landscape;
×
396
        landscape = Q_NULLPTR;
×
397
        qDebug() << "LandscapeMgr: Clearing cache of" << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
×
398
        landscapeCache.clear(); // deletes all objects within.
×
399
}
×
400

401
/*************************************************************************
402
 Reimplementation of the getCallOrder method
403
*************************************************************************/
404
double LandscapeMgr::getCallOrder(StelModuleActionName actionName) const
×
405
{
406
        if (actionName==StelModule::ActionDraw)
×
407
                return StelApp::getInstance().getModuleMgr().getModule("SporadicMeteorMgr")->getCallOrder(actionName)+20;
×
408
        if (actionName==StelModule::ActionUpdate)
×
409
                return StelApp::getInstance().getModuleMgr().getModule("SolarSystem")->getCallOrder(actionName)+10;
×
410
        // GZ The next 2 lines are only required to test landscape transparency. They should be commented away for releases.
411
        if (actionName==StelModule::ActionHandleMouseClicks)
×
412
                return StelApp::getInstance().getModuleMgr().getModule("StelMovementMgr")->getCallOrder(actionName)-1;
×
413
        return 0.;
×
414
}
415

416
void LandscapeMgr::update(double deltaTime)
×
417
{
418
        if(needToRecreateAtmosphere && !loadingAtmosphere)
×
419
                createAtmosphere();
×
420

421
        const auto core = StelApp::getInstance().getCore();
×
422
        const auto drawer = core->getSkyDrawer();
×
423

424
        if(loadingAtmosphere && loadingAtmosphere->isLoading())
×
425
        {
426
                try
427
                {
428
                        // Use no more than 1/60th of a second for this batch of loading
429
                        QElapsedTimer timer;
×
430
                        timer.start();
×
431
                        Atmosphere::LoadingStatus status={1,1};
×
432
                        while(loadingAtmosphere->isLoading() && timer.elapsed() < 1000/60)
×
433
                                status = loadingAtmosphere->stepDataLoading();
×
434
                        if(loadingAtmosphere->isLoading())
×
435
                        {
436
                                setAtmosphereShowMySkyStoppedWithError(false);
×
437
                                const auto percentDone = std::lround(100.*status.stepsDone/status.stepsToDo);
×
438
                                setAtmosphereShowMySkyStatusText(QString("%1 %2% %3").arg(q_("Loading..."), QString::number(percentDone), qc_("done","percentage of done")));
×
439
                                qDebug() << "Finished this batch of loading at" << percentDone << "%, will continue in the next frame";
×
440
                        }
441
                        else
442
                        {
443
                                setAtmosphereShowMySkyStatusText(q_("Switching models..."));
×
444
                        }
445
                }
446
                catch(Atmosphere::InitFailure const& error)
×
447
                {
448
                        qWarning() << "ERROR: Failed to load atmosphere model data:" << error.what();
×
449
                        qWarning() << "WARNING: Falling back to the Preetham's model";
×
450
                        setAtmosphereShowMySkyStoppedWithError(true);
×
451
                        setAtmosphereShowMySkyStatusText(error.what());
×
452
                        loadingAtmosphere.reset();
×
453
                }
×
454
        }
455

456
        if(loadingAtmosphere && loadingAtmosphere->isReadyToRender())
×
457
        {
458
                bool loaded = false;
×
459
                if(drawer->getFlagHasAtmosphere())
×
460
                {
461
                        // Fade out current atmosphere, then fade in the new one
462
                        if(atmosphere->getFlagShow())
×
463
                        {
464
                                atmosphere->setFlagShow(false);
×
465
                        }
466
                        else if(atmosphere->getFadeIntensity() == 0)
×
467
                        {
468
                                loadingAtmosphere->setFlagShow(true);
×
469
                                loadingAtmosphere->setFadeDuration(atmosphere->getFadeDuration());
×
470
                                loadingAtmosphere->setLightPollutionLuminance(atmosphere->getLightPollutionLuminance());
×
471
                                loaded = true;
×
472
                        }
473
                }
474
                else
475
                {
476
                        loaded = true;
×
477
                }
478

479
                if(loaded)
×
480
                {
481
                        atmosphere = std::move(loadingAtmosphere);
×
482
#ifdef ENABLE_SHOWMYSKY
483
                        if(dynamic_cast<AtmosphereShowMySky*>(atmosphere.get()))
×
484
                                setAtmosphereShowMySkyStatusText(q_("Loaded successfully"));
×
485
#endif
486
                        emit atmosphereModelChanged(getAtmosphereModel());
×
487
                }
488
        }
489

490
        atmosphere->update(deltaTime);
×
491

492
        if (oldLandscape)
×
493
        {
494
                // This is only when transitioning to newly loaded landscape. We must draw the old one until the new one is faded in completely.
495
                oldLandscape->update(deltaTime);
×
496
                if (getIsLandscapeFullyVisible())
×
497
                {
498
                        oldLandscape->setFlagShow(false);
×
499

500
                        if (oldLandscape->getEffectiveLandFadeValue()< 0.01f)
×
501
                        {
502
                                // new logic: try to put old landscape to cache.
503
                                //qDebug() << "LandscapeMgr::update: moving oldLandscape " << oldLandscape->getId() << "to Cache. Cost:" << oldLandscape->getMemorySize()/(1024*1024)+1;
504
                                landscapeCache.insert(oldLandscape->getId(), oldLandscape, oldLandscape->getMemorySize()/(1024*1024)+1);
×
505
                                //qDebug() << "--> LandscapeMgr::update(): cache now contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
506
                                oldLandscape=Q_NULLPTR;
×
507
                        }
508
                }
509
        }
510
        landscape->update(deltaTime);
×
511
        cardinalPoints->update(deltaTime);
×
512
        Landscape::illumFader.update(static_cast<int>(deltaTime*1000));
×
513
        Landscape::labelFader.update(static_cast<int>(deltaTime*1000));
×
514

515
        // Compute the atmosphere color and intensity
516
        // Compute the sun position in local coordinate
517
        SolarSystem* ssystem = static_cast<SolarSystem*>(StelApp::getInstance().getModuleMgr().getModule("SolarSystem"));
×
518

519
        // Compute the moon position in local coordinate
520
        const auto sun   = ssystem->getSun();
×
521
        const auto moon  = ssystem->getMoon();
×
522
        const auto earth = ssystem->getEarth();
×
523
        const auto currentPlanet = core->getCurrentPlanet();
×
524
        const bool currentIsEarth = currentPlanet->getID() == earth->getID();
×
525
        // First parameter in next call is used for particularly earth-bound computations in Schaefer's sky brightness model. Difference DeltaT makes no difference here.
526
        // Temperature = 15°C, relative humidity = 40%
527
        try
528
        {
529
                atmosphere->computeColor(core, core->getJDE(), *currentPlanet, *sun,
×
530
                                                                 currentIsEarth ? moon.data() : nullptr, core->getCurrentLocation(),
×
531
                                                                 15.f, 40.f, static_cast<float>(drawer->getExtinctionCoefficient()), atmosphereNoScatter);
×
532
        }
533
        catch(Atmosphere::InitFailure const& error)
×
534
        {
535
                qWarning().noquote() << "ShowMySky atmosphere model crashed:" << error.what();
×
536
                qWarning() << "Loading Preetham model";
×
537
                showMessage(q_("ShowMySky atmosphere model crashed. Loading Preetham model as a fallback."));
×
538
                resetToFallbackAtmosphere();
×
539
        }
×
540

541
        core->getSkyDrawer()->reportLuminanceInFov(3.75f+atmosphere->getAverageLuminance()*3.5f, true);
×
542

543
        // NOTE: Simple workaround for brightness of landscape when observing from the Sun.
544
        if (currentPlanet->getID() == sun->getID())
×
545
        {
546
                landscape->setBrightness(1.0, 1.0);
×
547
                landscape->setTint(Vec3f(1.f));
×
548
                return;
×
549
        }
550

551
        // Compute the ground luminance based on every planets around
552
        // TBD: Reactivate and verify this code!? Source, reference?
553
//        float groundLuminance = 0;
554
//        const vector<Planet*>& allPlanets = ssystem->getAllPlanets();
555
//        for (auto i=allPlanets.begin();i!=allPlanets.end();++i)
556
//        {
557
//                Vec3d pos = (*i)->getAltAzPos(core);
558
//                pos.normalize();
559
//                if (pos[2] <= 0)
560
//                {
561
//                        // No need to take this body into the landscape illumination computation
562
//                        // because it is under the horizon
563
//                }
564
//                else
565
//                {
566
//                        // Compute the Illuminance E of the ground caused by the planet in lux = lumen/m^2
567
//                        float E = pow10(((*i)->get_mag(core)+13.988)/-2.5);
568
//                        //qDebug() << "mag=" << (*i)->get_mag(core) << " illum=" << E;
569
//                        // Luminance in cd/m^2
570
//                        groundLuminance += E/0.44*pos[2]*pos[2]; // 1m^2 from 1.5 m above the ground is 0.44 sr.
571
//                }
572
//        }
573
//        groundLuminance*=atmosphere->getFadeIntensity();
574
//        groundLuminance=atmosphere->getAverageLuminance()/50;
575
//        qDebug() << "Atmosphere lum=" << atmosphere->getAverageLuminance() << " ground lum=" <<  groundLuminance;
576
//        qDebug() << "Adapted Atmosphere lum=" << eye->adaptLuminance(atmosphere->getAverageLuminance()) << " Adapted ground lum=" << eye->adaptLuminance(groundLuminance);
577

578
        // compute global ground brightness in a simplistic way, directly in RGB
579

580
        double landscapeBrightness=0.0;
×
581
        if (getFlagLandscapeUseMinimalBrightness())
×
582
        {
583
                // Setting from landscape.ini has priority if enabled
584
                if (getFlagLandscapeSetsMinimalBrightness() && landscape->getLandscapeMinimalBrightness()>=0)
×
585
                        landscapeBrightness = landscape->getLandscapeMinimalBrightness();
×
586
                else
587
                        landscapeBrightness = getDefaultMinimalBrightness();
×
588
        }
589

590
        Vec3d sunPos = sun->getAltAzPosAuto(core);
×
591
        sunPos.normalize();
×
592
        Vec3d moonPos = moon->getAltAzPosAuto(core);
×
593
        moonPos.normalize();
×
594

595
        // With atmosphere on, we define the solar brightness contribution zero when the sun is 8 degrees below the horizon.
596
        // The multiplier of 1.5 just looks better, it somehow represents illumination by scattered sunlight.
597
        // Else, we should account for sun's diameter but else just apply Lambertian Cos-rule and check with landscape opacity.
598
        double sinSunAngle = 0.0;
×
599
        if(atmosphere->getFlagShow())
×
600
        {
601
                sinSunAngle=sin(qMin(M_PI_2, asin(sunPos[2])+8.*M_PI/180.));
×
602
                if(sinSunAngle > -0.1/1.5 )
×
603
                        landscapeBrightness +=  1.5*(sinSunAngle+0.1/1.5);
×
604
        }
605
        else
606
        {
607
                // In case we have exceptionally deep horizons ("Little Prince planet"), the sun will rise somehow over that line and demand light on the landscape.
608
                sinSunAngle=sin(qMin(M_PI_2, asin(qBound(-1.0, sunPos[2]-landscape->getSinMinAltitudeLimit(), 1.0) ) + (0.25 *M_PI_180)));
×
609
                if(sinSunAngle > 0.0)
×
610
                        landscapeBrightness +=  (1.0-static_cast<double>(landscape->getOpacity(sunPos)))*sinSunAngle;
×
611
        }
612

613
        // GZ: 2013-09-25 Take light pollution into account!
614
        const float nelm = StelCore::luminanceToNELM(drawer->getLightPollutionLuminance());
×
615
        float pollutionAddonBrightness=(15.5f-2*nelm)*0.025f; // 0..8, so we assume empirical linear brightening 0..0.02
×
616
        float lunarAddonBrightness=0.f;
×
617
        if (currentIsEarth && moonPos[2] > -0.1/1.5)
×
618
                lunarAddonBrightness = qMax(0.2f/-12.f*moon->getVMagnitudeWithExtinction(core),0.f)*static_cast<float>(moonPos[2]);
×
619

620
        landscapeBrightness += static_cast<double>(qMax(lunarAddonBrightness, pollutionAddonBrightness));
×
621

622
        // TODO make this more generic for non-atmosphere planets
623
        if(atmosphere->getFadeIntensity() > 0.99999f )
×
624
        {
625
                // If the atmosphere is on, a solar eclipse might darken the sky
626
                // otherwise we just use the sun position calculation above
627
                landscapeBrightness *= static_cast<double>(atmosphere->getRealDisplayIntensityFactor()+0.1f);
×
628
        }
629
        // TODO: should calculate dimming with solar eclipse even without atmosphere on
630

631
        // Brightness can't be over 1.f (see https://bugs.launchpad.net/stellarium/+bug/1115364)
632
        if (landscapeBrightness>0.95)
×
633
                landscapeBrightness = 0.95;
×
634

635
        // GZ's rules and intentions for lightscape brightness:
636
        // lightscapeBrightness >0 makes sense only for sun below horizon.
637
        // If atmosphere on, we mix it in with darkening twilight. If atmosphere off, we can switch on more apruptly.
638
        // Note however that lightscape rendering does not per se depend on atmosphere on/off.
639
        // This allows for illuminated windows or light panels on spaceships. If a landscape's lightscape
640
        // contains light smog of a city, it should also be shown if atmosphere is switched off.
641
        // (Configure another landscape without light smog to avoid, or just switch off lightscape.)
642
        double lightscapeBrightness=0.0;
×
643
        const double sinSunAlt = sunPos[2];
×
644
        if (atmosphere->getFlagShow())
×
645
        {
646
                // light pollution layer is mixed in at -3...-8 degrees.
647
                if (sinSunAlt<-0.14)
×
648
                        lightscapeBrightness=1.0;
×
649
                else if (sinSunAlt<-0.05)
×
650
                        lightscapeBrightness = 1.0-(sinSunAlt+0.14)/(-0.05+0.14);
×
651
        }
652
        else
653
        {
654
                // If we have no atmosphere, we can assume windows and panels on spaceships etc. are switched on whenever the sun does not shine, i.e. when sun is blocked by landscape.
655
                lightscapeBrightness= static_cast<double>(landscape->getOpacity(sunPos));
×
656
        }
657
        landscape->setBrightness(landscapeBrightness, lightscapeBrightness);
×
658

659
        // extra colorful sunrise/sunset management.
660
        landscape->setTint(landscapeTint);
×
661

662
        messageFader.update(static_cast<int>(deltaTime*1000));
×
663
}
×
664

665
void LandscapeMgr::draw(StelCore* core)
×
666
{
667
        // For observers we never draw anything of landscape, atmosphere, cardinals.
668
        if (core->getCurrentPlanet()->getPlanetType()==Planet::isObserver)
×
669
                return;
×
670

671
        StelSkyDrawer* drawer=core->getSkyDrawer();
×
672

673
        // Draw the atmosphere
674
        if (!getFlagAtmosphereNoScatter())
×
675
            atmosphere->draw(core);
×
676

677
        // GZ 2016-01: When we draw the atmosphere with a low sun, it is possible that the glaring red ball is overpainted and thus invisible.
678
        // Attempt to draw the sun only here while not having drawn it by SolarSystem:
679
        //if (atmosphere->getFlagShow())
680
        if (drawer->getFlagDrawSunAfterAtmosphere())
×
681
        {
682
                static SolarSystem* ssys = GETSTELMODULE(SolarSystem);
×
683
                PlanetP sun=ssys->getSun();
×
684
                QFont font;
×
685
                font.setPixelSize(StelApp::getInstance().getScreenFontSize());
×
686
                sun->draw(core, 0, font, 1.0);
×
687
        }
×
688

689
        // Draw the landscape
690
        Landscape::setTransparency( getFlagLandscapeUseTransparency() ? landscapeTransparency : 0.0);
×
691

692
        if (oldLandscape)
×
693
        {
694
                oldLandscape->draw(core, flagPolyLineDisplayedOnly);
×
695
        }
696
        landscape->draw(core, flagPolyLineDisplayedOnly);
×
697

698
        // Draw the cardinal points
699
        cardinalPoints->draw(core, static_cast<double>(StelApp::getInstance().getCore()->getCurrentLocation().getLatitude()));
×
700

701
        if(messageFader.getInterstate())
×
702
        {
703
                const StelProjectorP prj = core->getProjection(StelCore::FrameEquinoxEqu);
×
704
                StelPainter painter(prj);
×
705
                QFont font;
×
706
                font.setPixelSize(16);
×
707
                painter.setFont(font);
×
708
                painter.setColor(1, 0, 0, messageFader.getInterstate());
×
709
                painter.drawText(83, 70, messageToShow);
×
710
        }
×
711
}
712

713
// Some element in drawing order behind LandscapeMgr can call this at the end of its own draw() to overdraw with the polygon line and gazetteer.
714
void LandscapeMgr::drawPolylineOnly(StelCore* core)
×
715
{
716
        // For observers we never draw anything of landscape, atmosphere, cardinals.
717
        if (core->getCurrentPlanet()->getPlanetType()==Planet::isObserver)
×
718
                return;
×
719

720
        // Draw the landscape
721
        if (oldLandscape && oldLandscape->hasLandscapePolygon())
×
722
                oldLandscape->draw(core, true);
×
723
        if (landscape->hasLandscapePolygon())
×
724
                landscape->draw(core, true);
×
725

726
        // Draw the cardinal points
727
        cardinalPoints->draw(core, static_cast<double>(StelApp::getInstance().getCore()->getCurrentLocation().getLatitude()));
×
728
}
729

730
void LandscapeMgr::createAtmosphere()
×
731
{
732
        const auto modelName=getAtmosphereModel();
×
733
        const auto modelConfig=modelName.toLower();
×
734
        bool needResetConfig=false;
×
735
        if(modelConfig==ATMOSPHERE_MODEL_CONF_VAL_PREETHAM)
×
736
        {
737
                loadingAtmosphere.reset(new AtmospherePreetham(skylight));
×
738
        }
739
#ifdef ENABLE_SHOWMYSKY
740
        else if(modelConfig==ATMOSPHERE_MODEL_CONF_VAL_SHOWMYSKY)
×
741
        {
742
                try
743
                {
744
                        // Clear status so that if a repeated error happens, we do emit a signal that will update the GUI.
745
                        setAtmosphereShowMySkyStatusText("");
×
746
                        setAtmosphereShowMySkyStoppedWithError(false);
×
747

748
                        const auto core = StelApp::getInstance().getCore();
×
749
                        loadingAtmosphere.reset(new AtmosphereShowMySky(core->getCurrentLocation().altitude));
×
750
                        if(!atmosphere)
×
751
                        {
752
                                // We're just loading the first atmosphere in the run of Stellarium. Initialize it synchronously.
753
                                while(loadingAtmosphere->isLoading())
×
754
                                        loadingAtmosphere->stepDataLoading();
×
755

756
                                setAtmosphereShowMySkyStoppedWithError(false);
×
757
                                setAtmosphereShowMySkyStatusText(q_("Loaded successfully"));
×
758
                        }
759
                        else
760
                        {
761
                                setAtmosphereShowMySkyStoppedWithError(false);
×
762
                                setAtmosphereShowMySkyStatusText(QString("%1 0% %2").arg(q_("Loading..."), qc_("done","percentage of done")));
×
763
                        }
764
                }
765
                catch(Atmosphere::InitFailure const& error)
×
766
                {
767
                        qWarning() << "ERROR: Failed to initialize ShowMySky atmosphere model:" << error.what();
×
768
                        qWarning() << "WARNING: Falling back to the Preetham's model";
×
769
                        loadingAtmosphere.reset(new AtmospherePreetham(skylight));
×
770
                        needResetConfig=true;
×
771

772
                        setAtmosphereShowMySkyStoppedWithError(true);
×
773
                        setAtmosphereShowMySkyStatusText(error.what());
×
774
                }
×
775
        }
776
#endif
777
        else
778
        {
779
                qWarning() << "Unsupported atmosphere model" << modelName;
×
780
                loadingAtmosphere.reset(new AtmospherePreetham(skylight));
×
781
                needResetConfig=true;
×
782
        }
783
        if(!atmosphere)
×
784
        {
785
                // We're just loading the first atmosphere in the run of Stellarium. The atmosphere is fully loaded by this point.
786
                atmosphere = std::move(loadingAtmosphere);
×
787

788
                const auto conf=StelApp::getInstance().getSettings();
×
789
                setFlagAtmosphere(conf->value("landscape/flag_atmosphere", true).toBool());
×
790
                setAtmosphereFadeDuration(conf->value("landscape/atmosphere_fade_duration",0.5).toFloat());
×
791

792
                const auto drawer = StelApp::getInstance().getCore()->getSkyDrawer();
×
793
                setAtmosphereLightPollutionLuminance(drawer->getLightPollutionLuminance());
×
794
        }
795

796
        if(needResetConfig)
×
797
        {
798
                // We've failed to apply the setting, so reset to the fallback value
799
                const auto conf=StelApp::getInstance().getSettings();
×
800
                conf->setValue(ATMOSPHERE_MODEL_CONFIG_KEY, ATMOSPHERE_MODEL_CONF_VAL_PREETHAM);
×
801
        }
802

803
        needToRecreateAtmosphere=false;
×
804
}
×
805

806
void LandscapeMgr::resetToFallbackAtmosphere()
×
807
{
808
        StelApp::getInstance().getSettings()->setValue(ATMOSPHERE_MODEL_CONFIG_KEY, ATMOSPHERE_MODEL_CONF_VAL_PREETHAM);
×
809
        atmosphere.reset();
×
810
        createAtmosphere();
×
811
}
×
812

813
void LandscapeMgr::init()
×
814
{
815
        QSettings* conf = StelApp::getInstance().getSettings();
×
816
        Q_ASSERT(conf);
×
817
        StelApp *app = &StelApp::getInstance();
×
818
        Q_ASSERT(app);
×
819

820
        landscapeCache.setMaxCost(conf->value("landscape/cache_size_mb", 100).toInt());
×
821
        qDebug() << "LandscapeMgr: initialized Cache for" << landscapeCache.maxCost() << "MB.";
×
822

823
        // SET SIMPLE PROPERTIES FIRST, before loading the landscape (Loading may already make use of them! GH#1237)
824
        setFlagLandscapeSetsLocation(conf->value("landscape/flag_landscape_sets_location",false).toBool());
×
825
        setFlagLandscapeAutoSelection(conf->value("viewing/flag_landscape_autoselection", false).toBool());
×
826
        setFlagEnvironmentAutoEnable(conf->value("viewing/flag_environment_auto_enable",true).toBool());
×
827
        // Set minimal brightness for landscape. This feature has been added for folks which say "landscape is super dark, please add light". --AW
828
        setDefaultMinimalBrightness(conf->value("landscape/minimal_brightness", 0.01).toDouble());
×
829
        setFlagLandscapeUseMinimalBrightness(conf->value("landscape/flag_minimal_brightness", false).toBool());
×
830
        setFlagLandscapeSetsMinimalBrightness(conf->value("landscape/flag_landscape_sets_minimal_brightness",false).toBool());
×
831

832
        const auto var = conf->value(ATMOSPHERE_MODEL_PATH_CONFIG_KEY);
×
833
        if(!var.isValid())
×
834
                conf->setValue(ATMOSPHERE_MODEL_PATH_CONFIG_KEY, getDefaultAtmosphereModelPath());
×
835

836
        createAtmosphere();
×
837
        // Put the atmosphere's Skylight under the StelProperty system (simpler and more consistent GUI)
838
        StelApp::getInstance().getStelPropertyManager()->registerObject(&skylight);
×
839

840
        defaultLandscapeID = conf->value("init_location/landscape_name").toString();
×
841

842
        // We must make sure to allow auto location or command-line location even if landscape usually should set location.
843
        StelCore *core = StelApp::getInstance().getCore();
×
844
        const bool setLocationFromIPorCLI=((conf->value("init_location/location", "auto").toString() == "auto") || (core->getCurrentLocation().state=="CLI"));
×
845
        const bool shouldThenSetLocation=getFlagLandscapeSetsLocation();
×
846
        if (setLocationFromIPorCLI) setFlagLandscapeSetsLocation(false);
×
847
        setCurrentLandscapeID(defaultLandscapeID);
×
848
        setFlagLandscapeSetsLocation(shouldThenSetLocation);
×
849
        setFlagUseLightPollutionFromDatabase(conf->value("viewing/flag_light_pollution_database", false).toBool());
×
850
        setFlagLandscape(conf->value("landscape/flag_landscape", conf->value("landscape/flag_ground", true).toBool()).toBool());
×
851
        setFlagFog(conf->value("landscape/flag_fog",true).toBool());
×
852
        setFlagIllumination(conf->value("landscape/flag_enable_illumination_layer", true).toBool());
×
853
        setFlagLabels(conf->value("landscape/flag_enable_labels", true).toBool());
×
854
        setFlagPolyLineOnlyDisplayed(conf->value("landscape/flag_polyline_only", false).toBool());
×
855
        setPolyLineThickness(conf->value("landscape/polyline_thickness", 1).toInt());
×
856
        setPolyLineColor(Vec3f(conf->value("landscape/polyline_color", "1.0,0.0,0.0").toString()));
×
857
        setLabelFontSize(conf->value("landscape/label_font_size", 18).toInt());
×
858
        setLabelColor(Vec3f(conf->value("landscape/label_color", "0.2,0.8,0.2").toString()));
×
859
        setLabelAngle(conf->value("landscape/label_angle", 45).toInt());
×
860

861
        setFlagLandscapeUseTransparency(conf->value("landscape/flag_transparency", false).toBool());
×
862
        setLandscapeTransparency(conf->value("landscape/transparency", 0.5).toDouble());
×
863

864
        cardinalPoints = new Cardinals();
×
865
        cardinalPoints->setFlagShow4WCRLabels(conf->value("viewing/flag_cardinal_points", true).toBool());
×
866
        cardinalPoints->setFlagShow8WCRLabels(conf->value("viewing/flag_ordinal_points", true).toBool());
×
867
        cardinalPoints->setFlagShow16WCRLabels(conf->value("viewing/flag_16wcr_points", false).toBool());
×
868
        cardinalPoints->setFlagShow32WCRLabels(conf->value("viewing/flag_32wcr_points", false).toBool());
×
869
        // Load colors from config file
870
        QString defaultColor = conf->value("color/default_color").toString();
×
871
        setColorCardinalPoints(Vec3f(conf->value("color/cardinal_color", defaultColor).toString()));
×
872

873
        currentPlanetName = app->getCore()->getCurrentLocation().planetName;
×
874
        //Bortle scale is managed by SkyDrawer
875
        StelSkyDrawer* drawer = app->getCore()->getSkyDrawer();
×
876
        Q_ASSERT(drawer);
×
877
        setAtmosphereLightPollutionLuminance(drawer->getLightPollutionLuminance());
×
878
        connect(app->getCore(), SIGNAL(locationChanged(StelLocation)), this, SLOT(onLocationChanged(StelLocation)));
×
879
        connect(app->getCore(), SIGNAL(targetLocationChanged(const StelLocation&, const QString&)), this, SLOT(onTargetLocationChanged(const StelLocation&, const QString&)));
×
880
        connect(drawer, &StelSkyDrawer::lightPollutionLuminanceChanged, this, &LandscapeMgr::setAtmosphereLightPollutionLuminance);
×
881
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
882

883
        QString displayGroup = N_("Display Options");
×
884
        addAction("actionShow_Atmosphere", displayGroup, N_("Atmosphere"), "atmosphereDisplayed", "A");
×
885
        addAction("actionShow_Fog", displayGroup, N_("Fog"), "fogDisplayed", "F");
×
886
        addAction("actionShow_Cardinal_Points", displayGroup, N_("Cardinal points"), "cardinalPointsDisplayed", "Q");
×
887
        addAction("actionShow_Intercardinal_Points", displayGroup, N_("Ordinal (Intercardinal) points"), "ordinalPointsDisplayed");
×
888
        addAction("actionShow_Secondary_Intercardinal_Points", displayGroup, N_("Secondary Intercardinal points"), "ordinal16WRPointsDisplayed");
×
889
        addAction("actionShow_Tertiary_Intercardinal_Points", displayGroup, N_("Tertiary Intercardinal points"), "ordinal32WRPointsDisplayed");
×
890
        addAction("actionShow_Ground", displayGroup, N_("Ground"), "landscapeDisplayed", "G");
×
891
        addAction("actionShow_LandscapeIllumination", displayGroup, N_("Landscape illumination"), "illuminationDisplayed", "Shift+G");
×
892
        addAction("actionShow_LandscapeLabels", displayGroup, N_("Landscape labels"), "labelsDisplayed", "Ctrl+Shift+G");
×
893
        addAction("actionShow_LightPollutionFromDatabase", displayGroup, N_("Light pollution data from locations database"), "flagUseLightPollutionFromDatabase");
×
894
        // Details: https://github.com/Stellarium/stellarium/issues/171
895
        addAction("actionShow_LightPollutionIncrease", displayGroup, N_("Increase light pollution"), "increaseLightPollution()");
×
896
        addAction("actionShow_LightPollutionReduce", displayGroup, N_("Reduce light pollution"), "reduceLightPollution()");
×
897
        addAction("actionShow_LightPollutionCyclicChange", displayGroup, N_("Cyclic change in light pollution"), "cyclicChangeLightPollution()");
×
898
}
×
899

900
bool LandscapeMgr::setCurrentLandscapeID(const QString& id, const double changeLocationDuration)
×
901
{
902
        if (id.isEmpty())
×
903
                return false;
×
904

905
        //prevent unnecessary changes/file access
906
        if(id==currentLandscapeID)
×
907
                return false;
×
908

909
        if (!getAllLandscapeIDs().contains(id))
×
910
        {
911
                qDebug() << "LandscapeMgr::setCurrentLandscapeID: unknown landscape" << id << ", using 'zero'";
×
912
                return setCurrentLandscapeID("zero", changeLocationDuration);
×
913
        }
914

915
        Landscape* newLandscape;
916

917
        // There is a slight chance that we switch back to oldLandscape while oldLandscape is still fading away.
918
        // in this case it is not yet stored in cache, but obviously available. So we just swap places.
919
        if (oldLandscape && oldLandscape->getId()==id)
×
920
        {
921
                newLandscape=oldLandscape;
×
922
        }
923
        else
924
        {
925
                // We want to lookup the landscape ID (dir) from the name.
926
                newLandscape= landscapeCache.take(id);
×
927

928
                if (newLandscape)
×
929
                {
930
#ifndef NDEBUG
931
                        qDebug() << "LandscapeMgr::setCurrentLandscapeID():: taken " << id << "from cache...";
×
932
                        qDebug() << ".-->LandscapeMgr::setCurrentLandscapeID(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
×
933
#endif
934
                }
935
                else
936
                {
937
#ifndef NDEBUG
938
                        qDebug() << "LandscapeMgr::setCurrentLandscapeID: Loading from file:" << id ;
×
939
#endif
940
                        newLandscape = createFromFile(StelFileMgr::findFile("landscapes/" + id + "/landscape.ini"), id);
×
941
                }
942

943
                if (!newLandscape)
×
944
                {
945
                        qWarning() << "ERROR while loading landscape " << "landscapes/" + id + "/landscape.ini";
×
946
                        return false;
×
947
                }
948
        }
949

950
        // Keep current landscape for a while, while new landscape fades in!
951
        // This prevents subhorizon sun or grid becoming briefly visible.
952
        if (landscape)
×
953
        {
954
                // Copy display parameters from previous landscape to new one. TODO: Sort out possible static ones!
955
                newLandscape->setFlagShow(landscape->getFlagShow());
×
956
                newLandscape->setFlagShowFog(landscape->getFlagShowFog());
×
957

958
                // If we have an oldLandscape that is not just swapped back, put that into cache.
959
                if (oldLandscape && oldLandscape!=newLandscape)
×
960
                {
961
#ifndef NDEBUG
962
                        qDebug() << "LandscapeMgr::setCurrent: moving oldLandscape " << oldLandscape->getId() << "to Cache. Cost:" << oldLandscape->getMemorySize()/(1024*1024)+1;
×
963
#endif
964
                        landscapeCache.insert(oldLandscape->getId(), oldLandscape, oldLandscape->getMemorySize()/(1024*1024)+1);
×
965
#ifndef NDEBUG
966
                        qDebug() << "-->LandscapeMgr::setCurrentLandscapeId(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
×
967
#endif
968
                }
969
                oldLandscape = landscape; // keep old while transitioning!
×
970
        }
971
        landscape=newLandscape;
×
972
        currentLandscapeID = id;
×
973

974
        if (getFlagLandscapeSetsLocation() && landscape->hasLocation())
×
975
        {
976
                StelCore *core = StelApp::getInstance().getCore();
×
977
                core->moveObserverTo(landscape->getLocation(), changeLocationDuration, changeLocationDuration, id);
×
978
                StelSkyDrawer* drawer=core->getSkyDrawer();
×
979

980
                if (landscape->getLocation().ianaTimeZone.length())
×
981
                {
982
                        core->setCurrentTimeZone(landscape->getLocation().ianaTimeZone);
×
983
                }
984
                if (landscape->getDefaultFogSetting() >-1)
×
985
                {
986
                        setFlagFog(static_cast<bool>(landscape->getDefaultFogSetting()));
×
987
                        landscape->setFlagShowFog(static_cast<bool>(landscape->getDefaultFogSetting()));
×
988
                }
989
                if (landscape->getDefaultLightPollutionLuminance().isValid())
×
990
                {
991
                        drawer->setLightPollutionLuminance(landscape->getDefaultLightPollutionLuminance().toFloat());
×
992
                }
993
                if (landscape->getDefaultAtmosphericExtinction() >= 0.0)
×
994
                {
995
                        drawer->setExtinctionCoefficient(landscape->getDefaultAtmosphericExtinction());
×
996
                }
997
                if (landscape->getDefaultAtmosphericTemperature() > -273.15)
×
998
                {
999
                        drawer->setAtmosphereTemperature(landscape->getDefaultAtmosphericTemperature());
×
1000
                }
1001
                if (landscape->getDefaultAtmosphericPressure() >= 0.0)
×
1002
                {
1003
                        drawer->setAtmospherePressure(landscape->getDefaultAtmosphericPressure());
×
1004
                }
1005
                else if (landscape->getDefaultAtmosphericPressure() < 0.0)
×
1006
                {
1007
                        // compute standard pressure for standard atmosphere in given altitude if landscape.ini coded as atmospheric_pressure=-1
1008
                        // International altitude formula found in Wikipedia.
1009
                        double alt=landscape->getLocation().altitude;
×
1010
                        double p=1013.25*std::pow(1-(0.0065*alt)/288.15, 5.255);
×
1011
                        drawer->setAtmospherePressure(p);
×
1012
                }
1013
        }
1014

1015
        emit currentLandscapeChanged(currentLandscapeID,getCurrentLandscapeName());
×
1016

1017
        // else qDebug() << "Will not set new location; Landscape location: planet: " << landscape->getLocation().planetName << "name: " << landscape->getLocation().name;
1018
        return true;
×
1019
}
1020

1021
bool LandscapeMgr::setCurrentLandscapeName(const QString& name, const double changeLocationDuration)
×
1022
{
1023
        if (name.isEmpty())
×
1024
                return false;
×
1025
        
1026
        QMap<QString,QString> nameToDirMap = getNameToDirMap();
×
1027
        if (nameToDirMap.find(name)!=nameToDirMap.end())
×
1028
        {
1029
                //qDebug() << "Resolving " << name << "as" << nameToDirMap[name];
1030
                return setCurrentLandscapeID(nameToDirMap[name], changeLocationDuration);
×
1031
        }
1032
        // Legacy mess-up: e.g. Scenery3D calls name but should mean ID.
1033
        else if (!setCurrentLandscapeID(name, changeLocationDuration))
×
1034
        {
1035
                qWarning() << "Can't find a landscape with name=" << name << StelUtils::getEndLineChar();
×
1036
                return false;
×
1037
        }
1038
        qDebug() << "Loading landscapeID" << name;
×
1039
        return true;
×
1040
}
×
1041

1042
// Load a landscape into cache.
1043
// @param id the ID of a landscape
1044
// @param replace true if existing landscape entry should be replaced (useful during development to reload after edit)
1045
// @return false if landscape could not be found, or existed already and replace was false.
1046
bool LandscapeMgr::precacheLandscape(const QString& id, const bool replace)
×
1047
{
1048
        if (landscapeCache.contains(id) && (!replace))
×
1049
                return false;
×
1050

1051
        Landscape* newLandscape = createFromFile(StelFileMgr::findFile("landscapes/" + id + "/landscape.ini"), id);
×
1052
        if (!newLandscape)
×
1053
        {
1054
                qWarning() << "ERROR while preloading landscape " << "landscapes/" + id + "/landscape.ini";
×
1055
                return false;
×
1056
        }
1057

1058
        bool res=landscapeCache.insert(id, newLandscape, newLandscape->getMemorySize()/(1024*1024)+1);
×
1059
#ifndef NDEBUG
1060
        if (res)
×
1061
        {
1062
                qDebug() << "LandscapeMgr::precacheLandscape(): Successfully added landscape with ID " << id << "to cache";
×
1063
        }
1064
        qDebug() << "LandscapeMgr::precacheLandscape(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
×
1065
#endif
1066
        return res;
×
1067
}
1068

1069
// Remove a landscape from the cache of loaded landscapes.
1070
// @param id the ID of a landscape
1071
// @return false if landscape could not be found
1072
bool LandscapeMgr::removeCachedLandscape(const QString& id)
×
1073
{
1074
        bool res= landscapeCache.remove(id);
×
1075
#ifndef NDEBUG
1076
        qDebug() << "LandscapeMgr::removeCachedLandscape(): cache contains " << landscapeCache.size() << "landscapes totalling about " << landscapeCache.totalCost() << "MB.";
×
1077
#endif
1078
        return res;
×
1079
}
1080

1081

1082
// Change the default landscape to the landscape with the ID specified.
1083
bool LandscapeMgr::setDefaultLandscapeID(const QString& id)
×
1084
{
1085
        if (id.isEmpty())
×
1086
                return false;
×
1087
        defaultLandscapeID = id;
×
1088
        QSettings* conf = StelApp::getInstance().getSettings();
×
1089
        conf->setValue("init_location/landscape_name", id);
×
1090
        emit defaultLandscapeChanged(id);
×
1091
        return true;
×
1092
}
1093

1094
void LandscapeMgr::updateI18n()
×
1095
{
1096
        // Translate all labels with the new language
1097
        if (cardinalPoints) cardinalPoints->updateI18n();
×
1098
        landscape->loadLabels(getCurrentLandscapeID());
×
1099
}
×
1100

1101
void LandscapeMgr::setFlagLandscape(const bool displayed)
×
1102
{
1103
        if (oldLandscape && !displayed)
×
1104
                oldLandscape->setFlagShow(false);
×
1105
        if(landscape->getFlagShow() != displayed) {
×
1106
                landscape->setFlagShow(displayed);
×
1107
                emit landscapeDisplayedChanged(displayed);
×
1108
        }
1109
        StelApp::immediateSave("landscape/flag_landscape", displayed);
×
1110
}
×
1111

1112
bool LandscapeMgr::getFlagLandscape() const
×
1113
{
1114
        return landscape->getFlagShow();
×
1115
}
1116

1117
bool LandscapeMgr::getIsLandscapeFullyVisible() const
×
1118
{
1119
        return landscape->getIsFullyVisible();
×
1120
}
1121

1122
double LandscapeMgr::getLandscapeSinMinAltitudeLimit() const
×
1123
{
1124
        if (flagLandscapeUseTransparency && landscapeTransparency>0.)
×
1125
                return -1.;
×
1126
        else
1127
                return landscape->getSinMinAltitudeLimit();
×
1128
}
1129

1130
bool LandscapeMgr::getFlagUseLightPollutionFromDatabase() const
×
1131
{
1132
        return flagLightPollutionFromDatabase;
×
1133
}
1134

1135
void LandscapeMgr::setFlagUseLightPollutionFromDatabase(const bool usage)
×
1136
{
1137
        if (flagLightPollutionFromDatabase != usage)
×
1138
        {
1139
                flagLightPollutionFromDatabase = usage;
×
1140
                StelApp::immediateSave("viewing/flag_light_pollution_database", usage);
×
1141

1142
                StelCore* core = StelApp::getInstance().getCore();
×
1143

1144
                //this was previously logic in ViewDialog, but should really be on a non-GUI layer
1145
                if (usage)
×
1146
                {
1147
                        StelLocation loc = core->getCurrentLocation();
×
1148
                        onLocationChanged(loc);
×
1149
                }
×
1150

1151
                emit flagUseLightPollutionFromDatabaseChanged(usage);
×
1152
        }
1153
}
×
1154

1155
void LandscapeMgr::onLocationChanged(const StelLocation &loc)
×
1156
{
1157
        if(flagLightPollutionFromDatabase)
×
1158
        {
1159
                //this was previously logic in ViewDialog, but should really be on a non-GUI layer
1160
                StelCore* core = StelApp::getInstance().getCore();
×
1161
                float lum=0.; // location not on Earth...
×
1162
                if (loc.planetName.contains("Earth"))
×
1163
                {
1164
                        if(loc.lightPollutionLuminance.isValid())
×
1165
                                lum = loc.lightPollutionLuminance.toFloat();
×
1166
                        else // ...or it is an observatory, or it is an unknown location
1167
                                lum = loc.DEFAULT_LIGHT_POLLUTION_LUMINANCE;
×
1168
                }
1169
                core->getSkyDrawer()->setLightPollutionLuminance(lum);
×
1170
        }
1171
}
×
1172

1173
// Load landscapeID, but do not load its associated location.
1174
// If landscapeID is empty but flagLandscapeAutoSelection is true, load a location fitting to loc's planet.
1175
void LandscapeMgr::onTargetLocationChanged(const StelLocation &loc, const QString& landscapeID)
×
1176
{
1177
        //qDebug() << "LandscapeMgr::onTargetLocationChanged:" << loc.serializeToLine().replace('\t', '|') << "Landscape requested:" << landscapeID;
1178
        if (!landscapeID.isEmpty() && getAllLandscapeIDs().contains(landscapeID))
×
1179
        {
1180
                const bool landscapeSetsLocation = getFlagLandscapeSetsLocation();
×
1181
                setFlagLandscapeSetsLocation(false);
×
1182
                setCurrentLandscapeID(landscapeID);
×
1183
                setFlagLandscapeSetsLocation(landscapeSetsLocation);
×
1184
        }
1185
        else if(landscapeID.startsWith("ZeroColor("))
×
1186
        {
1187
                // Load a zero landscape and recolor it.
1188
                // This can happen when clicking on the map. The point on the map can be sampled for color (e.g., desert, greengrass, ocean blue, polar white, ...)
1189
                const bool landscapeSetsLocation = getFlagLandscapeSetsLocation();
×
1190
                setFlagLandscapeSetsLocation(false);
×
1191
                setCurrentLandscapeID("zero");
×
1192
                Vec3f color(0.3);
×
1193
                static const QRegularExpression zeroColor("^ZeroColor\\(([0-9].[0-9]+,[0-9].[0-9]+,[0-9].[0-9]+)\\)$");
×
1194
                QRegularExpressionMatch match=zeroColor.match(landscapeID);
×
1195
                if (match.hasMatch())
×
1196
                        color=Vec3f(match.captured(1));
×
1197
                else
1198
                        qDebug() << "Cannot extract color from landscapeID" << landscapeID;
×
1199
                LandscapePolygonal *l=static_cast<LandscapePolygonal*>(landscape);
×
1200
                l->setGroundColor(color);
×
1201
                setFlagLandscapeSetsLocation(landscapeSetsLocation);
×
1202
        }
×
1203
        else if (flagLandscapeAutoSelection && (loc.planetName != currentPlanetName))
×
1204
        {
1205
                //qDebug() << "landscapeID empty. Try planet name" << loc.planetName << "or zero";
1206
                // If we have a landscape for selected planet then set it, otherwise use zero horizon landscape
1207
                const bool landscapeSetsLocation = getFlagLandscapeSetsLocation();
×
1208
                setFlagLandscapeSetsLocation(false);
×
1209
                if (getAllLandscapeNames().indexOf(loc.planetName)>0)
×
1210
                        setCurrentLandscapeName(loc.planetName);
×
1211
                else
1212
                        setCurrentLandscapeID("zero");
×
1213
                setFlagLandscapeSetsLocation(landscapeSetsLocation);
×
1214
        }
1215

1216
        if (loc.role==QChar('o')) // observer?
×
1217
        {
1218
                if (flagEnvironmentAutoEnabling)
×
1219
                {
1220
                        setFlagAtmosphere(false);
×
1221
                        setFlagFog(false);
×
1222
                        setFlagLandscape(false);
×
1223
                        setFlagCardinalPoints(false); // suppresses all
×
1224
                }
1225
        }
1226
        else
1227
        {
1228
                SolarSystem* ssystem = static_cast<SolarSystem*>(StelApp::getInstance().getModuleMgr().getModule("SolarSystem"));
×
1229
                PlanetP pl = ssystem->searchByEnglishName(loc.planetName);
×
1230
                if (pl && flagEnvironmentAutoEnabling && currentPlanetName!=loc.planetName)
×
1231
                {
1232
                        QSettings* conf = StelApp::getInstance().getSettings();
×
1233
                        setFlagAtmosphere(pl->hasAtmosphere() && conf->value("landscape/flag_atmosphere", true).toBool());
×
1234
                        setFlagFog(pl->hasAtmosphere() && conf->value("landscape/flag_fog", true).toBool());
×
1235
                        setFlagLandscape(conf->value("landscape/flag_landscape", true).toBool());
×
1236
                        setFlagCardinalPoints(conf->value("viewing/flag_cardinal_points", true).toBool());
×
1237
                        setFlagOrdinalPoints(conf->value("viewing/flag_ordinal_points", true).toBool());
×
1238
                        setFlagOrdinal16WRPoints(conf->value("viewing/flag_16wcr_points", false).toBool());
×
1239
                        setFlagOrdinal32WRPoints(conf->value("viewing/flag_32wcr_points", false).toBool());
×
1240
                }
1241
        }
×
1242
        currentPlanetName = loc.planetName;
×
1243
        //qDebug() << "LandscapeMgr::onTargetLocationChanged done" ;
1244
}
×
1245

1246
void LandscapeMgr::setFlagFog(const bool displayed)
×
1247
{
1248
        if (landscape->getFlagShowFog() != displayed) {
×
1249
                landscape->setFlagShowFog(displayed);
×
1250
                StelApp::immediateSave("landscape/flag_fog", displayed);
×
1251
                emit fogDisplayedChanged(displayed);
×
1252
        }
1253
}
×
1254

1255
bool LandscapeMgr::getFlagFog() const
×
1256
{
1257
        return landscape->getFlagShowFog();
×
1258
}
1259

1260
void LandscapeMgr::setFlagIllumination(const bool displayed)
×
1261
{
1262
        if (Landscape::getFlagShowIllumination() != displayed) {
×
1263
                Landscape::setFlagShowIllumination(displayed);
×
1264
                StelApp::immediateSave("landscape/flag_enable_illumination_layer", displayed);
×
1265
                emit illuminationDisplayedChanged(displayed);
×
1266
        }
1267
}
×
1268

1269
bool LandscapeMgr::getFlagIllumination() const
×
1270
{
1271
        return landscape->getFlagShowIllumination();
×
1272
}
1273

1274
void LandscapeMgr::setLandscapeTransparency(const double f)
×
1275
{
1276
        landscapeTransparency = f;
×
1277
        StelApp::immediateSave("landscape/transparency", f);
×
1278
        emit landscapeTransparencyChanged(f);
×
1279
}
×
1280

1281
double LandscapeMgr::getLandscapeTransparency() const
×
1282
{
1283
        return landscapeTransparency;
×
1284
}
1285

1286
// Return the value of the flag determining if a transparency should be used.
1287
bool LandscapeMgr::getFlagLandscapeUseTransparency() const
×
1288
{
1289
        return flagLandscapeUseTransparency;
×
1290
}
1291
// Set the value of the flag determining if a transparency should be used.
1292
void LandscapeMgr::setFlagLandscapeUseTransparency(bool b)
×
1293
{
1294
        if (b!=flagLandscapeUseTransparency)
×
1295
        {
1296
                flagLandscapeUseTransparency=b;
×
1297
                StelApp::immediateSave("landscape/flag_transparency", b);
×
1298
                emit flagLandscapeUseTransparencyChanged(b);
×
1299
        }
1300
}
×
1301

1302
void LandscapeMgr::setFlagLabels(const bool displayed)
×
1303
{
1304
        if (static_cast<bool>(Landscape::labelFader) != displayed) {
×
1305
                Landscape::labelFader=displayed;
×
1306
                StelApp::immediateSave("landscape/flag_enable_labels", displayed);
×
1307
                emit labelsDisplayedChanged(displayed);
×
1308
        }
1309
}
×
1310

1311
bool LandscapeMgr::getFlagLabels() const
×
1312
{
1313
        return static_cast<bool>(Landscape::labelFader);
×
1314
}
1315

1316
void LandscapeMgr::setLabelFontSize(const int size)
×
1317
{
1318
        Landscape::fontSize=size;
×
1319
        StelApp::immediateSave("landscape/label_font_size", size);
×
1320
        emit labelFontSizeChanged(size);
×
1321
}
×
1322

1323
int LandscapeMgr::getLabelFontSize() const
×
1324
{
1325
        return Landscape::fontSize;
×
1326
}
1327

1328
void LandscapeMgr::setLabelAngle(const int angleDeg)
×
1329
{
1330
        Landscape::labelAngle = angleDeg;
×
1331
        StelApp::immediateSave("landscape/label_angle", angleDeg);
×
1332
        emit labelAngleChanged(angleDeg);
×
1333
}
×
1334

1335
int LandscapeMgr::getLabelAngle() const
×
1336
{
1337
        return Landscape::labelAngle;
×
1338
}
1339

1340
void LandscapeMgr::setLabelColor(const Vec3f& c)
×
1341
{
1342
        Landscape::labelColor=c;
×
1343
        emit labelColorChanged(c);
×
1344
}
×
1345

1346
Vec3f LandscapeMgr::getLabelColor() const
×
1347
{
1348
        return Landscape::labelColor;
×
1349
}
1350

1351
//! Retrieve flag for rendering polygonal line (if one is defined)
1352
bool LandscapeMgr::getFlagPolyLineOnlyDisplayed() const
×
1353
{
1354
        return flagPolyLineDisplayedOnly;
×
1355
}
1356
//! Set flag for rendering polygonal line (if one is defined)
1357
void LandscapeMgr::setFlagPolyLineOnlyDisplayed(bool b)
×
1358
{
1359
        if(b!=flagPolyLineDisplayedOnly)
×
1360
        {
1361
                flagPolyLineDisplayedOnly=b;
×
1362
                StelApp::immediateSave("landscape/flag_polyline_only", b);
×
NEW
1363
                emit flagPolyLineOnlyDisplayedChanged(b);
×
1364
        }
1365
}
×
1366

1367
//! Retrieve thickness for rendering polygonal line (if one is defined)
1368
int LandscapeMgr::getPolyLineThickness() const
×
1369
{
1370
        return Landscape::horizonPolygonLineThickness;
×
1371
}
1372

1373
//! Set thickness for rendering polygonal line (if one is defined)
1374
void LandscapeMgr::setPolyLineThickness(int thickness)
×
1375
{
1376
        Landscape::horizonPolygonLineThickness=thickness;
×
1377
        StelApp::immediateSave("landscape/polyline_thickness", thickness);
×
1378
        emit polyLineThicknessChanged(thickness);
×
1379
}
×
1380

1381
void LandscapeMgr::setPolyLineColor(const Vec3f& c)
×
1382
{
1383
        Landscape::horizonPolygonLineColor = c;
×
1384
        emit polyLineColorChanged(c);
×
1385
}
×
1386

1387
Vec3f LandscapeMgr::getPolyLineColor() const
×
1388
{
1389
        return Landscape::horizonPolygonLineColor;
×
1390
}
1391

1392
// Return the value of the flag determining if a change of landscape will update the observer location.
1393
bool LandscapeMgr::getFlagLandscapeSetsLocation() const
×
1394
{
1395
        return flagLandscapeSetsLocation;
×
1396
}
1397
// Set the value of the flag determining if a change of landscape will update the observer location.
1398
void LandscapeMgr::setFlagLandscapeSetsLocation(bool b)
×
1399
{
1400
        if(b!=flagLandscapeSetsLocation)
×
1401
        {
1402
                flagLandscapeSetsLocation=b;
×
1403
                StelApp::immediateSave("landscape/flag_landscape_sets_location", b);
×
1404
                emit flagLandscapeSetsLocationChanged(b);
×
1405
        }
1406
}
×
1407

1408
// Return the value of the flag determining if a minimal brightness should be used to keep landscape visible.
1409
bool LandscapeMgr::getFlagLandscapeUseMinimalBrightness() const
×
1410
{
1411
        return flagLandscapeUseMinimalBrightness;
×
1412
}
1413

1414
// Set the value of the flag determining if a minimal brightness should be used to keep landscape visible.
1415
void LandscapeMgr::setFlagLandscapeUseMinimalBrightness(bool b)
×
1416
{
1417
        if(b!=flagLandscapeUseMinimalBrightness)
×
1418
        {
1419
                flagLandscapeUseMinimalBrightness=b;
×
1420
                StelApp::immediateSave("landscape/flag_minimal_brightness", b);
×
1421
                emit flagLandscapeUseMinimalBrightnessChanged(b);
×
1422
        }
1423
}
×
1424

1425
// Return the value of the flag determining if the minimal brightness should be taken from landscape.ini
1426
bool LandscapeMgr::getFlagLandscapeSetsMinimalBrightness() const
×
1427
{
1428
        return flagLandscapeSetsMinimalBrightness;
×
1429
}
1430
// Sets the value of the flag determining if the minimal brightness should be taken from landscape.ini
1431
void LandscapeMgr::setFlagLandscapeSetsMinimalBrightness(bool b)
×
1432
{
1433
        if(b!=flagLandscapeSetsMinimalBrightness)
×
1434
        {
1435
                flagLandscapeSetsMinimalBrightness=b;
×
1436
                StelApp::immediateSave("landscape/flag_landscape_sets_minimal_brightness", b);
×
1437
                emit flagLandscapeSetsMinimalBrightnessChanged(b);
×
1438
        }
1439
}
×
1440

1441

1442
void LandscapeMgr::setFlagLandscapeAutoSelection(bool enableAutoSelect)
×
1443
{
1444
        if(enableAutoSelect != flagLandscapeAutoSelection)
×
1445
        {
1446
                flagLandscapeAutoSelection = enableAutoSelect;
×
1447
                StelApp::immediateSave("viewing/flag_landscape_autoselection", enableAutoSelect);
×
1448
                emit flagLandscapeAutoSelectionChanged(enableAutoSelect);
×
1449
        }
1450
}
×
1451

1452
bool LandscapeMgr::getFlagLandscapeAutoSelection() const
×
1453
{
1454
        return flagLandscapeAutoSelection;
×
1455
}
1456

1457
void LandscapeMgr::setFlagEnvironmentAutoEnable(bool b)
×
1458
{
1459
        if(b != flagEnvironmentAutoEnabling)
×
1460
        {
1461
                flagEnvironmentAutoEnabling = b;
×
1462
                StelApp::immediateSave("viewing/flag_environment_auto_enable", b);
×
1463
                emit setFlagEnvironmentAutoEnableChanged(b);
×
1464
        }
1465
}
×
1466

1467
bool LandscapeMgr::getFlagEnvironmentAutoEnable() const
×
1468
{
1469
        return flagEnvironmentAutoEnabling;
×
1470
}
1471

1472
// Return the minimal brightness value of the landscape
1473
double LandscapeMgr::getDefaultMinimalBrightness() const
×
1474
{
1475
        return defaultMinimalBrightness;
×
1476
}
1477
// Set the minimal brightness value of the landscape.
1478
void LandscapeMgr::setDefaultMinimalBrightness(const double b)
×
1479
{
1480
        if(fabs(b-defaultMinimalBrightness)>0.0)
×
1481
        {
1482
                defaultMinimalBrightness=b;
×
1483
                StelApp::immediateSave("landscape/minimal_brightness", b);
×
1484
                emit defaultMinimalBrightnessChanged(b);
×
1485
        }
1486
}
×
1487

1488
/*********************************************************************
1489
 Retrieve list of the names of all the available landscapes
1490
 *********************************************************************/
1491
QStringList LandscapeMgr::getAllLandscapeNames() const
×
1492
{
1493
        return getNameToDirMap().keys();
×
1494
}
1495

1496
QStringList LandscapeMgr::getAllLandscapeIDs() const
×
1497
{
1498
        return getNameToDirMap().values();
×
1499
}
1500

1501
QStringList LandscapeMgr::getUserLandscapeIDs() const
×
1502
{
1503
        QStringList result;
×
1504
        QMapIterator<QString, QString> it(getNameToDirMap());
×
1505
        while (it.hasNext())
×
1506
        {
1507
                it.next();
×
1508
                if(!packagedLandscapeIDs.contains(it.value()))
×
1509
                        result.append(it.value());
×
1510
        }
1511
        return result;
×
1512
}
×
1513

1514
QString LandscapeMgr::getCurrentLandscapeName() const
×
1515
{
1516
        return landscape->getName();
×
1517
}
1518

1519
QString LandscapeMgr::getCurrentLandscapeHtmlDescription() const
×
1520
{
1521
        QString desc = getDescription();
×
1522

1523
        QString author = landscape->getAuthorName();
×
1524

1525
        desc += "<p>";
×
1526
        if (!author.isEmpty())
×
1527
                desc += QString("<b>%1</b>: %2<br />").arg(q_("Author"), author);
×
1528

1529
        // This previously showed 0/0 for locationless landscapes!
1530
        if (landscape->hasLocation())
×
1531
        {
1532
                //TRANSLATORS: Unit of measure for distance - meter
1533
                QString alt = qc_("m", "distance");
×
1534

1535
                desc += QString("<b>%1</b>: %2, %3, %4 %5").arg(
×
1536
                                q_("Location"),
×
1537
                                StelUtils::radToDmsStrAdapt(static_cast<double>(landscape->getLocation().getLatitude()) *M_PI_180),
×
1538
                                StelUtils::radToDmsStrAdapt(static_cast<double>(landscape->getLocation().getLongitude()) * M_PI_180),
×
1539
                                QString::number(landscape->getLocation().altitude),
×
1540
                                alt);
×
1541

1542
                QString planetName = landscape->getLocation().planetName;                
×
1543
                if (!planetName.isEmpty())
×
1544
                {
1545
                        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
1546
                        desc += QString(", %1").arg(trans.qtranslate(planetName, "major planet")); // TODO: Enhance the context support
×
1547
                }
1548
                desc += "<br />";
×
1549

1550
                QStringList atmosphere;
×
1551
                //atmosphere.clear(); // Huh?
1552

1553
                double pressure = landscape->getDefaultAtmosphericPressure();
×
1554
                if (pressure>0.)
×
1555
                {
1556
                        // 1 mbar = 1 hPa
1557
                        //TRANSLATORS: Unit of measure for pressure - hectopascals
1558
                        QString hPa = qc_("hPa", "pressure");
×
1559
                        atmosphere.append(QString("%1 %2").arg(QString::number(pressure, 'f', 1), hPa));
×
1560
                }
×
1561

1562
                double temperature = landscape->getDefaultAtmosphericTemperature();
×
1563
                if (temperature>-1000.0)
×
1564
                        atmosphere.append(QString("%1 %2C").arg(QString::number(temperature, 'f', 1)).arg(QChar(0x00B0)));
×
1565

1566
                double extcoeff = landscape->getDefaultAtmosphericExtinction();
×
1567
                if (extcoeff>-1.0)
×
1568
                        atmosphere.append(QString("%1: %2").arg(q_("extinction coefficient"), QString::number(extcoeff, 'f', 2)));
×
1569

1570
                if (!atmosphere.isEmpty())
×
1571
                        desc += QString("<b>%1</b>: %2<br />").arg(q_("Atmospheric conditions"), atmosphere.join(", "));
×
1572

1573
                const auto lightPollutionLum = landscape->getDefaultLightPollutionLuminance();
×
1574
                if (lightPollutionLum.isValid())
×
1575
                {
1576
                        const auto lum = lightPollutionLum.toFloat();
×
1577
                        auto scaledLum = lum;
×
1578
                        QString unit = q_("cd/m<sup>2</sup>");
×
1579
                        if(lum < 1e-6f)
×
1580
                        {
1581
                                scaledLum = lum*1e9f;
×
1582
                                unit = q_("ncd/m<sup>2</sup>");
×
1583
                        }
1584
                        else if(lum < 1e-3f)
×
1585
                        {
1586
                                scaledLum = lum*1e6f;
×
1587
                                unit = q_("&mu;cd/m<sup>2</sup>");
×
1588
                        }
1589
                        else if(lum < 1)
×
1590
                        {
1591
                                scaledLum = lum*1e3f;
×
1592
                                unit = q_("mcd/m<sup>2</sup>");
×
1593
                        }
1594
                        desc += q_("<b>Light pollution</b>: %1 %2 (NELM: %3; Bortle class: %4)")
×
1595
                                                .arg(scaledLum).arg(unit).arg(StelCore::luminanceToNELM(lum))
×
1596
                                                .arg(StelCore::luminanceToBortleScaleIndex(lum));
×
1597
                }
×
1598
        }        
×
1599
        return desc;
×
1600
}
×
1601

1602
//! Set flag for displaying cardinal points
1603
void LandscapeMgr::setFlagCardinalPoints(const bool displayed)
×
1604
{
1605
        if (cardinalPoints->getFlagShow4WCRLabels() != displayed)
×
1606
        {
1607
                cardinalPoints->setFlagShow4WCRLabels(displayed);
×
1608
                emit cardinalPointsDisplayedChanged(displayed);
×
1609
        }
1610
}
×
1611

1612
//! Get flag for displaying cardinal points
1613
bool LandscapeMgr::getFlagCardinalPoints() const
×
1614
{
1615
        return cardinalPoints->getFlagShowCardinals();
×
1616
}
1617

1618
//! Set flag for displaying ordinal points
1619
void LandscapeMgr::setFlagOrdinalPoints(const bool displayed)
×
1620
{
1621
        if (cardinalPoints->getFlagShow8WCRLabels() != displayed)
×
1622
        {
1623
                cardinalPoints->setFlagShow8WCRLabels(displayed);
×
1624
                emit ordinalPointsDisplayedChanged(displayed);
×
1625
        }
1626
}
×
1627

1628
//! Get flag for displaying ordinal points
1629
bool LandscapeMgr::getFlagOrdinalPoints() const
×
1630
{
1631
        return cardinalPoints->getFlagShow8WCRLabels();
×
1632
}
1633

1634
//! Set flag for displaying ordinal points
1635
void LandscapeMgr::setFlagOrdinal16WRPoints(const bool displayed)
×
1636
{
1637
        if (cardinalPoints->getFlagShow16WCRLabels() != displayed)
×
1638
        {
1639
                cardinalPoints->setFlagShow16WCRLabels(displayed);
×
1640
                emit ordinal16WRPointsDisplayedChanged(displayed);
×
1641
        }
1642
}
×
1643

1644
//! Get flag for displaying ordinal points
1645
bool LandscapeMgr::getFlagOrdinal16WRPoints() const
×
1646
{
1647
        return cardinalPoints->getFlagShow16WCRLabels();
×
1648
}
1649

1650
//! Set flag for displaying ordinal points
1651
void LandscapeMgr::setFlagOrdinal32WRPoints(const bool displayed)
×
1652
{
1653
        if (cardinalPoints->getFlagShow32WCRLabels() != displayed)
×
1654
        {
1655
                cardinalPoints->setFlagShow32WCRLabels(displayed);
×
1656
                emit ordinal32WRPointsDisplayedChanged(displayed);
×
1657
        }
1658
}
×
1659

1660
//! Get flag for displaying ordinal points
1661
bool LandscapeMgr::getFlagOrdinal32WRPoints() const
×
1662
{
1663
        return cardinalPoints->getFlagShow32WCRLabels();
×
1664
}
1665

1666
//! Set Cardinals Points color
1667
void LandscapeMgr::setColorCardinalPoints(const Vec3f& v)
×
1668
{
1669
        if(v != getColorCardinalPoints())
×
1670
        {
1671
                cardinalPoints->setColor(v);
×
1672
                emit cardinalPointsColorChanged(v);
×
1673
        }
1674
}
×
1675

1676
//! Get Cardinals Points color
1677
Vec3f LandscapeMgr::getColorCardinalPoints() const
×
1678
{
1679
        return cardinalPoints->getColor();
×
1680
}
1681

1682
///////////////////////////////////////////////////////////////////////////////////////
1683
// Atmosphere
1684
//! Set flag for displaying Atmosphere
1685
void LandscapeMgr::setFlagAtmosphere(const bool displayed)
×
1686
{
1687
        if (atmosphere->getFlagShow() != displayed) {
×
1688
                atmosphere->setFlagShow(displayed);
×
1689
                StelApp::getInstance().getCore()->getSkyDrawer()->setFlagHasAtmosphere(displayed);
×
1690
                emit atmosphereDisplayedChanged(displayed);
×
1691
                //if (StelApp::getInstance().getSettings()->value("landscape/flag_fog", true).toBool())
1692
                //        setFlagFog(displayed); // sync of visibility of fog because this is atmospheric phenomena
1693
                // GZ This did not work as it may have been intended. Switch off fog, switch off atmosphere. Switch on atmosphere, and you have fog?
1694
                // --> Fog is only drawn in Landscape if atmosphere is switched on!
1695
        }
1696
}
×
1697

1698
void LandscapeMgr::setAtmosphereModel(const QString& model)
×
1699
{
1700
        const auto modelToSet = model.toLower();
×
1701
        const auto oldModel = getAtmosphereModel().toLower();
×
1702
        if(modelToSet == oldModel)
×
1703
                return;
×
1704

1705
        StelApp::getInstance().getSettings()->setValue(ATMOSPHERE_MODEL_CONFIG_KEY, model);
×
1706

1707
        if(!(oldModel.isEmpty() && modelToSet == ATMOSPHERE_MODEL_CONF_VAL_DEFAULT))
×
1708
        {
1709
                // Can't call createAtmosphere() right now, because we likely have wrong OpenGL context (or even none).
1710
                // So just schedule it for the next draw.
1711
                needToRecreateAtmosphere=true;
×
1712
        }
1713
}
×
1714

1715
void LandscapeMgr::setAtmosphereModelPath(const QString& path)
×
1716
{
1717
        if(getAtmosphereModelPath()==path)
×
1718
                return;
×
1719

1720
        StelApp::getInstance().getSettings()->setValue(ATMOSPHERE_MODEL_PATH_CONFIG_KEY, path);
×
1721
        setAtmosphereModel(ATMOSPHERE_MODEL_CONF_VAL_SHOWMYSKY); // This is the only relevant model for this property
×
1722
        needToRecreateAtmosphere=true;
×
1723

1724
        emit atmosphereModelPathChanged(path);
×
1725
}
1726

1727
void LandscapeMgr::setAtmosphereShowMySkyStoppedWithError(const bool error)
×
1728
{
1729
        if(atmosphereShowMySkyStoppedWithError == error)
×
1730
                return;
×
1731
        atmosphereShowMySkyStoppedWithError = error;
×
1732
        emit atmosphereStoppedWithErrorChanged(error);
×
1733
}
1734

1735
void LandscapeMgr::setAtmosphereShowMySkyStatusText(const QString& text)
×
1736
{
1737
        if(atmosphereShowMySkyStatusText == text)
×
1738
                return;
×
1739
        atmosphereShowMySkyStatusText = text;
×
1740
        emit atmosphereStatusTextChanged(text);
×
1741
}
1742

1743
void LandscapeMgr::setFlagAtmosphereZeroOrderScattering(const bool enable)
×
1744
{
1745
        atmosphereZeroOrderScatteringEnabled=enable;
×
1746
        emit flagAtmosphereZeroOrderScatteringChanged(enable);
×
1747
}
×
1748

1749
void LandscapeMgr::setFlagAtmosphereSingleScattering(const bool enable)
×
1750
{
1751
        atmosphereSingleScatteringEnabled=enable;
×
1752
        emit flagAtmosphereSingleScatteringChanged(enable);
×
1753
}
×
1754

1755
void LandscapeMgr::setFlagAtmosphereMultipleScattering(const bool enable)
×
1756
{
1757
        atmosphereMultipleScatteringEnabled=enable;
×
1758
        emit flagAtmosphereMultipleScatteringChanged(enable);
×
1759
}
×
1760

1761
void LandscapeMgr::setAtmosphereEclipseSimulationQuality(const int quality)
×
1762
{
1763
        if(getAtmosphereEclipseSimulationQuality() == quality)
×
1764
                return;
×
1765

1766
        StelApp::getInstance().getSettings()->setValue(ATMOSPHERE_ECLIPSE_SIM_QUALITY_CONFIG_KEY, quality);
×
1767

1768
        emit atmosphereEclipseSimulationQualityChanged(quality);
×
1769
}
1770

1771
//! Get flag for displaying Atmosphere
1772
bool LandscapeMgr::getFlagAtmosphere() const
×
1773
{
1774
        return atmosphere->getFlagShow();
×
1775
}
1776

1777
//! Set flag for displaying Atmosphere
1778
void LandscapeMgr::setFlagAtmosphereNoScatter(const bool noScatter)
×
1779
{
1780
        atmosphereNoScatter=noScatter;
×
1781
        emit atmosphereNoScatterChanged(noScatter);
×
1782
}
×
1783

1784
//! Get flag for displaying Atmosphere
1785
bool LandscapeMgr::getFlagAtmosphereNoScatter() const
×
1786
{
1787
        return atmosphereNoScatter;
×
1788
}
1789

1790
QString LandscapeMgr::getAtmosphereModel() const
×
1791
{
1792
        const auto conf=StelApp::getInstance().getSettings();
×
1793
        return conf->value(ATMOSPHERE_MODEL_CONFIG_KEY, ATMOSPHERE_MODEL_CONF_VAL_DEFAULT).toString();
×
1794
}
1795

1796
QString LandscapeMgr::getAtmosphereModelPath() const
×
1797
{
1798
        const auto conf=StelApp::getInstance().getSettings();
×
1799

1800
        const auto var = conf->value(ATMOSPHERE_MODEL_PATH_CONFIG_KEY);
×
1801
        if(var.isValid()) return var.toString();
×
1802

1803
        return getDefaultAtmosphereModelPath();
×
1804
}
×
1805

1806
QString LandscapeMgr::getDefaultAtmosphereModelPath() const
×
1807
{
1808
        return QDir::toNativeSeparators(QString("%1/atmosphere/default").arg(StelFileMgr::getInstallationDir()));
×
1809
}
1810

1811
bool LandscapeMgr::getAtmosphereShowMySkyStoppedWithError() const
×
1812
{
1813
        return atmosphereShowMySkyStoppedWithError;
×
1814
}
1815

1816
QString LandscapeMgr::getAtmosphereShowMySkyStatusText() const
×
1817
{
1818
        return atmosphereShowMySkyStatusText;
×
1819
}
1820

1821
bool LandscapeMgr::getFlagAtmosphereZeroOrderScattering() const
×
1822
{
1823
        return atmosphereZeroOrderScatteringEnabled;
×
1824
}
1825

1826
bool LandscapeMgr::getFlagAtmosphereSingleScattering() const
×
1827
{
1828
        return atmosphereSingleScatteringEnabled;
×
1829
}
1830

1831
bool LandscapeMgr::getFlagAtmosphereMultipleScattering() const
×
1832
{
1833
        return atmosphereMultipleScatteringEnabled;
×
1834
}
1835

1836
int LandscapeMgr::getAtmosphereEclipseSimulationQuality() const
×
1837
{
1838
        const auto conf=StelApp::getInstance().getSettings();
×
1839
        return conf->value(ATMOSPHERE_ECLIPSE_SIM_QUALITY_CONFIG_KEY, 1).toInt();
×
1840
}
1841

1842
float LandscapeMgr::getAtmosphereFadeIntensity() const
×
1843
{
1844
        return atmosphere->getFadeIntensity();
×
1845
}
1846

1847
//! Set atmosphere fade duration in s
1848
void LandscapeMgr::setAtmosphereFadeDuration(const float f)
×
1849
{
1850
        atmosphere->setFadeDuration(f);
×
1851
}
×
1852

1853
//! Get atmosphere fade duration in s
1854
float LandscapeMgr::getAtmosphereFadeDuration() const
×
1855
{
1856
        return atmosphere->getFadeDuration();
×
1857
}
1858

1859
//! Set light pollution luminance level
1860
void LandscapeMgr::setAtmosphereLightPollutionLuminance(const float f)
×
1861
{
1862
        atmosphere->setLightPollutionLuminance(f);
×
1863
}
×
1864

1865
//! Get light pollution luminance level
1866
float LandscapeMgr::getAtmosphereLightPollutionLuminance() const
×
1867
{
1868
        return atmosphere->getLightPollutionLuminance();
×
1869
}
1870

1871
void LandscapeMgr::setZRotation(const float d)
×
1872
{
1873
        if (landscape)
×
1874
                landscape->setZRotation(d);
×
1875
}
×
1876

1877
float LandscapeMgr::getLuminance() const
×
1878
{
1879
        return atmosphere->getRealDisplayIntensityFactor();
×
1880
}
1881

1882
float LandscapeMgr::getAtmosphereAverageLuminance() const
×
1883
{
1884
        return atmosphere->getAverageLuminance();
×
1885
}
1886

1887
// Override auto-computed luminance. Only use when you know what you are doing, and don't forget to unfreeze the average by calling this function with a negative value.
1888
void LandscapeMgr::setAtmosphereAverageLuminance(const float overrideLum)
×
1889
{
1890
        atmosphere->setAverageLuminance(overrideLum);
×
1891
}
×
1892

1893
Landscape* LandscapeMgr::createFromFile(const QString& landscapeFile, const QString& landscapeId)
×
1894
{
1895
        QSettings landscapeIni(landscapeFile, StelIniFormat);
×
1896
        QString s;
×
1897
        if (landscapeIni.status() != QSettings::NoError)
×
1898
        {
1899
                qWarning() << "ERROR parsing landscape.ini file: " << QDir::toNativeSeparators(landscapeFile);
×
1900
                s = "";
×
1901
        }
1902
        else
1903
                s = landscapeIni.value("landscape/type").toString();
×
1904

1905
        Landscape* landscape = Q_NULLPTR;
×
1906
        if (s=="old_style")
×
1907
                landscape = new LandscapeOldStyle();
×
1908
        else if (s=="spherical")
×
1909
                landscape = new LandscapeSpherical();
×
1910
        else if (s=="fisheye")
×
1911
                landscape = new LandscapeFisheye();
×
1912
        else if (s=="polygonal")
×
1913
                landscape = new LandscapePolygonal();
×
1914
        else
1915
        {
1916
                qDebug() << "Unknown landscape type: \"" << s << "\"";
×
1917

1918
                // to avoid making this a fatal error, will load as a fisheye
1919
                // if this fails, it just won't draw
1920
                landscape = new LandscapeFisheye();
×
1921
        }
1922

1923
        landscape->load(landscapeIni, landscapeId);
×
1924
        return landscape;
×
1925
}
×
1926

1927

1928
QString LandscapeMgr::nameToID(const QString& name)
×
1929
{
1930
        QMap<QString,QString> nameToDirMap = getNameToDirMap();
×
1931

1932
        if (nameToDirMap.find(name)!=nameToDirMap.end())
×
1933
        {
1934
                Q_ASSERT(0);
×
1935
                return "error";
1936
        }
1937
        else
1938
        {
1939
                return nameToDirMap[name];
×
1940
        }
1941
}
×
1942

1943
/****************************************************************************
1944
 get a map of landscape names (from landscape.ini name field) to ID (dir name)
1945
 ****************************************************************************/
1946
QMap<QString,QString> LandscapeMgr::getNameToDirMap()
×
1947
{
1948
        QMap<QString,QString> result;
×
1949
        const QSet<QString> landscapeDirs = StelFileMgr::listContents("landscapes",StelFileMgr::Directory);
×
1950

1951
        for (const auto& dir : landscapeDirs)
×
1952
        {
1953
                QString fName = StelFileMgr::findFile("landscapes/" + dir + "/landscape.ini");
×
1954
                if (!fName.isEmpty())
×
1955
                {
1956
                        QSettings landscapeIni(fName, StelIniFormat);
×
1957
                        QString k = landscapeIni.value("landscape/name").toString();
×
1958
                        result[k] = dir;
×
1959
                }
×
1960
        }
×
1961
        return result;
×
1962
}
×
1963

1964
QString LandscapeMgr::installLandscapeFromArchive(QString sourceFilePath, const bool display, const bool toMainDirectory)
×
1965
{
1966
        Q_UNUSED(toMainDirectory)
1967
        if (!QFile::exists(sourceFilePath))
×
1968
        {
1969
                qDebug() << "LandscapeMgr: File does not exist:" << QDir::toNativeSeparators(sourceFilePath);
×
1970
                emit errorUnableToOpen(sourceFilePath);
×
1971
                return QString();
×
1972
        }
1973

1974
        QDir parentDestinationDir;
×
1975
        parentDestinationDir.setPath(StelFileMgr::getUserDir());
×
1976

1977
        if (!parentDestinationDir.exists("landscapes"))
×
1978
        {
1979
                //qDebug() << "LandscapeMgr: No 'landscapes' subdirectory exists in" << parentDestinationDir.absolutePath();
1980
                if (!parentDestinationDir.mkdir("landscapes"))
×
1981
                {
1982
                        qWarning() << "LandscapeMgr: Unable to install landscape: Unable to create sub-directory 'landscapes' in" << QDir::toNativeSeparators(parentDestinationDir.absolutePath());
×
1983
                        emit errorUnableToOpen(QDir::cleanPath(parentDestinationDir.filePath("landscapes")));//parentDestinationDir.absolutePath()
×
1984
                        return QString();
×
1985
                }
1986
        }
1987
        QDir destinationDir (parentDestinationDir.absoluteFilePath("landscapes"));
×
1988

1989
        #if USE_BUNDLED_QTCOMPRESS
1990
        Stel::QZipReader reader(sourceFilePath);
×
1991
        if (reader.status() != Stel::QZipReader::NoError)
×
1992
        #else
1993
        QZipReader reader(sourceFilePath);
1994
        if (reader.status() != QZipReader::NoError)
1995
        #endif
1996
        {
1997
                qWarning() << "LandscapeMgr: Unable to open as a ZIP archive:" << QDir::toNativeSeparators(sourceFilePath);
×
1998
                emit errorNotArchive();
×
1999
                return QString();
×
2000
        }
2001

2002
        //Detect top directory
2003
        QString topDir, iniPath;
×
2004
        const auto infoList = reader.fileInfoList();
×
2005
        for (const auto& info : infoList)
×
2006
        {
2007
                QFileInfo fileInfo(info.filePath);
×
2008
                if (fileInfo.fileName() == "landscape.ini")
×
2009
                {
2010
                        iniPath = info.filePath;
×
2011
                        topDir = fileInfo.dir().path();
×
2012
                        break;
×
2013
                }
2014
        }
×
2015
        if (topDir.isEmpty())
×
2016
        {
2017
                qWarning() << "LandscapeMgr: Unable to install landscape. There is no directory that contains a 'landscape.ini' file in the source archive.";
×
2018
                emit errorNotArchive();
×
2019
                return QString();
×
2020
        }
2021
        //Determine the landscape's identifier
2022
        QString landscapeID = QFileInfo(topDir).fileName();
×
2023
        if (landscapeID.length() < 2)
×
2024
        {
2025
                // If the archive has no top level directory
2026
                // use the first 65 characters of its file name for an identifier
2027
                QFileInfo sourceFileInfo(sourceFilePath);
×
2028
                landscapeID = sourceFileInfo.baseName().left(65);
×
2029
        }
×
2030

2031
        //Check for duplicate IDs
2032
        if (getAllLandscapeIDs().contains(landscapeID))
×
2033
        {
2034
                qWarning() << "LandscapeMgr: Unable to install landscape. A landscape with the ID" << landscapeID << "already exists.";
×
2035
                emit errorNotUnique(landscapeID);
×
2036
                return QString();
×
2037
        }
2038

2039
        //Read the .ini file and check if the landscape name is unique
2040
        QTemporaryFile tempLandscapeIni("landscapeXXXXXX.ini");
×
2041
        if (tempLandscapeIni.open())
×
2042
        {
2043
                QByteArray iniData = reader.fileData(iniPath);
×
2044
                tempLandscapeIni.write(iniData);
×
2045
                tempLandscapeIni.close();
×
2046
                QSettings confLandscapeIni(tempLandscapeIni.fileName(), StelIniFormat);
×
2047
                QString landscapeName = confLandscapeIni.value("landscape/name").toString();
×
2048
                if (getAllLandscapeNames().contains(landscapeName))
×
2049
                {
2050
                        qWarning() << "LandscapeMgr: Unable to install landscape. There is already a landscape named" << landscapeName;
×
2051
                        emit errorNotUnique(landscapeName);
×
2052
                        return QString();
×
2053
                }
2054
        }
×
2055

2056
        //Copy the landscape directory to the target
2057
        //This case already has been handled - and commented out - above. :)
2058
        if(destinationDir.exists(landscapeID))
×
2059
        {
2060
                qWarning() << "LandscapeMgr: A subdirectory" << landscapeID << "already exists in" << QDir::toNativeSeparators(destinationDir.absolutePath()) << "Its contents may be overwritten.";
×
2061
        }
2062
        else if(!destinationDir.mkdir(landscapeID))
×
2063
        {
2064
                qWarning() << "LandscapeMgr: Unable to install landscape. Unable to create" << landscapeID << "directory in" << QDir::toNativeSeparators(destinationDir.absolutePath());
×
2065
                emit errorUnableToOpen(QDir::cleanPath(destinationDir.filePath(landscapeID)));
×
2066
                return QString();
×
2067
        }
2068
        destinationDir.cd(landscapeID);
×
2069
        for (const auto& info : infoList)
×
2070
        {
2071
                QFileInfo fileInfo(info.filePath);
×
2072
                if (info.isFile && fileInfo.dir().path() == topDir)
×
2073
                {
2074
                        QByteArray data = reader.fileData(info.filePath);
×
2075
                        QFile out(destinationDir.filePath(fileInfo.fileName()));
×
2076
                        if (out.open(QIODevice::WriteOnly))
×
2077
                        {
2078
                                out.write(data);
×
2079
                                out.close();
×
2080
                        }
2081
                        else
2082
                        {
2083
                                qWarning() << "LandscapeMgr: cannot open " << QDir::toNativeSeparators(fileInfo.absoluteFilePath());
×
2084
                        }
2085
                }
×
2086
        }
×
2087
        reader.close();
×
2088
        //If necessary, make the new landscape the current landscape
2089
        if (display)
×
2090
        {
2091
                setCurrentLandscapeID(landscapeID);
×
2092
        }
2093

2094
        //Make sure that everyone knows that the list of available landscapes has changed
2095
        emit landscapesChanged();
×
2096

2097
        qDebug() << "LandscapeMgr: Successfully installed landscape directory" << landscapeID << "to" << QDir::toNativeSeparators(destinationDir.absolutePath());
×
2098
        return landscapeID;
×
2099
}
×
2100

2101
bool LandscapeMgr::removeLandscape(const QString landscapeID)
×
2102
{
2103
        if (landscapeID.isEmpty())
×
2104
        {
2105
                qWarning() << "LandscapeMgr: Error! No landscape ID passed to removeLandscape().";
×
2106
                return false;
×
2107
        }
2108

2109
        if (packagedLandscapeIDs.contains(landscapeID))
×
2110
        {
2111
                qWarning() << "LandscapeMgr: Landscapes that are part of the default installation cannot be removed.";
×
2112
                return false;
×
2113
        }
2114

2115
        qDebug() << "LandscapeMgr: Trying to remove landscape" << landscapeID;
×
2116

2117
        QString landscapePath = getLandscapePath(landscapeID);
×
2118
        if (landscapePath.isEmpty())
×
2119
                return false;
×
2120

2121
        QDir landscapeDir(landscapePath);
×
2122
        for (auto &fileName : landscapeDir.entryList(QDir::Files | QDir::NoDotAndDotDot))
×
2123
        {
2124
                if(!landscapeDir.remove(fileName))
×
2125
                {
2126
                        qWarning() << "LandscapeMgr: Unable to remove" << QDir::toNativeSeparators(fileName);
×
2127
                        emit errorRemoveManually(landscapeDir.absolutePath());
×
2128
                        return false;
×
2129
                }
2130
        }
×
2131
        landscapeDir.cdUp();
×
2132
        if(!landscapeDir.rmdir(landscapeID))
×
2133
        {
2134
                qWarning() << "LandscapeMgr: Error! Landscape" << landscapeID
×
2135
                                   << "could not be removed. "
×
2136
                                   << "Some files were deleted, but not all."
×
2137
                                   << StelUtils::getEndLineChar()
×
2138
                                   << "LandscapeMgr: You can delete manually" << QDir::cleanPath(landscapeDir.filePath(landscapeID));
×
2139
                emit errorRemoveManually(QDir::cleanPath(landscapeDir.filePath(landscapeID)));
×
2140
                return false;
×
2141
        }
2142

2143
        qDebug() << "LandscapeMgr: Successfully removed" << QDir::toNativeSeparators(landscapePath);
×
2144

2145
        //If the landscape has been selected, revert to the default one
2146
        //TODO: Make this optional?
2147
        if (getCurrentLandscapeID() == landscapeID)
×
2148
        {
2149
                if(getDefaultLandscapeID() == landscapeID)
×
2150
                {
2151
                        setDefaultLandscapeID(packagedLandscapeIDs.first());
×
2152
                        //TODO: Find what happens if a missing landscape is specified in the configuration file
2153
                }
2154

2155
                setCurrentLandscapeID(getDefaultLandscapeID());
×
2156
        }
2157

2158
        //Make sure that everyone knows that the list of available landscapes has changed
2159
        emit landscapesChanged();
×
2160

2161
        return true;
×
2162
}
×
2163

2164
QString LandscapeMgr::getLandscapePath(const QString landscapeID)
×
2165
{
2166
        QString result;
×
2167
        //Is this necessary? This function is private.
2168
        if (landscapeID.isEmpty())
×
2169
                return result;
×
2170

2171
        result = StelFileMgr::findFile("landscapes/" + landscapeID, StelFileMgr::Directory);
×
2172
        if (result.isEmpty())
×
2173
        {
2174
                qWarning() << "LandscapeMgr: Error! Unable to find" << landscapeID;
×
2175
                return result;
×
2176
        }
2177

2178
        return result;
×
2179
}
×
2180

2181
QString LandscapeMgr::loadLandscapeName(const QString landscapeID)
×
2182
{
2183
        QString landscapeName;
×
2184
        if (landscapeID.isEmpty())
×
2185
        {
2186
                qWarning() << "LandscapeMgr: Error! No landscape ID passed to loadLandscapeName().";
×
2187
                return landscapeName;
×
2188
        }
2189

2190
        QString landscapePath = getLandscapePath(landscapeID);
×
2191
        if (landscapePath.isEmpty())
×
2192
                return landscapeName;
×
2193

2194
        QDir landscapeDir(landscapePath);
×
2195
        if (landscapeDir.exists("landscape.ini"))
×
2196
        {
2197
                QString landscapeSettingsPath = landscapeDir.filePath("landscape.ini");
×
2198
                QSettings landscapeSettings(landscapeSettingsPath, StelIniFormat);
×
2199
                landscapeName = landscapeSettings.value("landscape/name").toString();
×
2200
        }
×
2201
        else
2202
        {
2203
                qWarning() << "LandscapeMgr: Error! Landscape directory" << QDir::toNativeSeparators(landscapePath) << "does not contain a 'landscape.ini' file";
×
2204
        }
2205

2206
        return landscapeName;
×
2207
}
×
2208

2209
quint64 LandscapeMgr::loadLandscapeSize(const QString landscapeID) const
×
2210
{
2211
        quint64 landscapeSize = 0;
×
2212
        if (landscapeID.isEmpty())
×
2213
        {
2214
                qWarning() << "LandscapeMgr: Error! No landscape ID passed to loadLandscapeSize().";
×
2215
                return landscapeSize;
×
2216
        }
2217

2218
        QString landscapePath = getLandscapePath(landscapeID);
×
2219
        if (landscapePath.isEmpty())
×
2220
                return landscapeSize;
×
2221

2222
        const QDir landscapeDir(landscapePath);
×
2223
        for (auto &file : landscapeDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot))
×
2224
        {
2225
                //qDebug() << "name:" << file.baseName() << "size:" << file.size();
2226
                landscapeSize += static_cast<quint64>(file.size());
×
2227
        }
×
2228

2229
        return landscapeSize;
×
2230
}
×
2231

2232
QString LandscapeMgr::getDescription() const
×
2233
{
2234
        QString lang, desc, descFile, locDescriptionFile, engDescriptionFile;
×
2235
        bool hasFile = true;
×
2236

2237
        lang = StelApp::getInstance().getLocaleMgr().getAppLanguage();
×
2238
        locDescriptionFile = StelFileMgr::findFile("landscapes/" + getCurrentLandscapeID(), StelFileMgr::Directory) + "/description." + lang + ".utf8";
×
2239
        engDescriptionFile = StelFileMgr::findFile("landscapes/" + getCurrentLandscapeID(), StelFileMgr::Directory) + "/description.en.utf8";
×
2240

2241
        // OK. Check the file with full name of locale
2242
        if (!QFileInfo::exists(locDescriptionFile))
×
2243
        {
2244
                // Oops...  File not exists! What about short name of locale?
2245
                lang = lang.split("_").at(0);
×
2246
                locDescriptionFile = StelFileMgr::findFile("landscapes/" + getCurrentLandscapeID(), StelFileMgr::Directory) + "/description." + lang + ".utf8";
×
2247
        }
2248

2249
        // Check localized description for landscape
2250
        if (!locDescriptionFile.isEmpty() && QFileInfo::exists(locDescriptionFile))
×
2251
        {                
2252
                descFile = locDescriptionFile;
×
2253
        }
2254
        // OK. Localized description of landscape not exists. What about english description of its?
2255
        else if (!engDescriptionFile.isEmpty() && QFileInfo::exists(engDescriptionFile))
×
2256
        {
2257
                descFile = engDescriptionFile;
×
2258
        }
2259
        // That file not exists too? OK. Will be used description from landscape.ini file.
2260
        else
2261
        {
2262
                hasFile = false;
×
2263
        }
2264

2265
        if (hasFile)
×
2266
        {
2267
                QFile file(descFile);
×
2268
                if(file.open(QIODevice::ReadOnly | QIODevice::Text))
×
2269
                {
2270
                        QTextStream in(&file);
×
2271
#if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
2272
                        in.setEncoding(QStringConverter::Utf8);
×
2273
#else
2274
                        in.setCodec("UTF-8");
2275
#endif
2276
                        desc = in.readAll();
×
2277
                        file.close();
×
2278
                }
×
2279
        }
×
2280
        else
2281
        {
2282
                desc = QString("<h2>%1</h2>").arg(q_(landscape->getName()));
×
2283
                desc += landscape->getDescription();
×
2284
        }
2285

2286
        return desc;
×
2287
}
×
2288

2289
void LandscapeMgr::increaseLightPollution()
×
2290
{
2291
        StelCore* core = StelApp::getInstance().getCore();
×
2292
        const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
×
2293
        auto bidx = core->luminanceToBortleScaleIndex(lum) + 1;
×
2294
        if (bidx>9)
×
2295
                bidx = 9;
×
2296
        const auto newLum = core->bortleScaleIndexToLuminance(bidx);
×
2297
        core->getSkyDrawer()->setLightPollutionLuminance(newLum);
×
2298
}
×
2299

2300
void LandscapeMgr::reduceLightPollution()
×
2301
{
2302
        StelCore* core = StelApp::getInstance().getCore();
×
2303
        const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
×
2304
        auto bidx = core->luminanceToBortleScaleIndex(lum) - 1;
×
2305
        if (bidx<1)
×
2306
                bidx = 1;
×
2307
        const auto newLum = core->bortleScaleIndexToLuminance(bidx);
×
2308
        core->getSkyDrawer()->setLightPollutionLuminance(newLum);
×
2309
}
×
2310

2311
void LandscapeMgr::cyclicChangeLightPollution()
×
2312
{
2313
        StelCore* core = StelApp::getInstance().getCore();
×
2314
        const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
×
2315
        auto bidx = core->luminanceToBortleScaleIndex(lum) + 1;
×
2316
        if (bidx>9)
×
2317
                bidx = 1;
×
2318
        const auto newLum = core->bortleScaleIndexToLuminance(bidx);
×
2319
        core->getSkyDrawer()->setLightPollutionLuminance(newLum);
×
2320
}
×
2321

2322
/*
2323
// GZ: Addition to identify landscape transparency. Used for development and debugging only, should be commented out in release builds.
2324
// Also, StelMovementMgr l.382 event->accept() must be commented out for this here to work!
2325
void LandscapeMgr::handleMouseClicks(QMouseEvent *event)
2326
{
2327
        switch (event->button())
2328
        {
2329
        case Qt::LeftButton :
2330
                if (event->type()==QEvent::MouseButtonRelease)
2331
                {
2332
                        Vec3d v;
2333
                        StelApp::getInstance().getCore()->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff)->unProject(event->x(),event->y(),v);
2334
                        v.normalize();
2335
                        float trans=landscape->getOpacity(v);
2336
                        qDebug() << "Landscape opacity at screen X=" << event->x() << ", Y=" << event->y() << ": " << trans;
2337
                }
2338
                break;
2339
        default: break;
2340

2341
        }
2342
        // do not event->accept(), so that it is forwarded to other modules.
2343
        return;
2344
}
2345
*/
2346

2347
void LandscapeMgr::showMessage(const QString& message)
×
2348
{
2349
        messageToShow=message;
×
2350
        messageFader=true;
×
2351
        messageTimer->start();
×
2352
}
×
2353

2354
void LandscapeMgr::clearMessage()
×
2355
{
2356
        messageFader = false;
×
2357
}
×
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