geo-经纬度计算

Posted bronk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了geo-经纬度计算相关的知识,希望对你有一定的参考价值。

经纬度计算, 本质上是球面三角函数的应用, 将数学公式转换为代码的过程, 

站在前人的肩膀上, 自己又补充了一点: 

package com.iwhere.easy.travel.tool;

public class GeoTools {
    
    public static String getScopeByGeoLevel(Integer geolevel) {
        return ((16 - geolevel) * 5) + "公里";
    }

    public static double getAngle(double lat1, double lng1, double lat2, double lng2) {
        double x1 = lng1;
        double y1 = lat1;
        double x2 = lng2;
        double y2 = lat2;
        double pi = Math.PI;
        double w1 = y1 / 180 * pi;
        double j1 = x1 / 180 * pi;
        double w2 = y2 / 180 * pi;
        double j2 = x2 / 180 * pi;
        double ret;
        if (j1 == j2) {
            if (w1 > w2)
                return 270; // 北半球的情况,南半球忽略
            else if (w1 < w2)
                return 90;
            else
                return -1;// 位置完全相同
        }
        ret = 4 * Math.pow(Math.sin((w1 - w2) / 2), 2)
                - Math.pow(Math.sin((j1 - j2) / 2) * (Math.cos(w1) - Math.cos(w2)), 2);
        ret = Math.sqrt(ret);
        double temp = (Math.sin(Math.abs(j1 - j2) / 2) * (Math.cos(w1) + Math.cos(w2)));
        ret = ret / temp;
        ret = Math.atan(ret) / pi * 180;
        if (j1 > j2) { // 1为参考点坐标
            if (w1 > w2)
                ret += 180;
            else
                ret = 180 - ret;
        } else if (w1 > w2)
            ret = 360 - ret;
        return ret;
    }

    /**
     * @param lat1
     *            纬度1,参考点
     * @param lng1
     *            经度1,参考点
     * @param lat2
     *            纬度2
     * @param lng2
     *            经度2
     * @return 方向
     */
    public static String getDirection(double lat1, double lng1, double lat2, double lng2) {
        double jiaodu = getAngle(lat1, lng1, lat2, lng2);
        if ((jiaodu <= 10) || (jiaodu > 350))
            return "正东方";
        if ((jiaodu > 10) && (jiaodu <= 80))
            return "东北方";
        if ((jiaodu > 80) && (jiaodu <= 100))
            return "正北方";
        if ((jiaodu > 100) && (jiaodu <= 170))
            return "西北方";
        if ((jiaodu > 170) && (jiaodu <= 190))
            return "正西方";
        if ((jiaodu > 190) && (jiaodu <= 260))
            return "西南方";
        if ((jiaodu > 260) && (jiaodu <= 280))
            return "正南方";
        if ((jiaodu > 280) && (jiaodu <= 350))
            return "东南方";
        return "";
    }

    /**
     * 获取方位角描述
     * 前一个点
     * 参照点
     * 目标点
     * @author wenbronk
     */
    public static String getAzimuth(double preLng, double preLat, double referLng, double referLat, double poiLng,
            double poiLat) {
        double jiaodu1 = getAngle(preLat, preLng, referLat, referLng);
        double jiaodu2 = getAngle(referLat, referLng, poiLat, poiLng);
        double jiaodu = jiaodu2 - jiaodu1;
        if (((jiaodu <=10 && jiaodu > 0) || jiaodu > 350) || ((jiaodu >= -10 && jiaodu < 0) || jiaodu < -350)) {
            return "正前方";
        }else if ((jiaodu <= 80 && jiaodu > 10) || (jiaodu >= -350 && jiaodu < -280)) {
            return "左前方";
        }else if ((jiaodu <= 100 && jiaodu > 80) || (jiaodu >= -280 && jiaodu < -260)) {
            return "左侧";
        }else if ((jiaodu <= 170 && jiaodu > 100) || (jiaodu >= -260 && jiaodu < -190)) {
            return "左后方";
        }else if ((jiaodu <= 190 && jiaodu > 170) || (jiaodu >= -190 && jiaodu < -170)) {
            return "后方";
        }else if ((jiaodu <=260 && jiaodu > 190) || (jiaodu >= -170 && jiaodu < -100)) {
            return "右后方";
        }else if ((jiaodu <=280 && jiaodu > 260) || (jiaodu >= -100 && jiaodu < -80)) {
            return "右侧";
        }else if ((jiaodu <= 350 && jiaodu > 280) || (jiaodu >= -80 && jiaodu < -10)) {
            return "右前方";
        }
        return "";
    }
    
    /**
     * 判断是否在后方
     * @author wenbronk
     */
    public static Boolean isBehine(double preLng, double preLat, double referLng, double referLat, 
            double poiLng, double poiLat) {
        double x1 = referLng - preLng;
        double y1 = referLat - preLat;
        double x2 = poiLng - referLng;
        double y2 = poiLat - referLat;
        
        // 求 (x1, y1), (x2, y2) 向量的夹角的cos值
        double cos = (x1 * x2 + y1 * y2) / 
                (Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2)) + Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2)));
        if (cos >= 0) {
            return false;
        }
        return true;
    }
    
    public static void main(String[] args) {
        String str = getDirection(0, 0, -40, -34);
        System.out.println(str);
    }
}

 

以上是关于geo-经纬度计算的主要内容,如果未能解决你的问题,请参考以下文章

redis发布订阅HyperLogLog与GEO功能的介绍

计算指定区域的经纬度范围

如何加快 WordPress 中的 GEO 搜索

redis --- GEO类型使用

Day739.GEO经纬度数据结构&自定义数据结构 -Redis 核心技术与实战

(译)计算距离方位和更多经纬度之间的点