二本指ジェスチャでズームと平行移動
iPadの二本指のジェスチャで、拡大縮小と平行移動をしようと考えた。
最初は「二本の指の重心の移動量を平行移動、指の間隔の増減比率を拡大縮小にする」と実装したが、これは正しくない。
どう正しくないのか。タッチスタートの位置をo1, o2、現在のタッチ位置をp1, p2とする。
たとえば画面端で重心を保ちながら1/2に指を縮めたとする。(4, 0), (4, 4) → (4, 1), (4, 3)
この場合、上記の計算式だと平行移動なしで1/2に縮むことになる。原点に対してでも画面中心に対してでもおかしい。
二本の指の重心に対して縮む必要がある。
https://gyazo.com/dc7f454780c7554eb9cb8e63a42495f6
では変形fを一般に「原点に対してs倍になってからx, y平行移動する」と表現するなら、このs, x, yはそれぞれどうなるか。
$ f(o_1) = p_1, f(o_2) = p_2が理想だが、変形が回転を含まないのでタッチの動きによっては実現不能である。
そこで$ E = (f(o_1) - p_1) ^2 + (f(o_2) - p_2)^2 を最小化することにする。(最小二乗法) Eをそれぞれs, x, yで微分して0とおき、式を整理する。
$ x = ((p_1 + p_2)_x - s (o_1 + o_2)_x)/2
$ y = ((p_1 + p_2)_y - s (o_1 + o_2)_y)/2
これをsでの微分に代入してx, yを決して整理するとsを求める式が得られる。
$ a = 2 (o_1 \cdot p_1 + o_2 \cdot p_2)
$ b = |o_1 - o_2|^2
$ c = (o_1 + o_2) \cdot (p_1 + p_2)
$ s = (a - c) / b
参考: sでの微分
https://gyazo.com/0d62efd2cb9596c8c22172b4e50dcfce
これが「二本の指の重心の移動量を平行移動、指の間隔の増減比率を拡大縮小にする」とは別物であることは簡単に示せる。
https://gyazo.com/d9d24e63d041fc296ffeb2c51c811447
例えばこういう移動をした場合、指の間隔の増減を拡大率にするタイプでは0.7倍ぐらいになる。
でも「回転しない」という条件下でもっとも誤差を少なくしようとすると、0.5倍するのが正しい。
上記の計算式は「0.5倍して(2, 1)移動」と適切に答えることができる。
https://gyazo.com/60bce24dfc5d6b8634156fa21dbeba3e