Skip to content

Commit

Permalink
Factorization of image rotation
Browse files Browse the repository at this point in the history
Refs: #16
  • Loading branch information
orontee committed Nov 2, 2024
1 parent 063502a commit 9cba00a
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 42 deletions.
1 change: 0 additions & 1 deletion .clang-format-ignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
src/about.cc
src/icons.cc
src/l10n.cc
35 changes: 4 additions & 31 deletions src/hourlyforecastbox.cc
Original file line number Diff line number Diff line change
Expand Up @@ -466,39 +466,12 @@ void HourlyForecastBox::draw_sunrise_sunset_lines() const {
std::map<int, std::vector<unsigned char>> rotated_icons;

const ibitmap *HourlyForecastBox::rotate_direction_icon(int 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,
// 90 East), but the icon arrow must show where the wind is blowing
// TO. Whats more OpenCV rotation is counter-clockwise for positive
// angle values.
auto found = rotated_icons.find(degree);
if (found == rotated_icons.end()) {
auto *const icon_to_rotate = const_cast<ibitmap *>(this->direction_icon);
const cv::Mat image{icon_to_rotate->height, icon_to_rotate->width, CV_8UC1,
icon_to_rotate->data};
const cv::Point2f center{
static_cast<float>((icon_to_rotate->width - 1) / 2.0),
static_cast<float>((icon_to_rotate->height - 1) / 2.0)};
const cv::Mat rotation_matrix =
cv::getRotationMatrix2D(center, arrow_angle, 1.0);
cv::Mat rotated_image{icon_to_rotate->height, icon_to_rotate->width,
CV_8UC1};
cv::warpAffine(image, rotated_image, rotation_matrix, image.size(),
cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0xFF);

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);

std::memcpy(rotated_bitmap_data.data(), icon_to_rotate, header_size);
// headers are the same for both bitmap

std::memcpy(rotated_bitmap_data.data() + header_size, rotated_image.data,
data_size);

return reinterpret_cast<ibitmap *>(rotated_bitmap_data.data());

rotated_icons[degree] = this->icons->rotate_icon(
const_cast<ibitmap *>(this->direction_icon), degree);
return reinterpret_cast<ibitmap *>(rotated_icons[degree].data());
}
return reinterpret_cast<ibitmap *>(found->second.data());
}
Expand Down
2 changes: 0 additions & 2 deletions src/hourlyforecastbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ class HourlyForecastBox : public Widget, public Paginated {
std::shared_ptr<Icons> icons;
std::shared_ptr<Fonts> fonts;

std::map<int, const ibitmap *> rotated_direction_icons;

const ibitmap *const direction_icon;

int bar_width;
Expand Down
46 changes: 46 additions & 0 deletions src/icons.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "icons.h"

#include <cstring>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>

namespace taranis {

std::vector<unsigned char> Icons::rotate_icon(ibitmap *icon_to_rotate,
int 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,
// 90 East), but the icon arrow must show where the wind is blowing
// TO. Whats more OpenCV rotation is counter-clockwise for positive
// angle values.
if (!icon_to_rotate) {
return {};
}
const cv::Mat image{icon_to_rotate->height, icon_to_rotate->width, CV_8UC1,
icon_to_rotate->data};
const cv::Point2f center{
static_cast<float>((icon_to_rotate->width - 1) / 2.0),
static_cast<float>((icon_to_rotate->height - 1) / 2.0)};
const cv::Mat rotation_matrix =
cv::getRotationMatrix2D(center, arrow_angle, 1.0);
cv::Mat rotated_image{icon_to_rotate->height, icon_to_rotate->width, CV_8UC1};
cv::warpAffine(image, rotated_image, rotation_matrix, image.size(),
cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0xFF);

const auto header_size = offsetof(ibitmap, data);
const auto data_size = icon_to_rotate->scanline * icon_to_rotate->height;

std::vector<unsigned char> rotated_bitmap_data;
rotated_bitmap_data.resize(header_size + data_size);

std::memcpy(rotated_bitmap_data.data(), icon_to_rotate, header_size);
// headers are the same for both bitmap

std::memcpy(rotated_bitmap_data.data() + header_size, rotated_image.data,
data_size);

return rotated_bitmap_data;
}
} // namespace taranis
6 changes: 5 additions & 1 deletion src/icons.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

#include <boost/log/trivial.hpp>
#include <inkview.h>
#include <string>
#include <vector>

#include <inkview.h>

extern const ibitmap icon_01n_2x;
extern const ibitmap icon_02n_2x;
Expand Down Expand Up @@ -102,5 +104,7 @@ class Icons {

return nullptr;
}

std::vector<unsigned char> rotate_icon(ibitmap *icon_to_rotate, int degree);
};
} // namespace taranis
15 changes: 8 additions & 7 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ pbres_command = find_program(
sed_command = find_program('sed', required: true)
# dependency of convert_resources_command

icons_c = custom_target(
icons_resources_c = custom_target(
'generate-icons-resources-c',
output: 'icons.c',
output: 'icon_resources.c',
input: icons,
command: [pbres_command, '-c', '@OUTPUT@', '-8', '@INPUT@']
)

convert_resources_command = find_program('../scripts/convert_ressources.sh',
required: true)

icons_cc = custom_target(
icon_resources_cc = custom_target(
'convert-resources-cc',
output: 'icons.cc',
input: icons_c,
depends: [icons_c],
output: 'icon_resources.cc',
input: icons_resources_c,
depends: [icons_resources_c],
command: [convert_resources_command, '@INPUT@', '@OUTPUT@']
)

Expand All @@ -59,7 +59,7 @@ l10n_cc = custom_target(
'@SOURCE_ROOT@/po']
)

sources = [about_cc, icons_cc, l10n_cc] + files(
sources = [about_cc, icon_resources_cc, l10n_cc] + files(
'alerts.cc',
'app.cc',
'config.cc',
Expand All @@ -71,6 +71,7 @@ sources = [about_cc, icons_cc, l10n_cc] + files(
'forecast.cc',
'hourlyforecastbox.cc',
'http.cc',
'icons.cc',
'locationbox.cc',
'locationselector.cc',
'logging.cc',
Expand Down

0 comments on commit 9cba00a

Please sign in to comment.