在实际应用中经常会遇到这样一种需求,由最大最小的经纬度给出一个矩形范围,然后判断一个点是否在这个范围内部,由于经纬度有负有正,而且经度跨越正负180度后变号并且反向增减,一两步计算不出来,下面给出一种计算方案,其中在经度的处理上,只有劣弧计入范围内部,也就是只有小于半球面的那部分算作区域内部,如果想算超过180的大面积,请求反操作。
下面是主要方法:
/** * * @param latitue 待测点的纬度 * @param longitude 待测点的经度 * @param areaLatitude1 纬度范围限制1 * @param areaLatitude2 纬度范围限制2 * @param areaLongitude1 经度限制范围1 * @param areaLongitude2 经度范围限制2 * @return */ public static boolean isInArea(double latitue,double longitude,double areaLatitude1,double areaLatitude2,double areaLongitude1,double areaLongitude2){ if(isInRange(latitue, areaLatitude1, areaLatitude2)){//如果在纬度的范围内 if(areaLongitude1*areaLongitude2>0){//如果都在东半球或者都在西半球 if(isInRange(longitude, areaLongitude1, areaLongitude2)){ return true; }else { return false; } }else {//如果一个在东半球,一个在西半球 if(Math.abs(areaLongitude1)+Math.abs(areaLongitude2)<180){//如果跨越0度经线在半圆的范围内 if(isInRange(longitude, areaLongitude1, areaLongitude2)){ return true; }else { return false; } }else{//如果跨越180度经线在半圆范围内 double left = Math.max(areaLongitude1, areaLongitude2);//东半球的经度范围left-180 double right = Math.min(areaLongitude1, areaLongitude2);//西半球的经度范围right-(-180) if(isInRange(longitude, left, 180)||isInRange(longitude, 0, right)){ return true; }else { return false; } } } }else{ return false; } } public static boolean isInRange(double point, double left,double right){ if(point>=Math.min(left, right)&&point<=Math.max(left, right)){ return true; }else { return false; } }
</pre><pre name="code" class="java">public static void main(String[] args) { // TODO Auto-generated method stub double myLatitude = 36.0;//待测点的纬度 double myLongitude = 120;//待测点的经度 //下面是经纬度的范围 double minLatitude = -60; double maxLatitude = 40.0; double minLongitude = 140; double maxLongitude = 100; if(isInArea(myLatitude, myLongitude, minLatitude, maxLatitude, minLongitude, maxLongitude)){ System.out.println("在范围内"); }else{ System.out.println("不在范围内"); } }
如果使用地图sdk的话会有更简单的方法
以谷歌地图为例,首先生成一个限制对象,然后用这个限制对象测点就行了,如下
final LatLngBounds boundary = new LatLngBounds(new LatLng(minlatitude, minlongitude), new LatLng(maxlatitude, maxlongitude)); boundary.including(new LatLng(36.0,120.0));
下面给出一个很实用的方法:给出一个经纬度点,然后给出一个距离和方向,求出这个点根据这个距离和方向算出的另一个点
//地理常量 private final static double EARTH_RADIUS = 6378138.0; private final static double PI = 3.14159265; private final static double Rc = 6378137; // 赤道半径 private final static double Rj = 6356725; // 极半径 // The shared path to all app expansion files private final static String EXP_PATH = "/Android/obb/"; static double DEF_PI = 3.14159265359; // PI static double DEF_2PI = 6.28318530712; // 2*PI static double DEF_PI180 = 0.01745329252; // PI/180.0 static double DEF_R = 6370693.5; // radius of earth
public static String[] getGPSLocation(double latitude, double longitude, double distance, double angle) { String[] result = {"0.0", "0.0"}; double m_Latitude; double m_RadLo, m_RadLa; double Ec; double Ed; m_Latitude = latitude; m_RadLo = longitude * PI / 180.0; m_RadLa = latitude * PI / 180.0; Ec = Rj + (Rc - Rj) * (90.0 - m_Latitude) / 90.0; Ed = Ec * Math.cos(m_RadLa); double dx = distance * 1000 * Math.sin(angle * PI / 180.0); double dy = distance * 1000 * Math.cos(angle * PI / 180.0); double BJD = (dx / Ed + m_RadLo) * 180.0 / PI; double BWD = (dy / Ec + m_RadLa) * 180.0 / PI; result[0] = BWD + ""; result[1] = BJD + ""; return result; }
下面是再提供几个比较实用的方法:根据经纬度计算两点间距离
public static double getGPSDistance(double lat_a, double lng_a, double lat_b, double lng_b) { final double M_PI = 3.14159265358979323846264338327950288; final double dd = M_PI / 180.0; double lon2 = lng_b; double lat2 = lat_b; double x1 = lat_a * dd, x2 = lat2 * dd; double y1 = lng_a * dd, y2 = lon2 * dd; double distance = (2 * EARTH_RADIUS * Math.asin(Math.sqrt(2 - 2 * Math.cos(x1) * Math.cos(x2) * Math.cos(y1 - y2) - 2 * Math.sin(x1) * Math.sin(x2)) / 2)); return distance; } //适用于近距离 public static double GetShortDistance(double lon1, double lat1, double lon2, double lat2) { double ew1, ns1, ew2, ns2; double dx, dy, dew; double distance; // 角度转换为弧度 ew1 = lon1 * DEF_PI180; ns1 = lat1 * DEF_PI180; ew2 = lon2 * DEF_PI180; ns2 = lat2 * DEF_PI180; // 经度差 dew = ew1 - ew2; // 若跨东经和西经180 度,进行调整 if (dew > DEF_PI) dew = DEF_2PI - dew; else if (dew < -DEF_PI) dew = DEF_2PI + dew; dx = DEF_R * Math.cos(ns1) * dew; // 东西方向长度(在纬度圈上的投影长度) dy = DEF_R * (ns1 - ns2); // 南北方向长度(在经度圈上的投影长度) // 勾股定理求斜边长 distance = Math.sqrt(dx * dx + dy * dy); return distance; } //适用于远距离 public static double GetLongDistance(double lon1, double lat1, double lon2, double lat2) { double ew1, ns1, ew2, ns2; double distance; // 角度转换为弧度 ew1 = lon1 * DEF_PI180; ns1 = lat1 * DEF_PI180; ew2 = lon2 * DEF_PI180; ns2 = lat2 * DEF_PI180; // 求大圆劣弧与球心所夹的角(弧度) distance = Math.sin(ns1) * Math.sin(ns2) + Math.cos(ns1) * Math.cos(ns2) * Math.cos(ew1 - ew2); // 调整到[-1..1]范围内,避免溢出 if (distance > 1.0) distance = 1.0; else if (distance < -1.0) distance = -1.0; // 求大圆劣弧长度 distance = DEF_R * Math.acos(distance); return distance; } /** * Unit:M */ public static String getGPSDistance(String lat_a, String lng_a, String lat_b, String lng_b) { double d_lat_a = 0.0; try { d_lat_a = Double.parseDouble(lat_a); } catch (Exception ex) { ex.printStackTrace(); } double d_lng_a = 0.0; try { d_lng_a = Double.parseDouble(lng_a); } catch (Exception ex) { ex.printStackTrace(); } double d_lat_b = 0.0; try { d_lat_b = Double.parseDouble(lat_b); } catch (Exception ex) { ex.printStackTrace(); } double d_lng_b = 0.0; try { d_lng_b = Double.parseDouble(lng_b); } catch (Exception ex) { ex.printStackTrace(); } return getGPSDistance(d_lat_a, d_lng_a, d_lat_b, d_lng_b) + ""; }