2006 年 3 月 7 日 23 時 35 分

中心を基準に回転


このアーカイブは同期化されません。 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);



Copyright (c) 1994-2007 Project Loafer. All rights reserved.