[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