|超过180 |时计算正确的经度?


11

我正在尝试开发一种“公式”以更正lat-lng值。

我正在使用vue传单,但是当您在“第一个”世界之外平移时,您会得到很多。大于+180或小于-180。

例如:当我向右平移(向东)到美国时,我的报酬是ng 215。 215-360=-145

当我向左平移东俄罗斯(西方向)时,例如得到-222,情况也是如此。现在我需要计算-222+360=138

但是,由于世界是不确定的,因此用户可以平移到第八世界,因此我不得不调整值。

是否可以计算正确的经度?(另一个要求是,当用户在第一世界时,24 lng应该仍然是24 lng。

Answers:


16

您需要反复向值添加(或减去)360,直到它位于-180-180的范围内。因此通常有一对循环,例如:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}

标志走错了路?在第一种情况下应为lon + = 360。
JimT

4
您可以仅执行一个循环就可以完成此操作,while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }尽管您的版本实际上与说明相符,但我没有提供它作为答案,而我的版本只是一个优化,可能没有任何区别。我将其保留为评论仅是为了提醒您可以以多种方式完成某项工作,其中某些方法比其他方法更优化。
安德烈

2
我认为我永远不会使用那个,因为它每个循环使用2个函数调用,并且只有一个循环会执行。在这个例子中可能没什么区别,但这是我的偏见
伊恩·特顿

JavaScript函数虽然看起来像函数,但应该更像带有冗长符号的运算符。从这个意义上说,我们也可以将+-甚至<作为函数。编辑:我这里有一个解决方案,它实际上不起作用
Andrei

2
你做不到lon %= 180吗?
基金莫妮卡的诉讼

15

避免条件和函数调用的答案:

longitude = (longitude % 360 + 540) % 360 - 180

我在https://jsperf.com/longitude-normalization上编写了一个快速的微基准测试,对于“合理的”输入值范围,条件代码似乎更快(在我的计算机上的Chrome中)。通常,您可能不必提前担心像这样的小型计算的性能,从而更加重视可读性和与其余代码库的一致性。

在这种情况下,可能更重要的问题是您的代码是否可能遇到极限输入值(1e10,Infinity等)。如果是这样,则循环实现最终可能会运行得非常缓慢或无声地挂起程序。这可能在极点附近执行的计算中发生,例如,尝试从极点向东或向西平移某个距离(而不是角度)可能会轻易导致无限的经度。


1
有趣。让我们对FP鸿沟进行有条件的跳跃。嗯,我想知道。
约书亚

1
@Joshua您不能使用条件跳转。您必须使用多个条件跳转,也就是循环。(加上循环包含附加的浮点数,这不是免费的。)循环需要进行多少次迭代取决于输入。因此,您必须了解一些有关数据的信息才能查看性能。如果绝大多数都在所需范围附近并且需要很少的迭代,那么可以肯定,加法循环可能会更快,但并不像您的讽刺所暗示的那样明显。
jpmc26 '18

1
@ jpmc26:在这种情况下,期望多次循环会很愚蠢。
约书亚

1
没有讽刺。我实际上不知道它会跌倒。
约书亚

1
@Joshua是的,我也不确定:)。我在性能(以及循环代码的潜在故障案例)的答案中添加了更多内容
Joe Lee-Moyet

5

单线:

normalized = remainder(longitude, 360);

说明:您想知道无视完整旋转(360°)后还剩下什么。

此过程称为规范化。

范例(cpp.sh)


1
这是否会导致[0,360)值,而不是Shadrix请求的[-180,180]值?
戴帽子的家伙

@TheGuywithTheHat检查以下示例:cpp.sh/7uy2v
基于

啊,不知道这是C ++。在Shadrix的JavaScript上下文中,我解释remaindermodulus。JS中的模数将得出[0,360)。
帽子的家伙

1
我认为那不行。您需要减去360 iff结果>180。我刚刚用JavaScript意识到的另一个问题是,模在0上是对称的,例如-1 % 3是-1,而不是2,因为它在这里工作是必需的。remainder是一个很棒的C ++解决方案,但是不幸的是,JS中没有足够类似的函数/运算符。
帽子的家伙

0

另一种选择:经度= atan2(cos(long),sin(long))


1
这似乎不是一个好主意。这很难理解,计算量很大,并且可能会产生舍入误差。
David Richerby

0

如果您使用的编程语言在浮点数上支持%(mod)运算符(例如Python和Ruby),则建议使用该语言。否则,某些其他语言(例如C和C ++)允许您使用fmod()。

(无论您使用哪种mod运算符,请提前确保它将对浮点数进行mod运算,并且始终会为您提供非负数的答案。否则,当您许多人纬度/经度点不正确。)

像这样使用它:

# Put the longitude in the range of [0,360):
longitude %= 360

# Put the longitude in the range of [-180,180):
if longitude >= 180:
    longitude -= 360

如果您想一口气做完这一切:

# Put the longitude in the range of [-180,180):
longitude = (longitude + 180) % 360 - 180

这些方法没有循环,因此,无论您的观测值绕地球转了多少圈,它们都可以对经度值进行归一化,而无需重复进行加法或减法。

编辑:

嗯...我只是注意到Javascript似乎并没有%像我想的那样处理负值。

在这种情况下,请尝试以下一种方法:

longitude = (longitude + 36180) % 360 - 180

36180我们正在增加是36000 + 180。36000是负的值移动到正域,并且180是转移过来,这样,当它被改装成360的范围内,这将是[0360) 。该- 180部分移回[-180,180)的范围内。

这是另一种单线,它不依赖于36,000是否足够大:

longitude = (longitude % 360 + 360 + 180) % 360 - 180

longitude % 360 + 360稍后将由修改时,该部件将确保该值保持在正数范围内360。该+ 180零件将其- 180移开,以便以后从中减去180(用)时,它将在[-180,180]的期望范围内。


1
注意:C,C ++ fmod(longitude, 360)->(-360.0 ... +360.0)和ilongitude % 360-> [-359 ... +359]。
chux-恢复莫妮卡

@chux-我对此一无所知,因此我对其进行了测试,看来您是正确的。感谢您指出这一点。
JL
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.