import math
class point:
def __init__(self, x=None, y = None):
if x is None:
x = 0
y = 0
self.x = x
self.y = y
def __str__(self):
return '{:.3f}, {:.3f}'.format(self.x, self.y)
def d2r(d):
return d/180 * math.pi
def r2d(d):
return d/math.pi * 180
def mkvec(angle):
return point(math.cos(angle), math.sin(angle))
def vec2ang(v):
return math.atan2(v.y, v.x)
PI=math.pi
sin = math.sin
cos = math.cos
def mk_rot_matrix(cos_val, sin_val):
return [ [cos_val, -sin_val],
[sin_val, cos_val] ]
def mul_mat2(mat_a, mat_b):
m0 = mat_a[0][0] * mat_b[0][0] + mat_a[0][1] * mat_b[1][0]
m1 = mat_a[0][0] * mat_b[0][1] + mat_a[0][1] * mat_b[1][1]
m2 = mat_a[1][0] * mat_b[0][0] + mat_a[1][1] * mat_b[1][0]
m3 = mat_a[1][0] * mat_b[0][1] + mat_a[1][1] * mat_b[1][1]
return [ [m0, m1],
[m2, m3] ]
def vec_mul(mat, vec):
x = vec.x * mat[0][0] + vec.y * mat[1][0]
y = vec.x * mat[0][1] + vec.y * mat[1][1]
return point(x,y)
def test_assumption(angle_1, angle_2):
v1 = mkvec(angle_1 * PI)
v2 = mkvec(angle_2 * PI)
v_exp = mkvec((angle_1 + angle_2) * PI)
mat_a = mk_rot_matrix(v1.x, v1.y)
mat_b = mk_rot_matrix(v2.x, v2.y)
mat_c = mul_mat2(mat_b, mat_a)
v3 = point(mat_c[0][0], -mat_c[0][1])
v3_angle = vec2ang(v3) / PI
expected = (angle_1 + angle_2)
print(\
'''
hack_rotation: {}
proper_trig_rotation: {}
result in radian: {:.3f}
({:.3f} + {:.3f}) PI == {:.3f} PI'
'''.format(v3, v_exp, v3_angle, angle_1, angle_2, expected))
test_assumption(1/6, 1/4)
test_assumption(0.345, 0.765)
test_assumption(0.845, 0.965)
test_assumption(0.845, -0.2365)
aW1wb3J0IG1hdGgKCmNsYXNzIHBvaW50OgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHg9Tm9uZSwgeSA9IE5vbmUpOgogICAgICAgIGlmIHggaXMgTm9uZToKICAgICAgICAgICAgeCA9IDAKICAgICAgICAgICAgeSA9IDAKICAgICAgICBzZWxmLnggPSB4CiAgICAgICAgc2VsZi55ID0geQogICAgZGVmIF9fc3RyX18oc2VsZik6CiAgICAgICAgcmV0dXJuICd7Oi4zZn0sIHs6LjNmfScuZm9ybWF0KHNlbGYueCwgc2VsZi55KQoKZGVmIGQycihkKToKICAgIHJldHVybiBkLzE4MCAqIG1hdGgucGkKZGVmIHIyZChkKToKICAgIHJldHVybiBkL21hdGgucGkgKiAxODAKCmRlZiBta3ZlYyhhbmdsZSk6CiAgICByZXR1cm4gcG9pbnQobWF0aC5jb3MoYW5nbGUpLCBtYXRoLnNpbihhbmdsZSkpCmRlZiB2ZWMyYW5nKHYpOgogICAgcmV0dXJuIG1hdGguYXRhbjIodi55LCB2LngpCgoKUEk9bWF0aC5waQpzaW4gPSBtYXRoLnNpbgpjb3MgPSBtYXRoLmNvcwoKZGVmIG1rX3JvdF9tYXRyaXgoY29zX3ZhbCwgc2luX3ZhbCk6CiAgICByZXR1cm4gWyBbY29zX3ZhbCwgLXNpbl92YWxdLAogICAgICAgICAgICAgW3Npbl92YWwsIGNvc192YWxdIF0KZGVmIG11bF9tYXQyKG1hdF9hLCBtYXRfYik6CiAgICBtMCA9IG1hdF9hWzBdWzBdICogbWF0X2JbMF1bMF0gKyBtYXRfYVswXVsxXSAqIG1hdF9iWzFdWzBdCiAgICBtMSA9IG1hdF9hWzBdWzBdICogbWF0X2JbMF1bMV0gKyBtYXRfYVswXVsxXSAqIG1hdF9iWzFdWzFdCiAgICBtMiA9IG1hdF9hWzFdWzBdICogbWF0X2JbMF1bMF0gKyBtYXRfYVsxXVsxXSAqIG1hdF9iWzFdWzBdCiAgICBtMyA9IG1hdF9hWzFdWzBdICogbWF0X2JbMF1bMV0gKyBtYXRfYVsxXVsxXSAqIG1hdF9iWzFdWzFdCiAgICByZXR1cm4gWyBbbTAsIG0xXSwKICAgICAgICAgICAgIFttMiwgbTNdIF0KZGVmIHZlY19tdWwobWF0LCB2ZWMpOgogICAgeCA9IHZlYy54ICogbWF0WzBdWzBdICsgdmVjLnkgKiBtYXRbMV1bMF0KICAgIHkgPSB2ZWMueCAqIG1hdFswXVsxXSArIHZlYy55ICogbWF0WzFdWzFdCiAgICByZXR1cm4gcG9pbnQoeCx5KQogICAgCmRlZiB0ZXN0X2Fzc3VtcHRpb24oYW5nbGVfMSwgYW5nbGVfMik6CiAgICB2MSA9IG1rdmVjKGFuZ2xlXzEgKiBQSSkKICAgIHYyID0gbWt2ZWMoYW5nbGVfMiAqIFBJKQogICAgdl9leHAgPSBta3ZlYygoYW5nbGVfMSArIGFuZ2xlXzIpICogUEkpCiAgICAKICAgIG1hdF9hID0gbWtfcm90X21hdHJpeCh2MS54LCB2MS55KQogICAgbWF0X2IgPSBta19yb3RfbWF0cml4KHYyLngsIHYyLnkpCiAgICBtYXRfYyA9IG11bF9tYXQyKG1hdF9iLCBtYXRfYSkKCiAgICB2MyA9IHBvaW50KG1hdF9jWzBdWzBdLCAtbWF0X2NbMF1bMV0pCiAgICB2M19hbmdsZSA9IHZlYzJhbmcodjMpIC8gUEkKICAgIGV4cGVjdGVkID0gKGFuZ2xlXzEgKyBhbmdsZV8yKQogICAgCiAgICBwcmludChcCicnJwpoYWNrX3JvdGF0aW9uOiB7fQpwcm9wZXJfdHJpZ19yb3RhdGlvbjoge30KcmVzdWx0IGluIHJhZGlhbjogezouM2Z9Cih7Oi4zZn0gKyB7Oi4zZn0pIFBJID09IHs6LjNmfSBQSScKJycnLmZvcm1hdCh2Mywgdl9leHAsIHYzX2FuZ2xlLCBhbmdsZV8xLCBhbmdsZV8yLCBleHBlY3RlZCkpCiAgICAgICAgICAgCgp0ZXN0X2Fzc3VtcHRpb24oMS82LCAxLzQpCnRlc3RfYXNzdW1wdGlvbigwLjM0NSwgMC43NjUpCnRlc3RfYXNzdW1wdGlvbigwLjg0NSwgMC45NjUpCnRlc3RfYXNzdW1wdGlvbigwLjg0NSwgLTAuMjM2NSkK