限制纬度和经度值的模数

问题描述 投票:0回答:4

我有代表纬度和经度的双精度值。
我可以使用以下函数轻松将经度限制为 (-180.0, 180.0]

double limitLon(double lon)
{
  return fmod(lon - 180.0, 360.0) + 180.0;
}

这是有效的,因为一端是排他性的,另一端是包容性的。 fmod 包括 0 但不包括 -360.0。

有人能想到一种优雅的纬度方法吗?
所需的区间为 [-90.0, 90.0]。封闭式解决方案是最好的,即没有循环。我认为 fmod() 可能不会成功,因为现在两端都包含了。

编辑: 正如所指出的,无论如何都无法到达纬度 91 度。从技术上讲,91 应该映射到 89.0。哦,天哪,这改变了一切。

c math floating-point intervals modulo
4个回答
7
投票

使用三角函数

sin()/cos()
会耗费大量时间并导致精度损失。 使用
remainder()
功能会更好。 请注意,如果可能的话,结果与
x
具有相同的符号,并且幅度小于
y
的幅度。

OP走在正确的道路上! 下面的解决方案很容易根据 -180 和 + 180.0 的边缘值进行调整。

#include <math.h>

// Reduce to (-180.0, 180.0]
double Limit_Longitude(double longitude_degrees) {
  // A good implementation of `fmod()` will introduce _no_ loss of precision.
  // -360.0 <= longitude_reduced <=- 360.0
  double longitude_reduced = fmod(longitude_degrees, 360.0);

  if (longitude_reduced > 180.0) {
    longitude_reduced -= 360.0;
  } else if (longitude_reduced <= -180.0) {
    longitude_reduced += 360.0;
  }
  return longitude_reduced;
}

将纬度限制为 [-90 到 +90] 比较棘手,因为 +91 度的纬度会越过北极,但经度会切换 +/- 180 度。 为了保持经度精度,请将 180 度向 0 度调整。

void Limit_Latitude_Longitude(double *latitude_degrees, double *longitude_degrees) {
  *latitude_degrees = Limit_Longitude(*latitude_degrees);
  int flip = 0;
  if (*latitude_degrees > 90.0) {
    *latitude_degrees = 180.0 - *latitude_degrees;
    flip = 1;
  } else if (*latitude_degrees < -90.0) {
    *latitude_degrees = -180.0 - *latitude_degrees;
    flip = 1;
  }
  if (flip) {
    *longitude_degrees += *longitude_degrees > 0 ? -180.0 : 180.0;
  }
  *longitude_degrees = Limit_Longitude(*longitude_degrees);
}

次要:虽然目标是“将经度限制为 (-180.0, 180.0]”,但我预计 [-180.0, 180.0)、[-180.0, 180.0] 的范围更常见。


5
投票

有一种比使用 sin 和 arcsin 更有效的方法来做到这一点。最昂贵的操作是单个部门。观察所需间隔是否闭合是关键。

  • 除以 360 并取余数。这会产生区间

    [0, 360)
    中的数字,如观察到的,该数字是半开的。

  • 将间隔对折。如果余数 >=180,则从 360 中减去它。这会将区间

    [180, 360)
    映射到区间
    (0, 180]
    。该区间与下半部分的并集是闭区间
    [0, 180]

  • 从结果中减去 90。此间隔为

    [-90, 90]
    ,如所需。

这确实与

arcsin(sin(x))
完全相同,但没有费用或任何数字稳定性问题。


2
投票

使用

sin
和反函数怎么样?

asin(sin((lat/180.0)*3.14159265)) * (180.0/3.14159265);

2
投票

提供的两个答案(D Stanley,eh9)都不起作用......尽管对于 eh9 我可能会误解某些内容。 尝试使用多个值。

不幸的是,正确的答案很昂贵。 请参阅 Microsoft Research 的以下内容:https://web.archive.org/web/20150109080324/http://research.microsoft.com/en-us/projects/wraplatitudelongitude/.

从那里,答案是:

latitude_new = atan(sin(latitude)/fabs(cos(latitude)))
-- 注意 cos(纬度) 周围的绝对值

longitude_new = atan2(sin(longitude),cos(longitude))

请注意,在 C 语言中,您可能需要使用

atan2f
(浮点型与双精度型)。 此外,所有三角函数都采用弧度。

© www.soinside.com 2019 - 2024. All rights reserved.