diff --git a/rotation.cpp b/rotation.cpp index 57f2830..052cfbf 100644 --- a/rotation.cpp +++ b/rotation.cpp @@ -88,7 +88,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int& Point p(0, 0); double angle = convert_radian(src, p, ratio); - DPoint tl = convert_abs_coord(angle + rotation, ratio); + DPoint const tl = convert_abs_coord(angle + rotation, ratio); min_w = min(min_w, tl.x); max_w = max(max_w, tl.x); min_h = min(min_h, tl.y); @@ -96,7 +96,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int& p = Point(src.width - 1, 0); angle = convert_radian(src, p, ratio); - DPoint tr = convert_abs_coord(angle + rotation, ratio); + DPoint const tr = convert_abs_coord(angle + rotation, ratio); min_w = min(min_w, tr.x); max_w = max(max_w, tr.x); min_h = min(min_h, tr.y); @@ -104,7 +104,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int& p = Point(0, src.height - 1); angle = convert_radian(src, p, ratio); - DPoint bl = convert_abs_coord(angle + rotation, ratio); + DPoint const bl = convert_abs_coord(angle + rotation, ratio); min_w = min(min_w, bl.x); max_w = max(max_w, bl.x); min_h = min(min_h, bl.y); @@ -112,7 +112,7 @@ void compute_output_size(Image const& src, double const rotation, unsigned int& p = Point(src.width - 1, src.height - 1); angle = convert_radian(src, p, ratio); - DPoint br = convert_abs_coord(angle + rotation, ratio); + DPoint const br = convert_abs_coord(angle + rotation, ratio); min_w = min(min_w, br.x); max_w = max(max_w, br.x); min_h = min(min_h, br.y); @@ -164,12 +164,11 @@ inline void rotate_pixel(Image const& src, Point const& src_rotated_point, unsigned int const src_limit, - pvalue_t* rotate_buffer, unsigned int rot_index) + pvalue_t* rotate_buffer, unsigned int rot_index, + unsigned int q_pow, unsigned int q) { - unsigned int const quantize = 8; - - int const src_x = src_rotated_point.x >> 3; - int const src_y = src_rotated_point.y >> 3; + int const src_x = src_rotated_point.x >> q_pow; + int const src_y = src_rotated_point.y >> q_pow; unsigned int src_index = (src_y * src.width + src_x) * src.pixel_size; @@ -182,17 +181,17 @@ void rotate_pixel(Image const& src, if (src_index_4 >= src_limit) return; - unsigned int x_delta = src_rotated_point.x & 0x07;; - unsigned int y_delta = src_rotated_point.y & 0x07; - unsigned int const inv_x = quantize - x_delta; - unsigned int const inv_y = quantize - y_delta; + unsigned int x_delta = src_rotated_point.x & 0x0f; + unsigned int y_delta = src_rotated_point.y & 0x0f; + unsigned int const inv_x = q - x_delta; + unsigned int const inv_y = q - y_delta; #ifndef SIMD unsigned int src_index_2 = src_index_1 + src.pixel_size; rotate_buffer[rot_index] = ((src.buffer[src_index_1] * inv_x + src.buffer[src_index_2] * x_delta) * inv_y - + (src.buffer[src_index_3] * inv_x + src.buffer[src_index_4] * x_delta) * y_delta) >> 6; + + (src.buffer[src_index_3] * inv_x + src.buffer[src_index_4] * x_delta) * y_delta) >> (2 * q_pow); // rotate_buffer[rot_index + 1] = ((src.buffer[src_index_1 + 1] * inv_x + src.buffer[src_index_2 + 1] * x_delta) * inv_y // + (src.buffer[src_index_3 + 1] * inv_x + src.buffer[src_index_4 + 1] * x_delta) * y_delta) >> 6; // rotate_buffer[rot_index + 2] = ((src.buffer[src_index_1 + 2] * inv_x + src.buffer[src_index_2 + 2] * x_delta) * inv_y @@ -214,7 +213,7 @@ void rotate_pixel(Image const& src, bottom = _mm_mullo_epi16(bottom, coef); top = _mm_add_epi16(top, bottom); - top = _mm_srli_epi16(top, 6); + top = _mm_srli_epi16(top, 2 * q_pow); rotate_buffer[rot_index] = _mm_extract_epi16(top, 0) + _mm_extract_epi16(top, 4); // rotate_buffer[rot_index + 1] = _mm_extract_epi16(top, 1) + _mm_extract_epi16(top, 5); @@ -232,29 +231,20 @@ Image* rotate(Image const& src, double angle) compute_output_size(src, rotation, w, h); Image* rotated = new Image(w, h, src.type); - // corner points in rotated image - // TODO: add one ligne for smooth border - DPoint const tl_grid = get_mapped_point(src, Point(0, 0), rotation); - Point const tl = convert_img_coord(*rotated, tl_grid); - - // corner points in source image - DPoint src_tl = get_mapped_point(*rotated, tl, -rotation); - src_tl = convert_img_coord_precision(src, src_tl); - DPoint const src_origin = get_mapped_point(*rotated, Point(0, 0), -rotation); - DPoint src_delta_x = get_mapped_point(*rotated, Point(1, 0), -rotation); - DPoint src_delta_y = get_mapped_point(*rotated, Point(0, 1), -rotation); - + DPoint src_delta_x = get_mapped_point(*rotated, Point(src.width - 1, 0), -rotation); + DPoint src_delta_y = get_mapped_point(*rotated, Point(0, src.height - 1), -rotation); src_delta_x.x = src_delta_x.x - src_origin.x; src_delta_x.y = src_delta_x.y - src_origin.y; - round_if_very_small(src_delta_x.x); - round_if_very_small(src_delta_x.y); src_delta_y.x = src_delta_y.x - src_origin.x; src_delta_y.y = src_delta_y.y - src_origin.y; - round_if_very_small(src_delta_y.x); - round_if_very_small(src_delta_y.y); - unsigned int const src_limit = src.width * src.height * src.pixel_size; + // Quantized delta + unsigned int const q_pow = 4; + int const q = pow(2, q_pow); + // TODO: we could have only one delta and deduce the other one + Point const qdx((src_delta_x.x * q) / src.width, (src_delta_x.y * q) / src.width); + Point const qdy((src_delta_y.x * q) / src.height, (src_delta_y.y * q) / src.height); DPoint const rot_origin_in_src_grid = get_mapped_point(*rotated, Point(0, 0), -rotation); DPoint const rot_origin_in_src = convert_img_coord_precision(src, rot_origin_in_src_grid); @@ -262,28 +252,30 @@ Image* rotate(Image const& src, double angle) unsigned int buffer_index = 0; pvalue_t* buffer = rotated->buffer; - unsigned int const quantize = 8; - int const& src_qwidth = src.width * quantize; - int const& src_qheight = src.height * quantize; + int const src_qwidth = src.width * q; + int const src_qheight = src.height * q; - for (unsigned int y = 0; y < rotated->height; ++y) + unsigned int const src_limit = src_qwidth * src_qheight * src.pixel_size; + + for (int y = 0; y < (int) rotated->height; ++y) { - Point const src_rotated_point((rot_origin_in_src.x + y * src_delta_y.x) * quantize, - (rot_origin_in_src.y + y * src_delta_y.y) * quantize); + Point src_rotated_point((rot_origin_in_src.x * q) + y * qdy.x, + (rot_origin_in_src.y * q) + y * qdy.y); for (unsigned int x = 0; x < rotated->width; ++x) { - Point const src_runner(src_rotated_point.x + x * src_delta_x.x * quantize, - src_rotated_point.y + x * src_delta_x.y * quantize); - - if (src_runner.x >= 0 && src_runner.x < src_qwidth - && src_runner.y >= 0 && src_runner.y < src_qheight) + if (src_rotated_point.x >= 0 && src_rotated_point.x < src_qwidth + && src_rotated_point.y >= 0 && src_rotated_point.y < src_qheight) { - rotate_pixel(src, src_runner, + rotate_pixel(src, src_rotated_point, src_limit, - buffer, buffer_index); + buffer, buffer_index, + q_pow, q); } + src_rotated_point.x += qdx.x; + src_rotated_point.y += qdx.y; + buffer_index += rotated->pixel_size; } }