[Kstars-devel] [kstars] kstars/tools: - Draw correctly skycalendar horizon for locations beyond the polar circle.

Jérôme SONRIER jsid at emor3j.fr.eu.org
Sun Apr 15 12:48:31 UTC 2012


Git commit 449b4409894c3b555886f937b18681f63a5262bb by Jérôme SONRIER.
Committed on 22/03/2012 at 03:12.
Pushed by jsonrier into branch 'master'.

- Draw correctly skycalendar horizon for locations beyond the polar circle.
- Rescale calendar view, so the whole night is always visible.

CCMAIL: kstars-devel at kde.org
CCBUG: 267213

M  +133  -54   kstars/tools/calendarwidget.cpp
M  +9    -0    kstars/tools/calendarwidget.h
M  +7    -4    kstars/tools/skycalendar.cpp

http://commits.kde.org/kstars/449b4409894c3b555886f937b18681f63a5262bb

diff --git a/kstars/tools/calendarwidget.cpp b/kstars/tools/calendarwidget.cpp
index 9832b3f..58df120 100644
--- a/kstars/tools/calendarwidget.cpp
+++ b/kstars/tools/calendarwidget.cpp
@@ -38,6 +38,9 @@ CalendarWidget::CalendarWidget( QWidget *parent )
 {
     setAntialiasing( true );
     setTopPadding( 40 );
+    
+    maxRTime = 24.0;
+    minSTime = -24.0;
 }
     
 void CalendarWidget::paintEvent( QPaintEvent *e ) {
@@ -65,54 +68,103 @@ void CalendarWidget::paintEvent( QPaintEvent *e ) {
     
 }
 
-void CalendarWidget::drawHorizon( QPainter *p ) {
+void CalendarWidget::setHorizon() {
     KSSun thesun;
-    // FIXME: OMG!!!
     SkyCalendar *skycal = (SkyCalendar*)topLevelWidget();
-    int y = skycal->year();
-    KStarsDateTime kdt( QDate( y, 1, 1 ), QTime( 12, 0, 0 ) );
+    KStarsDateTime kdt( QDate( skycal->year(), 1, 1 ), QTime( 12, 0, 0 ) );
     
-    QPolygonF polySunRise;
-    QPolygonF polySunSet;
-    //Add points along curved edge of horizon polygons
-    int imonth = -1;
-    float rTime, sTime;
+    maxRTime = 0.0;
+    minSTime = 0.0;
     
+    // Clear date, rise and set time lists
+    dateList.clear();
     riseTimeList.clear();
     setTimeList.clear();
-
-    while ( y == kdt.date().year() ) {
-        rTime = thesun.riseSetTime( kdt.djd() + 1.0, skycal->get_geo(), true, true ).secsTo(QTime())*-24.0/86400.0;
-        sTime = thesun.riseSetTime( kdt.djd(),       skycal->get_geo(), false, true  ).secsTo(QTime())*-24.0/86400.0 - 24.0;
-
-        // FIXME why do the above two give different values ? ( Difference < 1 min though )
-        if ( kdt.date().month() != imonth ) {
-            riseTimeList.append( rTime );
-            setTimeList.append( sTime );
-            imonth = kdt.date().month();
+    
+    float rTime, sTime;
+    
+    // Get rise and set time every 7 days for 1 year
+    while ( skycal->year() == kdt.date().year() ) {
+        QTime tmp_rTime, tmp_sTime;
+        tmp_rTime = thesun.riseSetTime( kdt.djd() + 1.0, skycal->get_geo(), true, true );
+        tmp_sTime = thesun.riseSetTime( kdt.djd(), skycal->get_geo(), false, true );
+        
+        /* riseSetTime seems buggy since it sometimes returns the same time for rise and set (01:00:00).
+         * In this case, we just reset tmp_rTime and tmp_sTime so they will be considered invalid
+         * in the folowing lines. */
+        if ( tmp_rTime == tmp_sTime ) {
+            tmp_rTime = QTime();
+            tmp_sTime = QTime();
+        }
+        
+        // If rise and set times are valid, the sun rise and set...
+        if ( tmp_rTime.isValid() && tmp_sTime.isValid() ) {
+            rTime = tmp_rTime.secsTo( QTime() ) * -24.0 / 86400.0;
+            sTime = tmp_sTime.secsTo( QTime() ) * -24.0 / 86400.0 - 24.0;            
+        }
+        /* else, the sun don't rise and/or don't set.
+         * we look at the altitude of the sun at transit time, if it is above the horizon,
+         * there is no night, else there is no day. */
+        else {
+            if ( thesun.transitAltitude( kdt.djd(), skycal->get_geo() ).degree() > 0 ) {
+                rTime = -4.0;
+                sTime =  4.0;
+            } else {
+                rTime =  24.0;
+                sTime = -24.0;
+            }
         }
         
-        float t = kdt.date().daysInYear() - kdt.date().dayOfYear();
-        polySunRise << mapToWidget( QPointF( rTime, t ) );
-        polySunSet  << mapToWidget( QPointF( sTime, t ) );
+        // Get max rise time and min set time
+        if ( rTime > maxRTime )
+            maxRTime = rTime;
+        if ( sTime < minSTime )
+            minSTime = sTime;
         
+        // Keep the day, rise time and set time in lists
+        dateList.append( kdt.date() );
+        riseTimeList.append( rTime );
+        setTimeList.append( sTime );
+
+        // Next week
         kdt = kdt.addDays( 7 );
     }
+    
+    // Set widget limits
+    maxRTime = ceil( maxRTime );
+    if ( (int) maxRTime % 2 != 0 )
+        maxRTime++;
+    if ( maxRTime > 22.0 )
+        maxRTime = 22.0;
+    minSTime = floor( minSTime );
+    if ( (int) minSTime % 2 != 0 )
+        minSTime--;
+    if ( minSTime < -22.0 )
+        minSTime = -22.0;
+    setLimits( minSTime, maxRTime, 0.0, 366.0 );
+    setPixRect();
+}
 
-    //Add last rise/set times to the list
-    riseTimeList.append( rTime );
-    setTimeList.append( sTime );
+void CalendarWidget::drawHorizon( QPainter *p ) {
+    polySunRise.clear();
+    polySunSet.clear();
+    
+    for ( int date=0; date<dateList.size(); date++ ) {
+        int day = dateList.at( date ).daysInYear() - dateList.at( date ).dayOfYear();
+        polySunRise << mapToWidget( QPointF( riseTimeList.at( date ), day ) );
+        polySunSet  << mapToWidget( QPointF( setTimeList.at( date ), day ) );
+    }
     
     //Finish polygons by adding pixRect corners
-    polySunRise << mapToWidget( QPointF( rTime,              dataRect().top() ) )
-                << mapToWidget( QPointF( dataRect().right(), dataRect().top() ) )
-                << mapToWidget( QPointF( dataRect().right(), dataRect().bottom() ) )
-                << mapToWidget( QPointF( riseTimeList[0],    dataRect().bottom() ) );
-    polySunSet << mapToWidget( QPointF( sTime,             dataRect().top() ) )
-               << mapToWidget( QPointF( dataRect().left(), pixRect().top() ) )
-               << mapToWidget( QPointF( dataRect().left(), pixRect().bottom() ) )
-               << mapToWidget( QPointF( setTimeList[0],    dataRect().bottom() ) );
-
+    polySunRise << mapToWidget( QPointF( riseTimeList.last(),  dataRect().top() ) )
+                << mapToWidget( QPointF( dataRect().right(),   dataRect().top() ) )
+                << mapToWidget( QPointF( dataRect().right(),   dataRect().bottom() ) )
+                << mapToWidget( QPointF( riseTimeList.first(), dataRect().bottom() ) );
+    polySunSet << mapToWidget( QPointF( setTimeList.last(),  dataRect().top() ) )
+               << mapToWidget( QPointF( dataRect().left(),   pixRect().top() ) )
+               << mapToWidget( QPointF( dataRect().left(),   pixRect().bottom() ) )
+               << mapToWidget( QPointF( setTimeList.first(), dataRect().bottom() ) );
+    
     p->setPen( Qt::darkGreen );
     p->setBrush( Qt::darkGreen );
     p->drawPolygon( polySunRise );
@@ -133,7 +185,7 @@ void CalendarWidget::drawAxes( QPainter *p ) {
     p->setFont( f );
 
     //Top/Bottom axis tickmarks and time labels
-    for ( float xx=-8.0; xx<= 8.0; xx += 2.0 ) {
+    for ( float xx = minSTime; xx <= maxRTime; xx += 2.0 ) {
         int h = int(xx);
         if ( h < 0 ) h += 24;
         QString sTime = KGlobal::locale()->formatTime( QTime( h, 0, 0 ) );
@@ -169,14 +221,31 @@ void CalendarWidget::drawAxes( QPainter *p ) {
     p->setFont( QFont( "Monospace", origFont.pointSize() + 5 ) );
     int textFlags = Qt::TextSingleLine | Qt::AlignCenter;
     QFontMetricsF fm( p->font(), p->device() );
-    for ( int imonth=1; imonth <= 12; ++ imonth ) {
-        QRectF riseLabelRect = fm.boundingRect( QRectF(0,0,1,1), textFlags, QDate::shortMonthName( imonth ) );
-        QRectF setLabelRect = fm.boundingRect( QRectF(0,0,1,1), textFlags, QDate::shortMonthName( imonth ) );
+    
+    for ( int date=0; date<dateList.size(); date++ ) {
+        if ( dateList.at( date ).day() < 12 || dateList.at( date ).day() > 18 )
+            continue;
+        
+        bool noNight = false;
+        if ( riseTimeList.at( date ) < setTimeList.at( date ) )
+            noNight = true;
+        
+        int imonth = dateList.at( date ).month();
+        
+        QString shortMonthName = QDate::shortMonthName( dateList.at( date ).month() );
+        QRectF riseLabelRect = fm.boundingRect( QRectF(0,0,1,1), textFlags, shortMonthName );
+        QRectF setLabelRect = fm.boundingRect( QRectF(0,0,1,1), textFlags, shortMonthName );
         
         QDate dt( y, imonth, 15 );
         float doy = float( dt.daysInYear() - dt.dayOfYear() );
-        float xRiseLabel = 0.5*( riseTimeList[imonth-1] + riseTimeList[imonth] ) + 0.6;
-        float xSetLabel = 0.5*( setTimeList[imonth-1] + setTimeList[imonth] ) - 0.6;
+        float xRiseLabel, xSetLabel;
+        if ( noNight ) {
+            xRiseLabel = 0.0;
+            xSetLabel = 0.0;
+        } else {
+            xRiseLabel = riseTimeList.at( date ) + 0.6;
+            xSetLabel = setTimeList.at( date )- 0.6;
+        }
         QPointF pRiseLabel = mapToWidget( QPointF( xRiseLabel, doy ) );
         QPointF pSetLabel = mapToWidget( QPointF( xSetLabel, doy ) );
         
@@ -185,26 +254,36 @@ void CalendarWidget::drawAxes( QPainter *p ) {
         float doy1 = float( dt1.daysInYear() - dt1.dayOfYear() );
         QDate dt2( y, imonth, dt1.daysInMonth() );
         float doy2 = float( dt2.daysInYear() - dt2.dayOfYear() );
-        QPointF p1 = mapToWidget( QPointF( riseTimeList[imonth-1], doy1 ) );
-        QPointF p2 = mapToWidget( QPointF( riseTimeList[imonth], doy2 ) );
-        float rAngle = atan2( p2.y() - p1.y(), p2.x() - p1.x() )/dms::DegToRad;
         
-        p1 = mapToWidget( QPointF( setTimeList[imonth-1], doy1 ) );
-        p2 = mapToWidget( QPointF( setTimeList[imonth], doy2 ) );
-        float sAngle = atan2( p2.y() - p1.y(), p2.x() - p1.x() )/dms::DegToRad;
-                
+        QPointF p1, p2;
+        float rAngle, sAngle;
+        if ( noNight ) {
+            rAngle = 90.0;
+        } else {
+            p1 = mapToWidget( QPointF( riseTimeList.at( date-2 ), doy1 ) );
+            p2 = mapToWidget( QPointF( riseTimeList.at( date+2 ), doy2 ) );
+            rAngle = atan2( p2.y() - p1.y(), p2.x() - p1.x() )/dms::DegToRad;
+            
+            p1 = mapToWidget( QPointF( setTimeList.at( date-2 ), doy1 ) );
+            p2 = mapToWidget( QPointF( setTimeList.at( date+2 ), doy2 ) );
+            sAngle = atan2( p2.y() - p1.y(), p2.x() - p1.x() )/dms::DegToRad;
+        }
+        
         p->save();
         p->translate( pRiseLabel );
         p->rotate( rAngle );
-        p->drawText( riseLabelRect, textFlags, QDate::shortMonthName( imonth ) );
+        p->drawText( riseLabelRect, textFlags, shortMonthName );
         p->restore();
         
-        p->save();
-        p->translate( pSetLabel );
-        p->rotate( sAngle );
-        p->drawText( setLabelRect, textFlags, QDate::shortMonthName( imonth ) );
-        p->restore();
-    }        
+        if ( ! noNight ) {
+            p->save();
+            p->translate( pSetLabel );
+            p->rotate( sAngle );
+            p->drawText( setLabelRect, textFlags, shortMonthName );
+            p->restore();
+        }
+    }
+     
     p->setFont( origFont );
 }
 
diff --git a/kstars/tools/calendarwidget.h b/kstars/tools/calendarwidget.h
index 8b1aaa0..19526e2 100644
--- a/kstars/tools/calendarwidget.h
+++ b/kstars/tools/calendarwidget.h
@@ -18,6 +18,7 @@
 #ifndef CALENDARWIDGET_H_
 #define CALENDARWIDGET_H_
 
+#include <QDate>
 #include <kplotwidget.h>
 
 /**@class CalendarWidget
@@ -28,6 +29,7 @@ class CalendarWidget : public KPlotWidget
     Q_OBJECT
     public:
         explicit CalendarWidget( QWidget *parent=0 );
+        void setHorizon();
     
     protected:
         void paintEvent( QPaintEvent *e );
@@ -36,8 +38,15 @@ class CalendarWidget : public KPlotWidget
         void drawHorizon( QPainter *p );
         void drawAxes( QPainter *p );
         
+        QList<QDate> dateList;
         QList<float> riseTimeList;
         QList<float> setTimeList;
+        
+        float minSTime;
+        float maxRTime;
+        
+        QPolygonF polySunRise;
+        QPolygonF polySunSet;
 };
 
 #endif
diff --git a/kstars/tools/skycalendar.cpp b/kstars/tools/skycalendar.cpp
index 915c1a8..428d1f1 100644
--- a/kstars/tools/skycalendar.cpp
+++ b/kstars/tools/skycalendar.cpp
@@ -80,12 +80,13 @@ SkyCalendar::SkyCalendar( QWidget *parent )
         scUI->CalendarView->setMinimumSize( 400, 600 );
     }
     
-    scUI->CalendarView->setLimits( -9.0, 9.0, 0.0, 366.0 );
     scUI->CalendarView->setShowGrid( false ); 
     scUI->Year->setValue( KStarsData::Instance()->lt().date().year() );
 
     scUI->LocationButton->setText( geo->fullName() );
     setButtonGuiItem( KDialog::User1, KGuiItem( i18n("&Print..."), "document-print", i18n("Print the Sky Calendar") ) );
+    
+    scUI->CalendarView->setHorizon();
 
     connect( scUI->CreateButton, SIGNAL(clicked()), this, SLOT(slotFillCalendar()) );
     connect( scUI->LocationButton, SIGNAL(clicked()), this, SLOT(slotLocation()) );
@@ -99,7 +100,7 @@ int SkyCalendar::year()  { return scUI->Year->value(); }
 
 void SkyCalendar::slotFillCalendar() {
     scUI->CalendarView->resetPlot();
-    scUI->CalendarView->setLimits( -9.0, 9.0, 0.0, 366.0 );
+    scUI->CalendarView->setHorizon();
     
     if ( scUI->checkBox_Mercury->isChecked() )
         addPlanetEvents( KSPlanetBase::MERCURY );
@@ -118,7 +119,7 @@ void SkyCalendar::slotFillCalendar() {
     if ( scUI->checkBox_Pluto->isChecked() )
         addPlanetEvents( KSPlanetBase::PLUTO );
     
-    update();
+    scUI->CalendarView->update();
 }
 
 // FIXME: For the time being, adjust with dirty, cluttering labels that don't align to the line
@@ -218,7 +219,6 @@ void SkyCalendar::addPlanetEvents( int nPlanet ) {
     scUI->CalendarView->addPlotObject( oRise );
     scUI->CalendarView->addPlotObject( oSet );
     scUI->CalendarView->addPlotObject( oTransit );
-    scUI->CalendarView->update();
 }
 
 void SkyCalendar::slotPrint() {
@@ -300,6 +300,9 @@ void SkyCalendar::slotLocation() {
         }
     }
     delete ld;
+    
+    scUI->CalendarView->setHorizon();
+    slotFillCalendar();
 }
 
 GeoLocation* SkyCalendar::get_geo()



More information about the Kstars-devel mailing list