地图坐标换算


总结的一些地图坐标计算方法,包括:
  • 地球坐标、百度坐标、火星坐标相互转换
  • 两点坐标距离计算
  • 根据坐标及半径求坐标范围(附近的XXX功能)
package com.thon.commons.utils;

import java.text.DecimalFormat;

/**
 * @ClassName: MapUtil
 * @author: SuperZemo
 * @email: chenzeming@lanbaoo.com
 * @Date 10/21/14 14:21
 * @Description 地图工具类
 * 参考文档:
 * https://github.com/googollee/eviltransform/blob/master/c/transform.c
 * http://www.cnblogs.com/kelite/p/3549390.html
 * http://my.oschina.net/lcdmusic/blog/343505
 * http://tech.meituan.com/lucene-distance.html
 */
public class MapUtil {
    private static final double PI = 3.14159265358979324;       //圆周率
    private static final double R = 6378245.0;                  //地球半径 单位:米
    private static final double ee = 0.00669342162296594323;
    private final static DecimalFormat DOUBLE_FORMAT = new DecimalFormat("#.000000");
    private final static double DEFAULT_LNG = 116.390471;// 默认经度
    private final static double DEFAULT_LAT = 39.861012;// 默认纬度
    private double mgLat;
    private double mgLon;

    /**
     * WGS-84 to GCJ-02
     * 地球坐标转换火星坐标
     *
     * @param wgLat wgs84坐标纬度
     * @param wgLon wgs84坐标精度
     */
    public void wgs2gcj(double wgLat, double wgLon) {
        if (outOfChina(wgLat, wgLon)) {
            this.mgLat = wgLat;
            this.mgLon = wgLon;
            return;
        }
        double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
        double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
        double radLat = toRadians(wgLat);
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((R * (1 - ee)) / (magic * sqrtMagic) * PI);
        dLon = (dLon * 180.0) / (R / sqrtMagic * Math.cos(radLat) * PI);
        this.mgLat = wgLat + dLat;
        this.mgLon = wgLon + dLon;
    }

    /**
     * GCJ-02 to WGS-84
     * 火星坐标转换地球坐标
     *
     * @param gcjLat
     * @param gcjLng
     */
    public void gcj2wgs(double gcjLat, double gcjLng) {

        if (outOfChina(gcjLat, gcjLng)) {
            this.mgLat = gcjLat;
            this.mgLon = gcjLng;
            return;
        }
        double dLat = transformLat(gcjLng - 105.0, gcjLat - 35.0);
        double dLon = transformLon(gcjLng - 105.0, gcjLat - 35.0);
        double radLat = toRadians(gcjLat);
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((R * (1 - ee)) / (magic * sqrtMagic) * PI);
        dLon = (dLon * 180.0) / (R / sqrtMagic * Math.cos(radLat) * PI);
        this.mgLat = gcjLat - dLat;
        this.mgLon = gcjLng - dLon;
    }

    /**
     * DB-09 To GCJ-02
     * 百度坐标转换火星坐标
     *
     * @param bdLat 百度坐标纬度
     * @param bdLon 百度坐标精度
     */
    public void db2gcj(double bdLat, double bdLon) {
        if (outOfChina(bdLat, bdLon)) {
            this.mgLat = bdLat;
            this.mgLon = bdLon;
            return;
        }
        double x = bdLon - 0.0065, y = bdLat - 0.006;
        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * PI * 3000.0 / 180.0);
        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * PI * 3000.0 / 180.0);
        this.mgLon = z * Math.cos(theta);
        this.mgLat = z * Math.sin(theta);
    }

    /**
     * GCJ-02 To DB-09
     * 火星坐标转换百度坐标
     *
     * @param bdLat 百度坐标纬度
     * @param bdLon 百度坐标精度
     */
    public void gcj2db(double bdLat, double bdLon) {
        if (outOfChina(bdLat, bdLon)) {
            this.mgLat = bdLat;
            this.mgLon = bdLon;
            return;
        }
        double x = bdLon, y = bdLat;
        double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * PI * 3000.0 / 180.0);
        double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * PI * 3000.0 / 180.0);
        this.mgLon = z * Math.cos(theta) + 0.0065;
        this.mgLat = z * Math.sin(theta) + 0.006;
    }


    static boolean outOfChina(double lat, double lon) {
        if (lon < 72.004 || lon > 137.8347)
            return true;
        if (lat < 0.8293 || lat > 55.8271)
            return true;
        return false;
    }

    static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 获取坐标距离(米)
     *
     * @param lng1 起始经度
     * @param lat1 起始纬度
     * @param lng2 目地地经度
     * @param lat2 目的地纬度
     * @return
     */
    public static int getDistance(double lng1, double lat1, double lng2, double lat2) {
        /*double x, y, distance;
        x = (lon2 - lon1) * PI * R * Math.cos(((lat1 + lat2) / 2) * PI / 180) / 180;
        y = (lat2 - lat1) * PI * R / 180;
        distance = Math.hypot(x, y);
        return (int) (distance + 0.5);*/
        double dx = lng1 - lng2; // 经度差值
        double dy = lat1 - lat2; // 纬度差值
        double b = (lat1 + lat2) / 2.0; // 平均纬度
        double Lx = toRadians(dx) * R * Math.cos(toRadians(b)); // 东西距离
        double Ly = R * toRadians(dy); // 南北距离
        return (int) Math.sqrt(Lx * Lx + Ly * Ly);
    }

    public static double toRadians(double x) {
        return x * PI / 180;
    }

    /**
     * 将String经度转换成Double
     *
     * @param lon
     * @return
     */
    public static double getLongitude(String lon) {
        if (StringUtils.isBlank(lon)) {
            return DEFAULT_LNG;
        }
        if (lon.length() > 10) {
            lon = lon.substring(0, 10);
        }
        return StringUtils.toDouble(lon);
    }

    /**
     * 将String纬度转换成Double
     *
     * @param lat
     * @return
     */
    public static double getLatitude(String lat) {
        if (StringUtils.isBlank(lat)) {
            return DEFAULT_LAT;
        }
        if (lat.length() > 10) {
            lat = lat.substring(0, 10);
        }
        return StringUtils.toDouble(lat);
    }

    /**
     * 根据距离返回,经纬度范围 返回顺序 minLat,minLng,maxLat,maxLng
     *
     * @param lat
     * @param lon
     * @param raidus 距离(半径)单位:米
     * @return
     */
    public static double[] getAround(double lat, double lon, int raidus) {

        try {
            Double latitude = lat;
            Double longitude = lon;

            Double degree = (24901 * 1609) / 360.0; // 赤道周长24901英里 1609是转换成米的系数

            Double dpmLat = 1 / degree;
            Double radiusLat = dpmLat * raidus;
            Double minLat = latitude - radiusLat;
            Double maxLat = latitude + radiusLat;

            Double mpdLng = degree * Math.cos(toRadians(latitude));
            Double dpmLng = 1 / mpdLng;
            Double radiusLng = dpmLng * raidus;
            Double minLng = longitude - radiusLng;
            Double maxLng = longitude + radiusLng;

            // 格式化
            minLat = Double.parseDouble(DOUBLE_FORMAT.format(minLat));
            minLng = Double.parseDouble(DOUBLE_FORMAT.format(minLng));
            maxLat = Double.parseDouble(DOUBLE_FORMAT.format(maxLat));
            maxLng = Double.parseDouble(DOUBLE_FORMAT.format(maxLng));

            return new double[]{minLat, minLng, maxLat, maxLng};
        } catch (NumberFormatException e) {
        }
        return null;
    }

    /**
     * 判断是否超出规定距离范围
     *
     * @param lon1 起始经度
     * @param lat1 起始纬度
     * @param lon2 目地地经度
     * @param lat2 目的地纬度
     * @param lat2 目的地纬度
     * @return
     */
    public static boolean isOutOfRange(double lon1, double lat1, double lon2, double lat2, double raidus) {
        int distance = getDistance(lon1, lat1, lon2, lat2);
        if (distance > raidus) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    void delta(double lat, double lng) {

    }

    public double getMgLat() {
        return mgLat;
    }

    public double getMgLon() {
        return mgLon;
    }

    public static void main(String[] args) {
        double lat1 = 30.67521931451247;
        double lat2 = 30.681872;
        double lng1 = 104.0970145349406;
        double lng2 = 104.104885;

        System.out.println(getDistance(lng1, lat1, lng2, lat2));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GPSTool4.0(GPS工具箱) 操作说明 一、 总体介绍 本软件为GPS坐标转换工具(并具有线路设计的功能),程序分为标题栏(程序名称及版本号)、状态栏(输入提示及当前时间)、信息栏(提示打开及新建的工程名)、操作面板(转换操作输入),程序总体分为三大功能:单点转换、文件转换、线路设计。 无论做哪种操作,首先要新建项目,保存项目数据,详细的数据格式如下: [Version Information] Version=May 12 2006 [TouYin Par] nsCoord=2        ;源椭球 nCoord=2 ;目标椭球 nTouYin=0 ;投影类型 nDifang=0 ;是否使用四参数 nSevenPar=0 ;是否使用七参数 szdDa=6378137.0000000000 ;目标椭球长半轴 szdDf=298.2572235630   ;目标椭球扁率 szdDa1=6378137.0000000000;源椭求长半轴 szdDf1=298.2572235630 ;源椭球扁率 szdCenter=108.00000000 szlTx=0.000 szlTy=500000.000 szdTk=1.00000000 szdHigh=0.00000000 szdTlon=0.00000000 szdCenter1=114.0 szlTx1=0.000 szlTy1=500000.000 szdTk1=1.00000000 szdHigh1=0.00000000 szdTlon1=0.00000000 [Seven Par] szddx=0.000000000000 szddy=0.000000000000 szddz=0.000000000000 szdWx=0.000000000000 szdWy=0.000000000000 szdWz=0.000000000000 szddK=0.00000000000000000000 [Four Par] szdCx1=0.000000000000 szdCy1=0.000000000000 szdCa1=0.000000000000 szdCk1=0.000000000000 szdCx2=0.000000000000 szdCy2=0.000000000000 szdCa2=0.000000000000 szdCk2=0.000000000000 [Base Coordinate] szdBaseX=2558700.60750000 szdBaseY=435101.83010000 szdBaseH=45.00000000 nBLH=0 nRadioFormat=0 szdBaseAntH=1.20000000 nRadioRate=1 nUseCorr=0 szdCorrX=0.000000000000 szdCorrY=0.000000000000 szdCorrH=0.000000000000 [Nihe Par] nUseNihe=0 szA0=-2.500000000000 szA1=0.000000000000 szA2=0.000000000000 szA3=0.000000000000 szA4=0.000000000000 szA5=0.000000000000 szX0=100.000000000000 szY0=100.000000000000 [Job Par] Ellipsoid=2,2 ;源椭球,目标椭球 AngleType=0 ;角度类型 ConvertType=1 ;转换类型,是否是换带计算 DataType=0,2 ;数据类型 Change=0,114.00000000,114.00000000 ;转换前与转换后的中央子午线 SourcePoint=-1690039.93800000,5555519.86900000,2631658.92700000  ;源数据 TargetPoint=2713845.99600000,390578.41800000,917.25700000 ;目录数据 SourceFilename=6,D:\Documents and Settings\southgps\桌面\22.txt ;源格式,文件名 TargetFilename=1,D:\Documents and Settings\southgps\桌面\888.dat    ;目标,文件名 OutputFormat=0 OutputTitle=GpsTool 工具软件坐标转换成果表 最小化程序时,系统隐藏,双击任务栏图标即可最大化。 二、 单点转换 1、 新建工程中或打开工程 2、 选择源椭球与目标椭球,可以选择相同的椭球。 3、 选择投影方式 4、 选择源数据类型与目标数据类型。 共有三种数据格式:空间格式、大地格式、投影格式 5、 输入起算数据,进行数据格式转换 三、 文件转换      起始设置同单点转换的前四项,除此以外还有: 1、 新建格式 输入数据格式名称,文件扩展名,文件格式描述,数据分隔符等,      可以选择的数据项有:点名、纬度、经度、椭球高、北方向X、东方向Y、水准高、空间X、空间Y、空间Z、其它。       选择添加按钮添加数据项,删除最后数据项,清除所有数据项,添加完毕后完成创建,如果继续新建格式,选择新建格式。 2、 文件选择 从列表框中选择格式,并确认选择,在此框中可以删除格式与编辑格式,编辑格式对话框如下: 文件选择: 选择完数据文件名及数据格式后,开始转换,如果因为数据格式转换不成功,请查看数据格式是否正确,请确认源转换类型与目标转换类型与数据格式中的数据项相匹配。 如果查看数据内容请按 >> 四、 线路设计 1、元素模式 1、 新建或打开线路文件 2、 输入起始桩号。 3、 对线路进行添加元素,起点必须以点元素开始,直线相接,除点和直线外,线路中还可包括圆曲、缓曲。 4、 对线路进行保存并计算,查看线路图形。 5、 根据选择整桩距或整桩号生成中桩坐标文件:线路同名.dat文件,除此以外还可以通过COGO模拟线路的投影桩号及偏线距。 2、交点模式 图形输出如元素模式。 1、 建或打开线路文件 2、 输入起始桩号。 3、 对线路进行添加交点元素,左、右缓曲长可以相同,可以不同,当然也可以为零。  4、 对线路进行保存并计算,查看线路图形。 5、 根据选择整桩距或整桩号生成中桩坐标文件:线路同名.dat文件,除此以外还可以通过COGO模拟线路的投影桩号及偏线距。 五、 其它功能  1、 换带计算  输入换带后的投影参数,主要是换带后的中央子午线经度,此时计算为投影坐标到投影坐标的计算,主要是先由投影坐标到大地坐标,再由新的投影参数投到换带后的投影坐标。 2、参数计算:四参数计算、七参数计算、拟合参数计算 提供简单的参数计算功能。 四参数主要应用于地方坐标转换。 七参数主要应用于椭球之间的变换。本程序为避开投影,与国外软件相同只使用大地坐标进行变换参数。 拟合参数计算主要应用于根据大地高及相关联的水准高计算曲面拟合参数,基中包括两个辅助参数,X中数和Y中数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值