#!/usr/bin/python
# coding: utf8
# 3点からなる平面の法線ベクトルの傾きを求める
import math
import sys
# 2点からベクトルを求める
# 引数 p1, p2 : (x, y, z)のタプル
def get_vector(p1, p2):
x = p2[0] - p1[0]
y = p2[1] - p1[1]
z = p2[2] - p1[2]
return (x, y, z)
# 2つのベクトルから外積を求める
# 引数 v1, v2 : (x, y, z)のタプル
def get_cross_product(v1, v2):
x = (v1[1] * v2[2]) - (v1[2] * v2[1])
y = (v1[2] * v2[0]) - (v1[0] * v2[2])
z = (v1[0] * v2[1]) - (v1[1] * v2[0])
return (x, y, z)
# ベクトルの長さを求める
def get_length(v):
t = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]
return tr
# ベクトルの正規化
# 引数ベクトルの単位ベクトルを返す
def get_norm_vec(v):
pass
vl = get_length(v)
i = v[0] / vl
j = v[1] / vl
k = v[2] / vl
return (i, j, k )
# Z軸回りの回転行列へ角度をセット
# th:角度(rad)
def set_rotate_matrix_Z(th):
mat = (cos_th, -sin_th, 0,
sin_th, cos_th, 0,
0, 0, 1 )
return mat
# Y軸回りの回転行列へ角度をセット
# th:角度(rad)
def set_rotate_matrix_Y(th):
mat = (cos_th, 0, sin_th,
0, 1, 0,
-sin_th, 0, cos_th )
return mat
# ベクトルの回転
# v: ベクトル
# mat:回転行列
def rotate_vec(v, mat):
x = mat[0]*v[0] + mat[1]*v[1] + mat[2]*v[2]
y = mat[3]*v[0] + mat[4]*v[1] + mat[5]*v[2]
z = mat[6]*v[0] + mat[7]*v[1] + mat[8]*v[2]
return (x, y, z)
# cos(x)からsin(x)を求める
def get_sin(cos_x):
return math.
sqrt(1 - (cos_x
* cos_x
))
# メイン
def main():
pa = (50, 600, 900)
pb = (385, 630, 905)
pc = (260, 30, 915)
#ベクトルをつくる
vab = get_vector(pa, pb) # a から b へ向かうベクトル
vac = get_vector(pa, pc) # a から c へ向かうベクトル
vabn = get_norm_vec(vab) # 単位ベクトルへ変換
vacn = get_norm_vec(vac) # 単位ベクトルへ変換
# ベクトルvabnとvacnで作られる平面の法線ベクトル(=vabnとvacnの外積)を求める
vn = get_cross_product(vacn, vabn)
vnn= get_norm_vec(vn) # 単位ベクトルへ変換
print("法線ベクトル vnn = {}".format(vnn))
'''
法線ベクトルvnnが、Z軸単位ベクトル(0,0,1)を
1) Y軸回りに角度θ (rad) 範囲: 0 <= θ <= π
2) Z軸回りに角度φ (rad) 範囲: -π <= φ <= π
だけ回転させたものと考えれば
法線ベクトルvnnを
1) Z軸回りに角度 -φ
2) Y軸回りに角度 -θ
だけ回転させればZ軸単位ベクトル(0,0,1)と重なるはず
'''
# 法線ベクトルvnnとX軸のなす角度φを求める
# φ = atan(y / x )
ph
= math.
atan2(vnn
[1], vnn
[0]) print('vnnとx軸のなす角 φ : {}(rad), {}(deg)'.format(ph, ph*(180/math.pi)))
# 法線ベクトルvnnとZ軸のなす角度θを求める
# θ = atan( sqrt(x*x + y*y) / z )
th
= math.
atan2(math.
sqrt(vnn
[0]*vnn
[0] + vnn
[1]*vnn
[1]), vnn
[2]) print('vnnとz軸のなす角 θ : {}(rad), {}(deg)'.format(th, th*(180/math.pi)))
# 回転行列に値をセット
mat_rot_z = set_rotate_matrix_Z(-ph) # Z軸回りの回転行列
mat_rot_y = set_rotate_matrix_Y(-th) # Y軸回りの回転行列
#法線ベクトルの回転確認
#vn_rz = rotate_vec(vnn, mat_rot_z) # Z軸回りに -φ
#vn_ry = rotate_vec(vn_rz, mat_rot_y) # Y軸回りに -θ
#print('vnn = {}'.format(vnn))
#print('vn_rph= {}'.format(vn_rph))
#print('vn_rth= {}'.format(vn_rth))
#print('')
# ベクトルvab, vacに上記の回転を適用する
vab_rz = rotate_vec(vab, mat_rot_z)
vab_ry = rotate_vec(vab_rz, mat_rot_y)
vac_rz = rotate_vec(vac, mat_rot_z)
vac_ry = rotate_vec(vac_rz, mat_rot_y)
# vab, vacは 点b,c から 点aを始点とするベクトルだったので点a分をシフト
# φ,θ補正後の3点の座標
pa2 = pa
pb2 = (vab_ry[0]+pa[0], vab_ry[1]+pa[1], vab_ry[2]+pa[2])
pc2 = (vac_ry[0]+pa[0], vac_ry[1]+pa[1], vac_ry[2]+pa[2])
print('pa2= {}'.format(pa2))
print('pb2= {}'.format(pb2))
print('pc2= {}'.format(pc2))
# プログラム開始
if __name__ == '__main__':
main()
IyEvdXNyL2Jpbi9weXRob24KIyBjb2Rpbmc6IHV0ZjgKCiMgM+eCueOBi+OCieOBquOCi+W5s+mdouOBruazlee3muODmeOCr+ODiOODq+OBruWCvuOBjeOCkuaxguOCgeOCiwppbXBvcnQgbWF0aAppbXBvcnQgc3lzCgojIO+8kueCueOBi+OCieODmeOCr+ODiOODq+OCkuaxguOCgeOCiwojIOW8leaVsCBwMSwgcDIgOiAoeCwgeSwgeinjga7jgr/jg5fjg6sKZGVmIGdldF92ZWN0b3IocDEsIHAyKToKICAgIHggPSBwMlswXSAtIHAxWzBdCiAgICB5ID0gcDJbMV0gLSBwMVsxXQogICAgeiA9IHAyWzJdIC0gcDFbMl0KICAgIHJldHVybiAoeCwgeSwgeikKICAgICAgICAKIyDvvJLjgaTjga7jg5njgq/jg4jjg6vjgYvjgonlpJbnqY3jgpLmsYLjgoHjgosKIyDlvJXmlbAgdjEsIHYyIDogKHgsIHksIHop44Gu44K/44OX44OrCmRlZiBnZXRfY3Jvc3NfcHJvZHVjdCh2MSwgdjIpOgogICAgeCA9ICh2MVsxXSAqIHYyWzJdKSAtICh2MVsyXSAqIHYyWzFdKQogICAgeSA9ICh2MVsyXSAqIHYyWzBdKSAtICh2MVswXSAqIHYyWzJdKQogICAgeiA9ICh2MVswXSAqIHYyWzFdKSAtICh2MVsxXSAqIHYyWzBdKQogICAgcmV0dXJuICh4LCB5LCB6KQoKIyDjg5njgq/jg4jjg6vjga7plbfjgZXjgpLmsYLjgoHjgosKZGVmIGdldF9sZW5ndGgodik6CiAgICB0ID0gdlswXSp2WzBdICsgdlsxXSp2WzFdICsgdlsyXSp2WzJdCiAgICB0ciA9IG1hdGguc3FydCh0KQogICAgcmV0dXJuIHRyCgojIOODmeOCr+ODiOODq+OBruato+imj+WMlgojIOW8leaVsOODmeOCr+ODiOODq+OBruWNmOS9jeODmeOCr+ODiOODq+OCkui/lOOBmQpkZWYgZ2V0X25vcm1fdmVjKHYpOgogICAgcGFzcwogICAgdmwgPSBnZXRfbGVuZ3RoKHYpCiAgICBpID0gdlswXSAvIHZsCiAgICBqID0gdlsxXSAvIHZsCiAgICBrID0gdlsyXSAvIHZsCiAgICByZXR1cm4gKGksIGosIGsgKQoKIyBa6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiX44G46KeS5bqm44KS44K744OD44OICiMgdGg66KeS5bqmKHJhZCkKZGVmIHNldF9yb3RhdGVfbWF0cml4X1oodGgpOgogICAgY29zX3RoID0gbWF0aC5jb3ModGgpCiAgICBzaW5fdGggPSBtYXRoLnNpbih0aCkKICAgIG1hdCA9IChjb3NfdGgsIC1zaW5fdGgsICAgICAwLAogICAgICAgICAgIHNpbl90aCwgIGNvc190aCwgICAgIDAsCiAgICAgICAgICAgICAgICAwLCAgICAgICAwLCAgICAgMSApCiAgICByZXR1cm4gbWF0CgojIFnou7jlm57jgorjga7lm57ou6LooYzliJfjgbjop5LluqbjgpLjgrvjg4Pjg4gKIyB0aDrop5LluqYocmFkKQpkZWYgc2V0X3JvdGF0ZV9tYXRyaXhfWSh0aCk6CiAgICBjb3NfdGggPSBtYXRoLmNvcyh0aCkKICAgIHNpbl90aCA9IG1hdGguc2luKHRoKQogICAgbWF0ID0gKGNvc190aCwgICAgICAgMCwgc2luX3RoLAogICAgICAgICAgICAgICAgMCwgICAgICAgMSwgICAgICAwLAogICAgICAgICAgLXNpbl90aCwgICAgICAgMCwgY29zX3RoICkKICAgIHJldHVybiBtYXQKCiMg44OZ44Kv44OI44Or44Gu5Zue6LuiCiMgdjog44OZ44Kv44OI44OrCiMgbWF0OuWbnui7ouihjOWIlyAKZGVmIHJvdGF0ZV92ZWModiwgbWF0KToKICAgIHggPSBtYXRbMF0qdlswXSArIG1hdFsxXSp2WzFdICsgbWF0WzJdKnZbMl0KICAgIHkgPSBtYXRbM10qdlswXSArIG1hdFs0XSp2WzFdICsgbWF0WzVdKnZbMl0gCiAgICB6ID0gbWF0WzZdKnZbMF0gKyBtYXRbN10qdlsxXSArIG1hdFs4XSp2WzJdCiAgICByZXR1cm4gKHgsIHksIHopCgojIGNvcyh4KeOBi+OCiXNpbih4KeOCkuaxguOCgeOCiwpkZWYgZ2V0X3Npbihjb3NfeCk6CiAgICByZXR1cm4gIG1hdGguc3FydCgxIC0gKGNvc194ICogY29zX3gpKQoKIyDjg6HjgqTjg7MKZGVmIG1haW4oKToKICAgIHBhID0gKDUwLCA2MDAsIDkwMCkgICAKICAgIHBiID0gKDM4NSwgNjMwLCA5MDUpICAgIAogICAgcGMgPSAoMjYwLCAzMCwgOTE1KQoKICAgICPjg5njgq/jg4jjg6vjgpLjgaTjgY/jgosKICAgIHZhYiA9IGdldF92ZWN0b3IocGEsIHBiKSAgICAjIGEg44GL44KJIGIg44G45ZCR44GL44GG44OZ44Kv44OI44OrCiAgICB2YWMgPSBnZXRfdmVjdG9yKHBhLCBwYykgICAgIyBhIOOBi+OCiSBjIOOBuOWQkeOBi+OBhuODmeOCr+ODiOODqyAgICAgICAKICAgIHZhYm4gPSBnZXRfbm9ybV92ZWModmFiKSAgICAjIOWNmOS9jeODmeOCr+ODiOODq+OBuOWkieaPmwogICAgdmFjbiA9IGdldF9ub3JtX3ZlYyh2YWMpICAgICMg5Y2Y5L2N44OZ44Kv44OI44Or44G45aSJ5o+bCiAgICAKICAgICMg44OZ44Kv44OI44OrdmFibuOBqHZhY27jgafkvZzjgonjgozjgovlubPpnaLjga7ms5Xnt5rjg5njgq/jg4jjg6soPXZhYm7jgah2YWNu44Gu5aSW56mNKeOCkuaxguOCgeOCiwogICAgdm4gPSBnZXRfY3Jvc3NfcHJvZHVjdCh2YWNuLCB2YWJuKQogICAgdm5uPSBnZXRfbm9ybV92ZWModm4pICAgICAgICMg5Y2Y5L2N44OZ44Kv44OI44Or44G45aSJ5o+bCiAgICBwcmludCgi5rOV57ea44OZ44Kv44OI44OrIHZubiA9IHt9Ii5mb3JtYXQodm5uKSkKICAgIAogICAgJycnCiAgICDms5Xnt5rjg5njgq/jg4jjg6t2bm7jgYzjgIFa6Lu45Y2Y5L2N44OZ44Kv44OI44OrKDAsMCwxKeOCkgogICAgMSkgWei7uOWbnuOCiuOBq+inkuW6ps64IChyYWQpIOevhOWbsjogMCA8PSDOuCA8PSDPgAogICAgMikgWui7uOWbnuOCiuOBq+inkuW6ps+GIChyYWQpIOevhOWbsjogLc+AIDw9IM+GIDw9IM+ACiAgICDjgaDjgZHlm57ou6LjgZXjgZvjgZ/jgoLjga7jgajogIPjgYjjgozjgbAKICAgIOazlee3muODmeOCr+ODiOODq3ZubuOCkgogICAgMSkgWui7uOWbnuOCiuOBq+inkuW6piAtz4YKICAgIDIpIFnou7jlm57jgorjgavop5LluqYgLc64CiAgICDjgaDjgZHlm57ou6LjgZXjgZvjgozjgbBa6Lu45Y2Y5L2N44OZ44Kv44OI44OrKDAsMCwxKeOBqOmHjeOBquOCi+OBr+OBmgogICAgJycnCiAgICAjIOazlee3muODmeOCr+ODiOODq3ZubuOBqFjou7jjga7jgarjgZnop5LluqbPhuOCkuaxguOCgeOCiwogICAgIyDPhiA9IGF0YW4oeSAvIHggKQogICAgcGggPSBtYXRoLmF0YW4yKHZublsxXSwgdm5uWzBdKQogICAgcHJpbnQoJ3ZubuOBqHjou7jjga7jgarjgZnop5Igz4YgOiB7fShyYWQpLCB7fShkZWcpJy5mb3JtYXQocGgsIHBoKigxODAvbWF0aC5waSkpKQogICAgCiAgICAjIOazlee3muODmeOCr+ODiOODq3ZubuOBqFrou7jjga7jgarjgZnop5LluqbOuOOCkuaxguOCgeOCiwogICAgIyDOuCA9IGF0YW4oIHNxcnQoeCp4ICsgeSp5KSAvIHogKSAKICAgIHRoID0gbWF0aC5hdGFuMihtYXRoLnNxcnQodm5uWzBdKnZublswXSArIHZublsxXSp2bm5bMV0pLCB2bm5bMl0pCiAgICBwcmludCgndm5u44Goeui7uOOBruOBquOBmeinkiDOuCA6IHt9KHJhZCksIHt9KGRlZyknLmZvcm1hdCh0aCwgdGgqKDE4MC9tYXRoLnBpKSkpCiAgICAKICAgICMg5Zue6Lui6KGM5YiX44Gr5YCk44KS44K744OD44OICiAgICBtYXRfcm90X3ogPSBzZXRfcm90YXRlX21hdHJpeF9aKC1waCkgICAgIyBa6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiXCiAgICBtYXRfcm90X3kgPSBzZXRfcm90YXRlX21hdHJpeF9ZKC10aCkgICAgIyBZ6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiXCiAgICAKICAgICPms5Xnt5rjg5njgq/jg4jjg6vjga7lm57ou6Lnorroqo0KICAgICN2bl9yeiA9IHJvdGF0ZV92ZWModm5uLCBtYXRfcm90X3opICAgICAjIFrou7jlm57jgorjgasgLc+GCiAgICAjdm5fcnkgPSByb3RhdGVfdmVjKHZuX3J6LCBtYXRfcm90X3kpICAjIFnou7jlm57jgorjgasgLc6444CACiAgICAjcHJpbnQoJ3ZubiAgID0ge30nLmZvcm1hdCh2bm4pKQogICAgI3ByaW50KCd2bl9ycGg9IHt9Jy5mb3JtYXQodm5fcnBoKSkKICAgICNwcmludCgndm5fcnRoPSB7fScuZm9ybWF0KHZuX3J0aCkpCiAgICAjcHJpbnQoJycpCiAgICAKICAgICMg44OZ44Kv44OI44OrdmFiLCB2YWPjgavkuIroqJjjga7lm57ou6LjgpLpgannlKjjgZnjgosKICAgIHZhYl9yeiA9IHJvdGF0ZV92ZWModmFiLCBtYXRfcm90X3opICAgICAKICAgIHZhYl9yeSA9IHJvdGF0ZV92ZWModmFiX3J6LCBtYXRfcm90X3kpICAgIAogICAgdmFjX3J6ID0gcm90YXRlX3ZlYyh2YWMsIG1hdF9yb3RfeikKICAgIHZhY19yeSA9IHJvdGF0ZV92ZWModmFjX3J6LCBtYXRfcm90X3kpCiAgICAKICAgICMgdmFiLCB2YWPjga8g54K5YixjIOOBi+OCiSDngrlh44KS5aeL54K544Go44GZ44KL44OZ44Kv44OI44Or44Gg44Gj44Gf44Gu44Gn54K5YeWIhuOCkuOCt+ODleODiAogICAgIyDPhizOuOijnOato+W+jOOBrjPngrnjga7luqfmqJkKICAgIHBhMiA9IHBhCiAgICBwYjIgPSAodmFiX3J5WzBdK3BhWzBdLCB2YWJfcnlbMV0rcGFbMV0sIHZhYl9yeVsyXStwYVsyXSkKICAgIHBjMiA9ICh2YWNfcnlbMF0rcGFbMF0sIHZhY19yeVsxXStwYVsxXSwgdmFjX3J5WzJdK3BhWzJdKQogICAgcHJpbnQoJ3BhMj0ge30nLmZvcm1hdChwYTIpKQogICAgcHJpbnQoJ3BiMj0ge30nLmZvcm1hdChwYjIpKQogICAgcHJpbnQoJ3BjMj0ge30nLmZvcm1hdChwYzIpKQogICAgCgojIOODl+ODreOCsOODqeODoOmWi+WniwppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgbWFpbigpCg==