Split state from config, cleanup

master
Kenny Levinsen 2020-10-14 17:57:34 +02:00
parent 67896358cf
commit 7bd167e9d3
3 changed files with 84 additions and 70 deletions

View File

@ -24,11 +24,9 @@ static double degrees(double radians) {
return radians * 180.0 / M_PI; return radians * 180.0 / M_PI;
} }
static void sun_angle(struct tm *tm, double longitude, double latitude, time_t *sunrise, time_t *sunset, double angle) { void calc_sun(struct tm *tm, double longitude, double latitude, struct sun *sun) {
// https://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDF // https://www.esrl.noaa.gov/gmd/grad/solcalc/solareqns.PDF
double year_rad = 2 * M_PI / double year_rad = 2 * M_PI / days_in_year(tm->tm_year) * (tm->tm_yday - 1);
days_in_year(tm->tm_year) *
(tm->tm_yday - 1 + (tm->tm_hour - 12)/24);
double eqtime = 229.18 * (0.000075 + double eqtime = 229.18 * (0.000075 +
0.001868 * cos(year_rad) - 0.001868 * cos(year_rad) -
0.032077 * sin(year_rad) - 0.032077 * sin(year_rad) -
@ -41,16 +39,16 @@ static void sun_angle(struct tm *tm, double longitude, double latitude, time_t *
0.000907 * sin(2*year_rad) - 0.000907 * sin(2*year_rad) -
0.002697 * cos(3*year_rad) + 0.002697 * cos(3*year_rad) +
0.00148 * sin(3*year_rad); 0.00148 * sin(3*year_rad);
double ha = degrees(acos( double ha1 = degrees(acos(
cos(radians(angle)) / (cos(radians(latitude)) * cos(decl)) - cos(radians(SOLAR_HORIZON + SOLAR_START_TWILIGHT)) / (cos(radians(latitude)) * cos(decl)) -
tan(radians(latitude)) * tan(decl))); tan(radians(latitude)) * tan(decl)));
*sunrise = (720 - 4 * (longitude + fabs(ha)) - eqtime) * 60; double ha2 = degrees(acos(
*sunset = (720 - 4 * (longitude - fabs(ha)) - eqtime) * 60; cos(radians(SOLAR_HORIZON + SOLAR_END_TWILIGHT)) / (cos(radians(latitude)) * cos(decl)) -
} tan(radians(latitude)) * tan(decl)));
sun->dawn = (720 - 4 * (longitude + fabs(ha1)) - eqtime) * 60;
void sun(struct tm *tm, double longitude, double latitude, time_t *dawn, time_t *sunrise, time_t *sunset, time_t *dusk) { sun->sunrise = (720 - 4 * (longitude + fabs(ha2)) - eqtime) * 60;
sun_angle(tm, longitude, latitude, dawn, dusk, SOLAR_HORIZON + SOLAR_START_TWILIGHT); sun->sunset = (720 - 4 * (longitude - fabs(ha2)) - eqtime) * 60;
sun_angle(tm, longitude, latitude, sunrise, sunset, SOLAR_HORIZON + SOLAR_END_TWILIGHT); sun->dusk = (720 - 4 * (longitude - fabs(ha1)) - eqtime) * 60;
} }
static int illuminant_d(int temp, double *x, double *y) { static int illuminant_d(int temp, double *x, double *y) {

View File

@ -1,7 +1,16 @@
#ifndef _COLOR_MATH_H #ifndef _COLOR_MATH_H
#define _COLOR_MATH_H #define _COLOR_MATH_H
void sun(struct tm *tm, double longitude, double latitude, time_t *dawn, time_t *sunrise, time_t *sunset, time_t *dusk); #include "time.h"
struct sun {
time_t dawn;
time_t sunrise;
time_t sunset;
time_t dusk;
};
void calc_sun(struct tm *tm, double longitude, double latitude, struct sun *sun);
double clamp(double value); double clamp(double value);
void calc_whitepoint(int temp, double *rw, double *gw, double *bw); void calc_whitepoint(int temp, double *rw, double *gw, double *bw);

113
main.c
View File

@ -63,17 +63,17 @@ static int set_timer(timer_t timer, time_t deadline) {
} }
#endif #endif
struct context { struct config {
int high_temp; int high_temp;
int low_temp; int low_temp;
int duration; int duration;
double longitude; double longitude;
double latitude; double latitude;
};
time_t dawn; struct context {
time_t sunrise; struct config config;
time_t sunset; struct sun sun;
time_t dusk;
time_t dawn_step_time; time_t dawn_step_time;
time_t dusk_step_time; time_t dusk_step_time;
@ -270,38 +270,41 @@ static void set_temperature(struct wl_list *outputs, int temp, int gamma) {
static int anim_kelvin_step = 25; static int anim_kelvin_step = 25;
static void recalc_stops(struct context *ctx, time_t now) { static void recalc_stops(struct context *ctx, time_t now) {
time_t day = now - (now % 86400); if (now < ctx->sun.dusk) {
if (ctx->dusk == 0) {
// First calculation
} else if (now >= ctx->dusk) {
day += 86400;
} else if (day < ctx->dusk) {
return; return;
} }
struct tm tm = { 0 }; time_t day = now - (now % 86400);
gmtime_r(&now, &tm); if (day < ctx->sun.dusk) {
sun(&tm, ctx->longitude, ctx->latitude, &ctx->dawn, &ctx->sunrise, &ctx->sunset, &ctx->dusk); day += 86400;
if (ctx->duration != -1) {
ctx->dawn = ctx->sunrise - ctx->duration;
ctx->dusk = ctx->sunset + ctx->duration;
} }
ctx->dawn += day;
ctx->sunrise += day;
ctx->sunset += day;
ctx->dusk += day;
int temp_diff = ctx->high_temp - ctx->low_temp; struct tm tm = { 0 };
ctx->dawn_step_time = (ctx->sunrise - ctx->dawn) * anim_kelvin_step / temp_diff; gmtime_r(&day, &tm);
ctx->dusk_step_time = (ctx->dusk - ctx->sunset) * anim_kelvin_step / temp_diff; calc_sun(&tm, ctx->config.longitude, ctx->config.latitude, &ctx->sun);
if (ctx->config.duration != -1) {
ctx->sun.dawn = ctx->sun.sunrise - ctx->config.duration;
ctx->sun.dusk = ctx->sun.sunset + ctx->config.duration;
}
// TODO: Cap on eternal days?
ctx->sun.dawn += day;
ctx->sun.sunrise += day;
ctx->sun.sunset += day;
ctx->sun.dusk += day;
assert(ctx->sun.dusk > now);
int temp_diff = ctx->config.high_temp - ctx->config.low_temp;
ctx->dawn_step_time = (ctx->sun.sunrise - ctx->sun.dawn) * anim_kelvin_step / temp_diff;
ctx->dusk_step_time = (ctx->sun.dusk - ctx->sun.sunset) * anim_kelvin_step / temp_diff;
struct tm dawn, sunrise, sunset, dusk; struct tm dawn, sunrise, sunset, dusk;
localtime_r(&ctx->dawn, &dawn); localtime_r(&ctx->sun.dawn, &dawn);
localtime_r(&ctx->sunrise, &sunrise); localtime_r(&ctx->sun.sunrise, &sunrise);
localtime_r(&ctx->sunset, &sunset); localtime_r(&ctx->sun.sunset, &sunset);
localtime_r(&ctx->dusk, &dusk); localtime_r(&ctx->sun.dusk, &dusk);
fprintf(stderr, "calculated new sun trajectory: dawn %02d:%02d, sunrise %02d:%02d, sunset %02d:%02d, dusk %02d:%02d\n", fprintf(stderr, "calculated new sun trajectory: dawn %02d:%02d, sunrise %02d:%02d, sunset %02d:%02d, dusk %02d:%02d\n",
dawn.tm_hour, dusk.tm_min, dawn.tm_hour, dawn.tm_min,
sunrise.tm_hour, sunrise.tm_min, sunrise.tm_hour, sunrise.tm_min,
sunset.tm_hour, sunset.tm_min, sunset.tm_hour, sunset.tm_min,
dusk.tm_hour, dusk.tm_min); dusk.tm_hour, dusk.tm_min);
@ -314,31 +317,30 @@ static int interpolate_temperature(time_t now, time_t start, time_t stop, int te
} }
static int get_temperature(const struct context *ctx, time_t now) { static int get_temperature(const struct context *ctx, time_t now) {
if (now < ctx->dawn) { if (now < ctx->sun.dawn) {
return ctx->low_temp; return ctx->config.low_temp;
} else if (now < ctx->sunrise) { } else if (now < ctx->sun.sunrise) {
return interpolate_temperature(now, ctx->dawn, ctx->sunrise, ctx->low_temp, ctx->high_temp); return interpolate_temperature(now, ctx->sun.dawn, ctx->sun.sunrise, ctx->config.low_temp, ctx->config.high_temp);
} else if (now < ctx->sunset) { } else if (now < ctx->sun.sunset) {
return ctx->high_temp; return ctx->config.high_temp;
} else if (now < ctx->dusk) { } else if (now < ctx->sun.dusk) {
return interpolate_temperature(now, ctx->sunset, ctx->dusk, ctx->high_temp, ctx->low_temp); return interpolate_temperature(now, ctx->sun.sunset, ctx->sun.dusk, ctx->config.high_temp, ctx->config.low_temp);
} else { } else {
return ctx->low_temp; return ctx->config.low_temp;
} }
} }
static void update_timer(struct context *ctx, timer_t timer, time_t now) { static void update_timer(struct context *ctx, timer_t timer, time_t now) {
assert(now < ctx->dusk); assert(now < ctx->sun.dusk);
time_t deadline; time_t deadline;
if (now < ctx->dawn) { if (now < ctx->sun.dawn) {
deadline = ctx->dawn; deadline = ctx->sun.dawn;
} else if (now < ctx->sunrise) { } else if (now < ctx->sun.sunrise) {
deadline = now + ctx->dawn_step_time; deadline = now + ctx->dawn_step_time;
} else if (now < ctx->sunset) { } else if (now < ctx->sun.sunset) {
deadline = ctx->sunset; deadline = ctx->sun.sunset;
} else if (now < ctx->dusk) { } else if (now < ctx->sun.dusk) {
deadline = now + ctx->dusk_step_time; deadline = now + ctx->dusk_step_time;
} }
@ -413,9 +415,14 @@ int main(int argc, char *argv[]) {
// Initialize defaults // Initialize defaults
struct context ctx = { struct context ctx = {
.sun = { 0 },
.config = {
.high_temp = 6500, .high_temp = 6500,
.low_temp = 4000, .low_temp = 4000,
.duration = -1, .duration = -1,
.latitude = 0,
.longitude = 0,
}
}; };
double gamma = 1.0; double gamma = 1.0;
wl_list_init(&ctx.outputs); wl_list_init(&ctx.outputs);
@ -442,20 +449,20 @@ int main(int argc, char *argv[]) {
while ((opt = getopt(argc, argv, "hT:t:g:d:l:L:")) != -1) { while ((opt = getopt(argc, argv, "hT:t:g:d:l:L:")) != -1) {
switch (opt) { switch (opt) {
case 'T': case 'T':
ctx.high_temp = strtol(optarg, NULL, 10); ctx.config.high_temp = strtol(optarg, NULL, 10);
break; break;
case 't': case 't':
ctx.low_temp = strtol(optarg, NULL, 10); ctx.config.low_temp = strtol(optarg, NULL, 10);
break; break;
case 'l': case 'l':
ctx.latitude = strtod(optarg, NULL); ctx.config.latitude = strtod(optarg, NULL);
break; break;
case 'L': case 'L':
ctx.longitude = strtod(optarg, NULL); ctx.config.longitude = strtod(optarg, NULL);
break; break;
case 'd': case 'd':
fprintf(stderr, "using animation duration override\n"); fprintf(stderr, "using animation duration override\n");
ctx.duration = strtod(optarg, NULL) * 60; ctx.config.duration = strtod(optarg, NULL) * 60;
break; break;
case 'g': case 'g':
gamma = strtod(optarg, NULL); gamma = strtod(optarg, NULL);
@ -467,9 +474,9 @@ int main(int argc, char *argv[]) {
} }
} }
if (ctx.high_temp == ctx.low_temp) { if (ctx.config.high_temp == ctx.config.low_temp) {
fprintf(stderr, "high (%d) and low (%d) temperature must not be identical\n", fprintf(stderr, "high (%d) and low (%d) temperature must not be identical\n",
ctx.high_temp, ctx.low_temp); ctx.config.high_temp, ctx.config.low_temp);
return -1; return -1;
} }