DoJa

2007年2月18日 (日)

DoJaのアフィン変換

Affine

iアプリをチョコチョコといじってみてて、DoJaのアフィン変換描画を試してみました。

アフィン変換の行列計算も、難しくはないけど、なにげに面倒なので、計算結果でも書いておきます。

だれかの役に、たつんじゃないかなと。

作ってみたサンプルが、画像のやつで、こちら。

Qrcode_6 http://shin-ishimaru.cocolog-nifty.com/iapp/AffineDraw/Download.html

DoJaのアフィン変換描画APIがGraphicsの中にあります。

public void drawImage(Image image,
                      int[] matrix)

イメージに 2 次元のアフィン変換をかけて描画します。

イメージ上の座標 (x, y) の画素は、 以下のような行列演算によって求められる座標 (x', y') に描画されます。

 [ x']      1   [ m00 m01 m02  ] [ x ]
[ y'] = ------ [ m10 m11 m12  ] [ y ]
[ 1 ]    4096  [  0   0  4096 ] [ 1 ]

回転させて、指定の座標(dx, dy)に表示したい時は、回転行列に移動をくっつけて、

[ 4096*cosθ -4096*sinθ   dx ]
[ 4096*cosθ  4096*sinθ   dy  ]
[        0                0        4096]

とかしてしまいますが、これで計算してしまうと、画像の一番左上の点を軸に回転してしまう。

回転するんだったら、画像の中心を軸にして回転してほしいので、その分ずらす必要がある。

その移動量をex, eyとすると、

[ 4096*cosθ -4096*sinθ   dx  ][ 1  0  ex]
[ 4096*cosθ  4096*sinθ   dy  ][ 0  1  ey] =   
[        0                0        4096][ 0  0  1  ]

[ 4096*cosθ -4096*sinθ   (cosθ*ex - sinθ*ey + dx)*4096  ]
[ 4096*cosθ  4096*sinθ   (sinθ*ex + cosθ*ey + dy)*4096  ]   
[        0                0                             4096                     ]

これでOK。

ここまで来ると、もうひとつ欲張って、拡大、縮小も入れたくなってくるところ。

X方向の倍率をsx、Y方向の倍率をsyとすると、

[ 4096*cosθ -4096*sinθ   dx  ][sx 0  0][ 1  0  ex]
[ 4096*cosθ  4096*sinθ   dy  ][ 0 sy 0][ 0  1  ey] =   
[        0                0        4096][ 0  0 1 ][ 0  0  1  ]

[ 4096*cosθ -4096*sinθ   (cosθ*ex*sx - sinθ*ey*sy + dx)*4096  ]
[ 4096*cosθ  4096*sinθ   (sinθ*ex*sx + cosθ*ey*sy + dy)*4096  ]   
[        0                0                                      4096                     ]

これを、実際のJavaのコードで関数化して書いてみると、こんな感じ。

    /**
     * 回転、拡大して描画
     * @param i 描画するイメージ
     * @param x 描画する位置X
     * @param y 描画する位置Y
     * @param r 回転角度(4096MAX)
     * @param sx X方向の拡大
     * @param sy Y方向の拡大
     */
    void drawRotScale( Image i, int x, int y, int r, float sx, float sy ){
       
        int []m = new int[6];
       
        m[0] = (int)(Math.cos(r)*sx);
        m[1] = (int)(-Math.sin(r)*sy);
        m[2] = (int)(Math.cos(r)*(-i.getWidth()/2)*sx - Math.sin(r)*(-i.getHeight()/2)*sy + x*4096);
        m[3] = (int)(Math.sin(r)*sx);
        m[4] = (int)(Math.cos(r)*sy);
        m[5] = (int)(Math.sin(r)*(-i.getWidth()/2)*sx + Math.cos(r)*(-i.getHeight()/2)*sy + y*4096);

        g.drawImage(i,m);
   
    }

DoJaのMath.sin, cosは4096倍された数値が返ってくるため、コード上は計算式より、4096かけてるところが少ないのに注意。

ソースコードは、ここに置いときます。

画像は、んぱかさんのシューティングゲームサンプルから借用。

AffineDraw.zip


D703iでは、結構さくさく動作。

スーパーファミコンみたいで、良い感じですな。

drawImageに使われてる式が、なにげに4096かけたり割ったりしている、ちょっと変わった式なんで、計算してみないとよくわからず、計算してみたって感じですね。

このブログについて

  • S_Ishimaru is ...

    Mac、デジカメ、音楽、楽器ガジェット、プログラミング、iPhone、ケータイなど色々興味を持ったことについて書いているブログです。


    シン石丸について

AMAZON コンピュータ・インターネット本

AMAZON 本ベストセラー

GoogleAnalytics

Google BLOG内検索

無料ブログはココログ

AMAZON エレクトロニクス

AMAZON ゲームベストセラー

2015年11月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30