HTML5テクニカルノート EaselJSのMatrix2D.scale()メソッドを他の変換の後に呼出すと正しく伸縮されない
EaselJS 0.6.0のMatrix2Dクラスは、2次元平面における座標を行列により変換します。座標変換には、回転と伸縮、および平行移動があります。Matrix2D.scale()は、伸縮を担うメソッドです。ところが、他の変換の後にこのメソッドを呼出すと、正しく伸縮されないことがあります。 [追記: 2013年5月16日] 2013年5月15日付GitHubでこの問題は修正されました。 01 まったく伸縮されない例デフォルトのMatrix2Dオブジェクト(単位行列)をMatrix2D.rotate()メソッドで90度(π/2ラジアン)回転すると、Matrix2D.scale()メソッドで伸縮することはできなくなります。 たとえばつぎのコードは、新たなMatrix2DオブジェクトにMatrix2D.rotate()メソッドで90度(Math.PI / 2ラジアン)の回転を加えたうえ、Matrix2D.scale()メソッドによりxyともに2倍に拡大します。ところが、そのMatrix2DオブジェクトをMatrix2D.decompose()メソッドでインスタンス(myBitmap)に適用しても、90度回るだけで大きさが変わりせん(図001)。 図001■インスタンスは90度回るだけで拡大しない
jsdo.itにテストコードを掲げました。[Play]ボタンで実行して画像をクリックすると、前掲コードと同じ変換のスクリプト(リスナー関数testTransform())が適用されます。インスタンスはMatrix2D.rotate()メソッドで90度回転しても、Matrix2D.scale()メソッドによる大きさの変化は見られません。
前掲コードで、Matrix2D.rotate()とMatrix2D.scale()メソッドを呼出した後のMatrix2Dオブジェクトをそれぞれ文字列に表す(Matrix2D.toString())と、変換行列の成分値がわかります。 Matrix2D.rotate()メソッドで90度回転: わずかな誤差を丸めれば、ふたつの変換行列の成分はともにつぎの値になります。したがって、Matrix2D.scale()メソッドによる伸縮の変換は、変換行列の成分値に表れていないということです。 a=0 b=1 c=-1 d=0 tx=0 ty=0 02 Matrix2D.scale()メソッドの実装Matrix2D.scale()メソッドで伸縮の行列変換を行った結果、なぜ前述のように成分値が変わらないのかは、メソッドの実装を見れば確かめられます。Matrix2D.scale()メソッドは、つぎのコード001のように、引数のxy伸縮率を成分のa、d、tx、tyに乗じています。ところが、デフォルトのMatrix2Dオブジェクト(単位行列)を90度回転すると、前述のとおりこれら4成分値はすべて0になります。ですから、演算結果が変わらないのです。 コード001■Matrix2D.scale()メソッドの実装
逆にいえば、90度回転したMatrix2Dオブジェクトを伸縮するには、変換行列の成分bとcについても計算しなければならないということです。したがって、EaselJS 0.6.0のMatrix2D.scale()メソッドの実装が誤っています。正しい実装は、変換行列の計算をしなければなりませんので、次項で論じます。当面の対処法としては、Matrix2D.prependTransform()メソッドを用いることが考えられます。 Matrix2Dオブジェクト.prependTransform(x座標, y座標, x伸縮率, y伸縮率, 回転角, x傾斜角, y傾斜角, x基準点, y基準点) Matrix2D.scale()メソッドのふたつの引数と同じxyの伸縮率が、第3および第4引数で定められます。座標の移動はありませんので、第1および第2引数は0とします。そして、第5引数以降は省いて構いません。なお、前掲jsdo.itのテストコードにも、Matrix2D.prependTransform()メソッドはコメントアウトで添えてあります。
03 EaselJS 0.6.1で修正されたMatrix2D.scale()メソッドの実装2013年5月11日にGitHubで公開されたEaselJS 0.6.1では、Matrix2D.scale()メソッドの実装がつぎのコード002のように修正されました。「CreateJS Support」への5月5日の投稿「Calculation problem of Matrix2D.scale method」にもとづくものです。 コード002■EaselJS 0.6.1におけるMatrix2D.scale()メソッドの実装
成分bとcの計算が加えられました(第4〜5行目)。したがって、90度回転した後伸縮できないという問題はなくなります。他方で、成分txとtyの計算が除かれました。そのため、前述のMatrix2D.prependTransform()メソッドを用いた場合の結果とは、成分txとtyの値が異なります。同じ結果を得るには、次項04「Matrix2D.scale()メソッドを正しく実装する」のように実装しなければなりません。 [追記: 2013年5月16日] 2013年5月15日付のGitHubで以下の実装のとおり修正されました。 04 Matrix2D.scale()メソッドを正しく実装するでは、Matrix2D.scale()メソッドは、どう実装すれば正しい伸縮の変換ができるでしょう。Matrix2Dクラスが扱う2次元平面の変換行列は、つぎのような3行×3列の正方行列で表されます。ただし、第3行目の成分は定数([0 0 1])なので、実質の計算は6成分で行われます。
変換行列の演算は乗算です。xとyで伸縮するには、伸縮率を対角成分としたつぎの変換行列を掛合わせます。
Matrix2D.scale()メソッドの伸縮は、この行列を左から乗じます。水平と垂直の伸縮率をそれぞれxおよびyとすれば、つぎのような行列の掛け算になります。なお、行列の乗算については「変換行列を数学的に捉える」2.「行列の乗算」をお読みください。
この計算にもとづいてMatrix2D.scale()メソッドを正しく実装すると、つぎのコード003のようになります。前掲コード001に、成分bとcの演算が加わっています(第3〜4行目)。EaselJSライブラリの読込み後にこのコードを書けば、Matrix2D.scale()メソッドは伸縮の演算を正しく行います。なお、前掲jsdo.itのテストコードにもコメントアウトで加えてあります。 コード003■Matrix2D.scale()メソッドの正しい実装
作成者: 野中文雄 Copyright © 2001-2013 Fumio Nonaka. All rights reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||