From b9f0b8e3c0557037f5f706f7c4db8a9e9d72498d Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 19 Oct 2020 13:18:07 +0200 Subject: [PATCH] Move longitude time correction out of calc_sun calc_sun reported sun trajectory in seconds since the start of a UTC day, as they would occur for the specified UTC day. The caller would then add the UTC timestamp for the start of a UTC day to these numbers. This lead to complications, as e.g. a sunrise in China would be a negative value, as it occurred in the last UTC day. Futhermore, the start of a UTC day was used to signal the need for new sun calculations. This would lead to recalculations to possibly occur after its results were needed, such as after sunrise when the target longitude deviated significantly from the prime meridian. To fix this, we apply longitude time correction to the start of day calculation. This way recalculation will occur on the start of the longitude local day, close midnight for the observer. We also remove the longitude time correction from calc_sun, so that it simply returning the number of seconds since the start of the local day of the observer. The caller then adds the start of the longitude local day to get the final numbers. --- color_math.c | 14 +++++++------- color_math.h | 2 +- main.c | 25 ++++++++++++++++--------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/color_math.c b/color_math.c index ddff888..dedf3e5 100644 --- a/color_math.c +++ b/color_math.c @@ -43,9 +43,9 @@ static double sun_hour_angle(double latitude, double declination, double target_ tan(latitude) * tan(declination)); } -static time_t hour_angle_to_time(double longitude, double eqtime, double hour_angle) { +static time_t hour_angle_to_time(double hour_angle, double eqtime) { // https://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDF - return DEGREES((4.0 * M_PI - 4 * (longitude + hour_angle) - eqtime) * 60); + return DEGREES((4.0 * M_PI - 4 * hour_angle - eqtime) * 60); } static enum sun_condition condition(double latitude_rad, double sun_declination) { @@ -54,7 +54,7 @@ static enum sun_condition condition(double latitude_rad, double sun_declination) return sign_lat == sign_decl ? MIDNIGHT_SUN : POLAR_NIGHT; } -enum sun_condition calc_sun(struct tm *tm, double longitude, double latitude, struct sun *sun) { +enum sun_condition calc_sun(struct tm *tm, double latitude, struct sun *sun) { double orbit_angle = date_orbit_angle(tm); double decl = sun_declination(orbit_angle); double eqtime = equation_of_time(orbit_angle); @@ -62,10 +62,10 @@ enum sun_condition calc_sun(struct tm *tm, double longitude, double latitude, st double ha_twilight = sun_hour_angle(latitude, decl, SOLAR_START_TWILIGHT); double ha_daylight = sun_hour_angle(latitude, decl, SOLAR_END_TWILIGHT); - sun->dawn = hour_angle_to_time(longitude, eqtime, fabs(ha_twilight)); - sun->dusk = hour_angle_to_time(longitude, eqtime, -fabs(ha_twilight)); - sun->sunrise = hour_angle_to_time(longitude, eqtime, fabs(ha_daylight)); - sun->sunset = hour_angle_to_time(longitude, eqtime, -fabs(ha_daylight)); + sun->dawn = hour_angle_to_time(fabs(ha_twilight), eqtime); + sun->dusk = hour_angle_to_time(-fabs(ha_twilight), eqtime); + sun->sunrise = hour_angle_to_time(fabs(ha_daylight), eqtime); + sun->sunset = hour_angle_to_time(-fabs(ha_daylight), eqtime); return isnan(ha_twilight) || isnan(ha_daylight) ? condition(latitude, decl) : NORMAL; } diff --git a/color_math.h b/color_math.h index c7739ce..629d2b7 100644 --- a/color_math.h +++ b/color_math.h @@ -22,7 +22,7 @@ struct sun { time_t dusk; }; -enum sun_condition calc_sun(struct tm *tm, double longitude, double latitude, struct sun *sun); +enum sun_condition calc_sun(struct tm *tm, double latitude, struct sun *sun); void calc_whitepoint(int temp, double *rw, double *gw, double *bw); #endif diff --git a/main.c b/main.c index fe3b63e..74ace38 100644 --- a/main.c +++ b/main.c @@ -64,12 +64,16 @@ static inline void adjust_timerspec(struct itimerspec *timerspec) { } #endif -static time_t round_day(time_t now) { - return now - (now % 86400); +static time_t round_day_offset(time_t now, time_t offset) { + return now - ((now - offset) % 86400); } -static time_t tomorrow(time_t now) { - return round_day(now) + 86400; +static time_t tomorrow(time_t now, time_t offset) { + return round_day_offset(now, offset) + 86400; +} + +static time_t longitude_time_offset(double longitude) { + return longitude * 43200 / M_PI; } struct config { @@ -94,6 +98,8 @@ struct context { struct config config; struct sun sun; + double longitude_time_offset; + enum state state; enum sun_condition condition; @@ -149,7 +155,7 @@ static void print_trajectory(struct context *ctx) { static int anim_kelvin_step = 25; static void recalc_stops(struct context *ctx, time_t now) { - time_t day = round_day(now); + time_t day = round_day_offset(now, -ctx->longitude_time_offset); time_t last_day = ctx->calc_day; if (day == last_day) { return; @@ -159,7 +165,7 @@ static void recalc_stops(struct context *ctx, time_t now) { struct sun sun; struct tm tm = { 0 }; gmtime_r(&day, &tm); - enum sun_condition cond = calc_sun(&tm, ctx->config.longitude, ctx->config.latitude, &sun); + enum sun_condition cond = calc_sun(&tm, ctx->config.latitude, &sun); switch (cond) { case NORMAL: @@ -272,7 +278,7 @@ static time_t get_deadline_normal(const struct context *ctx, time_t now) { } else if (now < ctx->sun.dusk) { return now + ctx->dusk_step_time; } else { - return tomorrow(now); + return tomorrow(now, -ctx->longitude_time_offset); } } @@ -284,7 +290,7 @@ static time_t get_deadline_transition(const struct context *ctx, time_t now) { } // fallthrough case POLAR_NIGHT: - return tomorrow(now); + return tomorrow(now, -ctx->longitude_time_offset); default: abort(); } @@ -300,7 +306,7 @@ static void update_timer(const struct context *ctx, timer_t timer, time_t now) { deadline = get_deadline_transition(ctx, now); break; case STATE_STATIC: - deadline = tomorrow(now); + deadline = tomorrow(now, -ctx->longitude_time_offset); break; default: abort(); @@ -595,6 +601,7 @@ static int wlrun(struct config cfg) { struct context ctx = { .sun = { 0 }, .condition = SUN_CONDITION_LAST, + .longitude_time_offset = longitude_time_offset(cfg.longitude), .state = STATE_INITIAL, .config = cfg, };