如何查找两个地址之间的距离? (Java服务器端)

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

我正在开发一个“社交”地理感知应用程序,价值百万美元的问题是如何列出“我的位置”“X 英里内”的一组项目,因为有数百万个应用程序可以做到这一点,我惊讶地发现只有 Google Maps API 具有免费的网络服务,更糟糕的是,只有在 Google Map 中使用时才支持它。那么我必须开发自己的距离计算器吗?有没有免费/付费服务可以让我至少将地址转换为 XY 坐标?

我确信有一个行业标准解决方案(免费或商业),但我还没有找到它

google-maps geolocation distance street-address
5个回答
4
投票

实际上,Google 确实有 网络服务,您可以在服务器端使用来实现此目的。

首先,您需要使用 Geocoding API 将地址转换为纬度/经度坐标对。然后,您可以使用您认为合适的方式(即,如果您要存储这些数据,则针对您自己的数据库)

如果您想要查找的附近项目是 Google 可能已经知道的世界上的实际地点,您可以尝试 Google 新的 Places API,它可以为您提供特定半径内的结果。

您应该注意,从纬度/经度坐标到距离的转换确实需要一些数学,但我认为最好在本地完成(在您的应用程序运行的服务器上),而不是外包给某些外部服务器,因为它只是 数学。 谷歌搜索产生了this


4
投票

如果你使用 SQL(你没有说)...我想我是从 NerdDinner 项目复制的:

ALTER FUNCTION [dbo].[DistanceBetween] (@Lat1 as real,
                @Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
                 * COS (@dLat2InRad)
                 * SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END


ALTER FUNCTION [dbo].[NearestPeople]
    (
    @lat real,
    @long real,
    @maxdist real
    )
RETURNS  TABLE
AS
    RETURN
    SELECT     Person.ID
    FROM       Person
    WHERE dbo.DistanceBetween(@lat, @long, Latitude, Longitude) < @maxdist

然后我从服务器使用这些 SQL 函数,就像在 C# 中一样:

public IQueryable<Person> FindNearbyPeople(float latitude, float longitude, float maxdistance)
{
    var people = from person in FindAllPeople()
                 join i in db.NearestPeople(latitude, longitude, maxdistance)
                 on person.ID equals i.ID
                 select person;

    return people;
}

这告诉我谁(在本例中为人)在最大距离内靠近我。

这是免费版本。我认为 SQL Server 2008 可以使用地理包来执行此操作


4
投票

如果你幸运的话,你使用的是 mysql 或 postgresql,它们都是支持空间的数据库,你可以对它们执行空间查询。对于 mysql,有 空间扩展,对于 postgresql,有 postgis
如果您决定手动操作,请查看这个问题以供注意。另外,我不明白Google Places API如何帮助您,因为您正在查看半径内的您的数据而不是Google Places。 干杯


3
投票
  1. 您想要“直线距离”还是行车距离/时间?

  2. Mapquest 的 API 似乎更简单,因为您只需使用查询字符串即可。

另一个选项是 geocoder.us(如果是加拿大人,则为 .ca)


0
投票

通过 Java Google Maps SDK,您可以获取特定地址的 lat/lng,然后使用半正矢距离公式获取以 KM 为单位的距离。

    <dependency>
        <groupId>com.google.maps</groupId>
        <artifactId>google-maps-services</artifactId>
        <version>2.2.0</version>
    </dependency>

代码:

public static Double getDistanceInKmAsTheCrowFlies(String apiKey, String address1, String address2)
{
    GeocodingResult[] address1GeoCode = getGeocoding(apiKey, address1);
    GeocodingResult[] address2GeoCode = getGeocoding(apiKey, address2);

    if (address1GeoCode != null && address2GeoCode != null)
    {
        double lat1 = address1GeoCode[0].geometry.location.lat;
        double lng1 = address1GeoCode[0].geometry.location.lng;

        double lat2 = address2GeoCode[0].geometry.location.lat;
        double lng2 = address2GeoCode[0].geometry.location.lng;

        return getHaversineDistance(lat1, lng1, lat2, lng2);
    }
    return null;

}

public static GeocodingResult[] getGeocoding(String apiKey, String address)
{

    GeocodingApiRequest req = GeocodingApi.newRequest(new GeoApiContext.Builder()
            .apiKey(apiKey)
            .build());

    GeocodingResult[] query = req.address(address).awaitIgnoreError();

    if (query != null && query.length > 0)
    {
        return query;
    }
    return null;
}

public static double getHaversineDistance(double lat1, double lng1, double lat2, double lng2)
{
    int r = 6371; // average radius of the earth in km
    double dLat = Math.toRadians(lat2 - lat1);
    double dLon = Math.toRadians(lng2 - lng1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
            * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = r * c;
    return d;
}
© www.soinside.com 2019 - 2024. All rights reserved.