summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuslan Kabatsayev <b7.10110111@gmail.com>2022-02-01 06:30:21 +0300
committerGitHub <noreply@github.com>2022-02-01 10:30:21 +0700
commitfe006ab5b01abacd2798a25642433347b75b078e (patch)
tree724210df1590b77f0e2ab7ddec0d8154bd776399
parentb5c0bb76795f3d52c2883e57d36fc6c8f535297d (diff)
Switch from Bortle class to luminance as the quantity of light pollution (#2179)
* Switch from Bortle class to luminance as the quantity of light pollution Bortle scale has several disadvantages: 1. It was designed as a guide for humans, not input for machines. From this follows the next disadvantage. 2. It's discrete: each point on the scale corresponds to a range of NELM values, which makes it imprecise as input for a program. 3. It's subjective: based on naked-eye limiting magnitude that depends on observer's visual acuity. 4. It isn't as widely used (and thus validated) as photometric units. OTOH, luminance is the quantity that defines all the relevant effects of light pollution. This commit makes luminance in cd/m² the input parameter, leaving for backwards compatibility the option of supplying Bortle class in Landscapes. Some changes to calculations had to be introduced, as listed below. 1. `StelSkyDrawer::getNELMFromBortleScale` was reimplemented in `StelCore::bortleScaleIndexToNELM` using a bit different representative values of NELM - to simplify the comment documenting the choice. The values are almost the same: each old value except one will be reproduced by adding 0.05 to the new ones. 2. Calculation of `B_mpsas` in `Nebula.cpp` was trying to convert from Bortle class to magnitude scale using some formula from Schaefer paper, the same paper as I used in `StelCore::luminanceToNELM`, but without explaining the steps to get the formula. The old expression form `Nebula.cpp` (which is widespread over the Internet) doesn't work near NELM==8 (see the discussion at https://astronomy.stackexchange.com/q/43313), while the one I used does. Anyway, `Nebula`'s logic is tied to luminance, so if the user supplies luminance instead of Bortle class, it'll be as intended. For some reason, stars/init_bortle_scale setting defaulted to 3 while StelLocation::DEFAULT_BORTLE_SCALE_INDEX is 2. I've retained these preferences. Technical note: I had to use `QVariant` instead of an `optional` type because Stellarium isn't using C++≥17 (C++17 has `std::optional`), nor anything from Boost (which has `boost::optional`). The other alternative was to make my own `optional`, but that seemed like overkill. * Implement a better GUI for light pollution settings * Make brightness of the Milky Way, zodiacal light, landscape and the stars change smoothly with changes in light pollution * Update the docs for the View→Sky GUI * Add description of the light pollution model
-rw-r--r--guide/ch_interface.tex24
-rw-r--r--guide/ch_skylight.tex20
-rw-r--r--guide/guide.bib13
-rw-r--r--guide/pictures/view_dialog_sky_tab.pngbin287972 -> 166006 bytes
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/core/StelCore.cpp61
-rw-r--r--src/core/StelCore.hpp17
-rw-r--r--src/core/StelLocation.cpp20
-rw-r--r--src/core/StelLocation.hpp9
-rw-r--r--src/core/StelLocationMgr.cpp6
-rw-r--r--src/core/StelSkyDrawer.cpp59
-rw-r--r--src/core/StelSkyDrawer.hpp46
-rw-r--r--src/core/modules/Landscape.cpp16
-rw-r--r--src/core/modules/Landscape.hpp9
-rw-r--r--src/core/modules/LandscapeMgr.cpp54
-rw-r--r--src/core/modules/LandscapeMgr.hpp9
-rw-r--r--src/core/modules/MilkyWay.cpp6
-rw-r--r--src/core/modules/Nebula.cpp5
-rw-r--r--src/core/modules/ZodiacalLight.cpp3
-rw-r--r--src/gui/ConfigurationDialog.cpp2
-rw-r--r--src/gui/LightPollutionWidget.cpp324
-rw-r--r--src/gui/LightPollutionWidget.hpp57
-rw-r--r--src/gui/LogarithmicSpinBox.cpp24
-rw-r--r--src/gui/LogarithmicSpinBox.hpp13
-rw-r--r--src/gui/ViewDialog.cpp78
-rw-r--r--src/gui/ViewDialog.hpp5
-rw-r--r--src/gui/lightPollutionWidget.ui137
-rw-r--r--src/gui/viewDialog.ui58
-rw-r--r--src/scripting/StelMainScriptAPI.cpp3
29 files changed, 812 insertions, 271 deletions
diff --git a/guide/ch_interface.tex b/guide/ch_interface.tex
index 92cb6ceeb8..10a65824e8 100644
--- a/guide/ch_interface.tex
+++ b/guide/ch_interface.tex
@@ -460,12 +460,28 @@ for changing the general appearance of the main sky view and projections. Some h
brightness of faint objects when a bright object is in the field of
view. This simulates how the eye can be dazzled by a bright object
such as the moon, making it harder to see faint stars and galaxies.
+\begin{samepage} % If the list of options is page-broken from the beginning of the "Light pollution" item, it becomes hard to orient in the text due to starting a page with a nested list.
\item[Light pollution] In urban and suburban areas, the sky is
brightened by terrestrial light pollution reflected in the atmosphere.
- Stellarium simulates light pollution and is calibrated to the
- \emph{Bortle Dark Sky Scale} where 1 means a good dark sky, and 9 is
- a very badly light-polluted sky. See Appendix~\ref{ch:BortleScale}
- for more information.
+ Stellarium simulates light pollution and lets the user configure how bright
+ the night sky is.
+ There are several ways to set it up:
+ \begin{description}
+ \item[Automatic from locations database] option makes Stellarium find sky
+ brightness from its locations database and simulate light pollution
+ without any further user input.
+ \item[Manual] mode lets the user choose the amount of light pollution by
+ moving a slider. To make it easier to orient in the resulting amount of
+ light pollution, a tooltip will show the classification of the sky
+ according to the \emph{Bortle Dark Sky Scale} (See Appendix~\ref{ch:BortleScale}
+ for more information), as well as the naked-eye limiting magnitude.
+ \item[Manual from SQM] mode lets one enter the reading of a \emph{Sky Quality Meter}.
+ Stellarium can accept it in several units: physical ($\mathrm{cd/m^2}$,
+ $\mathrm{mcd/m^2}$, $\mathrm{\mu cd/m^2}$) as well as astronomical,
+ $\mathrm{mag/arcsec^2}$. To enter a value, first choose the unit, and
+ then type the number into the spinbox.
+ \end{description}
+\end{samepage}
\item[Solar altitude for Twilight Finder] You can configure \newFeature{0.21.2}
shortcut keys to go to the time when the sun reaches this altitude below the
mathematical horizon. See section~\ref{sec:gui:help:hotkeys:example}.
diff --git a/guide/ch_skylight.tex b/guide/ch_skylight.tex
index d455453b04..79d6f78e76 100644
--- a/guide/ch_skylight.tex
+++ b/guide/ch_skylight.tex
@@ -69,6 +69,26 @@ disk and the solar glare. It makes a slight difference whether the
Sun's disk is plotted before or after the glare, and whether the solar
sphere is rendered after the atmosphere.
+\section{Light Pollution}
+
+In urban and suburban areas the night sky is lit by ground sources of light.
+This light is scattered by the atmosphere, and the sky appears brighter. This
+reduces visibility of astronomical objects.
+
+Stellarium simulates this effect. The main physical quantity that describes light pollution is zenith luminance, measured in candelas per square meter ($\mathrm{cd/m^2}$). It can be measured using a device called \emph{sky quality meter} (SQM).
+
+For astronomical observations often another unit of sky brightness is useful: magnitudes per square arcsecond ($\mathrm{mag/arcsec^2}$). It is related to $\mathrm{cd/m^2}$ as
+\begin{equation}
+L=10.8\times10^{4-0.4M},
+\end{equation}
+where $L$ is the value in $\mathrm{cd/m^2}$, and $M$ is the value in $\mathrm{mag/arcsec^2}$. Some SQMs give readings in $\mathrm{mag/arcsec^2}$. Stellarium supports input in both units.
+
+Another way to characterize light pollution is by defining the \emph{naked-eye limiting magnitude} (NELM). Unlike luminance, which, although based on human vision, is well-standardized (in particular, the candela is part of the SI), NELM is subjective and variable: it is based on human vision, depends on weather conditions, and is not standardized. In Stellarium the calculations follow \citet{Schaefer:LimitingMagnitudes}. In particular, equation $(18)$ is used, assuming observer's acuity $F_s=1$ (as suggested in the text as ``typical observer''), and absorption term $k_v=0.3$ (as suggested for ``typical weather'').
+
+A related subjective characterization of light pollution is the \emph{Bortle Dark Sky Scale}, which assigns an integral number from 1 to 9 to the sky based on its brightness. This scale is described in detail in Appendix~\ref{ch:BortleScale}.
+
+Stellarium calculates both Bortle class and NELM for user convenience. They aren't used in the actual calculations for visualization.
+
\section{Tone Mapping}
Tone mapping is the process which attempts to compress the brightness
diff --git a/guide/guide.bib b/guide/guide.bib
index fe5a0c0b29..601f45f786 100644
--- a/guide/guide.bib
+++ b/guide/guide.bib
@@ -1942,6 +1942,19 @@ archivePrefix = {arXiv},
OPTnote = {},
OPTannote = {}
}
+@Article{Schaefer:LimitingMagnitudes,
+ author = {Bradley E. Schaefer},
+ title = {{Telescopic Limiting Magnitudes}},
+ journal = {Publications of the Astronomical Society of the Pacific},
+ year = {1990},
+ OPTkey = {},
+ volume = {102},
+ OPTnumber = {648},
+ pages = {212--229},
+ OPTmonth = {},
+ OPTnote = {},
+ OPTannote = {}
+}
@TechReport{HiPS,
author = {Pierre Fernique},
diff --git a/guide/pictures/view_dialog_sky_tab.png b/guide/pictures/view_dialog_sky_tab.png
index ad10cca114..2871134042 100644
--- a/guide/pictures/view_dialog_sky_tab.png
+++ b/guide/pictures/view_dialog_sky_tab.png
Binary files differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4ab557fb7b..cebde0f7fa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -320,6 +320,10 @@ IF(STELLARIUM_GUI_MODE STREQUAL "Standard")
gui/DateTimeDialog.cpp
gui/ViewDialog.hpp
gui/ViewDialog.cpp
+ gui/LightPollutionWidget.hpp
+ gui/LightPollutionWidget.cpp
+ gui/LogarithmicSpinBox.hpp
+ gui/LogarithmicSpinBox.cpp
gui/SearchDialog.hpp
gui/SearchDialog.cpp
gui/ConfigurationDialog.hpp
@@ -364,6 +368,7 @@ IF(STELLARIUM_GUI_MODE STREQUAL "Standard")
gui/shortcutsDialog.ui
gui/dateTimeDialogGui.ui
gui/viewDialog.ui
+ gui/lightPollutionWidget.ui
gui/searchDialogGui.ui
gui/configurationDialog.ui
gui/atmosphereDialog.ui
diff --git a/src/core/StelCore.cpp b/src/core/StelCore.cpp
index dbe60654e1..cfef1b53e5 100644
--- a/src/core/StelCore.cpp
+++ b/src/core/StelCore.cpp
@@ -1166,7 +1166,7 @@ void StelCore::moveObserverToSelected()
loc.state = "";
loc.longitude=ni->getLongitude();
loc.latitude=ni->getLatitude();
- loc.bortleScaleIndex=1;
+ loc.lightPollutionLuminance = 0;
moveObserverTo(loc);
objmgr->unSelect(); // no use to keep it: Marker will flicker around the screen.
@@ -2726,6 +2726,65 @@ QString StelCore::getIAUConstellation(const Vec3d positionEqJnow) const
return "(?)";
}
+// NELM = naked-eye limiting magnitude
+int StelCore::nelmToBortleScaleIndex(const float nelm)
+{
+ // Ref: Bortle, John E. (February 2001). "Gauging Light Pollution: The Bortle Dark-Sky Scale".
+ // Sky & Telescope. Sky Publishing Corporation.
+ // https://skyandtelescope.org/astronomy-resources/light-pollution-and-astronomy-the-bortle-dark-sky-scale/
+ if(nelm < 4.0) return 9;
+ if(nelm < 4.5) return 8;
+ if(nelm < 5.0) return 7;
+ if(nelm < 5.5) return 6;
+ if(nelm < 6.0) return 5;
+ if(nelm < 6.5) return 4;
+ if(nelm < 7.0) return 3;
+ if(nelm < 7.5) return 2;
+ return 1;
+}
+
+float StelCore::bortleScaleIndexToNELM(const int index)
+{
+ // This is kind of inverse of nelmToBortleScaleIndex(), where the "representative NELM" is chosen to be
+ // the middle of the interval of the NELM values for the inner indices (2-8), and the same distance from
+ // the boundary for outer indices (1 and 9).
+ switch(index)
+ {
+ case 1: return 7.75;
+ case 2: return 7.25;
+ case 3: return 6.75;
+ case 4: return 6.25;
+ case 5: return 5.75;
+ case 6: return 5.25;
+ case 7: return 4.75;
+ case 8: return 4.25;
+ case 9: return 3.75;
+ default:
+ qWarning().nospace() << "Bortle scale index " << index << " out of range";
+ return 0; // Let the problem be visible
+ }
+}
+
+float StelCore::luminanceToNELM(const float luminance)
+{
+ // Ref: Schaefer, B. E.. "Telescopic limiting magnitudes". Astronomical Society of the Pacific,
+ // Publications (ISSN 0004-6280), vol. 102, Feb. 1990, p. 212-229.
+ // http://adsbit.harvard.edu/cgi-bin/nph-iarticle_query?bibcode=1990PASP..102..212S
+ //
+ // Using formula (18), assuming observer's acuity Fₛ=1 (as suggested in the text as "typical observer"),
+ // absorption term kᵥ=0.3 (as suggested for "typical weather"), coefficient for Bₛ is adjusted to take
+ // the value in cd/m².
+ //
+ return 8.32f - 2.17147240951626f*std::log(1 + 88.5588612190873f*std::sqrt(luminance));
+}
+
+float StelCore::nelmToLuminance(const float nelm)
+{
+ // This is just the inverse of luminanceToNELM()
+ const auto toSquare = std::exp(3.8315015947420905f-0.46051701859880895f*nelm) - 1;
+ return toSquare*toSquare*0.0001275075653676456f;
+}
+
Vec3d StelCore::getMouseJ2000Pos() const
{
const StelProjectorP prj = getProjection(StelCore::FrameJ2000, StelCore::RefractionAuto);
diff --git a/src/core/StelCore.hpp b/src/core/StelCore.hpp
index 7dd789175e..59a2c14280 100644
--- a/src/core/StelCore.hpp
+++ b/src/core/StelCore.hpp
@@ -750,6 +750,23 @@ public slots:
//! @param positionEqJnow position vector in rectangular equatorial coordinates of current epoch&equinox.
QString getIAUConstellation(const Vec3d positionEqJnow) const;
+ //! Returns naked-eye limiting magnitude corresponding to the given sky luminance in cd/m².
+ static float luminanceToNELM(float luminance);
+ //! Returns sky luminance in cd/m² corresponding to the given naked-eye limiting magnitude.
+ static float nelmToLuminance(float nelm);
+ //! Returns some representative naked-eye limiting magnitude for the given Bortle scale index.
+ static float bortleScaleIndexToNELM(int index);
+ //! Returns some representative value of zenith luminance in cd/m² for the given Bortle scale index.
+ static float bortleScaleIndexToLuminance(const int index) { return nelmToLuminance(bortleScaleIndexToNELM(index)); }
+ //! Classifies the sky using the Bortle scale using zenith naked-eye limiting magnitude as input.
+ static int nelmToBortleScaleIndex(float nelm);
+ //! Classifies the sky using the Bortle scale using zenith luminance in cd/m² as input.
+ static int luminanceToBortleScaleIndex(const float luminance) { return nelmToBortleScaleIndex(luminanceToNELM(luminance)); }
+ //! Converts luminance in cd/m² to magnitude/arcsec².
+ static float luminanceToMPSAS(const float cdm2) { return std::log10(cdm2/10.8e4f) / -0.4f; }
+ //! Converts magnitude/arcsec² to luminance in cd/m².
+ static float mpsasToLuminance(const float mag) { return 10.8e4f*std::pow(10.f, -0.4f*mag); }
+
signals:
//! This signal is emitted when the observer location has changed.
void locationChanged(const StelLocation&);
diff --git a/src/core/StelLocation.cpp b/src/core/StelLocation.cpp
index 42ad3bb2a9..f13c40f006 100644
--- a/src/core/StelLocation.cpp
+++ b/src/core/StelLocation.cpp
@@ -27,7 +27,7 @@
#include <QTimeZone>
#include <QStringList>
-const int StelLocation::DEFAULT_BORTLE_SCALE_INDEX = 2;
+const float StelLocation::DEFAULT_LIGHT_POLLUTION_LUMINANCE = StelCore::bortleScaleIndexToLuminance(2);
int StelLocation::metaTypeId = initMetaType();
int StelLocation::initMetaType()
@@ -50,7 +50,8 @@ QString StelLocation::serializeToLine() const
latitude<0 ? QString("%1S").arg(-latitude, 0, 'f', 6) : QString("%1N").arg(latitude, 0, 'f', 6),
longitude<0 ? QString("%1W").arg(-longitude, 0, 'f', 6) : QString("%1E").arg(longitude, 0, 'f', 6),
QString::number(altitude),
- QString::number(bortleScaleIndex)).arg(
+ QString::number(lightPollutionLuminance.isValid() ? lightPollutionLuminance.toFloat() : DEFAULT_LIGHT_POLLUTION_LUMINANCE)
+ ).arg(
sanitizedTZ,
planetName,
landscapeKey);
@@ -70,13 +71,18 @@ QString StelLocation::getID() const
// GZ TODO: These operators may require sanitizing for timezone names!
QDataStream& operator<<(QDataStream& out, const StelLocation& loc)
{
- out << loc.name << loc.state << loc.region << loc.role << loc.population << loc.latitude << loc.longitude << loc.altitude << loc.bortleScaleIndex << loc.ianaTimeZone << loc.planetName << loc.landscapeKey << loc.isUserLocation;
+ const auto lum = loc.lightPollutionLuminance.toFloat();
+ const int bortleScaleIndex = loc.lightPollutionLuminance.isValid() ? StelCore::luminanceToBortleScaleIndex(lum) : -1;
+ out << loc.name << loc.state << loc.region << loc.role << loc.population << loc.latitude << loc.longitude << loc.altitude << bortleScaleIndex << loc.ianaTimeZone << loc.planetName << loc.landscapeKey << loc.isUserLocation;
return out;
}
QDataStream& operator>>(QDataStream& in, StelLocation& loc)
{
- in >> loc.name >> loc.state >> loc.region >> loc.role >> loc.population >> loc.latitude >> loc.longitude >> loc.altitude >> loc.bortleScaleIndex >> loc.ianaTimeZone >> loc.planetName >> loc.landscapeKey >> loc.isUserLocation;
+ int bortleScaleIndex;
+ in >> loc.name >> loc.state >> loc.region >> loc.role >> loc.population >> loc.latitude >> loc.longitude >> loc.altitude >> bortleScaleIndex >> loc.ianaTimeZone >> loc.planetName >> loc.landscapeKey >> loc.isUserLocation;
+ if(bortleScaleIndex > 0)
+ loc.lightPollutionLuminance = StelCore::bortleScaleIndexToLuminance(bortleScaleIndex);
return in;
}
@@ -126,12 +132,12 @@ StelLocation StelLocation::createFromLine(const QString& rawline)
if (splitline.size()>8)
{
bool ok;
- loc.bortleScaleIndex = splitline.at(8).toInt(&ok);
+ loc.lightPollutionLuminance = splitline.at(8).toFloat(&ok);
if (ok==false)
- loc.bortleScaleIndex = DEFAULT_BORTLE_SCALE_INDEX;
+ loc.lightPollutionLuminance = DEFAULT_LIGHT_POLLUTION_LUMINANCE;
}
else
- loc.bortleScaleIndex = DEFAULT_BORTLE_SCALE_INDEX;
+ loc.lightPollutionLuminance = DEFAULT_LIGHT_POLLUTION_LUMINANCE;
if (splitline.size()>9)
{
diff --git a/src/core/StelLocation.hpp b/src/core/StelLocation.hpp
index eb60c38a9a..e416df81b9 100644
--- a/src/core/StelLocation.hpp
+++ b/src/core/StelLocation.hpp
@@ -20,6 +20,7 @@
#define STELLOCATION_HPP
#include <QString>
+#include <QVariant>
#include <QMetaType>
class Planet;
@@ -29,7 +30,7 @@ class Planet;
class StelLocation
{
public:
- StelLocation() : longitude(0.f), latitude(0.f), altitude(0), bortleScaleIndex(2), population(0.f), role('X'), isUserLocation(true) {}
+ StelLocation() : longitude(0.f), latitude(0.f), altitude(0), population(0.f), role('X'), isUserLocation(true) {}
//! Return a short string which can be used in a list view.
QString getID() const;
@@ -65,8 +66,8 @@ public:
float latitude;
//! Altitude in meter
int altitude;
- //! Light pollution index following Bortle scale
- int bortleScaleIndex;
+ //! Zenith luminance at moonless night as could be measured by a Sky Quality Meter, in cd/m²
+ QVariant lightPollutionLuminance;
//! A hint for associating a landscape to the location
QString landscapeKey;
//! Population in number of inhabitants
@@ -110,7 +111,7 @@ public:
//! Used privately by the StelLocationMgr
bool isUserLocation;
- static const int DEFAULT_BORTLE_SCALE_INDEX;
+ static const float DEFAULT_LIGHT_POLLUTION_LUMINANCE;
private:
static QString getRegionFromCode(const QString& code);
//Register with Qt
diff --git a/src/core/StelLocationMgr.cpp b/src/core/StelLocationMgr.cpp
index cca0d82ca1..d7521ffd8b 100644
--- a/src/core/StelLocationMgr.cpp
+++ b/src/core/StelLocationMgr.cpp
@@ -223,7 +223,7 @@ void LibGPSLookupHelper::query()
if (verbose)
qDebug() << "GPSD location" << QString("lat %1, long %2, alt %3").arg(loc.latitude).arg(loc.longitude).arg(loc.altitude);
- loc.bortleScaleIndex=StelLocation::DEFAULT_BORTLE_SCALE_INDEX;
+ loc.lightPollutionLuminance=StelLocation::DEFAULT_LIGHT_POLLUTION_LUMINANCE;
// Usually you don't leave your time zone with GPS.
loc.ianaTimeZone=StelApp::getInstance().getCore()->getCurrentTimeZone();
loc.isUserLocation=true;
@@ -385,7 +385,7 @@ void NMEALookupHelper::nmeaUpdated(const QGeoPositionInfo &update)
loc.altitude=( qIsNaN(coord.altitude()) ? 0 : static_cast<int>(floor(coord.altitude())));
if (verbose)
qDebug() << "Location in progress: Long=" << loc.longitude << " Lat=" << loc.latitude << " Alt" << loc.altitude;
- loc.bortleScaleIndex=StelLocation::DEFAULT_BORTLE_SCALE_INDEX;
+ loc.lightPollutionLuminance=StelLocation::DEFAULT_LIGHT_POLLUTION_LUMINANCE;
// Usually you don't leave your time zone with GPS.
loc.ianaTimeZone=core->getCurrentTimeZone();
loc.isUserLocation=true;
@@ -1043,7 +1043,7 @@ void StelLocationMgr::changeLocationFromNetworkLookup()
loc.latitude = static_cast<float>(latitude);
loc.longitude = static_cast<float>(longitude);
loc.altitude = 0;
- loc.bortleScaleIndex = StelLocation::DEFAULT_BORTLE_SCALE_INDEX;
+ loc.lightPollutionLuminance = StelLocation::DEFAULT_LIGHT_POLLUTION_LUMINANCE;
loc.ianaTimeZone = (ipTimeZone.isEmpty() ? "" : ipTimeZone);
loc.planetName = "Earth";
loc.landscapeKey = "";
diff --git a/src/core/StelSkyDrawer.cpp b/src/core/StelSkyDrawer.cpp
index 4efe36d03a..d2a8caedba 100644
--- a/src/core/StelSkyDrawer.cpp
+++ b/src/core/StelSkyDrawer.cpp
@@ -67,7 +67,6 @@ StelSkyDrawer::StelSkyDrawer(StelCore* acore) :
customStarMagLimit(0.0),
customNebulaMagLimit(0.0),
customPlanetMagLimit(0.0),
- bortleScaleIndex(3),
inScale(1.f),
starShaderProgram(Q_NULLPTR),
starShaderVars(StarShaderVars()),
@@ -100,7 +99,7 @@ StelSkyDrawer::StelSkyDrawer(StelCore* acore) :
setFlagNebulaMagnitudeLimit(conf->value("astro/flag_nebula_magnitude_limit", false).toBool());
setCustomNebulaMagnitudeLimit(conf->value("astro/nebula_magnitude_limit", 8.5).toDouble());
- setBortleScaleIndex(conf->value("stars/init_bortle_scale", 3).toInt());
+ setLightPollutionLuminance(conf->value("stars/init_light_pollution_luminance", StelCore::bortleScaleIndexToLuminance(3)).toFloat());
setRelativeStarScale(conf->value("stars/relative_scale", 1.0).toDouble());
setAbsoluteStarScale(conf->value("stars/absolute_scale", 1.0).toDouble());
setExtinctionCoefficient(conf->value("landscape/atmospheric_extinction_coefficient", 0.13).toDouble());
@@ -214,15 +213,17 @@ void StelSkyDrawer::update(double)
fov = minAdaptFov;
}
- // GZ: Light pollution must take global atmosphere setting into acount!
- // moved parts from setBortleScale() here
- // These value have been calibrated by hand, looking at the faintest star in stellarium at around 40 deg FOV
- // They should roughly match the scale described at http://en.wikipedia.org/wiki/Bortle_Dark-Sky_Scale
- static const float bortleToInScale[9] = {2.45f, 1.55f, 1.0f, 0.63f, 0.40f, 0.24f, 0.23f, 0.145f, 0.09f};
if (getFlagHasAtmosphere() && core->getJD()>2387627.5) // JD given is J1825.0; ignore Bortle scale index before that.
- setInputScale(bortleToInScale[bortleScaleIndex-1]);
+ {
+ // GZ: Light pollution must take global atmosphere setting into acount!
+ // moved parts from setBortleScale() here
+ // This formula is a fit to a set of values calibrated by hand, looking at the faintest star in stellarium at around 40 deg FOV.
+ // It should roughly match the scale described at http://en.wikipedia.org/wiki/Bortle_Dark-Sky_Scale
+ const auto nelm = StelCore::luminanceToNELM(lightPollutionLuminance);
+ setInputScale(3.3541f*std::exp(-0.404f*(16.5f-2*nelm)));
+ }
else
- setInputScale(bortleToInScale[0]);
+ setInputScale(2.45f);
// This factor is fully arbitrary. It corresponds to the collecting area x exposure time of the instrument
// It is based on a power law, so that it varies progressively with the FOV to smoothly switch from human
@@ -661,25 +662,17 @@ void StelSkyDrawer::preDraw()
}
-// Set the parameters so that the stars disappear at about the limit given by the bortle scale
-// See http://en.wikipedia.org/wiki/Bortle_Dark-Sky_Scale
-void StelSkyDrawer::setBortleScaleIndex(int bIndex)
+void StelSkyDrawer::setLightPollutionLuminance(const double luminance)
{
- if(bortleScaleIndex!=bIndex)
- {
- // Associate the Bortle index (1 to 9) to inScale value
- if ((bIndex<1) || (bIndex>9))
- {
- qWarning() << "WARNING: Bortle scale index range is [1;9], given" << bIndex;
- }
- bortleScaleIndex = qBound(1, bIndex, 9);
- emit bortleScaleIndexChanged(bortleScaleIndex);
- // GZ: I moved this block to update()
- // These value have been calibrated by hand, looking at the faintest star in stellarium at around 40 deg FOV
- // They should roughly match the scale described at http://en.wikipedia.org/wiki/Bortle_Dark-Sky_Scale
- // static const float bortleToInScale[9] = {2.45, 1.55, 1.0, 0.63, 0.40, 0.24, 0.23, 0.145, 0.09};
- // setInputScale(bortleToInScale[bIndex-1]);
- }
+ if(lightPollutionLuminance==luminance)
+ return;
+ lightPollutionLuminance=luminance;
+ emit lightPollutionLuminanceChanged(luminance);
+}
+
+int StelSkyDrawer::getBortleScaleIndex() const
+{
+ return StelCore::luminanceToBortleScaleIndex(lightPollutionLuminance);
}
void StelSkyDrawer::setFlagStarSpiky(bool b)
@@ -691,18 +684,6 @@ void StelSkyDrawer::setFlagStarSpiky(bool b)
}
}
-float StelSkyDrawer::getNELMFromBortleScale() const
-{
- return getNELMFromBortleScale(getBortleScaleIndex());
-}
-
-float StelSkyDrawer::getNELMFromBortleScale(int idx)
-{
- const float nelms[9] = {7.8f, 7.3f, 6.8f, 6.3f, 5.8f, 5.3f, 4.8f, 4.3f, 4.0f};
- idx = qBound(1, idx, 9);
- return nelms[idx-1];
-}
-
// colors for B-V display
Vec3f StelSkyDrawer::colorTable[128] = {
Vec3f(0.602745f,0.713725f,1.000000f),
diff --git a/src/core/StelSkyDrawer.hpp b/src/core/StelSkyDrawer.hpp
index 787fb0e6a1..0497aaf10c 100644
--- a/src/core/StelSkyDrawer.hpp
+++ b/src/core/StelSkyDrawer.hpp
@@ -56,7 +56,7 @@ class StelSkyDrawer : public QObject, protected QOpenGLFunctions
Q_PROPERTY(double absoluteStarScale READ getAbsoluteStarScale WRITE setAbsoluteStarScale NOTIFY absoluteStarScaleChanged)
Q_PROPERTY(double twinkleAmount READ getTwinkleAmount WRITE setTwinkleAmount NOTIFY twinkleAmountChanged)
Q_PROPERTY(bool flagStarTwinkle READ getFlagTwinkle WRITE setFlagTwinkle NOTIFY flagTwinkleChanged)
- Q_PROPERTY(int bortleScaleIndex READ getBortleScaleIndex WRITE setBortleScaleIndex NOTIFY bortleScaleIndexChanged)
+ Q_PROPERTY(double lightPollutionLuminance READ getLightPollutionLuminance WRITE setLightPollutionLuminance NOTIFY lightPollutionLuminanceChanged)
Q_PROPERTY(bool flagDrawBigStarHalo READ getFlagDrawBigStarHalo WRITE setFlagDrawBigStarHalo NOTIFY flagDrawBigStarHaloChanged)
Q_PROPERTY(bool flagStarSpiky READ getFlagStarSpiky WRITE setFlagStarSpiky NOTIFY flagStarSpikyChanged)
@@ -195,36 +195,14 @@ public slots:
//! @note option for planetariums
bool getFlagForcedTwinkle() const {return flagForcedTwinkle;}
- //! Set the parameters so that the stars disappear at about the limit given by the bortle scale
+ //! Set the parameters so that the stars disappear at about the naked-eye limiting magnitude corresponding
+ //! to the given zenith luminance at moonless night.
//! The limit is valid only at a given zoom level (around 60 deg)
- //! @see https://en.wikipedia.org/wiki/Bortle_scale
- void setBortleScaleIndex(int index);
- //! Get the current Bortle scale index
- //! @see https://en.wikipedia.org/wiki/Bortle_scale
- int getBortleScaleIndex() const {return bortleScaleIndex;}
- //! Get the average Naked-Eye Limiting Magnitude (NELM) for current Bortle scale index:
- //! Class 1 = NELM 7.6-8.0; average NELM is 7.8
- //! Class 2 = NELM 7.1-7.5; average NELM is 7.3
- //! Class 3 = NELM 6.6-7.0; average NELM is 6.8
- //! Class 4 = NELM 6.1-6.5; average NELM is 6.3
- //! Class 5 = NELM 5.6-6.0; average NELM is 5.8
- //! Class 6 = NELM 5.1-5.5; average NELM is 5.3
- //! Class 7 = NELM 4.6-5.0; average NELM is 4.8
- //! Class 8 = NELM 4.1-4.5; average NELM is 4.3
- //! Class 9 = NELM 4.0
- float getNELMFromBortleScale() const;
- //! Get the average Naked-Eye Limiting Magnitude (NELM) for given Bortle scale index [1..9]
- //! Class 1 = NELM 7.6-8.0; average NELM is 7.8
- //! Class 2 = NELM 7.1-7.5; average NELM is 7.3
- //! Class 3 = NELM 6.6-7.0; average NELM is 6.8
- //! Class 4 = NELM 6.1-6.5; average NELM is 6.3
- //! Class 5 = NELM 5.6-6.0; average NELM is 5.8
- //! Class 6 = NELM 5.1-5.5; average NELM is 5.3
- //! Class 7 = NELM 4.6-5.0; average NELM is 4.8
- //! Class 8 = NELM 4.1-4.5; average NELM is 4.3
- //! Class 9 = NELM 4.0
- //! @arg idx Bortle Scale Index (valid: 1..9, will be forced to valid range)
- static float getNELMFromBortleScale(int idx);
+ void setLightPollutionLuminance(double luminance);
+ //! Get the current zenith luminance at moonless night.
+ double getLightPollutionLuminance() const {return lightPollutionLuminance;}
+
+ Q_DECL_DEPRECATED int getBortleScaleIndex() const;
//! Set flag for drawing a halo around bright stars.
void setFlagDrawBigStarHalo(bool b) {if(b!=flagDrawBigStarHalo){ flagDrawBigStarHalo=b; emit flagDrawBigStarHaloChanged(b);}}
@@ -368,8 +346,8 @@ signals:
void twinkleAmountChanged(double b);
//! Emitted whenever the twinkle flag is toggled
void flagTwinkleChanged(bool b);
- //! Emitted whenever the Bortle scale index changed
- void bortleScaleIndexChanged(int index);
+ //! Emitted whenever light pollution luminance changed
+ void lightPollutionLuminanceChanged(double luminance);
//! Emitted when flag to draw big halo around stars changed
void flagDrawBigStarHaloChanged(bool b);
//! Emitted on change of star texture
@@ -517,8 +495,8 @@ private:
//! Contains the list of colors matching a given B-V index
static Vec3f colorTable[128];
- //! The current Bortle Scale index
- int bortleScaleIndex;
+ //! The current light pollution luminance
+ double lightPollutionLuminance;
//! The scaling applied to input luminance before they are converted by the StelToneReproducer
float inScale;
diff --git a/src/core/modules/Landscape.cpp b/src/core/modules/Landscape.cpp
index c983b6e4c5..f6c54a413b 100644
--- a/src/core/modules/Landscape.cpp
+++ b/src/core/modules/Landscape.cpp
@@ -52,7 +52,6 @@ Landscape::Landscape(float _radius)
, angleRotateZ(0.)
, angleRotateZOffset(0.)
, sinMinAltitudeLimit(-0.035) //sin(-2 degrees))
- , defaultBortleIndex(-1)
, defaultFogSetting(-1)
, defaultExtinctionCoefficient(-1.)
, defaultTemperature(-1000.)
@@ -119,9 +118,22 @@ void Landscape::loadCommon(const QSettings& landscapeIni, const QString& landsca
if ((tzString.length() > 0))
location.ianaTimeZone=StelLocationMgr::sanitizeTimezoneStringFromLocationDB(tzString);
- defaultBortleIndex = landscapeIni.value("location/light_pollution", -1).toInt();
+ auto defaultBortleIndex = landscapeIni.value("location/light_pollution", -1).toInt();
if (defaultBortleIndex<=0) defaultBortleIndex=-1; // neg. values in ini file signal "no change".
if (defaultBortleIndex>9) defaultBortleIndex=9; // correct bad values.
+ const auto lum = landscapeIni.value("location/light_pollution_luminance");
+ if (lum.isValid())
+ {
+ defaultLightPollutionLuminance = lum;
+
+ if (defaultBortleIndex>=0)
+ {
+ qWarning() << "Landscape light pollution is specified both as luminance and as Bortle scale index."
+ "Only one value should be specified, preferably luminance.";
+ }
+ }
+ else if (defaultBortleIndex>=0)
+ defaultLightPollutionLuminance = StelCore::bortleScaleIndexToLuminance(defaultBortleIndex);
defaultFogSetting = landscapeIni.value("location/display_fog", -1).toInt();
defaultExtinctionCoefficient = landscapeIni.value("location/atmospheric_extinction_coefficient", -1.0).toDouble();
diff --git a/src/core/modules/Landscape.hpp b/src/core/modules/Landscape.hpp
index be3b7d91c2..e0b6194145 100644
--- a/src/core/modules/Landscape.hpp
+++ b/src/core/modules/Landscape.hpp
@@ -34,6 +34,7 @@
#include <QImage>
#include <QList>
#include <QFont>
+#include <QVariant>
class QSettings;
class StelLocation;
@@ -140,8 +141,8 @@ public:
const StelLocation& getLocation() const {return location;}
//! Return if the location is valid (a valid location has a valid planetName!)
bool hasLocation() const {return (!(location.planetName.isEmpty()));}
- //! Return default Bortle index (light pollution value) or -1 (unknown/no change)
- int getDefaultBortleIndex() const {return defaultBortleIndex;}
+ //! Return default light pollution luminance in cd/m², if present
+ QVariant getDefaultLightPollutionLuminance() const {return defaultLightPollutionLuminance;}
//! Return default fog setting (0/1) or -1 (no change)
int getDefaultFogSetting() const {return defaultFogSetting;}
//! Return default atmosperic extinction [mag/airmass], or -1 (no change)
@@ -233,7 +234,9 @@ protected:
double sinMinAltitudeLimit; //! Minimal altitude of landscape cover. Can be used to construct bounding caps, so that e.g. no stars are drawn below this altitude. Default -0.035, i.e. sin(-2 degrees).
StelLocation location; //! OPTIONAL. If present, can be used to set location.
- int defaultBortleIndex; //! May be given in landscape.ini:[location]light_pollution. Default: -1 (no change).
+ /** May be given in landscape.ini:light_pollution_luminance in cd/m². Default: no change.
+ * Another way (deprecated) is to use landscape.ini:[location]light_pollution to set Bortle scale index. Default: -1 (no change). */
+ QVariant defaultLightPollutionLuminance;
int defaultFogSetting; //! May be given in landscape.ini:[location]display_fog: -1(no change), 0(off), 1(on). Default: -1.
double defaultExtinctionCoefficient; //! May be given in landscape.ini:[location]atmospheric_extinction_coefficient. Default -1 (no change).
double defaultTemperature; //! [Celsius] May be given in landscape.ini:[location]atmospheric_temperature. default: -1000.0 (no change)
diff --git a/src/core/modules/LandscapeMgr.cpp b/src/core/modules/LandscapeMgr.cpp
index 250a673658..53d9043c24 100644
--- a/src/core/modules/LandscapeMgr.cpp
+++ b/src/core/modules/LandscapeMgr.cpp
@@ -404,7 +404,8 @@ void LandscapeMgr::update(double deltaTime)
}
// GZ: 2013-09-25 Take light pollution into account!
- float pollutionAddonBrightness=static_cast<float>(drawer->getBortleScaleIndex()-1)*0.025f; // 0..8, so we assume empirical linear brightening 0..0.02
+ const float nelm = StelCore::luminanceToNELM(drawer->getLightPollutionLuminance());
+ float pollutionAddonBrightness=(15.5f-2*nelm)*0.025f; // 0..8, so we assume empirical linear brightening 0..0.02
float lunarAddonBrightness=0.f;
if (moonPos[2] > -0.1/1.5)
lunarAddonBrightness = qMax(0.2f/-12.f*ssystem->getMoon()->getVMagnitudeWithExtinction(core),0.f)*static_cast<float>(moonPos[2]);
@@ -557,10 +558,10 @@ void LandscapeMgr::init()
//Bortle scale is managed by SkyDrawer
StelSkyDrawer* drawer = app->getCore()->getSkyDrawer();
Q_ASSERT(drawer);
- setAtmosphereBortleLightPollution(drawer->getBortleScaleIndex());
+ setAtmosphereLightPollutionLuminance(drawer->getLightPollutionLuminance());
connect(app->getCore(), SIGNAL(locationChanged(StelLocation)), this, SLOT(onLocationChanged(StelLocation)));
connect(app->getCore(), SIGNAL(targetLocationChanged(StelLocation)), this, SLOT(onTargetLocationChanged(StelLocation)));
- connect(drawer, SIGNAL(bortleScaleIndexChanged(int)), this, SLOT(setAtmosphereBortleLightPollution(int)));
+ connect(drawer, &StelSkyDrawer::lightPollutionLuminanceChanged, this, &LandscapeMgr::setAtmosphereLightPollutionLuminance);
connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
QString displayGroup = N_("Display Options");
@@ -660,9 +661,9 @@ bool LandscapeMgr::setCurrentLandscapeID(const QString& id, const double changeL
setFlagFog(static_cast<bool>(landscape->getDefaultFogSetting()));
landscape->setFlagShowFog(static_cast<bool>(landscape->getDefaultFogSetting()));
}
- if (landscape->getDefaultBortleIndex() > 0)
+ if (landscape->getDefaultLightPollutionLuminance().isValid())
{
- drawer->setBortleScaleIndex(landscape->getDefaultBortleIndex());
+ drawer->setLightPollutionLuminance(landscape->getDefaultLightPollutionLuminance().toFloat());
}
if (landscape->getDefaultAtmosphericExtinction() >= 0.0)
{
@@ -823,13 +824,15 @@ void LandscapeMgr::onLocationChanged(const StelLocation &loc)
{
//this was previously logic in ViewDialog, but should really be on a non-GUI layer
StelCore* core = StelApp::getInstance().getCore();
- int bIdx = loc.bortleScaleIndex;
+ float lum;
if (!loc.planetName.contains("Earth")) // location not on Earth...
- bIdx = 1;
- if (bIdx<1) // ...or it observatory, or it unknown location
- bIdx = loc.DEFAULT_BORTLE_SCALE_INDEX;
+ lum = 0;
+ else if(loc.lightPollutionLuminance.isValid())
+ lum = loc.lightPollutionLuminance.toFloat();
+ else // ...or it is an observatory, or it is an unknown location
+ lum = loc.DEFAULT_LIGHT_POLLUTION_LUMINANCE;
- core->getSkyDrawer()->setBortleScaleIndex(bIdx);
+ core->getSkyDrawer()->setLightPollutionLuminance(lum);
}
}
@@ -1032,9 +1035,9 @@ QString LandscapeMgr::getCurrentLandscapeHtmlDescription() const
if (atmosphere.size()>0)
desc += QString("<b>%1</b>: %2<br />").arg(q_("Atmospheric conditions"), atmosphere.join(", "));
- int bortle = landscape->getDefaultBortleIndex();
- if (bortle>-1)
- desc += QString("<b>%1</b>: %2 (%3)").arg(q_("Light pollution")).arg(bortle).arg(q_("by Bortle scale"));
+ const auto lightPollutionLum = landscape->getDefaultLightPollutionLuminance();
+ if (lightPollutionLum.isValid())
+ desc += q_("<b>Light pollution</b>: %1 cd/m<sup>2</sup>").arg(lightPollutionLum.toFloat());
}
return desc;
}
@@ -1167,13 +1170,6 @@ float LandscapeMgr::getAtmosphereLightPollutionLuminance() const
return atmosphere->getLightPollutionLuminance();
}
-//! Set the light pollution following the Bortle Scale
-void LandscapeMgr::setAtmosphereBortleLightPollution(const int bIndex)
-{
- // This is an empirical formula
- setAtmosphereLightPollutionLuminance(qMax(0.f,0.0004f*powf(static_cast<float>(bIndex-1), 2.1f)));
-}
-
void LandscapeMgr::setZRotation(const float d)
{
if (landscape)
@@ -1588,28 +1584,34 @@ QString LandscapeMgr::getDescription() const
void LandscapeMgr::increaseLightPollution()
{
StelCore* core = StelApp::getInstance().getCore();
- int bidx = core->getSkyDrawer()->getBortleScaleIndex() + 1;
+ const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
+ auto bidx = core->luminanceToBortleScaleIndex(lum) + 1;
if (bidx>9)
bidx = 9;
- core->getSkyDrawer()->setBortleScaleIndex(bidx);
+ const auto newLum = core->bortleScaleIndexToLuminance(bidx);
+ core->getSkyDrawer()->setLightPollutionLuminance(newLum);
}
void LandscapeMgr::reduceLightPollution()
{
StelCore* core = StelApp::getInstance().getCore();
- int bidx = core->getSkyDrawer()->getBortleScaleIndex() - 1;
+ const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
+ auto bidx = core->luminanceToBortleScaleIndex(lum) - 1;
if (bidx<1)
bidx = 1;
- core->getSkyDrawer()->setBortleScaleIndex(bidx);
+ const auto newLum = core->bortleScaleIndexToLuminance(bidx);
+ core->getSkyDrawer()->setLightPollutionLuminance(newLum);
}
void LandscapeMgr::cyclicChangeLightPollution()
{
StelCore* core = StelApp::getInstance().getCore();
- int bidx = core->getSkyDrawer()->getBortleScaleIndex() + 1;
+ const auto lum = core->getSkyDrawer()->getLightPollutionLuminance();
+ auto bidx = core->luminanceToBortleScaleIndex(lum) + 1;
if (bidx>9)
bidx = 1;
- core->getSkyDrawer()->setBortleScaleIndex(bidx);
+ const auto newLum = core->bortleScaleIndexToLuminance(bidx);
+ core->getSkyDrawer()->setLightPollutionLuminance(newLum);
}
/*
diff --git a/src/core/modules/LandscapeMgr.hpp b/src/core/modules/LandscapeMgr.hpp
index 999ca9762a..6450301787 100644
--- a/src/core/modules/LandscapeMgr.hpp
+++ b/src/core/modules/LandscapeMgr.hpp
@@ -612,10 +612,6 @@ signals:
void currentLandscapeChanged(QString currentLandscapeID,QString currentLandscapeName);
private slots:
- //! Set the light pollution following the Bortle Scale.
- //! This should not be called from script code, use StelMainScriptAPI::setBortleScaleIndex if you want to change the light pollution.
- void setAtmosphereBortleLightPollution(const int bIndex);
-
//! Reacts to StelCore::locationChanged.
void onLocationChanged(const StelLocation &loc);
void onTargetLocationChanged(const StelLocation &loc);
@@ -628,12 +624,11 @@ private slots:
void cyclicChangeLightPollution();
private:
- //! Get light pollution luminance level.
+ //! Get light pollution luminance level in cd/m².
float getAtmosphereLightPollutionLuminance() const;
- //! Set light pollution luminance level.
+ //! Set light pollution luminance level in cd/m².
void setAtmosphereLightPollutionLuminance(const float f);
-
//! For a given landscape name, return the landscape ID.
//! This takes a name of the landscape, as described in the landscape:name item in the
//! landscape.ini, and returns the landscape ID which corresponds to that name.
diff --git a/src/core/modules/MilkyWay.cpp b/src/core/modules/MilkyWay.cpp
index 30b24139c8..0587c55bec 100644
--- a/src/core/modules/MilkyWay.cpp
+++ b/src/core/modules/MilkyWay.cpp
@@ -165,11 +165,9 @@ void MilkyWay::draw(StelCore* core)
// We must also adjust milky way to light pollution.
// Is there any way to calibrate this?
- // We compute a float 1..9 from Bortle index and atmosphere display value (allows smooth fade when switching)
float atmFadeIntensity = GETSTELMODULE(LandscapeMgr)->getAtmosphereFadeIntensity();
- int bortle=drawer->getBortleScaleIndex();
- float bortleIntensity = 1.f+ static_cast<float>(bortle-1)*atmFadeIntensity; // Bortle index moderated by atmosphere fader.
- //aLum*=(11.0f-bortle)*0.1f;
+ const float nelm = StelCore::luminanceToNELM(drawer->getLightPollutionLuminance());
+ float bortleIntensity = 1.f+(15.5f-2*nelm)*atmFadeIntensity; // smoothed Bortle index moderated by atmosphere fader.
float lum = drawer->surfaceBrightnessToLuminance(12.f+0.15f*bortleIntensity); // was 11.5; Source? How to calibrate the new texture?
diff --git a/src/core/modules/Nebula.cpp b/src/core/modules/Nebula.cpp
index 4d60f126d9..bfe2554288 100644
--- a/src/core/modules/Nebula.cpp
+++ b/src/core/modules/Nebula.cpp
@@ -586,9 +586,8 @@ float Nebula::getContrastIndex(const StelCore* core) const
// Compute an extended object's contrast index: http://www.unihedron.com/projects/darksky/NELM2BCalc.html
// Sky brightness
- // Source: Schaefer, B.E. Feb. 1990. Telescopic Limiting Magnitude. PASP 102:212-229
- // URL: http://adsbit.harvard.edu/cgi-bin/nph-iarticle_query?bibcode=1990PASP..102..212S [1990PASP..102..212S]
- const float B_mpsas = 21.58f - 5*log10(std::pow(10.f, 1.586f - static_cast<float>(core->getSkyDrawer()->getNELMFromBortleScale())*0.2f)-1);
+ const auto luminance = core->getSkyDrawer()->getLightPollutionLuminance();
+ const float B_mpsas = StelCore::luminanceToMPSAS(luminance);
// Compute an extended object's contrast index
// Source: Clark, R.N., 1990. Appendix E in Visual Astronomy of the Deep Sky, Cambridge University Press and Sky Publishing.
// URL: http://www.clarkvision.com/visastro/appendix-e.html
diff --git a/src/core/modules/ZodiacalLight.cpp b/src/core/modules/ZodiacalLight.cpp
index d32af5783a..a437d88ade 100644
--- a/src/core/modules/ZodiacalLight.cpp
+++ b/src/core/modules/ZodiacalLight.cpp
@@ -184,7 +184,8 @@ void ZodiacalLight::draw(StelCore* core)
if ( (drawer->getFlagHasAtmosphere()) && (bortle > 5) ) return;
float atmFadeIntensity = GETSTELMODULE(LandscapeMgr)->getAtmosphereFadeIntensity();
- float bortleIntensity = 1.f+ static_cast<float>(bortle-1)*atmFadeIntensity; // Bortle index moderated by atmosphere fader.
+ const float nelm = StelCore::luminanceToNELM(drawer->getLightPollutionLuminance());
+ float bortleIntensity = 1.f+(15.5f-2*nelm)*atmFadeIntensity; // smoothed Bortle index moderated by atmosphere fader.
// The ZL is best observed from Earth only. On the Moon, we must be happy with ZL along the J2000 ecliptic. (Sorry for LP:1628765, I don't find a general solution.)
StelProjector::ModelViewTranformP transfo;
diff --git a/src/gui/ConfigurationDialog.cpp b/src/gui/ConfigurationDialog.cpp
index 9d61cb2fca..b7e38066ab 100644
--- a/src/gui/ConfigurationDialog.cpp
+++ b/src/gui/ConfigurationDialog.cpp
@@ -1055,7 +1055,7 @@ void ConfigurationDialog::saveAllSettings()
conf->setValue("landscape/minimal_brightness", propMgr->getStelPropertyValue("LandscapeMgr.defaultMinimalBrightness").toFloat());
conf->setValue("landscape/flag_polyline_only", propMgr->getStelPropertyValue("LandscapeMgr.flagPolyLineDisplayedOnly").toBool());
conf->setValue("landscape/polyline_thickness", propMgr->getStelPropertyValue("LandscapeMgr.polyLineThickness").toInt());
- conf->setValue("stars/init_bortle_scale", propMgr->getStelPropertyValue("StelSkyDrawer.bortleScaleIndex").toInt());
+ conf->setValue("stars/init_light_pollution_luminance", propMgr->getStelPropertyValue("StelSkyDrawer.lightPollutionLuminance").toFloat());
conf->setValue("landscape/atmospheric_extinction_coefficient", propMgr->getStelPropertyValue("StelSkyDrawer.extinctionCoefficient").toFloat());
conf->setValue("landscape/pressure_mbar", propMgr->getStelPropertyValue("StelSkyDrawer.atmospherePressure").toFloat());
conf->setValue("landscape/temperature_C", propMgr->getStelPropertyValue("StelSkyDrawer.atmosphereTemperature").toFloat());
diff --git a/src/gui/LightPollutionWidget.cpp b/src/gui/LightPollutionWidget.cpp
new file mode 100644
index 0000000000..04e39f6184
--- /dev/null
+++ b/src/gui/LightPollutionWidget.cpp
@@ -0,0 +1,324 @@
+#include "LightPollutionWidget.hpp"
+#include "StelApp.hpp"
+#include "StelCore.hpp"
+#include "StelLocaleMgr.hpp"
+#include <QCursor>
+#include <QToolTip>
+#include <QSettings>
+
+static constexpr double MIN_LIGHT_POLLUTION_LUMINANCE_MPSAS = 15;
+static constexpr double MAX_LIGHT_POLLUTION_LUMINANCE_MPSAS = 26.5;
+static constexpr char SETTINGS_KEY_MODE[] = "gui/light_pollution_widget_mode";
+static constexpr char SETTINGS_KEY_UNIT[] = "gui/light_pollution_unit";
+static constexpr char MODE_NAME_MANUAL[] = "manual";
+static constexpr char MODE_NAME_MANUAL_FROM_SQM[] = "sqm";
+static constexpr char UNIT_NAME_MPSAS[] = "mpsas";
+static constexpr char UNIT_NAME_CDM2[] = "cdm2";
+static constexpr char UNIT_NAME_MCDM2[] = "mcdm2";
+static constexpr char UNIT_NAME_UCDM2[] = "ucdm2";
+static constexpr char PROPERTY_LUMINANCE[] = "StelSkyDrawer.lightPollutionLuminance";
+static constexpr char PROPERTY_USE_DB[] = "LandscapeMgr.flagUseLightPollutionFromDatabase";
+
+LightPollutionWidget::LightPollutionWidget(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui_lightPollutionWidget)
+{
+}
+
+void LightPollutionWidget::setup()
+{
+ ui->setupUi(this);
+ connect(&StelApp::getInstance(), &StelApp::languageChanged, this, &LightPollutionWidget::retranslate);
+ populate();
+
+ ui->manualSlider->setTracking(true);
+ connect(ui->manualSlider, &QSlider::valueChanged, this, &LightPollutionWidget::onSliderMoved);
+ connect(ui->fromSQMmag_SB, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
+ &LightPollutionWidget::onSpinboxEdited);
+ connect(ui->fromSQMcdm2_logSB, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
+ &LightPollutionWidget::onSpinboxEdited);
+ connect(ui->modeCB, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ [this](const int index){ setMode(static_cast<Mode>(index)); });
+ connect(ui->unitCB, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ [this](const int index){ setUnit(static_cast<Unit>(index)); });
+
+ const auto luminanceProp = StelApp::getInstance().getStelPropertyManager()->getProperty(PROPERTY_LUMINANCE);
+ connect(this, &LightPollutionWidget::luminanceChanged, luminanceProp, &StelProperty::setValue);
+ connect(luminanceProp, &StelProperty::changed, this, &LightPollutionWidget::onLuminancePropertyChanged);
+
+ const auto databaseUseProp = StelApp::getInstance().getStelPropertyManager()->getProperty(PROPERTY_USE_DB);
+ connect(this, &LightPollutionWidget::databaseUseChanged, databaseUseProp, &StelProperty::setValue);
+ connect(databaseUseProp, &StelProperty::changed, this, &LightPollutionWidget::onUseDBPropertyChanged);
+}
+
+void LightPollutionWidget::retranslate()
+{
+ ui->retranslateUi(this);
+ updateBortleScaleToolTip();
+}
+
+void LightPollutionWidget::populate()
+{
+ const auto conf = StelApp::getInstance().getSettings();
+ const auto propMan = StelApp::getInstance().getStelPropertyManager();
+
+ const bool useDB = propMan->getStelPropertyValue(PROPERTY_USE_DB).toBool();
+ const auto modeStr = conf->value(SETTINGS_KEY_MODE).toString();
+ if (useDB)
+ setMode(Mode::AutoFromDB);
+ else if(modeStr==MODE_NAME_MANUAL)
+ setMode(Mode::Manual);
+ else if(modeStr==MODE_NAME_MANUAL_FROM_SQM)
+ setMode(Mode::ManualFromSQM);
+ else
+ setMode(Mode::Manual);
+
+ const auto unitName = conf->value(SETTINGS_KEY_UNIT).toString();
+ if(unitName==UNIT_NAME_MPSAS)
+ setUnit(Unit::mpsas);
+ else if(unitName==UNIT_NAME_CDM2)
+ setUnit(Unit::cdm2);
+ else if(unitName==UNIT_NAME_MCDM2)
+ setUnit(Unit::mcdm2);
+ else if(unitName==UNIT_NAME_UCDM2)
+ setUnit(Unit::ucdm2);
+ else // if not set
+ setUnit(Unit::mpsas);
+
+ const auto luminance = propMan->getStelPropertyValue(PROPERTY_LUMINANCE).toDouble();
+ setLuminance(luminance);
+}
+
+void LightPollutionWidget::setMode(const Mode mode)
+{
+ // Prevent window resizes on switching between modes
+ const auto minSpinBoxWidth = std::max(ui->fromSQMcdm2_logSB->minimumSizeHint().width(),
+ ui->fromSQMmag_SB->minimumSizeHint().width());
+ const auto minManipulatorWidth = minSpinBoxWidth + ui->unitCB->minimumSizeHint().width();
+ ui->manualSlider->setMinimumWidth(minManipulatorWidth);
+
+ ui->modeCB->setCurrentIndex(static_cast<int>(mode));
+ const auto propUseDB = StelApp::getInstance().getStelPropertyManager()->getProperty(PROPERTY_USE_DB);
+ switch(mode)
+ {
+ case Mode::AutoFromDB:
+ ui->horizontalSpacer->changeSize(minManipulatorWidth,0, QSizePolicy::Minimum);
+ ui->manualSlider->hide();
+ ui->fromSQMcdm2_logSB->hide();
+ ui->fromSQMmag_SB->hide();
+ ui->unitCB->hide();
+ propUseDB->setValue(true);
+ break;
+ case Mode::Manual:
+ ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Preferred);
+ ui->manualSlider->show();
+ ui->fromSQMcdm2_logSB->hide();
+ ui->fromSQMmag_SB->hide();
+ ui->unitCB->hide();
+ propUseDB->setValue(false);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_MODE, MODE_NAME_MANUAL);
+ break;
+ case Mode::ManualFromSQM:
+ ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Preferred);
+ ui->manualSlider->hide();
+ if(unit()==Unit::mpsas)
+ {
+ ui->fromSQMcdm2_logSB->hide();
+ ui->fromSQMmag_SB->show();
+ }
+ else
+ {
+ ui->fromSQMcdm2_logSB->show();
+ ui->fromSQMmag_SB->hide();
+ }
+ ui->unitCB->show();
+ propUseDB->setValue(false);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_MODE, MODE_NAME_MANUAL_FROM_SQM);
+ break;
+ }
+ if(ui->fromSQMmag_SB->isVisible() || ui->fromSQMcdm2_logSB->isVisible())
+ updateSpinBoxValue();
+ if(ui->manualSlider->isVisible())
+ updateSliderValue();
+}
+
+void LightPollutionWidget::setUnit(const Unit unit)
+{
+ {
+ QSignalBlocker b(ui->unitCB);
+ ui->unitCB->setCurrentIndex(static_cast<int>(unit));
+ }
+ {
+ QSignalBlocker bm(ui->fromSQMmag_SB);
+ QSignalBlocker bc(ui->fromSQMcdm2_logSB);
+ switch(unit)
+ {
+ case Unit::mpsas:
+ ui->fromSQMmag_SB->setDecimals(1);
+ ui->fromSQMmag_SB->setRange(MIN_LIGHT_POLLUTION_LUMINANCE_MPSAS, MAX_LIGHT_POLLUTION_LUMINANCE_MPSAS);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_UNIT, UNIT_NAME_MPSAS);
+ break;
+ case Unit::cdm2:
+ ui->fromSQMcdm2_logSB->setDecimals(7);
+ ui->fromSQMcdm2_logSB->setRange(0, 1);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_UNIT, UNIT_NAME_CDM2);
+ break;
+ case Unit::mcdm2:
+ ui->fromSQMcdm2_logSB->setDecimals(4);
+ ui->fromSQMcdm2_logSB->setRange(0, 999);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_UNIT, UNIT_NAME_MCDM2);
+ break;
+ case Unit::ucdm2:
+ ui->fromSQMcdm2_logSB->setDecimals(1);
+ ui->fromSQMcdm2_logSB->setRange(0, 999999);
+ StelApp::getInstance().getSettings()->setValue(SETTINGS_KEY_UNIT, UNIT_NAME_UCDM2);
+ break;
+ }
+ if(mode()==Mode::ManualFromSQM)
+ {
+ if(unit == Unit::mpsas)
+ {
+ ui->fromSQMmag_SB->show();
+ ui->fromSQMcdm2_logSB->hide();
+ }
+ else
+ {
+ ui->fromSQMmag_SB->hide();
+ ui->fromSQMcdm2_logSB->show();
+ }
+ }
+ }
+ if(ui->fromSQMmag_SB->isVisible() || ui->fromSQMcdm2_logSB->isVisible())
+ updateSpinBoxValue();
+}
+
+void LightPollutionWidget::updateSliderValue()
+{
+ const auto mag = StelCore::luminanceToMPSAS(luminanceValue_);
+ const auto min = MIN_LIGHT_POLLUTION_LUMINANCE_MPSAS;
+ const auto max = MAX_LIGHT_POLLUTION_LUMINANCE_MPSAS;
+ {
+ QSignalBlocker b(ui->manualSlider);
+ ui->manualSlider->setValue((mag - min) / (max - min) * ui->manualSlider->minimum());
+ }
+}
+
+void LightPollutionWidget::updateSpinBoxValue()
+{
+ QSignalBlocker bm(ui->fromSQMmag_SB);
+ QSignalBlocker bc(ui->fromSQMcdm2_logSB);
+ switch(unit())
+ {
+ case Unit::mpsas:
+ ui->fromSQMmag_SB->setValue(StelCore::luminanceToMPSAS(luminanceValue_));
+ break;
+ case Unit::cdm2:
+ ui->fromSQMcdm2_logSB->setValue(luminanceValue_);
+ break;
+ case Unit::mcdm2:
+ ui->fromSQMcdm2_logSB->setValue(luminanceValue_ * 1e3);
+ break;
+ case Unit::ucdm2:
+ ui->fromSQMcdm2_logSB->setValue(luminanceValue_ * 1e6);
+ break;
+ }
+}
+
+void LightPollutionWidget::setLuminance(const double luminance)
+{
+ luminanceValue_ = luminance;
+ updateSliderValue();
+ updateSpinBoxValue();
+ updateBortleScaleToolTip();
+}
+
+void LightPollutionWidget::onSpinboxEdited()
+{
+ switch(unit())
+ {
+ case Unit::cdm2:
+ luminanceValue_ = ui->fromSQMcdm2_logSB->value();
+ break;
+ case Unit::mcdm2:
+ luminanceValue_ = ui->fromSQMcdm2_logSB->value() * 1e-3;
+ break;
+ case Unit::ucdm2:
+ luminanceValue_ = ui->fromSQMcdm2_logSB->value() * 1e-6;
+ break;
+ case Unit::mpsas:
+ luminanceValue_ = StelCore::mpsasToLuminance(ui->fromSQMmag_SB->value());
+ break;
+ }
+ updateBortleScaleToolTip();
+ emit luminanceChanged(luminanceValue_);
+}
+
+void LightPollutionWidget::onSliderMoved(const int value)
+{
+ const auto min = MIN_LIGHT_POLLUTION_LUMINANCE_MPSAS;
+ const auto max = MAX_LIGHT_POLLUTION_LUMINANCE_MPSAS;
+ const auto mag = value * (max - min) / ui->manualSlider->minimum() + min;
+ luminanceValue_ = StelCore::mpsasToLuminance(mag);
+ updateBortleScaleToolTip();
+ emit luminanceChanged(luminanceValue_);
+ QToolTip::showText(QCursor::pos(), ui->fromSQMmag_SB->toolTip(), ui->manualSlider);
+}
+
+void LightPollutionWidget::onUseDBPropertyChanged(const QVariant& useVar)
+{
+ const bool useDB = useVar.toBool();
+ if(useDB != (mode()==Mode::AutoFromDB))
+ setMode(useDB ? Mode::AutoFromDB : Mode::Manual);
+}
+
+void LightPollutionWidget::onLuminancePropertyChanged(const QVariant& lumVar)
+{
+ const auto lum = lumVar.toDouble();
+ if(lum != luminanceValue_)
+ setLuminance(lum);
+}
+
+auto LightPollutionWidget::unit() const -> Unit
+{
+ return static_cast<Unit>(ui->unitCB->currentIndex());
+}
+
+auto LightPollutionWidget::mode() const -> Mode
+{
+ return static_cast<Mode>(ui->modeCB->currentIndex());
+}
+
+void LightPollutionWidget::updateBortleScaleToolTip()
+{
+ QStringList list;
+ //TRANSLATORS: Short description for Class 1 of the Bortle scale
+ list.append(q_("excellent dark-sky site"));
+ //TRANSLATORS: Short description for Class 2 of the Bortle scale
+ list.append(q_("typical truly dark site"));
+ //TRANSLATORS: Short description for Class 3 of the Bortle scale
+ list.append(q_("rural sky"));
+ //TRANSLATORS: Short description for Class 4 of the Bortle scale
+ list.append(q_("rural/suburban transition"));
+ //TRANSLATORS: Short description for Class 5 of the Bortle scale
+ list.append(q_("suburban sky"));
+ //TRANSLATORS: Short description for Class 6 of the Bortle scale
+ list.append(q_("bright suburban sky"));
+ //TRANSLATORS: Short description for Class 7 of the Bortle scale
+ list.append(q_("suburban/urban transition"));
+ //TRANSLATORS: Short description for Class 8 of the Bortle scale
+ list.append(q_("city sky"));
+ //TRANSLATORS: Short description for Class 9 of the Bortle scale
+ list.append(q_("inner-city sky"));
+
+ const auto nelm = StelCore::luminanceToNELM(luminanceValue_);
+ const auto bortleIndex = StelCore::nelmToBortleScaleIndex(nelm);
+
+ QString tooltip = q_("Bortle class %1: %2\nNaked-eye limiting magnitude: %3")
+ .arg(bortleIndex)
+ .arg(list.at(bortleIndex - 1))
+ .arg(std::round(nelm*10)*0.1);
+
+ ui->manualSlider->setToolTip(tooltip);
+ ui->fromSQMmag_SB->setToolTip(tooltip);
+ ui->fromSQMcdm2_logSB->setToolTip(tooltip);
+}
diff --git a/src/gui/LightPollutionWidget.hpp b/src/gui/LightPollutionWidget.hpp
new file mode 100644
index 0000000000..ff0f6f4aac
--- /dev/null
+++ b/src/gui/LightPollutionWidget.hpp
@@ -0,0 +1,57 @@
+#ifndef LIGHT_POLLUTION_WIDGET_20210606
+#define LIGHT_POLLUTION_WIDGET_20210606
+
+#include <memory>
+#include <QWidget>
+#include "ui_lightPollutionWidget.h"
+
+class LightPollutionWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ LightPollutionWidget(QWidget* parent = nullptr);
+ void setup();
+ void retranslate();
+
+signals:
+ void luminanceChanged(double luminance);
+ void databaseUseChanged(bool enabled);
+
+private:
+ enum class Mode
+ {
+ // Must be in the same order as in the combobox
+ AutoFromDB,
+ Manual,
+ ManualFromSQM,
+ };
+ enum class Unit
+ {
+ // Must be in the same order as in the combobox
+ cdm2, //!< cd/m²
+ mcdm2, //!< mcd/m²
+ ucdm2, //!< μcd/m²
+ mpsas, //!< mag/arcsec²
+ };
+
+private:
+ Unit unit() const;
+ Mode mode() const;
+ void populate();
+ void updateSliderValue();
+ void updateSpinBoxValue();
+ void updateBortleScaleToolTip();
+ void setMode(Mode mode);
+ void setUnit(Unit unit);
+ void setLuminance(double luminance);
+ void onSpinboxEdited();
+ void onSliderMoved(int value);
+ void onUseDBPropertyChanged(const QVariant& useVar);
+ void onLuminancePropertyChanged(const QVariant& lumVar);
+
+private:
+ double luminanceValue_ = 0;
+ std::unique_ptr<Ui_lightPollutionWidget> ui;
+};
+
+#endif
diff --git a/src/gui/LogarithmicSpinBox.cpp b/src/gui/LogarithmicSpinBox.cpp
new file mode 100644
index 0000000000..0a1613377d
--- /dev/null
+++ b/src/gui/LogarithmicSpinBox.cpp
@@ -0,0 +1,24 @@
+#include "LogarithmicSpinBox.hpp"
+#include <cmath>
+
+LogarithmicSpinBox::LogarithmicSpinBox(QWidget* parent)
+ : QDoubleSpinBox(parent)
+{
+}
+
+void LogarithmicSpinBox::stepBy(const int steps)
+{
+ auto value = this->value();
+
+ const auto numIterations = std::abs(steps);
+ // Doing it one-by-one, to prevent overstepping the step change boundary
+ for(int n=0; n < numIterations; ++n)
+ {
+ const double minOrder = -decimals();
+ const auto order = std::max(minOrder, std::floor(std::log10(value)) - 1);
+ const auto step = std::pow(10., order);
+ value = steps>0 ? value+step : value-step;
+ }
+
+ setValue(value);
+}
diff --git a/src/gui/LogarithmicSpinBox.hpp b/src/gui/LogarithmicSpinBox.hpp
new file mode 100644
index 0000000000..c29e63c31a
--- /dev/null
+++ b/src/gui/LogarithmicSpinBox.hpp
@@ -0,0 +1,13 @@
+#ifndef LOGARITHMIC_SPINBOX_20210618
+#define LOGARITHMIC_SPINBOX_20210618
+
+#include <QDoubleSpinBox>
+
+class LogarithmicSpinBox : public QDoubleSpinBox
+{
+public:
+ LogarithmicSpinBox(QWidget* parent = nullptr);
+ void stepBy(int steps) override;
+};
+
+#endif
diff --git a/src/gui/ViewDialog.cpp b/src/gui/ViewDialog.cpp
index 8930d053c7..1fcb0abd25 100644
--- a/src/gui/ViewDialog.cpp
+++ b/src/gui/ViewDialog.cpp
@@ -104,7 +104,7 @@ void ViewDialog::retranslate()
populateToolTips();
populatePlanetMagnitudeAlgorithmsList();
populatePlanetMagnitudeAlgorithmDescription();
- setBortleScaleToolTip(StelApp::getInstance().getCore()->getSkyDrawer()->getBortleScaleIndex());
+ ui->lightPollutionWidget->retranslate();
populateHipsGroups();
updateHips();
//Hack to shrink the tabs to optimal size after language change
@@ -165,7 +165,6 @@ void ViewDialog::createDialogContent()
// TODOs after properties merge:
- // New method: populateLightPollution may be useful. Make sure it is.
// Jupiter's GRS should become property, and recheck the other "from trunk" entries.
connect(ui->culturesListWidget, SIGNAL(currentTextChanged(const QString&)),&StelApp::getInstance().getSkyCultureMgr(),SLOT(setCurrentSkyCultureNameI18(QString)));
connect(&StelApp::getInstance().getSkyCultureMgr(), SIGNAL(currentSkyCultureChanged(QString)), this, SLOT(skyCultureChanged()));
@@ -199,16 +198,10 @@ void ViewDialog::createDialogContent()
connectBoolProperty(ui->adaptationCheckbox, "StelSkyDrawer.flagLuminanceAdaptation");
connectDoubleProperty(ui->twilightAltitudeDoubleSpinBox, "StelObjectMgr.twilightAltitude");
- // Light pollution
StelModule* lmgr = StelApp::getInstance().getModule("LandscapeMgr");
Q_ASSERT(lmgr);
- StelSkyDrawer* drawer = StelApp::getInstance().getCore()->getSkyDrawer();
- Q_ASSERT(drawer);
- populateLightPollution();
- connectBoolProperty(ui->useLightPollutionFromLocationDataCheckBox, "LandscapeMgr.flagUseLightPollutionFromDatabase");
- connect(lmgr, SIGNAL(flagUseLightPollutionFromDatabaseChanged(bool)), this, SLOT(populateLightPollution()));
- connectIntProperty(ui->lightPollutionSpinBox, "StelSkyDrawer.bortleScaleIndex");
- connect(drawer, SIGNAL(bortleScaleIndexChanged(int)), this, SLOT(setBortleScaleToolTip(int)));
+ // Light pollution
+ ui->lightPollutionWidget->setup();
// atmosphere details
connect(ui->pushButtonAtmosphereDetails, SIGNAL(clicked()), this, SLOT(showAtmosphereDialog()));
@@ -871,71 +864,6 @@ void ViewDialog::updateSelectedTypesCheckBoxes()
ui->checkBoxOtherType->setChecked(flags & Nebula::TypeOther);
}
-// 20160411. New function introduced with trunk merge. Not sure yet if useful or bad with property connections?.
-void ViewDialog::populateLightPollution()
-{
- StelCore *core = StelApp::getInstance().getCore();
- StelModule *lmgr = StelApp::getInstance().getModule("LandscapeMgr");
- int bIdx = core->getSkyDrawer()->getBortleScaleIndex();
- if (lmgr->property("flagUseLightPollutionFromDatabase").toBool())
- {
- StelLocation loc = core->getCurrentLocation();
- bIdx = loc.bortleScaleIndex;
- if (!loc.planetName.contains("Earth")) // location not on Earth...
- bIdx = 1;
- if (bIdx<1) // ...or it observatory, or it unknown location
- bIdx = loc.DEFAULT_BORTLE_SCALE_INDEX;
- ui->lightPollutionSpinBox->setEnabled(false);
- }
- else
- ui->lightPollutionSpinBox->setEnabled(true);
-
- ui->lightPollutionSpinBox->setValue(bIdx);
- setBortleScaleToolTip(bIdx);
-}
-
-void ViewDialog::setBortleScaleToolTip(int Bindex)
-{
- int i = Bindex-1;
- const QStringList list={
- //TRANSLATORS: Short description for Class 1 of the Bortle scale
- q_("Excellent dark-sky site"),
- //TRANSLATORS: Short description for Class 2 of the Bortle scale
- q_("Typical truly dark site"),
- //TRANSLATORS: Short description for Class 3 of the Bortle scale
- q_("Rural sky"),
- //TRANSLATORS: Short description for Class 4 of the Bortle scale
- q_("Rural/suburban transition"),
- //TRANSLATORS: Short description for Class 5 of the Bortle scale
- q_("Suburban sky"),
- //TRANSLATORS: Short description for Class 6 of the Bortle scale
- q_("Bright suburban sky"),
- //TRANSLATORS: Short description for Class 7 of the Bortle scale
- q_("Suburban/urban transition"),
- //TRANSLATORS: Short description for Class 8 of the Bortle scale
- q_("City sky"),
- //TRANSLATORS: Short description for Class 9 of the Bortle scale
- q_("Inner-city sky")};
-
- static const QStringList nelm={
- "7.6-8.0",
- "7.1-7.5",
- "6.6-7.0",
- "6.1-6.5",
- "5.6-6.0",
- "5.1-5.5",
- "4.6-5.0",
- "4.1-4.5",
- "4.0"};
-
- QString tooltip = QString("%1 (%2 %3)")
- .arg(list.at(i))
- .arg(q_("The naked-eye limiting magnitude is"))
- .arg(nelm.at(i));
-
- ui->lightPollutionSpinBox->setToolTip(tooltip);
-}
-
void ViewDialog::populateToolTips()
{
ui->planetUseObjModelsCheckBox->setToolTip(QString("<p>%1</p>").arg(q_("Uses a polygonal 3D model for some selected subplanetary objects (small moons, asteroids, comets) instead of a spherical approximation")));
diff --git a/src/gui/ViewDialog.hpp b/src/gui/ViewDialog.hpp
index 2b2337fa30..155e49a0b3 100644
--- a/src/gui/ViewDialog.hpp
+++ b/src/gui/ViewDialog.hpp
@@ -61,7 +61,6 @@ private slots:
void changeLandscape(QListWidgetItem* item);
void landscapeChanged(QString id,QString name);
void updateZhrDescription(int zhr);
- void setBortleScaleToolTip(int Bindex);
void setCurrentLandscapeAsDefault(void);
void setCurrentCultureAsDefault(void);
void updateDefaultSkyCulture();
@@ -78,10 +77,6 @@ public slots:
void showConfigureOrbitColorsDialog();
private slots:
-
- //void setLightPollutionSpinBoxStatus();
- // Two new from the unwanted trunk-rework Not sure if we need them at all?
- void populateLightPollution();
void populatePlanetMagnitudeAlgorithmsList();
void populatePlanetMagnitudeAlgorithmDescription();
void setPlanetMagnitudeAlgorithm(int algorithmID);
diff --git a/src/gui/lightPollutionWidget.ui b/src/gui/lightPollutionWidget.ui
new file mode 100644
index 0000000000..d70f883d1b
--- /dev/null
+++ b/src/gui/lightPollutionWidget.ui
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>lightPollutionWidget</class>
+ <widget class="QWidget" name="lightPollutionWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>536</width>
+ <height>34</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QComboBox" name="modeCB">
+ <item>
+ <property name="text">
+ <string>automatic from locations database</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>manual</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>manual from SQM</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSlider" name="manualSlider">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>-999999999</number>
+ </property>
+ <property name="maximum">
+ <number>0</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="fromSQMmag_SB">
+ <property name="decimals">
+ <number>2</number>
+ </property>
+ <property name="maximum">
+ <double>0.990000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.100000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="LogarithmicSpinBox" name="fromSQMcdm2_logSB"/>
+ </item>
+ <item>
+ <widget class="QComboBox" name="unitCB">
+ <item>
+ <property name="text">
+ <string>cd/m²</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>mcd/m²</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>μcd/m²</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>mag/arcsec²</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>LogarithmicSpinBox</class>
+ <extends>QDoubleSpinBox</extends>
+ <header>LogarithmicSpinBox.hpp</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/gui/viewDialog.ui b/src/gui/viewDialog.ui
index 57c1641290..6ce13bc645 100644
--- a/src/gui/viewDialog.ui
+++ b/src/gui/viewDialog.ui
@@ -510,56 +510,7 @@
</widget>
</item>
<item>
- <widget class="QSpinBox" name="lightPollutionSpinBox">
- <property name="maximumSize">
- <size>
- <width>75</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="maximum">
- <number>9</number>
- </property>
- <property name="value">
- <number>1</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>or</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QCheckBox" name="useLightPollutionFromLocationDataCheckBox">
- <property name="toolTip">
- <string>Use light pollution data from locations database and ignore settings for light pollution in left box</string>
- </property>
- <property name="text">
- <string>take from locations database</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_12">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
+ <widget class="LightPollutionWidget" name="lightPollutionWidget" native="true"/>
</item>
</layout>
</item>
@@ -5053,6 +5004,12 @@
<header>Dialog.hpp</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>LightPollutionWidget</class>
+ <extends>QWidget</extends>
+ <header>LightPollutionWidget.hpp</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<tabstops>
<tabstop>page_sky</tabstop>
@@ -5070,7 +5027,6 @@
<tabstop>zodiacalLightCheckBox</tabstop>
<tabstop>zodiacalLightBrightnessDoubleSpinBox</tabstop>
<tabstop>adaptationCheckbox</tabstop>
- <tabstop>lightPollutionSpinBox</tabstop>
<tabstop>zhrSlider</tabstop>
<tabstop>zhrSpinBox</tabstop>
<tabstop>page_DSO</tabstop>
diff --git a/src/scripting/StelMainScriptAPI.cpp b/src/scripting/StelMainScriptAPI.cpp
index acff9da86e..078af0c722 100644
--- a/src/scripting/StelMainScriptAPI.cpp
+++ b/src/scripting/StelMainScriptAPI.cpp
@@ -1293,7 +1293,8 @@ int StelMainScriptAPI::getBortleScaleIndex()
void StelMainScriptAPI::setBortleScaleIndex(int index)
{
- StelApp::getInstance().getCore()->getSkyDrawer()->setBortleScaleIndex(index);
+ const auto lum = StelCore::bortleScaleIndexToLuminance(index);
+ StelApp::getInstance().getCore()->getSkyDrawer()->setLightPollutionLuminance(lum);
}
double StelMainScriptAPI::refraction(double altitude, bool apparent)