gint/src/image/image_rotate_around_scale.c

61 lines
2.0 KiB
C

#include <gint/image.h>
#include <math.h>
#include "fixed.h"
void image_rotate_around_scale(image_t const *src, float alpha, int gamma,
bool resize, int *center_x, int *center_y, struct image_linear_map *map)
{
if(!image_valid(src))
return;
map->src_w = src->width;
map->src_h = src->height;
/* Compute the rotation basis */
int cos_alpha = fconst(cosf(alpha));
int sin_alpha = fconst(sinf(alpha));
int inv_gamma = fdiv(fconst(1.0), gamma);
map->dx_u = fmul(cos_alpha, inv_gamma);
map->dx_v = fmul(sin_alpha, inv_gamma);
map->dy_u = -fmul(sin_alpha, inv_gamma);
map->dy_v = fmul(cos_alpha, inv_gamma);
/* Don't try to resize cleanly; just make the longest diagonal the width if
[resize=true] to make sure everything fits */
if(resize) {
int diag = isqrt(src->width * src->width + src->height * src->height);
map->dst_w = fround(gamma * diag);
map->dst_h = fround(gamma * diag);
}
else {
map->dst_w = fround(gamma * src->width);
map->dst_h = fround(gamma * src->height);
}
/* Compute the new location of the anchor relative to the image center.
This is found by a neat trick: rotate it with the same angle */
int ax = *center_x - map->src_w / 2;
int ay = *center_y - map->src_h / 2;
int ax2 = fround(fmul(gamma, cos_alpha * ax + sin_alpha * ay));
int ay2 = fround(fmul(gamma, -sin_alpha * ax + cos_alpha * ay));
int new_center_x = ax2 + map->dst_w / 2;
int new_center_y = ay2 + map->dst_h / 2;
/* Finally, determine the initial value of (u,v). We now that it evaluates
to (center_x, center_y) when on the new center point (new_center_x,
new_center_y); apply the difference accordingly. */
map->u = fconst(*center_x)
- map->dx_u * new_center_x
- map->dy_u * new_center_y;
map->v = fconst(*center_y)
- map->dx_v * new_center_x
- map->dy_v * new_center_y;
*center_x = new_center_x;
*center_y = new_center_y;
}