NISHIO Hirokazu[Translate]
二本指ジェスチャでズームと平行移動
iPadの二本指のジェスチャで、拡大縮小と平行移動をしようと考えた。

最初は「二本の指の重心の移動量を平行移動、指の間隔の増減比率を拡大縮小にする」と実装したが、これは正しくない。

どう正しくないのか。タッチスタートの位置をo1, o2、現在のタッチ位置をp1, p2とする。
たとえば画面端で重心を保ちながら1/2に指を縮めたとする。 (4, 0), (4, 4) → (4, 1), (4, 3)
この場合、上記の計算式だと平行移動なしで1/2に縮むことになる。原点に対してでも画面中心に対してでもおかしい。
二本の指の重心に対して縮む必要がある。

では変形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での微分

これが「二本の指の重心の移動量を平行移動、指の間隔の増減比率を拡大縮小にする」とは別物であることは簡単に示せる。
例えばこういう移動をした場合、指の間隔の増減を拡大率にするタイプでは0.7倍ぐらいになる。
でも「回転しない」という条件下でもっとも誤差を少なくしようとすると、0.5倍するのが正しい。
上記の計算式は「0.5倍して(2, 1)移動」と適切に答えることができる。


"Engineer's way of creating knowledge" the English version of my book is now available on [Engineer's way of creating knowledge]

(C)NISHIO Hirokazu / Converted from [Scrapbox] at [Edit]