在地图上计算两点之间的距离其实就是计算地球弧度距离,将用角度表示的角转换为近似相等的用弧度表示的角。
首先需要获取某个地点的经纬度,这里可以借用百度地图 API 进行计算得到。
通过百度 API 求取距离
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 百度 API 经纬度计算位置
* </p>
* 发送 GET 请求借助 httpclient,需要在 POM 中引入:
* <a href="http://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient"></a>
*
* @author MinGRn <br > MinGRn97@gmail.com
* @date 01/10/2018 15:17
*/
public class DistanceUtil {
/** 百度获取位置经纬度 URL */
private static final String LNG_LAT_POINT_URL = "http://api.map.baidu.com/geocoder/v2/?output=json&ak=RguGdBfvanKG10lrLHtUAtka&address=";
/** 百度Map距离求取 URL */
private static final String WAY_POINTS_DISTANCE_URL = "http://api.map.baidu.com/telematics/v3/distance?output=json&ak=RguGdBfvanKG10lrLHtUAtka&waypoints=";
/**
* 获取具体位置的经纬度
* </p>
* 如: location = 上海市徐汇区零陵小区
* result:{"status":0,"result":{"location":{"lng":121.45078363819293,"lat":31.193489388753848},"precise":1,"confidence":70,"comprehension":100,"level":"地产小区"}}
*
* @param location 地理位置
*/
private static void getLngAndLat(String location) {
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
HttpUriRequest uriRequest = RequestBuilder.get(LNG_LAT_POINT_URL + location).build();
http4BaiduApi(httpClient, uriRequest);
} catch (IOException e) {
// Handler IO Exception
}
}
/**
* 计算两个坐标点的距离
* <br>
* 返回结果: 距离(米)
*
* @param startLng 起点经度
* @param startLat 起点纬度
* @param endLng 终点经度
* @param endLat 终点纬度
*/
private static void twoLocationDistance(Double startLng, Double startLat, Double endLng, Double endLat) {
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
String builderPoint = startLng + "," + startLat + ";" + endLng + "," + endLat;
HttpUriRequest uriRequest = RequestBuilder.get(WAY_POINTS_DISTANCE_URL + builderPoint).build();
http4BaiduApi(httpClient, uriRequest);
} catch (IOException e) {
// Handler IO Exception
}
}
private static void http4BaiduApi(CloseableHttpClient httpClient, HttpUriRequest uriRequest) {
StringBuilder builder = new StringBuilder();
try (InputStream inputStream = httpClient.execute(uriRequest).getEntity().getContent()) {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
while ((line = br.readLine()) != null) {
builder.append(line);
}
System.out.println(builder.toString());
} catch (IOException e) {
// Handler IO Exception
}
}
}
现在进行测试:
public static void main(String[] args){
getLngAndLat("上海市徐汇区零陵小区");
}
输出结果为:
result:{"status":0,"result":{"location":{"lng":121.45078363819293,"lat":31.193489388753848},"precise":1,"confidence":70,"comprehension":100,"level":"地产小区"}}
这样就可以得到具体某个位置的经纬度了,得到两个地区的经纬度后调用 twoLocationDistance(Double startLng, Double startLat, Double endLng, Double endLat)
方法来获取距离信息:
public static void main(String[] args){
twoLocationDistance(121.455244, 31.234076, 121.488301, 31.237534);
}
可以看到具体数据结果为:{"status":"Success","results":[3166.3643236737]}
。说明两点距离是 3166 米。
通过弧度角进行求取距离
现在来看下怎么自己通过计算地球弧度距离,直接看如下这个工具类:
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 根据圆周率计算两点地图经纬度距离
* </p>
*
* @author MinGRn <br > MinGRn97@gmail.com
*/
public class PI4MapHelper {
/**
* 地球半径(km)
*/
private static final double EARTH_RADIUS = 6378.137;
/**
* 等同于 Math.toRadians(), 将用角度表示的角转换为近似相等的用弧度表示的角
* </p>
* JS 没有 Math.toRadians(),如在 JS 直接使用该方法即可。
*
* <pre class="java">
* Math.toRadians(startLat);
* </pre>
* <pre class="JavaScript">
* radians(startLat)
* </pre>
*
* @param angle 角度
*/
private static double radians(double angle) {
return angle * Math.PI / 180.0;
}
/**
* 计算两个坐标点的距离
* </p>
* 距离四舍五入保留一位小数,单位KM
*
* @param startLng 起点经度
* @param startLat 起点纬度
* @param endLng 终点经度
* @param endLat 终点纬度
* @return 距离(千米)
*/
private static double twoLocationDistance(double startLng, double startLat, double endLng, double endLat) {
double startRadLat = Math.toRadians(startLat), endRadLat = Math.toRadians(endLat);
double radLatDiff = startRadLat - endRadLat, radLngDiff = Math.toRadians(startLng) - Math.toRadians(endLng);
double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(radLatDiff / 2), 2) +
Math.cos(startRadLat) * Math.cos(endRadLat) * Math.pow(Math.sin(radLngDiff / 2), 2)));
distance = distance * EARTH_RADIUS;
//distance = Math.round(distance * 10000) / 10000;
//距离四舍五入保留一位小数
distance = new BigDecimal(distance).setScale(1, RoundingMode.HALF_UP).doubleValue();
return distance;
}
}
进行测试:
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
double dist = twoLocationDistance(121.455244, 31.234076, 121.488301, 31.237534);
System.out.println("两点相距:" + dist + "千米");
}
可以看到输出结果为:耗时:0毫秒 两点相距:3.2千米
。可以看到两个结果相同,只是这里进行了四舍五入处理。所以,计算两个经纬度的距离可以直接使用该工具类进行计算。
另外,如果通过调用百度 API 进行求取需要发送 GET 请求,这里借助的工具是 httpclient
可以在 MAVEN 中央仓库进行下载:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
参看资料: