Java根据两点经纬度计算距离

  1. 云栖社区>
  2. 博客>
  3. 正文

Java根据两点经纬度计算距离

心月狐 2018-10-08 10:49:28 浏览2613
展开阅读全文

这些经纬线是怎样定出来的呢?地球是在不停地绕地轴旋转(地轴是一根通过地球南北两极和地球中心的
假想线),在地球中腰画一个与地轴垂直的大圆圈,使圈上的每一点都和南北两极的距离相等,这个圆圈
就叫作“赤道”。在赤道的南北两边,画出许多和赤道平行的圆圈,就是“纬圈”;构成这些圆圈的线段,
叫做纬线。我们把赤道定为纬度零度,向南向北各为90度,在赤道以南的叫南纬,在赤道以北的叫北纬。
北极就是北纬90度,南极就是南纬90度。纬度的高低也标志着气候的冷热,如赤道和低纬度地地区无冬,
两极和高纬度地区无夏,中纬度地区四季分明。
其次,从北极点到南极点,可以画出许多南北方向的与地球赤道垂直的大圆圈,这叫作“经圈”;构成这
些圆圈的线段,就叫经线。公元1884平面坐标图年,国际上规定以通过英国伦敦近郊的格林尼治天文台的
经线作为计算经度的起点,即经度零度零分零秒,也称“本初子午线”。在它东面的为东经,共180度;
在它西面的为西经,共180度。因为地球是圆的,所以东经180度和西经180度的经线是同一条经线。各国
公定180度经线为“国际日期变更线”。为了避免同一地区使用两个不同的日期,国际日期变线在遇陆地时
略有偏离。
每一经度和纬度还可以再细分为60分,每一分再分为60秒以及秒的小数。利用经纬线,我们就可以确定
地球上每一个地方的具体位置,并且把它在地图或地球仪上表示出来。例如问北京的经纬度是多少?我们
很容易从地图上查出来是东经116度24分,北纬39度54分。在大海中航行的船只,只要把所在地的经度测
出来,就可以确定船在海洋中的位置和前进方向。 纬度共有90度。赤道为0度,向两极排列,圈子越小,
度数越大。
横线是纬度,竖线是经度。
当然可以计算,四元二次方程。
经度和纬度都是一种角度。经度是个两面角,是两个经线平面的夹角。因所有经线都是一样长,为了度量
经度选取一个起点面,经1884年国际会议协商,决定以通过英国伦敦近郊、泰晤士河南岸的格林尼治皇家
天文台(旧址)的一台主要子午仪十字丝的那条经线为起始经线,称为本初子午线。本初子午线平面是起
点面,终点面是本地经线平面。某一点的经度,就是该点所在的经线平面与本初子午线平面间的夹角。在
赤道上度量,自本初子午线平面作为起点面,分别往东往西度量,往东量值称为东经度,往西量值称为西
经度。由此可见,一地的经度是该地对于本初子午线的方向和角距离。本初子午线是0°经度,东经度的最
大值为180°,西经度的最大值为180°,东、西经180°经线是同一根经线,因此不分东经或西经,而统称
180°经线。
纬度是个线面角。起点面是赤道平面,线是本地的地面法线。所谓法线,即垂直于参考扁球体表面的线。
某地的纬度就是该地的法线与赤道平面之间的夹角。纬度在本地经线上度量,由赤道向南、北度量,向北
量值称为北纬度,向南量值称为南纬度。由此可见,一地的纬度是该地对于赤道的方向和角距离。赤道是
0°纬线,北纬度的最大值为90°,即北极点;南纬度的最大值为90°,即南极点。
经纬度互换
度换算成度分秒
度(DDD):E 108.90593度 N 34.21630度
如 何将度(DDD):: 108.90593度换算成度分秒(DMS)东经E 108度54分22.2秒?转换方法是将108.90593整数位不变取108(度),用0.9059360=54.3558,取整数位 54(分),0.355860=21.348再取整数位21(秒),故转化为108度54分21秒.
同样将度分秒(DMS):东经E 108度54分22.2秒 换算成度(DDD)的方法如下:108度54分22.2秒=108+(54/60)+(22.2/3600)=108.90616度
因为计算时小数位保留的原因,导致正反计算存在一定误差,但误差影响不是很大。1秒的误差就是几米的样子。GPS车友可以用上述方法换算成自己需要的单位坐标。

关于经纬度十进制表示法
对于两个点,在纬度相等的情况下:
经度每隔0.00001度,距离相差约1米;每隔0.0001度,距离相差约10米;每隔0.001度,距离相差约100米;每隔0.01度,距离相差约1000米;每隔0.1度,距离相差约10000米。

对于两个点,在经度相等的情况下:
纬度每隔0.00001度,距离相差约1.1米;每隔0.0001度,距离相差约11米;每隔0.001度,距离相差约111米;每隔0.01度,距离相差约1113米;每隔0.1度,距离相差约11132米。
根据地球上任意两点的经纬度计算两点间的距离
923888_1212_jpeg

方 法1:由于地球是椭球体,这个太难算了,如果假设地球是球体,可以使用以下公式:设地球上某点的经度为A,纬度为B, 则这点的空间坐标是 x=cos(B)cos(A) y=cos(B)sin(A) z=sin(B) 设地球上两点的空间坐标分别为(x1,y1,z1),(x2,y2,z2) 则它们的夹角为 C=acos(x1x2+y1y2+z1z2),C是角度 则两地距离为 C/180pi*R,其中R为地球平均半径6371 误差不超过1%

地 球是一个近乎标准的椭球体,它的赤道半径为6378.140千米,极半径为 6356.755千米,平均半径6371.004千米。如果我们假设地球是一个完美的球体,那么它的半径就是地球的平均半径,记为R。如果以0度经线为基 准,那么根据地球表面任意两点的经纬度就可以计算出这两点间的地表距离(这里忽略地球表面地形对计算带来的误差,仅仅是理论上的估算值)。设第一点A的经 纬度为(LonA, LatA),第二点B的经纬度为(LonB, LatB),按照0度经线的基准,东经取经度的正值(Longitude),西经取经度负值(-Longitude),北纬取90-纬度值(90- Latitude),南纬取90+纬度值(90+Latitude),则经过上述处理过后的两点被计为(MLonA, MLatA)和(MLonB, MLatB)。那么根据三角推导,可以得到计算两点距离的如下公式:
C = sin(MLatA)sin(MLatB)cos(MLonA-MLonB) + cos(MLatA)*cos(MLatB)
Distance = RArccos(C)Pi/180

这里,R和Distance单位是相同,如果是采用6371.004千米作为半径,那么Distance就是千米为单位,如果要使用其他单位,比如mile,还需要做单位换算,1千米=0.621371192mile
如果仅对经度作正负的处理,而不对纬度作90-Latitude(假设都是北半球,南半球只有澳洲具有应用意义)的处理,那么公式将是:
C = sin(LatA)sin(LatB) + cos(LatA)cos(LatB)*cos(MLonA-MLonB)
Distance = RArccos(C)Pi/180
以上通过简单的三角变换就可以推出。
如果三角函数的输入和输出都采用弧度值,那么公式还可以写作:

C = sin(LatAPi/180)sin(LatBPi/180) + cos(LatAPi/180)cos(LatBPi/180)cos((MLonA-MLonB)Pi/180)
Distance = RArccos(C)Pi/180
也就是:
C = sin(LatA/57.2958)sin(LatB/57.2958) + cos(LatA/57.2958)cos(LatB/57.2958)*cos((MLonA-MLonB)/57.2958)
Distance = RArccos(C) = 6371.004Arccos(C)
kilometer = 0.6213711926371.004Arccos(C)
mile = 3958.758349716768*Arccos(C) mile

/**

  • Copyright (C), 2015-2018, 亚信(中国)科技有限公司
  • FileName: a
  • Author: zhoumoxuan
  • Date: 10/8/18 10:35 AM
  • Description: e
  • History:
  • 作者姓名 修改时间 版本号 描述
    */

package com.asiainfo.utils;

/**

  • 〈一句话功能简述〉
  • 〈e〉
    *
  • @author zhoumoxuan
  • @create 10/8/18
  • @since 1.0.0
    */

public class a {

private static final  double EARTH_RADIUS = 6378137;//赤道半径(单位m)  

/**
 * 转化为弧度(rad) 
 * */
private static double rad(double d)
{
    return d * Math.PI / 180.0;
}

/**
 * 基于余弦定理求两经纬度距离 
 * @param lon1 第一点的精度 
 * @param lat1 第一点的纬度 
 * @param lon2 第二点的精度 
 * @param lat3 第二点的纬度 
 * @return 返回的距离,单位km 
 * */
public static double LantitudeLongitudeDist(double lon1, double lat1,double lon2, double lat2) {
    double radLat1 = rad(lat1);
    double radLat2 = rad(lat2);

    double radLon1 = rad(lon1);
    double radLon2 = rad(lon2);

    if (radLat1 < 0)
        radLat1 = Math.PI / 2 + Math.abs(radLat1);// south  
    if (radLat1 > 0)
        radLat1 = Math.PI / 2 - Math.abs(radLat1);// north  
    if (radLon1 < 0)
        radLon1 = Math.PI * 2 - Math.abs(radLon1);// west  
    if (radLat2 < 0)
        radLat2 = Math.PI / 2 + Math.abs(radLat2);// south  
    if (radLat2 > 0)
        radLat2 = Math.PI / 2 - Math.abs(radLat2);// north  
    if (radLon2 < 0)
        radLon2 = Math.PI * 2 - Math.abs(radLon2);// west  
    double x1 = EARTH_RADIUS * Math.cos(radLon1) * Math.sin(radLat1);
    double y1 = EARTH_RADIUS * Math.sin(radLon1) * Math.sin(radLat1);
    double z1 = EARTH_RADIUS * Math.cos(radLat1);

    double x2 = EARTH_RADIUS * Math.cos(radLon2) * Math.sin(radLat2);
    double y2 = EARTH_RADIUS * Math.sin(radLon2) * Math.sin(radLat2);
    double z2 = EARTH_RADIUS * Math.cos(radLat2);

    double d = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)+ (z1 - z2) * (z1 - z2));
    //余弦定理求夹角  
    double theta = Math.acos((EARTH_RADIUS * EARTH_RADIUS + EARTH_RADIUS * EARTH_RADIUS - d * d) / (2 * EARTH_RADIUS * EARTH_RADIUS));
    double dist = theta * EARTH_RADIUS;
    return dist;
}

}
坐​标​与​距​离​换​算​,​经​测​试​,​相​差​一​米

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

public class LatitudeUtil {

public static final String KEY_1 = "ChwEVlrmoje34iED20piImPc";

/**
 * 根据地址查坐标
 *
 * @param address 地址,格式:深圳市罗湖区火车站
 * @return
 */

// @param key   申请ak(即获取密钥),若无百度账号则首先需要注册百度账号。     
public static Map<String, String> getGeocoderLatitude(String address) {
    BufferedReader in = null;
    if (CommonUtil.NotEmpty(key)) { //         
        return null;
    }
    try {
        address = URLEncoder.encode(address, "UTF-8");
        URL tirc = new URL("http://api.map.baidu.com/geocoder?address=" + address + "&output=json&key=" + KEY_1);
        in = new BufferedReader(new InputStreamReader(tirc.openStream(), "UTF-8"));
        String res;
        StringBuilder sb = new StringBuilder("");
        while ((res = in.readLine()) != null) {
            sb.append(res.trim());
        }
        String str = sb.toString();
        Map<String, String> map = new HashMap<String, String>();
        if (StringUtils.isNotEmpty(str)) {
            int lngStart = str.indexOf("lng\":");
            int lngEnd = str.indexOf(",\"lat");

            int latEnd = str.indexOf("},\"precise");
            if (lngStart > 0 && lngEnd > 0 && latEnd > 0)

            {
                String lng = str.substring(lngStart + 5, lngEnd);
                String lat = str.substring(lngEnd + 7, latEnd);
                map.put("lng", lng);
                map.put("lat", lat);
                return map;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

/**
 * 计算地球上任意两点(经纬度)距离
 * *
 * * @param lon1
 * *            第一点经度
 * * @param lat1
 * *            第一点纬度
 * * @param lon2
 * *            第二点经度
 * * @param lat2
 * *            第二点纬度
 * * @return 返回距离 单位:千米
 */
public static double getDistatce(
        double lon1, double lat1, double lon2, double lat2) {
    double R = 6371;
    double distance = 0.0;
    double dLat = (lat2 - lat1) * Math.PI / 180;
    double dLon = (lon2 - lon1) * Math.PI / 180;
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    distance = (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))) * R;
    return distance;
}

/**
 * 计算地球上任意两点(经纬度)距离      *       * @param long1       *            第一点经度      * @param lat1       *            第一点纬度      * @param long2       *            第二点经度      * @param lat2       *            第二点纬度      * @return 返回距离 单位:米
 */
public static double Distance(double long1, double lat1, double long2, double lat2) {
    double a, b, R;
    R = 6378137; // 地球半径         
    lat1 = lat1 * Math.PI / 180.0;
    lat2 = lat2 * Math.PI / 180.0;
    a = lat1 - lat2;
    b = (long1 - long2) * Math.PI / 180.0;
    double d;
    double sa2, sb2;
    sa2 = Math.sin(a / 2.0);
    sb2 = Math.sin(b / 2.0);
    d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
    return d;
}

/**
 * 查找一定范围内的经纬度值   * 传入值: 经度 纬度   查找半径(m)   * 返回值:最小经度、纬度,最大经度、纬度   113.957541,22.549392 朗峰大厦
 */
public static Map<String, Double> getAround(Double lon, Double lat, Double raidus) {
    Double PI = 3.14159265;    // 圆周率 
    Double EARTH_RADIUS = 6378137d;
    // 地球半径    
    Double RAD = Math.PI / 180.0;
    // 弧度      
    Double longitude = lon;
    //经度   
    Double latitude = lat;
    //纬度      
    Double degree = (24901 * 1609) / 360.0;
    Double raidusMile = raidus;
    //距离     
    Double dpmLat = 1 / degree;
    Double radiusLat = dpmLat * raidusMile;
    Double minLat = latitude - radiusLat;
    //最小纬度   
    Double maxLat = latitude + radiusLat;
    //最大纬度     
    Double mpdLng = degree * Math.cos(latitude * (PI / 180));
    Double dpmLng = 1 / mpdLng;
    Double radiusLng = dpmLng * raidusMile;
    Double minLng = longitude - radiusLng;
    //最小经度   
    Double maxLng = longitude + radiusLng;   ]
    //最大经度   
    Map<String, Double> m = new HashMap<String, Double>();
    m.put("minLng", minLng);
    //最小经度   
    m.put("minLat", minLat);
    //最小纬度   
    m.put("maxLng", maxLng);
    //最大经度   
    m.put("maxLat", maxLat);
    //最大纬度   
    System.err.println("最小经度:" + minLng);
    System.err.println("最小纬度:" + minLat);
    System.err.println("最大经度:" + maxLng);
    System.err.println("最大纬度:" + maxLat);
    return m;
}

public static void main(String args[]) {
    Map<String, String> json = LatitudeUtil.getGeocoderLatitude("深圳罗湖火车站");
    Map<String, String> json = LatitudeUtil.getGeocoderLatitude("tl");
    System.out.println("lng : " + json.get("lng"));
    System.out.println("lat : " + json.get("lat"));
    double d1 = getDistatce(113.993941, 22.596919, 114.156395, 22.581934);
    double d2 = Distance(113.993941, 22.596919, 114.156395, 22.581934);
    System.out.println("d1 -> " + d1 + ", d2 -> " + d2);
    double f = 111.234;
    BigDecimal bg = new BigDecimal(f);
    double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    System.out.println(f1);
}

}

/**

  • 经纬距离换算
    */

public class MapDistance {

private static final double PI = 3.14159265;
private static final double EARTH_RADIUS = 6378137;
private static final double RAD = Math.PI / 180.0;
private static Double a;

private static MapDistance mapDistance=null;

public MapDistance(){

}

public static MapDistance getInstance(){
    if(mapDistance==null){
        mapDistance=new MapDistance();
    }

    return mapDistance;
}

// @see of-a-Latitude-and-Longitude--65095/
// The circumference of the earth is 24,901 miles.
// 24,901/360 = 69.17 miles / degree
/**
 * 根据提供的经度和纬度、以及半径,取得此半径内的最大最小经纬度
 *  @param raidus 单位米 * 
 *  @return minLat,minLng,maxLat,maxLng 
 *  
 */
public static Double[] getAround(Double lat, Double lon, int raidus) {
    Double latitude = lat;//纬度
    Double longitude = lon;//经度
    Double degree = (24901 * 1609) / 360.0;//度
    double raidusMile = raidus;//半径
    Double dpmLat = 1 / degree;
    Double radiusLat = dpmLat * raidusMile;
    Double minLat = latitude - radiusLat;
    Double maxLat = latitude + radiusLat;
    Double mpdLng = degree * Math.cos(latitude * (PI / 180));
    Double dpmLng = 1 / mpdLng;
    Double radiusLng = dpmLng * raidusMile;
    Double minLng = longitude - radiusLng;
    Double maxLng = longitude + radiusLng;
    System.out.println(minLat+"   "+maxLat+"   "+minLng+"  "+maxLng);
    // System.out.println(&quot;[&quot;+minLat+&quot;,&quot;+minLng+&quot;,&quot;+maxLat+&quot;,&quot;+maxLng+&quot;]&quot;);
    return new Double[] { minLat,maxLat,minLng,maxLng };
}

/**
 * 根据两点间经纬度坐标(double值),计算两点间距离,单位为米 * 
 * @param lng1 *
 * @param lat1 
 * @param lng2  
 * @param lat2 
 * @return
 */
public static Double getDistance(Double lng1, Double lat1, Double lng2, Double lat2) {
    double radLat1 = lat1 * RAD;
    double radLat2 = lat2 * RAD;
    double a = radLat1 - radLat2;
    Double b = (lng1 - lng2) * RAD;
    Double s = 2 * Math.asin(Math.sqrt(
            Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
    s = s * EARTH_RADIUS;
    s = Math.round(s * 10000) / 10000.0;
    return s;
}

public static void main(String[] args) {

// Double lat1 = 34.264648;
// Double lon1 = 108.952736;
// int radius = 1000; // [34.25566276027792,108.94186385411045,34.27363323972208,108.96360814588955]
// getAround(lat1, lon1, radius); // 911717.0
//// // 34.264648,108.952736,39.904549,116.407288
//// Double dis = getDistance(108.952736, 34.264648, 116.407288, 39.904549);
//// System.out.println(dis);

    System.out.println((0!=0.0));
}

}

网友评论

登录后评论
0/500
评论
心月狐
+ 关注