From 3118ab04eea7407fd00eb306adab12deb4f1289b Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 26 Apr 2020 15:27:35 -0600 Subject: [PATCH 1/6] Add sun tests and many TODOs This commit adds a rough sketch of tests on the sun, all passing, along with many TODOs for things I want to refactor. --- src/calendar.cpp | 17 +++++- tests/sun_test.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/sun_test.cpp diff --git a/src/calendar.cpp b/src/calendar.cpp index 464a0fd53a3e3..bf738b3df27bd 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -74,6 +74,7 @@ moon_phase get_moon_phase( const time_point &p ) return static_cast( current_phase ); } +// TODO: Refactor sunrise / sunset time_point sunrise( const time_point &p ) { static_assert( static_cast( SPRING ) == 0, @@ -94,6 +95,7 @@ time_point sunrise( const time_point &p ) return midnight + time_duration::from_minutes( static_cast( time * 60 ) ); } +// TODO: Refactor sunrise / sunset time_point sunset( const time_point &p ) { static_assert( static_cast( SPRING ) == 0, @@ -125,28 +127,35 @@ time_point daylight_time( const time_point &p ) return sunrise( p ) + 15_minutes; } +// TODO: bool is_day( const time_point &p ) ? + bool is_night( const time_point &p ) { const time_duration now = time_past_midnight( p ); const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); const time_duration sunset = time_past_midnight( ::sunset( p ) ); + // TODO: Use >= sunset + twilight_duration return now > sunset + twilight_duration || now < sunrise; } +// TODO: Rename to is_dusk bool is_sunset_now( const time_point &p ) { const time_duration now = time_past_midnight( p ); const time_duration sunset = time_past_midnight( ::sunset( p ) ); + // TODO: Use >= sunset return now > sunset && now < sunset + twilight_duration; } +// TODO: Rename to is_dawn bool is_sunrise_now( const time_point &p ) { const time_duration now = time_past_midnight( p ); const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); + // TODO: Use >= sunrise return now > sunrise && now < sunrise + twilight_duration; } @@ -195,15 +204,21 @@ float sunlight( const time_point &p, const bool vision ) 0; if( now > sunset + twilight_duration || now < sunrise ) { - // Night + // if( is_night( p ) ) + // Night (after dusk, before sunrise) return moonlight; } else if( now >= sunrise && now <= sunrise + twilight_duration ) { + // else if( is_sunrise_now( p ) ) + // Dawn (morning twilight) const double percent = ( now - sunrise ) / twilight_duration; return static_cast( moonlight ) * ( 1. - percent ) + daylight_level * percent; } else if( now >= sunset && now <= sunset + twilight_duration ) { + // else if( is_sunset_now( p ) ) + // Dusk (evening twilight) const double percent = ( now - sunset ) / twilight_duration; return daylight_level * ( 1. - percent ) + static_cast( moonlight ) * percent; } else { + // Day return daylight_level; } } diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp new file mode 100644 index 0000000000000..525c384f8cba1 --- /dev/null +++ b/tests/sun_test.cpp @@ -0,0 +1,144 @@ +#include "calendar.h" + +#include "catch/catch.hpp" + +// SUN TESTS + +static const time_point midday = calendar::turn_zero + 12_hours; +static const time_point midnight = calendar::turn_zero + 0_hours; + +const time_point today_sunrise = sunrise( midnight ); +const time_point today_sunset = sunset( midnight ); + +// is_night, is_sunrise_now, is_sunset_now +TEST_CASE( "daily solar cycle", "[sun][cycle]" ) +{ + // INFO( "Sunrise today: " + to_string( today_sunrise ) ); // 6:00 AM + // INFO( "Sunset today: " + to_string( today_sunset ) ); // 7:00 PM + + // Night + CHECK( is_night( midnight ) ); + CHECK( is_night( midnight + 1_hours ) ); + CHECK( is_night( midnight + 2_hours ) ); + CHECK( is_night( midnight + 3_hours ) ); + CHECK( is_night( midnight + 4_hours ) ); + CHECK( is_night( midnight + 5_hours ) ); + + // FIXME: This time is neither night nor sunrise + CHECK_FALSE( is_night( today_sunrise ) ); + CHECK_FALSE( is_sunrise_now( today_sunrise ) ); + + // Dawn + CHECK( is_sunrise_now( today_sunrise + 1_seconds ) ); + CHECK( is_sunrise_now( today_sunrise + 30_minutes ) ); + CHECK( is_sunrise_now( today_sunrise + 59_minutes ) ); + CHECK_FALSE( is_sunrise_now( today_sunrise + 1_hours ) ); + + // FIXME: No function to tell when it is daytime + //CHECK( is_day( midday ) ); + + // FIXME: Sunset does not begin at sunset + CHECK_FALSE( is_sunset_now( today_sunset ) ); + + // Dusk + CHECK( is_sunset_now( today_sunset + 1_seconds ) ); + CHECK( is_sunset_now( today_sunset + 30_minutes ) ); + CHECK( is_sunset_now( today_sunset + 59_minutes ) ); + + // FIXME: This time is neither dusk nor night + CHECK_FALSE( is_sunset_now( today_sunset + 1_hours ) ); + CHECK_FALSE( is_night( today_sunset + 1_hours ) ); + + // Night again + CHECK( is_night( today_sunset + 1_hours + 1_seconds ) ); + CHECK( is_night( today_sunset + 2_hours ) ); + CHECK( is_night( today_sunset + 3_hours ) ); + CHECK( is_night( today_sunset + 4_hours ) ); +} + +TEST_CASE( "sunlight", "[sun]" ) +{ + CHECK( sunlight( midnight ) == 1.0f ); + CHECK( sunlight( today_sunrise ) == 1.0f ); + CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); + CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); + CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); + CHECK( sunlight( midday ) == default_daylight_level() ); // 100.0 + CHECK( sunlight( today_sunset ) == default_daylight_level() ); // 100.0 + CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); + CHECK( sunlight( today_sunset + 30_minutes ) == 50.50f ); + CHECK( sunlight( today_sunset + 45_minutes ) == 25.75f ); +} + +TEST_CASE( "sunrise", "[sun][sunrise]" ) +{ + const time_point spring = calendar::turn_zero; + const time_point summer = spring + 91_days; + const time_point autumn = summer + 91_days; + const time_point winter = autumn + 91_days; + + CHECK( "Year 1, Spring, day 1 6:00:00 AM" == to_string( sunrise( spring ) ) ); + CHECK( "Year 1, Spring, day 31 5:40:00 AM" == to_string( sunrise( spring + 30_days ) ) ); + CHECK( "Year 1, Spring, day 61 5:20:00 AM" == to_string( sunrise( spring + 60_days ) ) ); + CHECK( "Year 1, Spring, day 91 5:00:00 AM" == to_string( sunrise( spring + 90_days ) ) ); + + CHECK( "Year 1, Summer, day 1 5:00:00 AM" == to_string( sunrise( summer ) ) ); + CHECK( "Year 1, Summer, day 31 5:19:00 AM" == to_string( sunrise( summer + 30_days ) ) ); + CHECK( "Year 1, Summer, day 61 5:39:00 AM" == to_string( sunrise( summer + 60_days ) ) ); + CHECK( "Year 1, Summer, day 91 5:59:00 AM" == to_string( sunrise( summer + 90_days ) ) ); + + CHECK( "Year 1, Autumn, day 1 6:00:00 AM" == to_string( sunrise( autumn ) ) ); + CHECK( "Year 1, Autumn, day 31 6:19:00 AM" == to_string( sunrise( autumn + 30_days ) ) ); + CHECK( "Year 1, Autumn, day 61 6:39:00 AM" == to_string( sunrise( autumn + 60_days ) ) ); + CHECK( "Year 1, Autumn, day 91 6:59:00 AM" == to_string( sunrise( autumn + 90_days ) ) ); + + CHECK( "Year 1, Winter, day 1 7:00:00 AM" == to_string( sunrise( winter ) ) ); + CHECK( "Year 1, Winter, day 31 6:40:00 AM" == to_string( sunrise( winter + 30_days ) ) ); + CHECK( "Year 1, Winter, day 61 6:20:00 AM" == to_string( sunrise( winter + 60_days ) ) ); + CHECK( "Year 1, Winter, day 91 6:00:00 AM" == to_string( sunrise( winter + 90_days ) ) ); +} + +TEST_CASE( "sunset", "[sun][sunset]" ) +{ + const time_point spring = calendar::turn_zero; + const time_point summer = spring + 91_days; + const time_point autumn = summer + 91_days; + const time_point winter = autumn + 91_days; + + CHECK( "Year 1, Spring, day 1 7:00:00 PM" == to_string( sunset( spring ) ) ); + CHECK( "Year 1, Spring, day 31 7:39:00 PM" == to_string( sunset( spring + 30_days ) ) ); + CHECK( "Year 1, Spring, day 61 8:19:00 PM" == to_string( sunset( spring + 60_days ) ) ); + CHECK( "Year 1, Spring, day 91 8:58:00 PM" == to_string( sunset( spring + 90_days ) ) ); + + CHECK( "Year 1, Summer, day 1 9:00:00 PM" == to_string( sunset( summer ) ) ); + CHECK( "Year 1, Summer, day 31 8:20:00 PM" == to_string( sunset( summer + 30_days ) ) ); + CHECK( "Year 1, Summer, day 61 7:40:00 PM" == to_string( sunset( summer + 60_days ) ) ); + CHECK( "Year 1, Summer, day 91 7:01:00 PM" == to_string( sunset( summer + 90_days ) ) ); + + CHECK( "Year 1, Autumn, day 1 7:00:00 PM" == to_string( sunset( autumn ) ) ); + CHECK( "Year 1, Autumn, day 31 6:20:00 PM" == to_string( sunset( autumn + 30_days ) ) ); + CHECK( "Year 1, Autumn, day 61 5:40:00 PM" == to_string( sunset( autumn + 60_days ) ) ); + CHECK( "Year 1, Autumn, day 91 5:01:00 PM" == to_string( sunset( autumn + 90_days ) ) ); + + CHECK( "Year 1, Winter, day 1 5:00:00 PM" == to_string( sunset( winter ) ) ); + CHECK( "Year 1, Winter, day 31 5:39:00 PM" == to_string( sunset( winter + 30_days ) ) ); + CHECK( "Year 1, Winter, day 61 6:19:00 PM" == to_string( sunset( winter + 60_days ) ) ); + CHECK( "Year 1, Winter, day 91 6:58:00 PM" == to_string( sunset( winter + 90_days ) ) ); +} + +TEST_CASE( "current daylight level", "[sun][daylight]" ) +{ + // TODO + // based on season_of_year + // SPRING + // SUMMER + // AUTUMN + // WINTER +} + +TEST_CASE( "full moon", "[moon]" ) +{ + const time_point full_moon = calendar::turn_zero + calendar::season_length() / 6; + REQUIRE( get_moon_phase( full_moon ) == MOON_FULL ); +} + From aa869cdb217901f40fcb1c38a3c202291df4897e Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 27 Apr 2020 17:19:40 -0600 Subject: [PATCH 2/6] Add solstices and equinoxes --- tests/sun_test.cpp | 162 ++++++++++++++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 55 deletions(-) diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 525c384f8cba1..297cd12b9a34b 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -7,12 +7,17 @@ static const time_point midday = calendar::turn_zero + 12_hours; static const time_point midnight = calendar::turn_zero + 0_hours; -const time_point today_sunrise = sunrise( midnight ); -const time_point today_sunset = sunset( midnight ); +// FIXME - rework these // is_night, is_sunrise_now, is_sunset_now TEST_CASE( "daily solar cycle", "[sun][cycle]" ) { + // TODO: Generalize based on sunrise/sunset + + // Use sunrise/sunset on the first day (spring equinox) + const time_point today_sunrise = sunrise( calendar::turn_zero ); + const time_point today_sunset = sunset( calendar::turn_zero ); + // INFO( "Sunrise today: " + to_string( today_sunrise ) ); // 6:00 AM // INFO( "Sunset today: " + to_string( today_sunset ) ); // 7:00 PM @@ -58,72 +63,117 @@ TEST_CASE( "daily solar cycle", "[sun][cycle]" ) TEST_CASE( "sunlight", "[sun]" ) { + const time_point today_sunrise = sunrise( calendar::turn_zero ); + const time_point today_sunset = sunset( calendar::turn_zero ); + CHECK( sunlight( midnight ) == 1.0f ); CHECK( sunlight( today_sunrise ) == 1.0f ); + // Dawn CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); + // Midday CHECK( sunlight( midday ) == default_daylight_level() ); // 100.0 CHECK( sunlight( today_sunset ) == default_daylight_level() ); // 100.0 + // Dusk CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); CHECK( sunlight( today_sunset + 30_minutes ) == 50.50f ); CHECK( sunlight( today_sunset + 45_minutes ) == 25.75f ); } -TEST_CASE( "sunrise", "[sun][sunrise]" ) -{ - const time_point spring = calendar::turn_zero; - const time_point summer = spring + 91_days; - const time_point autumn = summer + 91_days; - const time_point winter = autumn + 91_days; - - CHECK( "Year 1, Spring, day 1 6:00:00 AM" == to_string( sunrise( spring ) ) ); - CHECK( "Year 1, Spring, day 31 5:40:00 AM" == to_string( sunrise( spring + 30_days ) ) ); - CHECK( "Year 1, Spring, day 61 5:20:00 AM" == to_string( sunrise( spring + 60_days ) ) ); - CHECK( "Year 1, Spring, day 91 5:00:00 AM" == to_string( sunrise( spring + 90_days ) ) ); - - CHECK( "Year 1, Summer, day 1 5:00:00 AM" == to_string( sunrise( summer ) ) ); - CHECK( "Year 1, Summer, day 31 5:19:00 AM" == to_string( sunrise( summer + 30_days ) ) ); - CHECK( "Year 1, Summer, day 61 5:39:00 AM" == to_string( sunrise( summer + 60_days ) ) ); - CHECK( "Year 1, Summer, day 91 5:59:00 AM" == to_string( sunrise( summer + 90_days ) ) ); - - CHECK( "Year 1, Autumn, day 1 6:00:00 AM" == to_string( sunrise( autumn ) ) ); - CHECK( "Year 1, Autumn, day 31 6:19:00 AM" == to_string( sunrise( autumn + 30_days ) ) ); - CHECK( "Year 1, Autumn, day 61 6:39:00 AM" == to_string( sunrise( autumn + 60_days ) ) ); - CHECK( "Year 1, Autumn, day 91 6:59:00 AM" == to_string( sunrise( autumn + 90_days ) ) ); - - CHECK( "Year 1, Winter, day 1 7:00:00 AM" == to_string( sunrise( winter ) ) ); - CHECK( "Year 1, Winter, day 31 6:40:00 AM" == to_string( sunrise( winter + 30_days ) ) ); - CHECK( "Year 1, Winter, day 61 6:20:00 AM" == to_string( sunrise( winter + 60_days ) ) ); - CHECK( "Year 1, Winter, day 91 6:00:00 AM" == to_string( sunrise( winter + 90_days ) ) ); -} - -TEST_CASE( "sunset", "[sun][sunset]" ) +TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) { - const time_point spring = calendar::turn_zero; - const time_point summer = spring + 91_days; - const time_point autumn = summer + 91_days; - const time_point winter = autumn + 91_days; - - CHECK( "Year 1, Spring, day 1 7:00:00 PM" == to_string( sunset( spring ) ) ); - CHECK( "Year 1, Spring, day 31 7:39:00 PM" == to_string( sunset( spring + 30_days ) ) ); - CHECK( "Year 1, Spring, day 61 8:19:00 PM" == to_string( sunset( spring + 60_days ) ) ); - CHECK( "Year 1, Spring, day 91 8:58:00 PM" == to_string( sunset( spring + 90_days ) ) ); - - CHECK( "Year 1, Summer, day 1 9:00:00 PM" == to_string( sunset( summer ) ) ); - CHECK( "Year 1, Summer, day 31 8:20:00 PM" == to_string( sunset( summer + 30_days ) ) ); - CHECK( "Year 1, Summer, day 61 7:40:00 PM" == to_string( sunset( summer + 60_days ) ) ); - CHECK( "Year 1, Summer, day 91 7:01:00 PM" == to_string( sunset( summer + 90_days ) ) ); - - CHECK( "Year 1, Autumn, day 1 7:00:00 PM" == to_string( sunset( autumn ) ) ); - CHECK( "Year 1, Autumn, day 31 6:20:00 PM" == to_string( sunset( autumn + 30_days ) ) ); - CHECK( "Year 1, Autumn, day 61 5:40:00 PM" == to_string( sunset( autumn + 60_days ) ) ); - CHECK( "Year 1, Autumn, day 91 5:01:00 PM" == to_string( sunset( autumn + 90_days ) ) ); - - CHECK( "Year 1, Winter, day 1 5:00:00 PM" == to_string( sunset( winter ) ) ); - CHECK( "Year 1, Winter, day 31 5:39:00 PM" == to_string( sunset( winter + 30_days ) ) ); - CHECK( "Year 1, Winter, day 61 6:19:00 PM" == to_string( sunset( winter + 60_days ) ) ); - CHECK( "Year 1, Winter, day 91 6:58:00 PM" == to_string( sunset( winter + 90_days ) ) ); + static const time_duration one_season = calendar::season_length(); + static const time_point spring = calendar::turn_zero; + static const time_point summer = spring + one_season; + static const time_point autumn = summer + one_season; + static const time_point winter = autumn + one_season; + + SECTION( "spring equinox is day 1 of spring" ) { + // - sunrise_equinox = (average of summer and winter sunrises) + // - sunset_equinox = (average of summer and winter sunsets) + // 11 hours of daylight + CHECK( "Year 1, Spring, day 1 6:00:00 AM" == to_string( sunrise( spring ) ) ); + CHECK( "Year 1, Spring, day 1 7:00:00 PM" == to_string( sunset( spring ) ) ); + + THEN( "sunrise gets earlier" ) { + CHECK( "6:00:00 AM" == to_string_time_of_day( sunrise( spring ) ) ); + CHECK( "5:40:00 AM" == to_string_time_of_day( sunrise( spring + 30_days ) ) ); + CHECK( "5:20:00 AM" == to_string_time_of_day( sunrise( spring + 60_days ) ) ); + CHECK( "5:00:00 AM" == to_string_time_of_day( sunrise( spring + 90_days ) ) ); + } + THEN( "sunset gets later" ) { + CHECK( "7:00:00 PM" == to_string_time_of_day( sunset( spring ) ) ); + CHECK( "7:39:00 PM" == to_string_time_of_day( sunset( spring + 30_days ) ) ); + CHECK( "8:19:00 PM" == to_string_time_of_day( sunset( spring + 60_days ) ) ); + CHECK( "8:58:00 PM" == to_string_time_of_day( sunset( spring + 90_days ) ) ); + } + } + + SECTION( "summer solstice is day 1 of summer" ) { + // Summer solstice: + // - sunrise_summer = 5 + // - sunser_summer = 21 + // 14 hours of daylight + CHECK( "Year 1, Summer, day 1 5:00:00 AM" == to_string( sunrise( summer ) ) ); + CHECK( "Year 1, Summer, day 1 9:00:00 PM" == to_string( sunset( summer ) ) ); + + THEN( "sunrise gets later" ) { + CHECK( "5:00:00 AM" == to_string_time_of_day( sunrise( summer ) ) ); + CHECK( "5:19:00 AM" == to_string_time_of_day( sunrise( summer + 30_days ) ) ); + CHECK( "5:39:00 AM" == to_string_time_of_day( sunrise( summer + 60_days ) ) ); + CHECK( "5:59:00 AM" == to_string_time_of_day( sunrise( summer + 90_days ) ) ); + } + THEN( "sunset gets earlier" ) { + CHECK( "9:00:00 PM" == to_string_time_of_day( sunset( summer ) ) ); + CHECK( "8:20:00 PM" == to_string_time_of_day( sunset( summer + 30_days ) ) ); + CHECK( "7:40:00 PM" == to_string_time_of_day( sunset( summer + 60_days ) ) ); + CHECK( "7:01:00 PM" == to_string_time_of_day( sunset( summer + 90_days ) ) ); + } + } + + SECTION( "autumn equinox is day 1 of autumn" ) { + // - sunrise_equinox = (average of summer and winter sunrises) + // - sunset_equinox = (average of summer and winter sunsets) + // 11 hours of daylight + CHECK( "Year 1, Autumn, day 1 6:00:00 AM" == to_string( sunrise( autumn ) ) ); + CHECK( "Year 1, Autumn, day 1 7:00:00 PM" == to_string( sunset( autumn ) ) ); + + THEN( "sunrise gets later" ) { + CHECK( "6:00:00 AM" == to_string_time_of_day( sunrise( autumn ) ) ); + CHECK( "6:19:00 AM" == to_string_time_of_day( sunrise( autumn + 30_days ) ) ); + CHECK( "6:39:00 AM" == to_string_time_of_day( sunrise( autumn + 60_days ) ) ); + CHECK( "6:59:00 AM" == to_string_time_of_day( sunrise( autumn + 90_days ) ) ); + } + THEN( "sunset gets earlier" ) { + CHECK( "7:00:00 PM" == to_string_time_of_day( sunset( autumn ) ) ); + CHECK( "6:20:00 PM" == to_string_time_of_day( sunset( autumn + 30_days ) ) ); + CHECK( "5:40:00 PM" == to_string_time_of_day( sunset( autumn + 60_days ) ) ); + CHECK( "5:01:00 PM" == to_string_time_of_day( sunset( autumn + 90_days ) ) ); + } + } + + SECTION( "winter solstice is day 1 of winter" ) { + // Winter solstice: + // - sunrise_winter = 7 + // - sunser_winter = 17 + // 10 hours of daylight + CHECK( "Year 1, Winter, day 1 7:00:00 AM" == to_string( sunrise( winter ) ) ); + CHECK( "Year 1, Winter, day 1 5:00:00 PM" == to_string( sunset( winter ) ) ); + + THEN( "sunrise gets earlier" ) { + CHECK( "7:00:00 AM" == to_string_time_of_day( sunrise( winter ) ) ); + CHECK( "6:40:00 AM" == to_string_time_of_day( sunrise( winter + 30_days ) ) ); + CHECK( "6:20:00 AM" == to_string_time_of_day( sunrise( winter + 60_days ) ) ); + CHECK( "6:00:00 AM" == to_string_time_of_day( sunrise( winter + 90_days ) ) ); + } + THEN( "sunset gets later" ) { + CHECK( "5:00:00 PM" == to_string_time_of_day( sunset( winter ) ) ); + CHECK( "5:39:00 PM" == to_string_time_of_day( sunset( winter + 30_days ) ) ); + CHECK( "6:19:00 PM" == to_string_time_of_day( sunset( winter + 60_days ) ) ); + CHECK( "6:58:00 PM" == to_string_time_of_day( sunset( winter + 90_days ) ) ); + } + } } TEST_CASE( "current daylight level", "[sun][daylight]" ) @@ -138,7 +188,9 @@ TEST_CASE( "current daylight level", "[sun][daylight]" ) TEST_CASE( "full moon", "[moon]" ) { + /* const time_point full_moon = calendar::turn_zero + calendar::season_length() / 6; REQUIRE( get_moon_phase( full_moon ) == MOON_FULL ); + */ } From 5155fbde87326fe44b60fb38a0f084b269746782 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 28 Apr 2020 13:53:22 -0600 Subject: [PATCH 3/6] Rename is_(sunrise|sunset)_now to is_dawn|is_dusk --- src/calendar.cpp | 10 +++----- src/calendar.h | 10 ++++---- src/iuse.cpp | 4 +-- tests/sun_test.cpp | 64 ++++++++++++++++++++++++---------------------- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index bf738b3df27bd..802f3815db91d 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -139,8 +139,7 @@ bool is_night( const time_point &p ) return now > sunset + twilight_duration || now < sunrise; } -// TODO: Rename to is_dusk -bool is_sunset_now( const time_point &p ) +bool is_dusk( const time_point &p ) { const time_duration now = time_past_midnight( p ); const time_duration sunset = time_past_midnight( ::sunset( p ) ); @@ -149,8 +148,7 @@ bool is_sunset_now( const time_point &p ) return now > sunset && now < sunset + twilight_duration; } -// TODO: Rename to is_dawn -bool is_sunrise_now( const time_point &p ) +bool is_dawn( const time_point &p ) { const time_duration now = time_past_midnight( p ); const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); @@ -208,12 +206,12 @@ float sunlight( const time_point &p, const bool vision ) // Night (after dusk, before sunrise) return moonlight; } else if( now >= sunrise && now <= sunrise + twilight_duration ) { - // else if( is_sunrise_now( p ) ) + // else if( is_dawn( p ) ) // Dawn (morning twilight) const double percent = ( now - sunrise ) / twilight_duration; return static_cast( moonlight ) * ( 1. - percent ) + daylight_level * percent; } else if( now >= sunset && now <= sunset + twilight_duration ) { - // else if( is_sunset_now( p ) ) + // else if( is_dusk( p ) ) // Dusk (evening twilight) const double percent = ( now - sunset ) / twilight_duration; return daylight_level * ( 1. - percent ) + static_cast( moonlight ) * percent; diff --git a/src/calendar.h b/src/calendar.h index 262a95675740d..27cc08f43572b 100644 --- a/src/calendar.h +++ b/src/calendar.h @@ -540,12 +540,12 @@ time_point sunset( const time_point &p ); time_point daylight_time( const time_point &p ); /** Returns the time it gets dark based on sunset */ time_point night_time( const time_point &p ); -/** Returns whether it's currently after sunset + TWILIGHT_SECONDS or before sunrise - TWILIGHT_SECONDS. */ +/** Returns true if it's currently night time - after dusk and before dawn. */ bool is_night( const time_point &p ); -/** Returns true if it's currently after sunset and before sunset + TWILIGHT_SECONDS. */ -bool is_sunset_now( const time_point &p ); -/** Returns true if it's currently after sunrise and before sunrise + TWILIGHT_SECONDS. */ -bool is_sunrise_now( const time_point &p ); +/** Returns true if it's currently dusk - between sunset and and twilight_duration after sunset. */ +bool is_dusk( const time_point &p ); +/** Returns true if it's currently dawn - between sunrise and twilight_duration after sunrise. */ +bool is_dawn( const time_point &p ); /** Returns the current seasonally-adjusted maximum daylight level */ double current_daylight_level( const time_point &p ); /** How much light is provided in full daylight */ diff --git a/src/iuse.cpp b/src/iuse.cpp index 8f3dc24634b58..8f5634966f651 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -7441,9 +7441,9 @@ static extended_photo_def photo_def_for_camera_point( const tripoint &aim_point, if( g->get_levz() >= 0 && need_store_weather ) { photo_text += "\n\n"; - if( is_sunrise_now( calendar::turn ) ) { + if( is_dawn( calendar::turn ) ) { photo_text += _( "It is sunrise. " ); - } else if( is_sunset_now( calendar::turn ) ) { + } else if( is_dusk( calendar::turn ) ) { photo_text += _( "It is sunset. " ); } else if( is_night( calendar::turn ) ) { photo_text += _( "It is night. " ); diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 297cd12b9a34b..46e3b3c6260e4 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -4,54 +4,57 @@ // SUN TESTS -static const time_point midday = calendar::turn_zero + 12_hours; -static const time_point midnight = calendar::turn_zero + 0_hours; - -// FIXME - rework these - -// is_night, is_sunrise_now, is_sunset_now +// is_night, is_dawn, is_dusk TEST_CASE( "daily solar cycle", "[sun][cycle]" ) { - // TODO: Generalize based on sunrise/sunset - // Use sunrise/sunset on the first day (spring equinox) - const time_point today_sunrise = sunrise( calendar::turn_zero ); - const time_point today_sunset = sunset( calendar::turn_zero ); - - // INFO( "Sunrise today: " + to_string( today_sunrise ) ); // 6:00 AM - // INFO( "Sunset today: " + to_string( today_sunset ) ); // 7:00 PM + const time_point midnight = calendar::turn_zero; + const time_point today_sunrise = sunrise( midnight ); + const time_point today_sunset = sunset( midnight ); + + REQUIRE( "Year 1, Spring, day 1 6:00:00 AM" == to_string( today_sunrise ) ); + REQUIRE( "Year 1, Spring, day 1 7:00:00 PM" == to_string( today_sunset ) ); + + // 00:00 is_night + // : is_night + // 06:00 is_night && is_dawn (sunrise time) + // : is_dawn (sunrise + twilight ) + // 07:00 is_dawn && is_day + // : is_day + // 19:00 is_day && is_dusk (sunset time) + // : is_dusk (sunset + twilight ) + // 20:00 is_dusk && is_night + // : is_night + // 23:59 is_night - // Night CHECK( is_night( midnight ) ); - CHECK( is_night( midnight + 1_hours ) ); + CHECK( is_night( midnight + 1_seconds ) ); CHECK( is_night( midnight + 2_hours ) ); CHECK( is_night( midnight + 3_hours ) ); CHECK( is_night( midnight + 4_hours ) ); - CHECK( is_night( midnight + 5_hours ) ); // FIXME: This time is neither night nor sunrise CHECK_FALSE( is_night( today_sunrise ) ); - CHECK_FALSE( is_sunrise_now( today_sunrise ) ); + CHECK_FALSE( is_dawn( today_sunrise ) ); // Dawn - CHECK( is_sunrise_now( today_sunrise + 1_seconds ) ); - CHECK( is_sunrise_now( today_sunrise + 30_minutes ) ); - CHECK( is_sunrise_now( today_sunrise + 59_minutes ) ); - CHECK_FALSE( is_sunrise_now( today_sunrise + 1_hours ) ); + CHECK( is_dawn( today_sunrise + 1_seconds ) ); + CHECK( is_dawn( today_sunrise + 30_minutes ) ); + CHECK( is_dawn( today_sunrise + 59_minutes ) ); + CHECK_FALSE( is_dawn( today_sunrise + 1_hours ) ); // FIXME: No function to tell when it is daytime - //CHECK( is_day( midday ) ); // FIXME: Sunset does not begin at sunset - CHECK_FALSE( is_sunset_now( today_sunset ) ); + CHECK_FALSE( is_dusk( today_sunset ) ); // Dusk - CHECK( is_sunset_now( today_sunset + 1_seconds ) ); - CHECK( is_sunset_now( today_sunset + 30_minutes ) ); - CHECK( is_sunset_now( today_sunset + 59_minutes ) ); + CHECK( is_dusk( today_sunset + 1_seconds ) ); + CHECK( is_dusk( today_sunset + 30_minutes ) ); + CHECK( is_dusk( today_sunset + 59_minutes ) ); // FIXME: This time is neither dusk nor night - CHECK_FALSE( is_sunset_now( today_sunset + 1_hours ) ); + CHECK_FALSE( is_dusk( today_sunset + 1_hours ) ); CHECK_FALSE( is_night( today_sunset + 1_hours ) ); // Night again @@ -63,8 +66,9 @@ TEST_CASE( "daily solar cycle", "[sun][cycle]" ) TEST_CASE( "sunlight", "[sun]" ) { - const time_point today_sunrise = sunrise( calendar::turn_zero ); - const time_point today_sunset = sunset( calendar::turn_zero ); + const time_point midnight = calendar::turn_zero; + const time_point today_sunrise = sunrise( midnight ); + const time_point today_sunset = sunset( midnight ); CHECK( sunlight( midnight ) == 1.0f ); CHECK( sunlight( today_sunrise ) == 1.0f ); @@ -73,7 +77,7 @@ TEST_CASE( "sunlight", "[sun]" ) CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); // Midday - CHECK( sunlight( midday ) == default_daylight_level() ); // 100.0 + CHECK( sunlight( midnight + 12_hours ) == default_daylight_level() ); // 100.0 CHECK( sunlight( today_sunset ) == default_daylight_level() ); // 100.0 // Dusk CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); From 897691956522339ecaa4a0dc1931987a37ca15e7 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 28 Apr 2020 14:34:02 -0600 Subject: [PATCH 4/6] Expand the sunlight test, clean things up --- tests/sun_test.cpp | 149 ++++++++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 50 deletions(-) diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 46e3b3c6260e4..c99b82c17c6e6 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -5,12 +5,12 @@ // SUN TESTS // is_night, is_dawn, is_dusk -TEST_CASE( "daily solar cycle", "[sun][cycle]" ) +TEST_CASE( "daily solar cycle", "[sun][night][dawn][day][dusk]" ) { // Use sunrise/sunset on the first day (spring equinox) - const time_point midnight = calendar::turn_zero; - const time_point today_sunrise = sunrise( midnight ); - const time_point today_sunset = sunset( midnight ); + static const time_point midnight = calendar::turn_zero; + static const time_point today_sunrise = sunrise( midnight ); + static const time_point today_sunset = sunset( midnight ); REQUIRE( "Year 1, Spring, day 1 6:00:00 AM" == to_string( today_sunrise ) ); REQUIRE( "Year 1, Spring, day 1 7:00:00 PM" == to_string( today_sunset ) ); @@ -64,38 +64,113 @@ TEST_CASE( "daily solar cycle", "[sun][cycle]" ) CHECK( is_night( today_sunset + 4_hours ) ); } -TEST_CASE( "sunlight", "[sun]" ) +// current_daylight_level returns seasonally-adjusted maximum daylight level +TEST_CASE( "current daylight level", "[sun][daylight]" ) { - const time_point midnight = calendar::turn_zero; - const time_point today_sunrise = sunrise( midnight ); - const time_point today_sunset = sunset( midnight ); + static const time_duration one_season = calendar::season_length(); + static const time_point spring = calendar::turn_zero; + static const time_point summer = spring + one_season; + static const time_point autumn = summer + one_season; + static const time_point winter = autumn + one_season; - CHECK( sunlight( midnight ) == 1.0f ); - CHECK( sunlight( today_sunrise ) == 1.0f ); - // Dawn - CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); - CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); - CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); - // Midday - CHECK( sunlight( midnight + 12_hours ) == default_daylight_level() ); // 100.0 - CHECK( sunlight( today_sunset ) == default_daylight_level() ); // 100.0 - // Dusk - CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); - CHECK( sunlight( today_sunset + 30_minutes ) == 50.50f ); - CHECK( sunlight( today_sunset + 45_minutes ) == 25.75f ); + // For ~Boston: solstices are +/- 25% sunlight intensity from equinoxes + CHECK( 100.0f == current_daylight_level( spring ) ); + CHECK( 125.0f == current_daylight_level( summer ) ); + CHECK( 100.0f == current_daylight_level( autumn ) ); + CHECK( 75.0f == current_daylight_level( winter ) ); } -TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) +// The calendar `sunlight` function returns light level for both sun and moon. +TEST_CASE( "sunlight and moonlight", "[sun][sunlight][moonlight]" ) { + // Use sunrise/sunset on the first day (spring equinox) + static const time_point midnight = calendar::turn_zero; + static const time_point today_sunrise = sunrise( midnight ); + static const time_point today_sunset = sunset( midnight ); + + // Tests assume 100.0f maximum + REQUIRE( default_daylight_level() == 100.0f ); + + SECTION( "sunlight" ) { + // Before dawn + CHECK( sunlight( midnight ) == 1.0f ); + CHECK( sunlight( today_sunrise ) == 1.0f ); + // Dawn + CHECK( sunlight( today_sunrise + 1_seconds ) == Approx( 1.0275f ) ); + CHECK( sunlight( today_sunrise + 1_minutes ) == Approx( 2.65f ) ); + CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); + CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); + CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); + CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); + // 1 second before full daylight + CHECK( sunlight( today_sunrise + 1_hours - 1_seconds ) == Approx( 99.9725f ) ); + CHECK( sunlight( today_sunrise + 1_hours ) == 100.0f ); + // End of dawn, full light all day + CHECK( sunlight( today_sunrise + 2_hours ) == 100.0f ); + CHECK( sunlight( today_sunrise + 3_hours ) == 100.0f ); + // Noon + CHECK( sunlight( midnight + 12_hours ) == 100.0f ); + CHECK( sunlight( midnight + 13_hours ) == 100.0f ); + CHECK( sunlight( midnight + 14_hours ) == 100.0f ); + // Dusk begins + CHECK( sunlight( today_sunset ) == 100.0f ); + // 1 second after dusk begins + CHECK( sunlight( today_sunset + 1_seconds ) == Approx( 99.9725f ) ); + CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); + CHECK( sunlight( today_sunset + 30_minutes ) == 50.50f ); + CHECK( sunlight( today_sunset + 45_minutes ) == 25.75f ); + // 1 second before full night + CHECK( sunlight( today_sunset + 1_hours - 1_seconds ) == Approx( 1.0275f ) ); + CHECK( sunlight( today_sunset + 1_hours ) == 1.0f ); + // After dusk + CHECK( sunlight( today_sunset + 2_hours ) == 1.0f ); + CHECK( sunlight( today_sunset + 3_hours ) == 1.0f ); + } + + // This moonlight test is intentionally simple, only checking new moon (minimal light) and full + // moon (maximum moonlight). More detailed tests of moon phase and light should be expressed in + // `moon_test.cpp`. Including here simply to check that `sunlight` also calculates moonlight. + SECTION( "moonlight" ) { + static const time_duration phase_time = calendar::season_length() / 6; + static const time_point new_moon = calendar::turn_zero; + static const time_point full_moon = new_moon + phase_time; + + WHEN( "the moon is new" ) { + REQUIRE( get_moon_phase( new_moon ) == MOON_NEW ); + THEN( "moonlight is 1.0" ) { + CHECK( sunlight( new_moon ) == 1.0f ); + } + } + + WHEN( "the moon is full" ) { + REQUIRE( get_moon_phase( full_moon ) == MOON_FULL ); + THEN( "moonlight is 10.0" ) { + CHECK( sunlight( full_moon ) == 10.0f ); + } + } + } +} + +// The times of sunrise and sunset vary throughout the year. For simplicity, equinoxes occur on the +// first day of spring and autumn, and solstices occur on the first day of summer and winter. +TEST_CASE( "sunrise and sunset", "[sun][sunrise][sunset][equinox][solstice]" ) +{ + // Due to the "NN_days" math below, this test requires a default 91-day season length + REQUIRE( calendar::season_from_default_ratio() == Approx( 1.0f ) ); + static const time_duration one_season = calendar::season_length(); static const time_point spring = calendar::turn_zero; static const time_point summer = spring + one_season; static const time_point autumn = summer + one_season; static const time_point winter = autumn + one_season; + // The expected sunrise/sunset times depend on internal values in `calendar.cpp` including: + // - sunrise_winter, sunrise_summer, sunrise_equinox + // - sunset_winter, sunset_summer, sunset_equinox + // These being constants based on the default game setting in New England, planet Earth. + // Were these to become variable, the tests would need to adapt. + SECTION( "spring equinox is day 1 of spring" ) { - // - sunrise_equinox = (average of summer and winter sunrises) - // - sunset_equinox = (average of summer and winter sunsets) // 11 hours of daylight CHECK( "Year 1, Spring, day 1 6:00:00 AM" == to_string( sunrise( spring ) ) ); CHECK( "Year 1, Spring, day 1 7:00:00 PM" == to_string( sunset( spring ) ) ); @@ -115,9 +190,6 @@ TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) } SECTION( "summer solstice is day 1 of summer" ) { - // Summer solstice: - // - sunrise_summer = 5 - // - sunser_summer = 21 // 14 hours of daylight CHECK( "Year 1, Summer, day 1 5:00:00 AM" == to_string( sunrise( summer ) ) ); CHECK( "Year 1, Summer, day 1 9:00:00 PM" == to_string( sunset( summer ) ) ); @@ -137,8 +209,6 @@ TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) } SECTION( "autumn equinox is day 1 of autumn" ) { - // - sunrise_equinox = (average of summer and winter sunrises) - // - sunset_equinox = (average of summer and winter sunsets) // 11 hours of daylight CHECK( "Year 1, Autumn, day 1 6:00:00 AM" == to_string( sunrise( autumn ) ) ); CHECK( "Year 1, Autumn, day 1 7:00:00 PM" == to_string( sunset( autumn ) ) ); @@ -158,9 +228,6 @@ TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) } SECTION( "winter solstice is day 1 of winter" ) { - // Winter solstice: - // - sunrise_winter = 7 - // - sunser_winter = 17 // 10 hours of daylight CHECK( "Year 1, Winter, day 1 7:00:00 AM" == to_string( sunrise( winter ) ) ); CHECK( "Year 1, Winter, day 1 5:00:00 PM" == to_string( sunset( winter ) ) ); @@ -180,21 +247,3 @@ TEST_CASE( "sunrise", "[sun][sunrise][sunset]" ) } } -TEST_CASE( "current daylight level", "[sun][daylight]" ) -{ - // TODO - // based on season_of_year - // SPRING - // SUMMER - // AUTUMN - // WINTER -} - -TEST_CASE( "full moon", "[moon]" ) -{ - /* - const time_point full_moon = calendar::turn_zero + calendar::season_length() / 6; - REQUIRE( get_moon_phase( full_moon ) == MOON_FULL ); - */ -} - From 7aca668e0df611fa9d87fb8f075ccb136af89806 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 28 Apr 2020 15:49:10 -0600 Subject: [PATCH 5/6] Make is_night, is_dawn, is_dusk include endpoints --- src/calendar.cpp | 22 ++++++---------------- tests/sun_test.cpp | 22 +++++++++++++--------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index 802f3815db91d..c80399781cc32 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -135,8 +135,7 @@ bool is_night( const time_point &p ) const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); const time_duration sunset = time_past_midnight( ::sunset( p ) ); - // TODO: Use >= sunset + twilight_duration - return now > sunset + twilight_duration || now < sunrise; + return now >= sunset + twilight_duration || now <= sunrise; } bool is_dusk( const time_point &p ) @@ -144,8 +143,7 @@ bool is_dusk( const time_point &p ) const time_duration now = time_past_midnight( p ); const time_duration sunset = time_past_midnight( ::sunset( p ) ); - // TODO: Use >= sunset - return now > sunset && now < sunset + twilight_duration; + return now >= sunset && now <= sunset + twilight_duration; } bool is_dawn( const time_point &p ) @@ -153,8 +151,7 @@ bool is_dawn( const time_point &p ) const time_duration now = time_past_midnight( p ); const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); - // TODO: Use >= sunrise - return now > sunrise && now < sunrise + twilight_duration; + return now >= sunrise && now <= sunrise + twilight_duration; } double current_daylight_level( const time_point &p ) @@ -201,22 +198,15 @@ float sunlight( const time_point &p, const bool vision ) const int moonlight = vision ? 1 + static_cast( current_phase * moonlight_per_quarter ) : 0; - if( now > sunset + twilight_duration || now < sunrise ) { - // if( is_night( p ) ) - // Night (after dusk, before sunrise) + if( is_night( p ) ) { return moonlight; - } else if( now >= sunrise && now <= sunrise + twilight_duration ) { - // else if( is_dawn( p ) ) - // Dawn (morning twilight) + } else if( is_dawn( p ) ) { const double percent = ( now - sunrise ) / twilight_duration; return static_cast( moonlight ) * ( 1. - percent ) + daylight_level * percent; - } else if( now >= sunset && now <= sunset + twilight_duration ) { - // else if( is_dusk( p ) ) - // Dusk (evening twilight) + } else if( is_dusk( p ) ) { const double percent = ( now - sunset ) / twilight_duration; return daylight_level * ( 1. - percent ) + static_cast( moonlight ) * percent; } else { - // Day return daylight_level; } } diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index c99b82c17c6e6..564f708160152 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -33,29 +33,33 @@ TEST_CASE( "daily solar cycle", "[sun][night][dawn][day][dusk]" ) CHECK( is_night( midnight + 3_hours ) ); CHECK( is_night( midnight + 4_hours ) ); - // FIXME: This time is neither night nor sunrise - CHECK_FALSE( is_night( today_sunrise ) ); - CHECK_FALSE( is_dawn( today_sunrise ) ); + // The point of sunrise is both "night" and "dawn" + CHECK( is_night( today_sunrise ) ); + CHECK( is_dawn( today_sunrise ) ); // Dawn CHECK( is_dawn( today_sunrise + 1_seconds ) ); CHECK( is_dawn( today_sunrise + 30_minutes ) ); CHECK( is_dawn( today_sunrise + 59_minutes ) ); - CHECK_FALSE( is_dawn( today_sunrise + 1_hours ) ); + + // The endpoint of dawn is both "dawn" and "day" + CHECK( is_dawn( today_sunrise + 1_hours ) ); + //CHECK( is_day( today_sunrise + 1_hours ) ); // FIXME: No function to tell when it is daytime - // FIXME: Sunset does not begin at sunset - CHECK_FALSE( is_dusk( today_sunset ) ); + // The beginning of sunset is both "day" and "dusk" + //CHECK( is_day( today_sunset ) ); + CHECK( is_dusk( today_sunset ) ); // Dusk CHECK( is_dusk( today_sunset + 1_seconds ) ); CHECK( is_dusk( today_sunset + 30_minutes ) ); CHECK( is_dusk( today_sunset + 59_minutes ) ); - // FIXME: This time is neither dusk nor night - CHECK_FALSE( is_dusk( today_sunset + 1_hours ) ); - CHECK_FALSE( is_night( today_sunset + 1_hours ) ); + // The point when dusk ends is both "dusk" and "night" + CHECK( is_dusk( today_sunset + 1_hours ) ); + CHECK( is_night( today_sunset + 1_hours ) ); // Night again CHECK( is_night( today_sunset + 1_hours + 1_seconds ) ); From d4bcccae98f948a7ca2e78dd035c01edb9a02177 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 28 Apr 2020 18:40:05 -0600 Subject: [PATCH 6/6] Add new is_day function with tests; final cleanup --- src/calendar.cpp | 13 ++- src/calendar.h | 2 + tests/sun_test.cpp | 194 ++++++++++++++++++++++++++++++--------------- 3 files changed, 143 insertions(+), 66 deletions(-) diff --git a/src/calendar.cpp b/src/calendar.cpp index c80399781cc32..aec69d6235200 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -75,6 +75,7 @@ moon_phase get_moon_phase( const time_point &p ) } // TODO: Refactor sunrise / sunset +// The only difference between them is the start_hours array time_point sunrise( const time_point &p ) { static_assert( static_cast( SPRING ) == 0, @@ -95,7 +96,6 @@ time_point sunrise( const time_point &p ) return midnight + time_duration::from_minutes( static_cast( time * 60 ) ); } -// TODO: Refactor sunrise / sunset time_point sunset( const time_point &p ) { static_assert( static_cast( SPRING ) == 0, @@ -127,8 +127,6 @@ time_point daylight_time( const time_point &p ) return sunrise( p ) + 15_minutes; } -// TODO: bool is_day( const time_point &p ) ? - bool is_night( const time_point &p ) { const time_duration now = time_past_midnight( p ); @@ -138,6 +136,15 @@ bool is_night( const time_point &p ) return now >= sunset + twilight_duration || now <= sunrise; } +bool is_day( const time_point &p ) +{ + const time_duration now = time_past_midnight( p ); + const time_duration sunrise = time_past_midnight( ::sunrise( p ) ); + const time_duration sunset = time_past_midnight( ::sunset( p ) ); + + return now >= sunrise + twilight_duration && now <= sunset; +} + bool is_dusk( const time_point &p ) { const time_duration now = time_past_midnight( p ); diff --git a/src/calendar.h b/src/calendar.h index 27cc08f43572b..4d6df98ab316c 100644 --- a/src/calendar.h +++ b/src/calendar.h @@ -542,6 +542,8 @@ time_point daylight_time( const time_point &p ); time_point night_time( const time_point &p ); /** Returns true if it's currently night time - after dusk and before dawn. */ bool is_night( const time_point &p ); +/** Returns true if it's currently day time - after dawn and before dusk. */ +bool is_day( const time_point &p ); /** Returns true if it's currently dusk - between sunset and and twilight_duration after sunset. */ bool is_dusk( const time_point &p ); /** Returns true if it's currently dawn - between sunrise and twilight_duration after sunrise. */ diff --git a/tests/sun_test.cpp b/tests/sun_test.cpp index 564f708160152..bb2a024e1780a 100644 --- a/tests/sun_test.cpp +++ b/tests/sun_test.cpp @@ -4,30 +4,51 @@ // SUN TESTS -// is_night, is_dawn, is_dusk +// The 24-hour solar cycle is divided into four parts, as returned by four calendar.cpp functions: +// +// is_night : from the end of dusk, until the following sunrise (start of dawn) +// is_dawn : begins at sunrise, lasts twilight_duration (1 hour) +// is_day : from the end of dawn, until sunset (start of dusk) +// is_dusk : begins at sunset, lasts twilight_duration (1 hour) +// +// These are inclusive at their endpoints; in other words, each overlaps with the next like so: +// +// 00:00 is_night +// : is_night +// 06:00 is_night && is_dawn ( sunrise ) +// : is_dawn ( sunrise + twilight ) +// 07:00 is_dawn && is_day +// : is_day +// 19:00 is_day && is_dusk ( sunset ) +// : is_dusk ( sunset + twilight ) +// 20:00 is_dusk && is_night +// : is_night +// 23:59 is_night +// +// The times of sunrise and sunset will naturally depend on the current time of year; this aspect is +// covered by the "sunrise and sunset" and solstice/equinox tests later in this file. Here we simply +// use the first day of spring as a baseline. +// +// This test covers is_night, is_dawn, is_day, is_dusk, and their behavior in relation to time of day. TEST_CASE( "daily solar cycle", "[sun][night][dawn][day][dusk]" ) { // Use sunrise/sunset on the first day (spring equinox) static const time_point midnight = calendar::turn_zero; + static const time_point noon = calendar::turn_zero + 12_hours; static const time_point today_sunrise = sunrise( midnight ); static const time_point today_sunset = sunset( midnight ); REQUIRE( "Year 1, Spring, day 1 6:00:00 AM" == to_string( today_sunrise ) ); REQUIRE( "Year 1, Spring, day 1 7:00:00 PM" == to_string( today_sunset ) ); - // 00:00 is_night - // : is_night - // 06:00 is_night && is_dawn (sunrise time) - // : is_dawn (sunrise + twilight ) - // 07:00 is_dawn && is_day - // : is_day - // 19:00 is_day && is_dusk (sunset time) - // : is_dusk (sunset + twilight ) - // 20:00 is_dusk && is_night - // : is_night - // 23:59 is_night - + // First, at the risk of stating the obvious CHECK( is_night( midnight ) ); + // And while we're at it + CHECK_FALSE( is_day( midnight ) ); + CHECK_FALSE( is_dawn( midnight ) ); + CHECK_FALSE( is_dusk( midnight ) ); + + // Yep, still dark CHECK( is_night( midnight + 1_seconds ) ); CHECK( is_night( midnight + 2_hours ) ); CHECK( is_night( midnight + 3_hours ) ); @@ -38,24 +59,56 @@ TEST_CASE( "daily solar cycle", "[sun][night][dawn][day][dusk]" ) CHECK( is_dawn( today_sunrise ) ); // Dawn + CHECK_FALSE( is_night( today_sunrise + 1_seconds ) ); CHECK( is_dawn( today_sunrise + 1_seconds ) ); CHECK( is_dawn( today_sunrise + 30_minutes ) ); - CHECK( is_dawn( today_sunrise + 59_minutes ) ); + CHECK( is_dawn( today_sunrise + 1_hours - 1_seconds ) ); + CHECK_FALSE( is_day( today_sunrise + 1_hours - 1_seconds ) ); // The endpoint of dawn is both "dawn" and "day" CHECK( is_dawn( today_sunrise + 1_hours ) ); - //CHECK( is_day( today_sunrise + 1_hours ) ); - - // FIXME: No function to tell when it is daytime + CHECK( is_day( today_sunrise + 1_hours ) ); + + // Breakfast + CHECK_FALSE( is_dawn( today_sunrise + 1_hours + 1_seconds ) ); + CHECK( is_day( today_sunrise + 1_hours + 1_seconds ) ); + CHECK( is_day( today_sunrise + 2_hours ) ); + // Second breakfast + CHECK( is_day( today_sunrise + 3_hours ) ); + CHECK( is_day( today_sunrise + 4_hours ) ); + // Luncheon + CHECK( is_day( noon - 3_hours ) ); + CHECK( is_day( noon - 2_hours ) ); + // Elevenses + CHECK( is_day( noon - 1_hours ) ); + + // Noon + CHECK( is_day( noon ) ); + CHECK_FALSE( is_dawn( noon ) ); + CHECK_FALSE( is_dusk( noon ) ); + CHECK_FALSE( is_night( noon ) ); + + // Afternoon tea + CHECK( is_day( noon + 1_hours ) ); + CHECK( is_day( noon + 2_hours ) ); + // Dinner + CHECK( is_day( noon + 3_hours ) ); + CHECK( is_day( today_sunset - 2_hours ) ); + // Supper + CHECK( is_day( today_sunset - 1_hours ) ); + CHECK( is_day( today_sunset - 1_seconds ) ); + CHECK_FALSE( is_dusk( today_sunset - 1_seconds ) ); // The beginning of sunset is both "day" and "dusk" - //CHECK( is_day( today_sunset ) ); + CHECK( is_day( today_sunset ) ); CHECK( is_dusk( today_sunset ) ); // Dusk + CHECK_FALSE( is_day( today_sunset + 1_seconds ) ); CHECK( is_dusk( today_sunset + 1_seconds ) ); CHECK( is_dusk( today_sunset + 30_minutes ) ); - CHECK( is_dusk( today_sunset + 59_minutes ) ); + CHECK( is_dusk( today_sunset + 1_hours - 1_seconds ) ); + CHECK_FALSE( is_night( today_sunset + 1_hours - 1_seconds ) ); // The point when dusk ends is both "dusk" and "night" CHECK( is_dusk( today_sunset + 1_hours ) ); @@ -68,22 +121,6 @@ TEST_CASE( "daily solar cycle", "[sun][night][dawn][day][dusk]" ) CHECK( is_night( today_sunset + 4_hours ) ); } -// current_daylight_level returns seasonally-adjusted maximum daylight level -TEST_CASE( "current daylight level", "[sun][daylight]" ) -{ - static const time_duration one_season = calendar::season_length(); - static const time_point spring = calendar::turn_zero; - static const time_point summer = spring + one_season; - static const time_point autumn = summer + one_season; - static const time_point winter = autumn + one_season; - - // For ~Boston: solstices are +/- 25% sunlight intensity from equinoxes - CHECK( 100.0f == current_daylight_level( spring ) ); - CHECK( 125.0f == current_daylight_level( summer ) ); - CHECK( 100.0f == current_daylight_level( autumn ) ); - CHECK( 75.0f == current_daylight_level( winter ) ); -} - // The calendar `sunlight` function returns light level for both sun and moon. TEST_CASE( "sunlight and moonlight", "[sun][sunlight][moonlight]" ) { @@ -92,43 +129,43 @@ TEST_CASE( "sunlight and moonlight", "[sun][sunlight][moonlight]" ) static const time_point today_sunrise = sunrise( midnight ); static const time_point today_sunset = sunset( midnight ); - // Tests assume 100.0f maximum - REQUIRE( default_daylight_level() == 100.0f ); + // Expected numbers below assume 100.0f maximum daylight level + // (maximum daylight is different at other times of year - see [daylight] tests) + REQUIRE( 100.0f == default_daylight_level() ); SECTION( "sunlight" ) { // Before dawn - CHECK( sunlight( midnight ) == 1.0f ); - CHECK( sunlight( today_sunrise ) == 1.0f ); + CHECK( 1.0f == sunlight( midnight ) ); + CHECK( 1.0f == sunlight( today_sunrise ) ); // Dawn - CHECK( sunlight( today_sunrise + 1_seconds ) == Approx( 1.0275f ) ); - CHECK( sunlight( today_sunrise + 1_minutes ) == Approx( 2.65f ) ); - CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); - CHECK( sunlight( today_sunrise + 15_minutes ) == 25.75f ); - CHECK( sunlight( today_sunrise + 30_minutes ) == 50.50f ); - CHECK( sunlight( today_sunrise + 45_minutes ) == 75.25f ); + CHECK( 1.0275f == sunlight( today_sunrise + 1_seconds ) ); + CHECK( 2.65f == sunlight( today_sunrise + 1_minutes ) ); + CHECK( 25.75f == sunlight( today_sunrise + 15_minutes ) ); + CHECK( 50.50f == sunlight( today_sunrise + 30_minutes ) ); + CHECK( 75.25f == sunlight( today_sunrise + 45_minutes ) ); // 1 second before full daylight - CHECK( sunlight( today_sunrise + 1_hours - 1_seconds ) == Approx( 99.9725f ) ); - CHECK( sunlight( today_sunrise + 1_hours ) == 100.0f ); + CHECK( 99.9725f == sunlight( today_sunrise + 1_hours - 1_seconds ) ); + CHECK( 100.0f == sunlight( today_sunrise + 1_hours ) ); // End of dawn, full light all day - CHECK( sunlight( today_sunrise + 2_hours ) == 100.0f ); - CHECK( sunlight( today_sunrise + 3_hours ) == 100.0f ); + CHECK( 100.0f == sunlight( today_sunrise + 2_hours ) ); + CHECK( 100.0f == sunlight( today_sunrise + 3_hours ) ); // Noon - CHECK( sunlight( midnight + 12_hours ) == 100.0f ); - CHECK( sunlight( midnight + 13_hours ) == 100.0f ); - CHECK( sunlight( midnight + 14_hours ) == 100.0f ); + CHECK( 100.0f == sunlight( midnight + 12_hours ) ); + CHECK( 100.0f == sunlight( midnight + 13_hours ) ); + CHECK( 100.0f == sunlight( midnight + 14_hours ) ); // Dusk begins - CHECK( sunlight( today_sunset ) == 100.0f ); + CHECK( 100.0f == sunlight( today_sunset ) ); // 1 second after dusk begins - CHECK( sunlight( today_sunset + 1_seconds ) == Approx( 99.9725f ) ); - CHECK( sunlight( today_sunset + 15_minutes ) == 75.25f ); - CHECK( sunlight( today_sunset + 30_minutes ) == 50.50f ); - CHECK( sunlight( today_sunset + 45_minutes ) == 25.75f ); + CHECK( 99.9725f == sunlight( today_sunset + 1_seconds ) ); + CHECK( 75.25f == sunlight( today_sunset + 15_minutes ) ); + CHECK( 50.50f == sunlight( today_sunset + 30_minutes ) ); + CHECK( 25.75f == sunlight( today_sunset + 45_minutes ) ); // 1 second before full night - CHECK( sunlight( today_sunset + 1_hours - 1_seconds ) == Approx( 1.0275f ) ); - CHECK( sunlight( today_sunset + 1_hours ) == 1.0f ); + CHECK( 1.0275f == sunlight( today_sunset + 1_hours - 1_seconds ) ); + CHECK( 1.0f == sunlight( today_sunset + 1_hours ) ); // After dusk - CHECK( sunlight( today_sunset + 2_hours ) == 1.0f ); - CHECK( sunlight( today_sunset + 3_hours ) == 1.0f ); + CHECK( 1.0f == sunlight( today_sunset + 2_hours ) ); + CHECK( 1.0f == sunlight( today_sunset + 3_hours ) ); } // This moonlight test is intentionally simple, only checking new moon (minimal light) and full @@ -142,19 +179,50 @@ TEST_CASE( "sunlight and moonlight", "[sun][sunlight][moonlight]" ) WHEN( "the moon is new" ) { REQUIRE( get_moon_phase( new_moon ) == MOON_NEW ); THEN( "moonlight is 1.0" ) { - CHECK( sunlight( new_moon ) == 1.0f ); + CHECK( 1.0f == sunlight( new_moon ) ); } } WHEN( "the moon is full" ) { REQUIRE( get_moon_phase( full_moon ) == MOON_FULL ); THEN( "moonlight is 10.0" ) { - CHECK( sunlight( full_moon ) == 10.0f ); + CHECK( 10.0f == sunlight( full_moon ) ); } } } } +// current_daylight_level returns seasonally-adjusted maximum daylight level +TEST_CASE( "current daylight level", "[sun][daylight][equinox][solstice]" ) +{ + static const time_duration one_season = calendar::season_length(); + static const time_point spring = calendar::turn_zero; + static const time_point summer = spring + one_season; + static const time_point autumn = summer + one_season; + static const time_point winter = autumn + one_season; + + SECTION( "baseline 100 daylight on the spring and autumn equinoxes" ) { + CHECK( 100.0f == current_daylight_level( spring ) ); + CHECK( 100.0f == current_daylight_level( autumn ) ); + } + + SECTION( "25 percent more daylight on the summer solstice" ) { + CHECK( 125.0f == current_daylight_level( summer ) ); + } + + SECTION( "25 percent less daylight on the winter solstice" ) { + CHECK( 75.0f == current_daylight_level( winter ) ); + } + + // Many other times of day have peak daylight level, but noon is for sure + SECTION( "noon is peak daylight level" ) { + CHECK( 100.0f == sunlight( spring + 12_hours ) ); + CHECK( 125.0f == sunlight( summer + 12_hours ) ); + CHECK( 100.0f == sunlight( autumn + 12_hours ) ); + CHECK( 75.0f == sunlight( winter + 12_hours ) ); + } +} + // The times of sunrise and sunset vary throughout the year. For simplicity, equinoxes occur on the // first day of spring and autumn, and solstices occur on the first day of summer and winter. TEST_CASE( "sunrise and sunset", "[sun][sunrise][sunset][equinox][solstice]" )