计算两个角度之间的差异

时间:2016-03-15 00:06:22

标签: python math

我意识到这是偶数问题中最常见的问题,但我的思绪完全陷入困境。

我有两个角度,代表两个单位的罗盘方向,比如说

unit1:90.0

unit2:45.0

如果它们的差异超过20度,则unit2需要采用unit1的方向,+ / - 20度,以便

1单元:90.0

UNIT2:70.0

我可以使用

找出这两个(签名)之间的度数差异
angle = 180 - abs(abs(unit1 - unit2) - 180)

但我需要知道是否要调整+20或-20。

例如,对于这个集合:

1单元:270

UNIT2:350

unit2需要变成290(对unit1加20度)

我很确定可能有一个python函数可以为我做这个,但我完全卡住了,不记得20年前我学到的任何数学。

我完全希望有人愚弄我,但无论如何我会很感激。

3 个答案:

答案 0 :(得分:4)

我明白为什么你会被困在那上面。另一个解决方案并没有真正解决像unit1处于30度而unit2处于340处的情况,它将通过360旋转到0。代码可以做一些清理,但我希望这有点帮助。

import math

# calculate and return the distance unit2 
# needs to move to reach unit1
def get_distance(unit1, unit2):
    phi = (unit2-unit1) % 360
    sign = -1
    # used to calculate sign
    if not ((phi >= 0 and phi <= 180) or (
            phi <= -180 and phi >= -360)):
        sign = 1
    if phi > 180:
        result = 360-phi
    else:
        result = phi
    return (result*sign), sign

def get_sign(unit1, unit2):
    phi = (unit2-unit1) % 360
    sign = 1
    if ((phi >= 0 and phi <= 180) or (
            phi <= -180 and phi >= -360)):
        sign = -1
    return sign

def new_position(unit1, unit2, variance = 20):
    distance_to_move, sign = get_distance(unit1, unit2)
    variance*=sign
    # %360 to keep it within the circle
    return (unit2+distance_to_move-variance)%360

# distance unit2 needs to move to reach unit1
assert (get_distance(90,45) == (45, 1))
assert (get_distance(270, 350) == (-80, -1))
assert (get_distance(350, 30) == (-40, -1))   
assert (get_distance(30, 350) == (40, 1))
assert (get_distance(50, 360*4) == (50, 1))
assert (get_distance(360*4, 50) == (-50, -1))
print "----------"
assert (new_position(90,45) == 70)
assert (new_position(270, 350) == 290) 
assert (new_position(350, 30) == 10)
assert (new_position(30, 350) == 10)
assert (new_position(50, 360*4) == 30)
assert (new_position(360*4, 50) == 20)

Tadhg指出,我已经将它改变了一点,以便工作超过360度。 20度的方差也不那么硬编码。

href

答案 1 :(得分:2)

从概念上讲,您正在寻找这种伪代码:

if angle_difference > 20:
    if unit1 > unit2:
        unit2 = unit1 - 20
    else:
        unit2 = unit1 + 20

也就是说,例如,如果unit1更大,那么unit2会增加,直到它比unit1小20。但是,我最初错过了一个技巧。如果角度差大于180,则它们的补码小于180,因此unit2从另一个方向接近unit1并且符号计算切换时更短。

def adjust_angle(a, b):
    angle = abs(a - b)
    if 340 > angle > 20:
        adjustment = -20 if angle < 180 else 20
        b = (a + adjustment if a > b else a - adjustment) % 360
    return a, b

这里有几点要解释。同样地,如果角度差小于20,则不必做任何事情,大于340(360-20)的情况也是如此。

摘录

if 340 > angle > 20:
    adjustment = -20 if angle < 180 else 20
    b = (a + adjustment if a > b else a - adjustment) % 360

在逻辑上等同于以下

if 340 > angle > 20:
    if angle < 180:
        b = (a - 20 if a > b else a + 20) % 360
    else:
        b = (a + 20 if a > b else a - 20) % 360

通过使用adjustment变量,我们可以简单地消除代码复制。

最后,使用模运算,因为有时在纯计算中unit2可能超过值360.例如,对于unit1 = 50unit2 = 340unit2必须增加50,有效地成为390.但是由于我们被限制在0到360度之间,结果将变成30度。

答案 2 :(得分:1)

如果两个方向相距360度以上,那么计算两个方向之间角度的当前方式将会分崩离析:

unit1 = 360 * 4
unit2 = 50
angle = 180 - abs(abs(unit1 - unit2) - 180)
print(angle) #outputs -1050

我强烈建议使用模数%来计算角度:

#this will calculate the angle so that 0<=angle<360
angle = (unit2 - unit1) % 360

#this alone will give you the angle such that:
assert 0<= angle <360
assert (unit1 + angle) %360 == unit2 %360

尽管使用介于-180和180而不是0到360之间的值会更容易,因此您可以将大于180的值减少为负数,如下所示:

angle = (unit2 - unit1) % 360
if angle>180:
    angle -=360

# or using @PM2Ring suggestion in comments
angle = 180 - (180 - unit2 + unit1) % 360

#now these two statements will always be True
assert -180< angle<=180
assert (unit1 + angle) %360 == unit2 %360

然后您可以检查超过20的值,或者低于-20的值:

if angle>20:
    unit2 = unit1 + 20
elif angle<-20:
    unit2 = unit1 - 20
#else leave unit2 unchanged

编辑: 如果您不介意使用0到360之间的角度,您仍然可以使用340作为截止值进行等效计算:

if 20<angle<=180:
    unit2 = unit1 + 20
elif angle<340: #elif angle in range(181,340):
    unit2 = unit1 - 20
#else: assert angle in range(21) or angle in range(340,360) #no change

这个和原来的帖子使用了3个检查来完成任务,但是这个方法没有一个可能的额外步骤来减少angle,所以这会更快地执行,但可能会更加混乱。