从伦敦的经纬度坐标算出半径50英里

时间:2020-06-13 22:23:55

标签: java geospatial

我写了一个Java API,它使用了另一个API(它是用户列表),并具有JSON格式的以下属性。用户具有名字,姓氏,IP地址,电子邮件以及纬度和经度的位置坐标。

编写的Java API应该能够吸引居住在伦敦和/或半径50英里范围内的所有用户。 我的不是,因为我无法找出检查居住在伦敦或半径50英里以内的用户所需的公式。

这是我的Java API:

package com.company;

import org.json.JSONArray;
import org.json.JSONObject;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main
{


    public static void main(String[] args)
    {
       // Using java.net.http.HttpClient
       HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://bpdts-test-app.herokuapp.com/city/London/users")).build();
        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenApply(Main::parse)
                .join();
    }

    // Parse the returned JSON data
    public static String parse(String responseBody)
    {
        System.out.println("People who live in London");
        JSONArray usersLondon = new JSONArray((responseBody));
        for (int i = 0; i < usersLondon.length(); i++)
        {
            JSONObject userLondon = usersLondon.getJSONObject(i);
            int id = userLondon.getInt("id");
            String first_name = userLondon.getString("first_name");
            String last_name = userLondon.getString("last_name");
            String email = userLondon.getString("email");
            String ip_address = userLondon.getString("ip_address");
            int latitude = userLondon.getInt("latitude");
            int longitude = userLondon.getInt("longitude");
            System.out.println("id: " + id + " " + "first name: " + first_name + " " + "last name: " + last_name + " " + "email: " + email + " "
                    + "IP Address: " + ip_address + " " + "latitude: " + latitude + " " + "longtitude: " + longitude);
        }
         return null;
    }
}

因此它仅返回6个用户,我知道这是不正确的。数学公式将是什么,以测试API用户的坐标是否居住在伦敦,和/或居住在伦敦半径50英里内?

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

正确和准确地计算地球上两点之间的距离的方法是使用Inverse/Forward formulas(写于1975年;据我所知,此后没有人设法提出更好的公式)。

由于距离很短,因此您可以使用基于球的计算来摆脱困境,但是如果您想真正正确,则可以使用“逆向/正向”方法。这是因为我们的星球不是一个完美的球体。极与极之间的距离略小于赤道直径,因此该行星是一个“压扁”球体,正式称为扁球形。导航和计算距离时,这种差异足够大,除非这些距离很小。

可以翻译原始的Inverse / Forward Fortran代码(我已经完成了多个项目),但是使用免费的库(例如this one)可能会更容易。

描述行星的极地和赤道直径之间的差异的数字被称为“参考椭球”。最常用的一种是WGS84椭球,对于大多数用途而言,它足够准确。碰巧上面的类定义了一个方便的静态WGS84实例。

在进行任何计算之前,首先需要定义“在50英里范围内”的含义。究竟在50英里内?伦敦中心吗?

Wikipedia says伦敦位于51°30′26″ N 0°7′39″ W处,这似乎是距离计算的起点。

传统上,纬度和经度在进行计算时以十进制度数表示,这意味着双精度浮点数(即Java double),其整数部分是数字度,其小数部分为分钟和秒。按照惯例,正值是北或东,而负值是南或西。

因此,北纬50°30′N 99°15′W的纬度为50.5,经度为-99.25(以十进制表示)。

您的代码获取的经度和纬度为整数。我非常怀疑您的位置是整数度数,因为很少有位置位于例如正北49°的位置。只有您知道这些int值如何表示分钟和秒。您可以将这些值转换为十进制度。

一旦您以十进制度度获得伦敦的位置,并且知道如何将用户位置转换为十进制度度,就可以调用我上面链接的Inverse类的Geodesic方法:

public static List<User> parse(String responseBody)
{
    List<User> qualifyingUsers = new ArrayList<>();

    // 51 deg 30 min 26 sec N
    double londonLat = 51 + (30 / 60.0) + (26 / 60.0 / 60.0);
    // 0 deg 7 min 39 sec W
    double londonLon = 0 - (7 / 60.0) - (39 / 60.0 / 60.0);

    for (int i = 0; i < usersLondon.length(); i++)
    {
        JSONObject userLondon = usersLondon.getJSONObject(i);
        // ...
        int latitude = userLondon.getInt("latitude");
        int longitude = userLondon.getInt("longitude");

        double userLat = convertToDecimalDegrees(latitude);
        double userLon = convertToDecimalDegrees(longitude);

        GeodesicData result =
            Geodesic.WGS84.Inverse(londonLat, londonLon, userLat, userLon);

        double distanceInMeters = result.s12;
        double distanceInMiles = distanceInMeters / 1609.34;

        if (distanceInMiles <= 50)
        {
            User user = new User();
            user.setId(id);
            user.setFirstName(first_name);
            // etc.

            qualifyingUsers.add(user);
        }
    }

    return qualifyingUsers;
}