File indexing completed on 2024-04-14 03:48:07

0001 // SPDX-FileCopyrightText: 2007-2009 David Roberts <dvdr18@gmail.com>
0002 // 
0003 // SPDX-License-Identifier: LGPL-2.1-or-later
0004 
0005 #include "SunLocator.h"
0006 
0007 #include "MarbleGlobal.h"
0008 #include "MarbleClock.h"
0009 #include "Planet.h"
0010 #include "MarbleMath.h"
0011  
0012 #include "MarbleDebug.h"
0013 
0014 #include <QDateTime>
0015 
0016 #include <cmath>
0017 
0018 namespace Marble
0019 {
0020 
0021 using std::sin;
0022 
0023 class SunLocatorPrivate
0024 {
0025 public:
0026     SunLocatorPrivate( const MarbleClock *clock, const Planet *planet )
0027         : m_lon( 0.0 ),
0028           m_lat( 0.0 ),
0029           m_twilightZone(planet->twilightZone()),
0030           m_clock( clock ),
0031           m_planet( planet )
0032     {
0033         planet->sunPosition(m_lon, m_lat, clock->dateTime());
0034     }
0035 
0036     qreal m_lon;
0037     qreal m_lat;
0038 
0039     qreal m_twilightZone;
0040 
0041     const MarbleClock *const m_clock;
0042     const Planet *m_planet;
0043 };
0044 
0045 
0046 SunLocator::SunLocator( const MarbleClock *clock, const Planet *planet )
0047   : QObject(),
0048     d( new SunLocatorPrivate( clock, planet ))
0049 {
0050 }
0051 
0052 SunLocator::~SunLocator()
0053 {
0054     delete d;
0055 }
0056 
0057 qreal SunLocator::shading(qreal lon, qreal a, qreal c) const
0058 {
0059     // haversine formula
0060     qreal b = sin((lon-d->m_lon)/2.0);
0061 //    qreal g = sin((lat-d->m_lat)/2.0);
0062 //    qreal h = (g*g)+cos(lat)*cos(d->m_lat)*(b*b); 
0063     qreal h = (a*a) + c * (b*b); 
0064 
0065     /*
0066       h = 0.0 // directly beneath sun
0067       h = 0.5 // sunrise/sunset line
0068       h = 1.0 // opposite side of earth to the sun
0069       theta = 2*asin(sqrt(h))
0070     */
0071 
0072     qreal brightness;
0073     if ( h <= 0.5 - d->m_twilightZone / 2.0 )
0074         brightness = 1.0;
0075     else if ( h >= 0.5 + d->m_twilightZone / 2.0 )
0076         brightness = 0.0;
0077     else
0078         brightness = ( 0.5 + d->m_twilightZone/2.0 - h ) / d->m_twilightZone;
0079 
0080     return brightness;
0081 }
0082 
0083 void SunLocator::shadePixel(QRgb &pixcol, qreal brightness)
0084 {
0085     // daylight - no change
0086     if ( brightness > 0.99999 )
0087         return;
0088 
0089     if ( brightness < 0.00001 ) {
0090         // night
0091         //      Doing  "pixcol = qRgb(r/2, g/2, b/2);" by shifting some electrons around ;)
0092         // by shifting some electrons around ;)
0093         pixcol = qRgb(qRed(pixcol) * 0.35, qGreen(pixcol) * 0.35, qBlue(pixcol)  * 0.35);
0094         // pixcol = (pixcol & 0xff000000) | ((pixcol >> 1) & 0x7f7f7f);
0095     } else {
0096         // gradual shadowing
0097         int r = qRed( pixcol );
0098         int g = qGreen( pixcol );
0099         int b = qBlue( pixcol );
0100         qreal  d = 0.65 * brightness + 0.35;
0101         pixcol = qRgb((int)(d * r), (int)(d * g), (int)(d * b));
0102     }
0103 }
0104 
0105 void SunLocator::shadePixelComposite(QRgb &pixcol, const QRgb &dpixcol,
0106                                      qreal brightness)
0107 {
0108     // daylight - no change
0109     if ( brightness > 0.99999 )
0110         return;
0111 
0112     if ( brightness < 0.00001 ) {
0113         // night
0114         pixcol = dpixcol;
0115     } else {
0116         // gradual shadowing
0117         qreal& d = brightness;
0118 
0119         int r = qRed( pixcol );
0120         int g = qGreen( pixcol );
0121         int b = qBlue( pixcol );
0122 
0123         int dr = qRed( dpixcol );
0124         int dg = qGreen( dpixcol );
0125         int db = qBlue( dpixcol );
0126 
0127         pixcol = qRgb( (int)( d * r + (1 - d) * dr ),
0128                        (int)( d * g + (1 - d) * dg ),
0129                        (int)( d * b + (1 - d) * db ) );
0130     }
0131 }
0132 
0133 void SunLocator::update()
0134 {
0135     d->m_planet->sunPosition(d->m_lon, d->m_lat, d->m_clock->dateTime());
0136 
0137     emit positionChanged( getLon(), getLat() );
0138 }
0139 
0140 void SunLocator::setPlanet( const Planet *planet )
0141 {
0142     /*
0143     // This won't work as expected if the same pointer 
0144     // points to different planets
0145     if ( planet == d->m_planet ) {
0146         return;
0147     }
0148     */
0149 
0150     const Planet *previousPlanet = d->m_planet;
0151 
0152     mDebug() << "SunLocator::setPlanet(Planet*)";
0153     d->m_planet = planet;
0154     d->m_twilightZone = planet->twilightZone();
0155     planet->sunPosition(d->m_lon, d->m_lat, d->m_clock->dateTime());
0156 
0157     // Initially there might be no planet set.
0158     // In that case we don't want an update.
0159     // Update the shading in all other cases.
0160     if ( !previousPlanet->id().isEmpty() ) {
0161         emit positionChanged( getLon(), getLat() );
0162     }
0163 }
0164 
0165 qreal SunLocator::getLon() const
0166 {
0167     return d->m_lon * RAD2DEG;
0168 }
0169 
0170 qreal SunLocator::getLat() const
0171 {
0172     return d->m_lat * RAD2DEG;
0173 }
0174 
0175 }
0176 
0177 #include "moc_SunLocator.cpp"