

3つの3次元ベクトルA,B,Cがあり、ABを2次元空間のx軸に、ACを2次元空間のy軸にそれぞれ当てはめるような座標変換をするにはどうすればいいでしょうか。

[![3つの3次元ベクトルから新しい3次元系に変換](https://i.stack.imgur.com/J4X5x.png)](https://i.stack.imgur.com/J4X5x.png)  
素人考えでは下記のような操作ができればと思っているのですが、具体的なプログラムが組めません…。

  1. ABが新しい3次元系のx軸になるように回転する
  2. ACが新しい3次元系のxy平面上にくるように回転する
  3. ACが新しい3次元系のy軸にくるようカメラ？のz座標を調整する

よろしくお願いいたします。


CC BY-SA 3.0
2016-05-12T03:13:38.523
24773
2016-05-12T07:10:40.900
15462
question
python numpy
3つの3次元ポイントを軸とする2次元に変換するには


与えられた座標pに対して  
1\. まずAが原点になるようにAを平行移動する `(p-A)`  
2\. ABがx軸， ACがy軸, ABとACのつくる平面に直行する軸をz軸とする(右手系で考える)， そのような変換をする回転行列Rをかける
`R*(p-A)`

どのように回転行列をつくるかを説明します． まずベクトルABを正規化したものをベクトルbとする． また同様にベクトルACの正規化したものをcとする．
ABC面と直行したベクトルをdとしこれはbとcの外積になっている．
このときb,c,dに回転行列Rを作用するとそれぞれx,y,z軸になるようにしたいので以下をみたす．  
Rb = (1, 0, 0)  
Rc = (0, 1, 0)  
Rd = (0, 0, 1)  
これをとくと R^-1 = (b, c, d) , R^-1は3x3の行列でたてベクトルb,c,dをならべたもの．  
よって R = (b, c, d)^-1 = (b, c, cross(b, c))^-1

[code]

    import numpy
    
    A = numpy.array([0.1,0.1,0.1])
    B = numpy.array([2,1,5])
    C = numpy.array([1,10,-1])
    
    b = (B-A)
    b = b/numpy.linalg.norm(b)
    c = (C-A)
    c = c/numpy.linalg.norm(c)
    d = numpy.cross(b, c)
    
    R = numpy.linalg.inv(numpy.array([b, c, d]))
    
    def transform(p):
        return numpy.dot(R, p-A)
    
[/code]


CC BY-SA 3.0
2016-05-12T04:11:25.457
24777
2016-05-12T04:42:34.770
2016-05-12T04:42:34.770
14418
14418
24773
answer


takoika
さんの回答を参考に、[グラム・シュミットの正規直交化法](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%83%A0%E3%83%BB%E3%82%B7%E3%83%A5%E3%83%9F%E3%83%83%E3%83%88%E3%81%AE%E6%AD%A3%E8%A6%8F%E7%9B%B4%E4%BA%A4%E5%8C%96%E6%B3%95)を使ってベクトルを変換できました。  
プログラムとテストケース、図を載せておきます。

[![動作確認用](https://i.stack.imgur.com/fL8qk.png)](https://i.stack.imgur.com/fL8qk.png)

[code]

    >>> import numpy as np
    >>> def transform(a, b, c, p):
    ...     v1 = b - a
    ...     v2 = c - a
    ...     u1 = v1
    ...     u1 = u1 / np.linalg.norm(u1)
    ...     u2 = v2 - (np.dot(u1, v2) / np.dot(u1, u1)) * u1
    ...     u2 = u2 / np.linalg.norm(u2)
    ...     u3 = np.cross(u1, u2)
    ...     u3 = u3 / np.linalg.norm(u3)
    ...     rot = np.array([u1, u2, u3])
    ...     return np.dot(rot, p - a)
    ... 
    >>> A = np.array((2, 0, 0))
    >>> B = np.array((2, 2, 0))
    >>> C = np.array((2, 2, 2))
    >>> p1 = np.array((0, 1, 0))
    >>> transform(A, B, C, p1)[:2]
    array([ 1.,  0.])
    >>> p2 = np.array((0, 1, 1))
    >>> transform(A, B, C, p2)[:2]
    array([ 1.,  1.])
    >>> p3 = np.array((0, 0, 1))
    >>> transform(A, B, C, p3)[:2]
    array([ 0.,  1.])
    >>> p4 = np.array((3, 0, 1))
    >>> transform(A, B, C, p4)[:2]
    array([ 0.,  1.])
    
[/code]


CC BY-SA 3.0
2016-05-12T07:10:40.900
24785
2016-05-12T07:10:40.900
15462
24773
answer