java - 在半径内随机生成一个 latlng 会产生一个超出范围的点

标签 java android

我试图在半径内生成一个点,但得到的值不正确。有人介意看一下并告诉我我在经度上做错了什么吗?这是针对不同问题发布的公式化方法...

  public static Location generateLocationWithinRadius(Location myCurrentLocation) {
    return getLocationInLatLngRad(1000, myCurrentLocation);
}

protected static Location getLocationInLatLngRad(double radiusInMeters, Location currentLocation) {
    double x0 = currentLocation.getLatitude();
    double y0 = currentLocation.getLongitude();

    Random random = new Random();

    // Convert radius from meters to degrees
    double radiusInDegrees = radiusInMeters / 111000f;

    double u = random.nextDouble();
    double v = random.nextDouble();
    double w = radiusInDegrees * Math.sqrt(u);
    double t = 2 * Math.PI * v;
    double x = w * Math.cos(t);
    double y = w * Math.sin(t);

    double new_x = x / Math.cos(y0);
    double new_y = y / Math.cos(x0);
    double foundLatitude;
    double foundLongitude;
    boolean shouldAddOrSubtractLat = random.nextBoolean();
    boolean shouldAddOrSubtractLon = random.nextBoolean();
    if (shouldAddOrSubtractLat) {
        foundLatitude = new_x + x0;
    } else {
        foundLatitude = x0 - new_x;
    }
    if (shouldAddOrSubtractLon) {
        foundLongitude = new_y + y0;
    } else {
        foundLongitude = y0 - new_y;
    }
    Location copy = new Location(currentLocation);
    copy.setLatitude(foundLatitude);
    copy.setLongitude(foundLongitude);
    return copy;
}

我还应该说,出于某种原因,有效点在观察时会产生一条统一的坐标线。

我认为纬度处理正确,而经度不正确。

最佳答案

您的代码似乎或多或少基于一个想法 which is presented at gis.stackexchange.com 并在 this discussion 中讨论了更多内容 在this discussion .

如果我们根据这些讨论仔细研究它,那么它可能更有意义。

为了轻松地将值限制为圆,它使用了随机化方向和距离的方法。首先我们得到两个介于 0.0 ... 1.0 之间的随机 double 值:

double u = random.nextDouble();
double v = random.nextDouble();

由于半径以米为单位且计算需要度数,因此将其转换为:

double radiusInDegrees = radiusInMeters / 111000f;

此处使用赤道的度数与米数之比。 (维基百科建议 111320 米。)

为了使随机点分布更均匀,距离用平方根补偿:

w = r * sqrt(u)

否则,靠近中心与远离中心的点数将存在统计偏差。 1的平方根是1,0当然是0,所以 将随机 double 的根乘以预期的最大值。 radius 总是给出一个介于 0 和半径之间的值。

然后另一个随机double乘以2 * pi因为一个完整的圆有2 * pi弧度:

t = 2 * Pi * v

我们现在有一个介于 0 ... 2 * pi 之间的角度,即 0 ... 360 度。

然后使用随机距离和随机角度使用基本三角学计算随机 x 和 y 坐标增量:

x = w * cos(t) 
y = w * sin(t)

然后,[x,y] 指向 t 方向,距离原始坐标一些随机距离 w

然后经度线之间的变化距离用三角函数补偿(y0 是中心的 y 坐标):

x' = x / cos(y0)

如果 cos() 期望角度为弧度,则需要将 y0 上方的值转换为弧度。在 Java 中是这样。

然后建议将这些增量值添加到原始坐标。 cossin 对于整个圆角的一半是负的,所以只相加就可以了。一些随机点将位于格林威治以西和赤道以南。没有必要随机化 应该做加法还是减法。

因此随机点将位于 (x'+x0, y+y0)

我不知道为什么你的代码有:

double new_y = y / Math.cos(x0);

正如所说,我们可以忽略 shouldAddOrSubtractLatshouldAddOrSubtractLon

在我看来,x 指的是从左到右或从西到东的东西。这就是经度值增长的方式,即使经度线是从南到北。因此,让我们使用 x 作为经度,使用 y 作为纬度。

那还剩下什么呢?像这样的东西:

protected static Location getLocationInLatLngRad(double radiusInMeters, Location currentLocation) {
    double x0 = currentLocation.getLongitude();
    double y0 = currentLocation.getLatitude();

    Random random = new Random();

    // Convert radius from meters to degrees.
    double radiusInDegrees = radiusInMeters / 111320f;

    // Get a random distance and a random angle.
    double u = random.nextDouble();
    double v = random.nextDouble();
    double w = radiusInDegrees * Math.sqrt(u);
    double t = 2 * Math.PI * v;
    // Get the x and y delta values.
    double x = w * Math.cos(t);
    double y = w * Math.sin(t);

    // Compensate the x value.
    double new_x = x / Math.cos(Math.toRadians(y0));

    double foundLatitude;
    double foundLongitude;

    foundLatitude = y0 + y;
    foundLongitude = x0 + new_x;

    Location copy = new Location(currentLocation);
    copy.setLatitude(foundLatitude);
    copy.setLongitude(foundLongitude);
    return copy;
}

关于java - 在半径内随机生成一个 latlng 会产生一个超出范围的点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36905396/

相关文章:

Java:发现很长,需要 int

java - 运行第一个HIPI程序时,出现JSON错误。我应该在哪里添加它以及如何添加?

java - 线程 "main"java.lang.NoClassDefFoundError : org/apache/hadoop/fs/FSDataInputStream 中的 SSH 异常

android - Android Studio 中的错误消息

android - 在 Android Honeycomb 上,如何将选项菜单添加到屏幕底部的主页栏?

java - SetImageBitMap 在 api 23 android java 中不起作用

java - 更新到4.2RC1,透明 Activity 不行?突然变黑

java - 如何找到两个角度之间的最小过渡

java - Camera 2 Api Error - 不拍照的错误

java - System.currentTimeMillis() 和夏令时