我正在开发一个“社交”地理感知应用程序,价值百万美元的问题是如何列出“我的位置”“X 英里内”的一组项目,因为有数百万个应用程序可以做到这一点,我惊讶地发现只有 Google Maps API 具有免费的网络服务,更糟糕的是,只有在 Google Map 中使用时才支持它。那么我必须开发自己的距离计算器吗?有没有免费/付费服务可以让我至少将地址转换为 XY 坐标?
我确信有一个行业标准解决方案(免费或商业),但我还没有找到它
实际上,Google 确实有 网络服务,您可以在服务器端使用来实现此目的。
首先,您需要使用 Geocoding API 将地址转换为纬度/经度坐标对。然后,您可以使用您认为合适的方式(即,如果您要存储这些数据,则针对您自己的数据库)
如果您想要查找的附近项目是 Google 可能已经知道的世界上的实际地点,您可以尝试 Google 新的 Places API,它可以为您提供特定半径内的结果。
您应该注意,从纬度/经度坐标到距离的转换确实需要一些数学,但我认为最好在本地完成(在您的应用程序运行的服务器上),而不是外包给某些外部服务器,因为它只是 数学。 谷歌搜索产生了this。
如果你使用 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 可以使用地理包来执行此操作
您想要“直线距离”还是行车距离/时间?
Mapquest 的 API 似乎更简单,因为您只需使用查询字符串即可。
另一个选项是 geocoder.us(如果是加拿大人,则为 .ca)
通过 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;
}