#!/usr/bin/python
# coding: utf8
# 3点からなる平面の法線ベクトルの傾きを求める
import math
# 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)
# メイン
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軸回りの回転行列
#pa, pb pcに回転行列を適用
pa_rz = rotate_vec(pa, mat_rot_z)
pa_ry = rotate_vec(pa_rz, mat_rot_y)
pb_rz = rotate_vec(pb, mat_rot_z)
pb_ry = rotate_vec(pb_rz, mat_rot_y)
pc_rz = rotate_vec(pc, mat_rot_z)
pc_ry = rotate_vec(pc_rz, mat_rot_y)
print('補正後 pa = {}'.format(pa_ry))
print('補正後 pb = {}'.format(pb_ry))
print('補正後 pc = {}'.format(pc_ry))
# プログラム開始
if __name__ == '__main__':
main()
IyEvdXNyL2Jpbi9weXRob24KIyBjb2Rpbmc6IHV0ZjgKCiMgM+eCueOBi+OCieOBquOCi+W5s+mdouOBruazlee3muODmeOCr+ODiOODq+OBruWCvuOBjeOCkuaxguOCgeOCiwppbXBvcnQgbWF0aAoKIyDvvJLngrnjgYvjgonjg5njgq/jg4jjg6vjgpLmsYLjgoHjgosKIyDlvJXmlbAgcDEsIHAyIDogKHgsIHksIHop44Gu44K/44OX44OrCmRlZiBnZXRfdmVjdG9yKHAxLCBwMik6CiAgICB4ID0gcDJbMF0gLSBwMVswXQogICAgeSA9IHAyWzFdIC0gcDFbMV0KICAgIHogPSBwMlsyXSAtIHAxWzJdCiAgICByZXR1cm4gKHgsIHksIHopCiAgICAgICAgCiMg77yS44Gk44Gu44OZ44Kv44OI44Or44GL44KJ5aSW56mN44KS5rGC44KB44KLCiMg5byV5pWwIHYxLCB2MiA6ICh4LCB5LCB6KeOBruOCv+ODl+ODqwpkZWYgZ2V0X2Nyb3NzX3Byb2R1Y3QodjEsIHYyKToKICAgIHggPSAodjFbMV0gKiB2MlsyXSkgLSAodjFbMl0gKiB2MlsxXSkKICAgIHkgPSAodjFbMl0gKiB2MlswXSkgLSAodjFbMF0gKiB2MlsyXSkKICAgIHogPSAodjFbMF0gKiB2MlsxXSkgLSAodjFbMV0gKiB2MlswXSkKICAgIHJldHVybiAoeCwgeSwgeikKCiMg44OZ44Kv44OI44Or44Gu6ZW344GV44KS5rGC44KB44KLCmRlZiBnZXRfbGVuZ3RoKHYpOgogICAgdCA9IHZbMF0qdlswXSArIHZbMV0qdlsxXSArIHZbMl0qdlsyXQogICAgdHIgPSBtYXRoLnNxcnQodCkKICAgIHJldHVybiB0cgoKIyDjg5njgq/jg4jjg6vjga7mraPopo/ljJYKIyDlvJXmlbDjg5njgq/jg4jjg6vjga7ljZjkvY3jg5njgq/jg4jjg6vjgpLov5TjgZkKZGVmIGdldF9ub3JtX3ZlYyh2KToKICAgIHBhc3MKICAgIHZsID0gZ2V0X2xlbmd0aCh2KQogICAgaSA9IHZbMF0gLyB2bAogICAgaiA9IHZbMV0gLyB2bAogICAgayA9IHZbMl0gLyB2bAogICAgcmV0dXJuIChpLCBqLCBrICkKCiMgWui7uOWbnuOCiuOBruWbnui7ouihjOWIl+OBuOinkuW6puOCkuOCu+ODg+ODiAojIHRoOuinkuW6pihyYWQpCmRlZiBzZXRfcm90YXRlX21hdHJpeF9aKHRoKToKICAgIGNvc190aCA9IG1hdGguY29zKHRoKQogICAgc2luX3RoID0gbWF0aC5zaW4odGgpCiAgICBtYXQgPSAoY29zX3RoLCAtc2luX3RoLCAgICAgMCwKICAgICAgICAgICBzaW5fdGgsICBjb3NfdGgsICAgICAwLAogICAgICAgICAgICAgICAgMCwgICAgICAgMCwgICAgIDEgKQogICAgcmV0dXJuIG1hdAoKIyBZ6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiX44G46KeS5bqm44KS44K744OD44OICiMgdGg66KeS5bqmKHJhZCkKZGVmIHNldF9yb3RhdGVfbWF0cml4X1kodGgpOgogICAgY29zX3RoID0gbWF0aC5jb3ModGgpCiAgICBzaW5fdGggPSBtYXRoLnNpbih0aCkKICAgIG1hdCA9IChjb3NfdGgsICAgICAgIDAsIHNpbl90aCwKICAgICAgICAgICAgICAgIDAsICAgICAgIDEsICAgICAgMCwKICAgICAgICAgIC1zaW5fdGgsICAgICAgIDAsIGNvc190aCApCiAgICByZXR1cm4gbWF0CgojIOODmeOCr+ODiOODq+OBruWbnui7ogojIHY6IOODmeOCr+ODiOODqwojIG1hdDrlm57ou6LooYzliJcgCmRlZiByb3RhdGVfdmVjKHYsIG1hdCk6CiAgICB4ID0gbWF0WzBdKnZbMF0gKyBtYXRbMV0qdlsxXSArIG1hdFsyXSp2WzJdCiAgICB5ID0gbWF0WzNdKnZbMF0gKyBtYXRbNF0qdlsxXSArIG1hdFs1XSp2WzJdIAogICAgeiA9IG1hdFs2XSp2WzBdICsgbWF0WzddKnZbMV0gKyBtYXRbOF0qdlsyXQogICAgcmV0dXJuICh4LCB5LCB6KQoKIyDjg6HjgqTjg7MKZGVmIG1haW4oKToKICAgIHBhID0gKDUwLCA2MDAsIDkwMCkgICAKICAgIHBiID0gKDM4NSwgNjMwLCA5MDUpICAgIAogICAgcGMgPSAoMjYwLCAzMCwgOTE1KQoKICAgICPjg5njgq/jg4jjg6vjgpLjgaTjgY/jgosKICAgIHZhYiA9IGdldF92ZWN0b3IocGEsIHBiKSAgICAjIGEg44GL44KJIGIg44G45ZCR44GL44GG44OZ44Kv44OI44OrCiAgICB2YWMgPSBnZXRfdmVjdG9yKHBhLCBwYykgICAgIyBhIOOBi+OCiSBjIOOBuOWQkeOBi+OBhuODmeOCr+ODiOODqyAgICAgICAKICAgIHZhYm4gPSBnZXRfbm9ybV92ZWModmFiKSAgICAjIOWNmOS9jeODmeOCr+ODiOODq+OBuOWkieaPmwogICAgdmFjbiA9IGdldF9ub3JtX3ZlYyh2YWMpICAgICMg5Y2Y5L2N44OZ44Kv44OI44Or44G45aSJ5o+bCiAgICAKICAgICMg44OZ44Kv44OI44OrdmFibuOBqHZhY27jgafkvZzjgonjgozjgovlubPpnaLjga7ms5Xnt5rjg5njgq/jg4jjg6soPXZhYm7jgah2YWNu44Gu5aSW56mNKeOCkuaxguOCgeOCiwogICAgdm4gPSBnZXRfY3Jvc3NfcHJvZHVjdCh2YWNuLCB2YWJuKQogICAgdm5uPSBnZXRfbm9ybV92ZWModm4pICAgICAgICMg5Y2Y5L2N44OZ44Kv44OI44Or44G45aSJ5o+bCiAgICBwcmludCgi5rOV57ea44OZ44Kv44OI44OrIHZubiA9IHt9Ii5mb3JtYXQodm5uKSkKICAgIAogICAgJycnCiAgICDms5Xnt5rjg5njgq/jg4jjg6t2bm7jgYzjgIFa6Lu45Y2Y5L2N44OZ44Kv44OI44OrKDAsMCwxKeOCkgogICAgMSkgWei7uOWbnuOCiuOBq+inkuW6ps64IChyYWQpIOevhOWbsjogMCA8PSDOuCA8PSDPgAogICAgMikgWui7uOWbnuOCiuOBq+inkuW6ps+GIChyYWQpIOevhOWbsjogLc+AIDw9IM+GIDw9IM+ACiAgICDjgaDjgZHlm57ou6LjgZXjgZvjgZ/jgoLjga7jgajogIPjgYjjgozjgbAKICAgIOazlee3muODmeOCr+ODiOODq3ZubuOCkgogICAgMSkgWui7uOWbnuOCiuOBq+inkuW6piAtz4YKICAgIDIpIFnou7jlm57jgorjgavop5LluqYgLc64CiAgICDjgaDjgZHlm57ou6LjgZXjgZvjgozjgbBa6Lu45Y2Y5L2N44OZ44Kv44OI44OrKDAsMCwxKeOBqOmHjeOBquOCi+OBr+OBmgogICAgJycnCiAgICAjIOazlee3muODmeOCr+ODiOODq3ZubuOBqFjou7jjga7jgarjgZnop5LluqbPhuOCkuaxguOCgeOCiwogICAgIyDPhiA9IGF0YW4oeSAvIHggKQogICAgcGggPSBtYXRoLmF0YW4yKHZublsxXSwgdm5uWzBdKQogICAgcHJpbnQoJ3ZubuOBqHjou7jjga7jgarjgZnop5Igz4YgOiB7fShyYWQpLCB7fShkZWcpJy5mb3JtYXQocGgsIHBoKigxODAvbWF0aC5waSkpKQogICAgCiAgICAjIOazlee3muODmeOCr+ODiOODq3ZubuOBqFrou7jjga7jgarjgZnop5LluqbOuOOCkuaxguOCgeOCiwogICAgIyDOuCA9IGF0YW4oIHNxcnQoeCp4ICsgeSp5KSAvIHogKSAKICAgIHRoID0gbWF0aC5hdGFuMihtYXRoLnNxcnQodm5uWzBdKnZublswXSArIHZublsxXSp2bm5bMV0pLCB2bm5bMl0pCiAgICBwcmludCgndm5u44Goeui7uOOBruOBquOBmeinkiDOuCA6IHt9KHJhZCksIHt9KGRlZyknLmZvcm1hdCh0aCwgdGgqKDE4MC9tYXRoLnBpKSkpCiAgICAKICAgICMg5Zue6Lui6KGM5YiX44Gr5YCk44KS44K744OD44OICiAgICBtYXRfcm90X3ogPSBzZXRfcm90YXRlX21hdHJpeF9aKC1waCkgICAgIyBa6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiXCiAgICBtYXRfcm90X3kgPSBzZXRfcm90YXRlX21hdHJpeF9ZKC10aCkgICAgIyBZ6Lu45Zue44KK44Gu5Zue6Lui6KGM5YiXCiAgICAKICAgICNwYSwgcGIgcGPjgavlm57ou6LooYzliJfjgpLpgannlKgKICAgIHBhX3J6ID0gcm90YXRlX3ZlYyhwYSwgbWF0X3JvdF96KSAgICAgCiAgICBwYV9yeSA9IHJvdGF0ZV92ZWMocGFfcnosIG1hdF9yb3RfeSkgICAgCiAgICBwYl9yeiA9IHJvdGF0ZV92ZWMocGIsIG1hdF9yb3RfeikgICAgIAogICAgcGJfcnkgPSByb3RhdGVfdmVjKHBiX3J6LCBtYXRfcm90X3kpICAgIAogICAgcGNfcnogPSByb3RhdGVfdmVjKHBjLCBtYXRfcm90X3opICAgICAKICAgIHBjX3J5ID0gcm90YXRlX3ZlYyhwY19yeiwgbWF0X3JvdF95KSAgICAKICAgIHByaW50KCfoo5zmraPlvowgcGEgPSB7fScuZm9ybWF0KHBhX3J5KSkKICAgIHByaW50KCfoo5zmraPlvowgcGIgPSB7fScuZm9ybWF0KHBiX3J5KSkKICAgIHByaW50KCfoo5zmraPlvowgcGMgPSB7fScuZm9ybWF0KHBjX3J5KSkKCiMg44OX44Ot44Kw44Op44Og6ZaL5aeLCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICBtYWluKCkK