座標を回転させる方法

MDSで二次元座標を作った。実験前と実験後の態度変容を見るために,2つのマップを書いたのだけどマップA→マップBにかわった,ということがわかるためにマップ内のある点p→p’を重ねて,他の座標がどう変わるかを見ようと思った。図は原点を中心にした点対象だから,ぐるぐる回せるのだね。つまり,p→p’の二つのベクトルから回転角を導いて,pre座標にかければよい。
ここまではすぐわかったのだけど,2つのベクトルがなす角ってどうやって算出するんだ,というところで手が止まってしまった。基礎的な素養がないとこういうときに困るのだね。

Twitter上で困ったなぁ,誰かわかる人募集,と呟いていたら,@masashikomoriさんが教えてくれました。感謝。
実は教えてもらってもすぐにできなくて,「あれ?回転させたはずなのに一致しないな」となったところ「反対回りになってないかチェックしてね」「ノルムを合わせないと」と丁寧にフォローしてくれました。で,できた答えがこれ。

<span class="synComment">#x,y x', y'の座標を設定</span>
a <span class="synStatement">&lt;-</span> c<span class="synSpecial">(</span><span class="synConstant">1</span><span class="synSpecial">,</span><span class="synConstant">2</span><span class="synSpecial">)</span>
b <span class="synStatement">&lt;-</span> c<span class="synSpecial">(</span><span class="synConstant">3</span><span class="synSpecial">,</span><span class="synConstant">4</span><span class="synSpecial">)</span>
<span class="synComment">#角度(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%B8%A5%A2%A5%F3">ラジアン</a>)をrotに</span>
rot = <a class="keyword" href="http://d.hatena.ne.jp/keyword/acos">acos</a> <span class="synSpecial">(</span>t<span class="synSpecial">(</span>a<span class="synSpecial">)</span> %*% b/sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>a<span class="synSpecial">)</span> %*% a<span class="synSpecial">)</span> * <span class="synSpecial">(</span>t<span class="synSpecial">(</span>b<span class="synSpecial">)</span> %*% b<span class="synSpecial">)))</span>
<span class="synComment">#回転行列</span>
rotmat <span class="synStatement">&lt;-</span> <span class="synType">matrix</span><span class="synSpecial">(</span>c<span class="synSpecial">(</span>cos<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>-sin<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>sin<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>cos<span class="synSpecial">(</span>rot<span class="synSpecial">)),</span> <span class="synConstant">2</span><span class="synSpecial">,</span> <span class="synConstant">2</span><span class="synSpecial">)</span>
<span class="synComment">#xyの回転後座標</span>
a_rotated <span class="synStatement">&lt;-</span> rotmat %*% a
<span class="synComment">#回転後のaをbのノルムにそろえる</span>
a_rotated %*% <span class="synSpecial">(</span>sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>b<span class="synSpecial">)</span> %*% b<span class="synSpecial">))</span>/sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>a<span class="synSpecial">)</span> %*% a<span class="synSpecial">)))</span>

ありがとうございました。

実際やりたかったことは,MDSの座標をつかうので,どの要素でも良いから1つ合わせるところを決めて回せばよかったのです。で,関数を作ってみた。

関数rotateConfigには,元の座標(pre),目的座標(post)に座標を入れて,何行目の要素で合わせるのかを指定し(key),ノルムをそろえるかどうか(norm.adj,デフォルトはFALSE),逆回転するかどうか(rev,デフォルトはFALSE((角度だけだとどっち向きかわからなくて,合わないこともある。合わなかったら逆を算出するようオプションをつけた。ホントはこれを自動化したいのだけど,時間が無かった。)))を指定すると,全体が回転された座標が返ってくるというもの。自慢になる関数ではないが,備忘録として書いておく。

rotateConfig <span class="synStatement">&lt;-</span> <span class="synType">function</span><span class="synSpecial">(</span>pre<span class="synSpecial">,</span>post<span class="synSpecial">,</span>key<span class="synSpecial">,</span>norm.adj=<span class="synConstant">FALSE</span><span class="synSpecial">,</span>rev=<span class="synConstant">FALSE</span><span class="synSpecial">){</span>
prePoint <span class="synStatement">&lt;-</span> pre<span class="synSpecial">[</span>key<span class="synSpecial">,]</span>
postPoint <span class="synStatement">&lt;-</span> post<span class="synSpecial">[</span>key<span class="synSpecial">,]</span>
<span class="synComment">#角度(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%B8%A5%A2%A5%F3">ラジアン</a>)をrotに</span>
rot = <a class="keyword" href="http://d.hatena.ne.jp/keyword/acos">acos</a> <span class="synSpecial">(</span>t<span class="synSpecial">(</span>prePoint<span class="synSpecial">)</span> %*% postPoint/sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>prePoint<span class="synSpecial">)</span> %*% prePoint<span class="synSpecial">)</span> * <span class="synSpecial">(</span>t<span class="synSpecial">(</span>postPoint<span class="synSpecial">)</span> %*% postPoint<span class="synSpecial">)))</span>
<span class="synStatement">if</span><span class="synSpecial">(</span>rev==T <span class="synSpecial">){</span> rot <span class="synStatement">&lt;-</span> rot *-<span class="synConstant">1</span> <span class="synSpecial">}</span>
<span class="synComment">#回転行列</span>
rotmat <span class="synStatement">&lt;-</span> <span class="synType">matrix</span><span class="synSpecial">(</span>c<span class="synSpecial">(</span>cos<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>-sin<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>sin<span class="synSpecial">(</span>rot<span class="synSpecial">),</span>cos<span class="synSpecial">(</span>rot<span class="synSpecial">)),</span> <span class="synConstant">2</span><span class="synSpecial">,</span> <span class="synConstant">2</span><span class="synSpecial">)</span>
<span class="synComment"># xyの回転後座標</span>
a_rotated <span class="synStatement">&lt;-</span> rotmat %*% t<span class="synSpecial">(</span>pre<span class="synSpecial">)</span>
<span class="synComment">#回転後のノルムをそろえる(オプション)</span>
<span class="synStatement">if</span><span class="synSpecial">(</span> norm.adj==<span class="synConstant">TRUE</span><span class="synSpecial">){</span>
ret <span class="synStatement">&lt;-</span>a_rotated * <span class="synSpecial">(</span>sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>postPoint<span class="synSpecial">)</span> %*% postPoint<span class="synSpecial">))</span>/sqrt<span class="synSpecial">((</span>t<span class="synSpecial">(</span>prePoint<span class="synSpecial">)</span> %*% prePoint<span class="synSpecial">)))[</span><span class="synConstant">1</span><span class="synSpecial">,</span><span class="synConstant">1</span><span class="synSpecial">]</span>
<span class="synSpecial">}</span><span class="synStatement">else</span><span class="synSpecial">{</span>
ret <span class="synStatement">&lt;-</span> a_rotated
<span class="synSpecial">}</span>
<span class="synStatement">return</span><span class="synSpecial">(</span>t<span class="synSpecial">(</span>ret<span class="synSpecial">))</span>
<span class="synSpecial">}</span>