diff --git a/NEWS.md b/NEWS.md index 2d2b16b..7dc3d2a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added +- Draw lines for sunrise and sunset + [#93](https://github.com/orontee/taranis/issues/93) + ### Changed ### Removed diff --git a/src/app.cc b/src/app.cc index 4fdf766..a600bcc 100644 --- a/src/app.cc +++ b/src/app.cc @@ -29,8 +29,8 @@ int App::process_event(int event_type, int param_one, int param_two) { if (event_type != EVT_MTSYNC) { // No need to log multi touch synchronization events - BOOST_LOG_TRIVIAL(debug) << "Processing event of type " - << format_event_type(event_type); + BOOST_LOG_TRIVIAL(debug) + << "Processing event of type " << format_event_type(event_type); } if (event_type == EVT_INIT) { this->setup(); diff --git a/src/compile_flags.txt b/src/compile_flags.txt index d813959..4a6de89 100644 --- a/src/compile_flags.txt +++ b/src/compile_flags.txt @@ -2,5 +2,6 @@ --language=c++ -I/home/matthias/Projets/taranis/SDK_6.3.0/SDK-B288/usr/arm-obreey-linux-gnueabi/lib/clang/7.0.0/include -I/home/matthias/Projets/taranis/SDK_6.3.0/SDK-B288/usr/arm-obreey-linux-gnueabi/include/c++/6.3.0 +-I/home/matthias/Projets/taranis/SDK_6.3.0/SDK-B288/usr/arm-obreey-linux-gnueabi/sysroot/include -I/home/matthias/Projets/taranis/SDK_6.3.0/SDK-B288/usr/arm-obreey-linux-gnueabi/sysroot/usr/include -I/home/matthias/Projets/taranis/SDK_6.3.0/SDK-B288/usr/arm-obreey-linux-gnueabi/sysroot/usr/local/include diff --git a/src/hourlyforecastbox.cc b/src/hourlyforecastbox.cc index c0ddd43..f6f9b82 100644 --- a/src/hourlyforecastbox.cc +++ b/src/hourlyforecastbox.cc @@ -60,6 +60,7 @@ void HourlyForecastBox::do_paint() { this->draw_frame_and_values(); this->draw_precipitation_histogram(); this->draw_temperature_curve(); + this->draw_sunrise_sunset_lines(); } bool HourlyForecastBox::handle_key_press(int key) { @@ -394,10 +395,52 @@ void HourlyForecastBox::draw_precipitation_histogram() const { } } +void HourlyForecastBox::draw_sunrise_sunset_lines() const { + BOOST_LOG_TRIVIAL(debug) << "Drawing sunrise and sunset lines"; + const auto separator_start_y = + this->weather_icon_y + this->icon_size + this->vertical_padding; + const auto separator_stop_y = this->temperature_y - vertical_padding; + + for (size_t bar_index = 0; bar_index < HourlyForecastBox::visible_bars; + ++bar_index) { + const auto forecast_index = this->forecast_offset + bar_index; + if (forecast_index < this->model->hourly_forecast.size()) { + const auto forecast = this->model->hourly_forecast[forecast_index]; + + for (const auto daily_forecast : this->model->daily_forecast) { + if (not are_same_day(forecast.date, daily_forecast.date)) { + continue; + } + + const auto minutes_before_sunrise = + get_duration_minutes(forecast.date, daily_forecast.sunrise); + + const auto minutes_before_sunset = + get_duration_minutes(forecast.date, daily_forecast.sunset); + + if (0 < minutes_before_sunrise and minutes_before_sunrise < 60) { + const int separator_x = bar_index * this->bar_width + + minutes_before_sunrise * this->bar_width / 60; + BOOST_LOG_TRIVIAL(debug) << "Drawing sunrise line"; + DrawDashLine(separator_x, separator_start_y, separator_x, + separator_stop_y, LGRAY, 10, 10); + } else if (0 < minutes_before_sunset and minutes_before_sunset < 60) { + const int separator_x = bar_index * this->bar_width + + minutes_before_sunset * this->bar_width / 60; + BOOST_LOG_TRIVIAL(debug) << "Drawing sunset line"; + DrawDashLine(separator_x, separator_start_y, separator_x, + separator_stop_y, LGRAY, 10, 10); + } + } + } else { + BOOST_LOG_TRIVIAL(debug) << "Out-of-range bar index"; + } + } +} + std::map> rotated_icons; const ibitmap *HourlyForecastBox::rotate_direction_icon(int degree) { - BOOST_LOG_TRIVIAL(debug) << "Rotating direction icon, " << degree; const auto arrow_angle = (180 - degree); // The parameter degree is an angle measure in degrees, interpreted // as the direction where the wind is blowing FROM (0 means North, @@ -419,29 +462,19 @@ const ibitmap *HourlyForecastBox::rotate_direction_icon(int degree) { cv::warpAffine(image, rotated_image, rotation_matrix, image.size(), cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0xFF); - BOOST_LOG_TRIVIAL(debug) << "Rotated image has size " << rotated_image.cols - << "×" << rotated_image.rows; - const auto header_size = offsetof(ibitmap, data); const auto data_size = icon_to_rotate->scanline * icon_to_rotate->height; auto &rotated_bitmap_data = rotated_icons[degree]; rotated_bitmap_data.resize(header_size + data_size); - BOOST_LOG_TRIVIAL(debug) << "Vector data for rotated icon added to cache"; - BOOST_LOG_TRIVIAL(debug) - << "Copying " << header_size << " bytes of header data"; std::memcpy(rotated_bitmap_data.data(), icon_to_rotate, header_size); // headers are the same for both bitmap - BOOST_LOG_TRIVIAL(debug) - << "Copying " << data_size << " bytes of image data"; std::memcpy(rotated_bitmap_data.data() + header_size, rotated_image.data, data_size); return reinterpret_cast(rotated_bitmap_data.data()); } - BOOST_LOG_TRIVIAL(debug) << "Rotated icon data found in cache"; - return reinterpret_cast(found->second.data()); } } // namespace taranis diff --git a/src/hourlyforecastbox.h b/src/hourlyforecastbox.h index 28c38a0..e48773f 100644 --- a/src/hourlyforecastbox.h +++ b/src/hourlyforecastbox.h @@ -88,6 +88,8 @@ class HourlyForecastBox : public Widget, public Paginated { void draw_precipitation_histogram() const; + void draw_sunrise_sunset_lines() const; + const ibitmap *rotate_direction_icon(int degree); }; diff --git a/src/util.cc b/src/util.cc index b7b12b7..9cdd76c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -223,6 +223,33 @@ std::string taranis::format_full_date(const TimePoint &time) { std::string{formatted_time}; } +bool taranis::are_same_day(const TimePoint &first, const TimePoint &second) { + const time_t first_time_since_epoch{static_cast( + std::chrono::duration_cast(first - TimePoint{}) + .count())}; + auto first_calendar_time = std::localtime(&first_time_since_epoch); + const time_t second_time_since_epoch{static_cast( + std::chrono::duration_cast(second - TimePoint{}) + .count())}; + auto second_calendar_time = std::localtime(&second_time_since_epoch); + if (first_calendar_time and second_calendar_time) { + const auto first_time_year = first_calendar_time->tm_year; + const auto first_time_year_day = first_calendar_time->tm_yday; + const auto second_time_year = second_calendar_time->tm_year; + const auto second_time_year_day = second_calendar_time->tm_yday; + return first_time_year == second_time_year and + first_time_year_day == second_time_year_day; + } + return false; +} + +int taranis::get_duration_minutes(const TimePoint &start, + const TimePoint &end) { + const auto duration = + std::chrono::duration_cast((end - start)); + return static_cast(duration.count()); +} + std::string taranis::format_duration(const TimePoint &start, const TimePoint &end) { const auto duration = @@ -231,11 +258,7 @@ std::string taranis::format_duration(const TimePoint &start, return "<1h"; } std::stringstream duration_text; - duration_text << static_cast( - std::chrono::duration_cast( - (end - start)) - .count()) - << "h"; + duration_text << static_cast(duration.count()) << "h"; return duration_text.str(); } diff --git a/src/util.h b/src/util.h index f7f1f03..eb5d497 100644 --- a/src/util.h +++ b/src/util.h @@ -69,6 +69,11 @@ std::string format_date(const TimePoint &time, bool shortcut = false); // Saturday, 21st October 2023, 17:05 std::string format_full_date(const TimePoint &time); +bool are_same_day(const TimePoint &first, const TimePoint &second); + +int get_duration_minutes(const TimePoint &start, const TimePoint &end); + +// <1h, 1h, 2h, etc. std::string format_duration(const TimePoint &start, const TimePoint &end); int remaining_hours(const TimePoint &time);