このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
昨日の回転では、回転の基準が左上となっていた。
なので、180 度とか回転すると、画面の外にいってしまう。
また、画面内に見えたとしても、画像の端が切れていた。
今日はそれを修正しよう。
まず、回転の基準を画像の中央にすること、
これは、画像の幅や高さの半分を引いてから
座標の計算をすれば良い。
次に、回転したときに端が切れないようにすること。
どの角度でも入りきるように長さを考えれば良い。
その長さとは、画像の左上から右下までの斜めの長さである。
これは、ピタゴラスの定理により、
(高さの自乗+幅の自乗)の平方根で求められる。
では、これを踏まえてやってみよう。
use POSIX;
no integer;
# 回転角を定義。今日は 170 度。
my $angle = 170 * (atan2(0, -1)) / 180;
# BMP 読み込み。
my $src = read_bmp;
# 画像の幅と高さを取得。
my $scx = @{$src->[0]};
my $scy = @$src;
# 画像の中心を求める。
my $sox = $scx / 2;
my $soy = $scy / 2;
# 新しい画像の幅と高さを十分に取っておく。
# 元の画像の斜めの長さを求めて使う。
my $dcx = ceil(sqrt($scx * $scx + $scy * $scy));
my $dcy = $dcx;
# 新しい画像の中心を求める。
my $dox = $dcx / 2;
my $doy = $dcy / 2;
# サインとコサインを求めておく。
my $sin = sin($angle);
my $cos = cos($angle);
# 新しい画像のデータを準備する。
my $dest = [ map { [ (0) x $dcx ] } 1 .. $dcy ];
for (my $dy = 0; $dy < $dcy; ++$dy) {
for (my $dx = 0; $dx < $dcx; ++$dx) {
no integer;
# 新しい要素番号に対応する元の要素番号を求める。
my $sx = $sox + $cos * ($dx - $dox + 0.5)
+ $sin * ($dy - $doy + 0.5);
my $sy = $soy + $cos * ($dy - $doy + 0.5)
- $sin * ($dx - $dox + 0.5);
# 最も近い要素位置を求める。
$sx = floor($sx); # floor($sx - 0.5 + 0.5)
$sy = floor($sy); # floor($sy - 0.5 + 0.5)
# 範囲内なら転送する。
if ($sx >= 0 and $sx < $scx and $sy >= 0 and $sy < $scy) {
$dest->[$dy][$dx] = $src->[$sy][$sx];
}
}
}
# BMP を書き出す。
write_bmp($dest, 24);