File indexing completed on 2025-01-05 03:58:43
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 <cmath> 0008 0009 #include <QDateTime> 0010 0011 #include "MarbleGlobal.h" 0012 #include "MarbleClock.h" 0013 #include "Planet.h" 0014 #include "MarbleMath.h" 0015 0016 #include "digikam_debug.h" 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 Q_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 qCDebug(DIGIKAM_MARBLE_LOG) << "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 Q_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"