Java实现经纬度坐标转换的示例代码
目录
- 一、坐标系统简介
- 1、经纬度坐标系
- 2、坐标系统
- 3、坐标转换简介
- 二、地图经纬度转换工具类
- 三、方法补充
一、坐标系统简介
坐标系统,是描述物质存在的空间位置(坐标)的参照系,通过定义特定基准及其参数形式来实现。
坐标是描述位置的一组数值,按坐标的维度一般分为一维坐标(公路里程碑)和二维坐标(笛卡尔平面直角坐标、高斯平面直角坐标)、三维坐标(大地坐标、空间直角坐标)。
为了描述或确定位置,必须建立坐标系统,坐标只有存在于某个坐标系统才有实际的意义与具体的位置。
地球是一个球体,球面上的位置,是以经纬度来表示,它称为“球面坐标系统”或“地理坐标系统”。
在球面上计算角度距离十分麻烦,而且地图是印刷在平面纸张上,要将球面上的物体画到纸上,就必须展平,这种将球面转化为平面的过程,称为“投影”。1、经纬度坐标系
经纬度坐标系是一种地理坐标系统,用于描述地球表面上任意位置的坐标。它是基于地球的自转和赤道的划分而建立的。
- 经度(Longitude):表示地球表面上一个点相对于本初子午线的东西方向的位置。经度的度量单位是度(°),范围从0°到180°,以东经为正值,西经为负值。本初子午线位于英国伦敦的皇家格林尼治天文台,它被定义为经度0°。
- 纬度(Latitude):表示地球表面上一个点相对于赤道的北南方向的位置。纬度的度量单位也是度(°),范围从0°到90°,以北纬为正值,南纬为负值。赤道位于纬度0°。
经纬度坐标系统是全球通用的地理坐标系统。
经纬度坐标系统使用经度和纬度的组合来确定地球表面上的特定位置。一个点的经纬度坐标表示为两个数值的组合,例如:40°N,120°E 表示北纬40度,东经120度的位置。
2、坐标系统
(1)WGS84(World Geodetic System 1984,GPS标准)
- 定义:WWGS84,全称“世界大地坐标系统1984”,是一个国际广泛接受的地心地固坐标系统,也是全球定位系统(GPS)的标准坐标系。WGS84是基于地球椭球体模型,提供全球统一的地理坐标框架,是开放和透明的,适用于全球范围内的导航、定位和地图制作。
- 历史:经历了多次精化,包括WGS84(G730)、WGS84(G873)和WGS84(G1150)。
- 参数:长半轴为6378137.0米,扁率为1/298.257223563。
- 应用场景:全球范围内的GPS定位、地图绘制等。
(2)GCJ-02(国测局坐标系,也被称为火星坐标系)
- 定义:GCJ-02,全称“中国国测局坐标系统”,也称为“火星坐标”或“火星加密算法”。它是中国国家测绘局制定的一种地理坐标系,用于对中国大陆的地理位置进行偏移加密处理。
- 特点:它是中国政府为了安全而对公开的WGS84坐标数据进行了加密处理,使得在未授权的情况下难以直接使用全球定位系统(GPS)获得精确的位置信息。相对于WGS84坐标系进行了加密处理,用于保护安全。
- 应用场景:在国内的地图服务、导航系统、地理信息系统等应用中得到广泛使用,例如高德地图、腾讯地图等。手机上的地图导航软件利用GCJ-02坐标系实现了高精度的定位和导航功能。
(3)BD-09(Baidu Coordinate System)
- 定义:BD-09是百度地图使用的一种坐标系。
- BD-09是百度地图使用的坐标系统,它是在GCJ-02的基础上进行的二次加密。
- 特点:由于百度地图在中国提供服务,它需要遵守GCJ-02的加密规则,但为了增强定位精度和防止第三方直接解密GCJ-02坐标,百度在其服务中采用了更复杂的加密算法。即基于GCJ-02坐标系进行了加密偏移,提供了更好的数据保护性能。因此,从WGS84到BD-09,需要经过两次转换,先由WGS84转为GCJ-02,然后再转为BD-09。
- 应用场景:主要用于中国境内各种位置服务应用,如百度地图的定位和导航服务。
(4)CGCS2000(中国2000国家大地坐标系)
- 定义:CGCS2000,全称“2000国家大地坐标系统”,是中国最新的地心地固坐标系统,替代了之前的北京54和西安80坐标系。以ITRF 97为参考框架,以2000.0作为参考历元。
- 特点:原点设定在地球的质量中心,Z轴指向IERS参考极,X轴和Y轴通过右手规则确定。
- CGCS2000基于地球椭球体模型,与国际标准兼容,尤其与北斗卫星导航系统配合使用时,提供高精度的定位服务。它是中国自主的全球定位系统,与WGS84类似,但更适合中国的地理特性。
- 与WGS84的关系:在定义上与WGS84非常相似,包括原点、尺度和定向。但在扁率上的差异会导致椭球面上的纬度和高度产生微小的变化。
- 应用场景:作为国家基础坐标系,用于各种测绘和地理信息系统工作。
3、坐标转换简介
在地图应用中,不同的地图服务商通常使用不同的坐标系,坐标转换就是将一个地图服务商的坐标系转换为另一个地图服务商的坐标系,以便在不同的地图上显示相同的位置信息。
GPS(谷歌地图)|高德|百度地图对坐标系统的使用:
- WGS84:地理坐标系统,GPS仪器记录的经纬度信息。Google Earth采用,Google Map中国范围外使用,高德地图中国范围外使用。
- GCJ-02:投影坐标系统,火星坐标系,中国国家测绘局制定的坐标系统,由 WGS-84加密后的坐标。适用于高德地图。
- BD-09:投影坐标系统,百度坐标系,GCJ-02加密后的坐标系,只适用于百度地图。
- CS2000:中国2000国家大地坐标系统,与WG-S84类似,只适用于北斗卫星。
注意:
- WGS84、GCJ-02和BD-09之间通过转换算法或者API可以实现互转。
- GCS2000与GCJ-02和BD-09之间没有直接的转换关系,通常需要将 GCS2000转换为 WGS84,然后通过这个中间坐标系(WGS84)来进行间接转换。
- 在国内是不允许直接用 WGS84坐标系标注经纬度的,必须经过加密后才能用。所以必须至少使用 GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的 BD-09坐标系。
不同地图服务商有提供其丰富的 API文档功能,包括经纬度坐标转换功能。有的地图服务商API需要收费。
二、地图经纬度转换工具类
对于 CGCS2000 需要引入 proj4j依赖:
<dependency> <groupId>org.locationtech.proj4j</groupId> <artifactId>proj4j</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.locationtech.proj4j</groupId> <artifactId>proj4j-epsg</artifactId> <version>1.3.0</version> </dependency>
/** * 坐标转换工具类 * <p> * 参考文章-实现的Java版本:https://github.com/wandergis/coordtransform */ @Slf4j public class CoordinateTransformUtil { static double x_pi = 3.14159265358979324 * 3000.0 / 180.0; // static double pi = 3.1415926535897932384626; // 长半轴 static double a = 6378245.0; // 扁率 static double ee = 0.00669342162296594323; /** * WGS84 转 GCJ-02 * * @param lng WGS84经度 * @param lat WGS84纬度 * @return */ public static Coordinate wgs84ToGcj02(double lng, double lat) { if (outOfChina(lng, lat)) { return new Coordinate(lng, lat); } double dlat = transformlat(lng - 105.0, lat - 35.0); double dlng = transformlng(lng - 105.0, lat - 35.0); double radlat = lat / 180.0 * pi; double magic = Math.sin(radlat); magic = 1 - ee * magic * magic; double sqrtmagic = Math.sqrt(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi); dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi); double mgLat = lat + dlat; double mgLng = lng + dlng; return new Coordinate(mgLng, mgLat); } /** * GCJ-02 转 WGS84 * * @param lng GCJ-02经度 * @param lat GCJ-02纬度 * @return */ public static Coordinate gcj02ToWgs84(double lng, double lat) { if (outOfChina(lng, lat)) { return new Coordinate(lng, lat); } double dlat = transformlat(lng - 105.0, lat - 35.0); double dlng = transformlng(lng - 105.0, lat - 35.0); double radlat = lat / 180.0 * pi; double magic = Math.sin(radlat); magic = 1 - ee * magic * magic; double sqrtmagic = Math.sqrt(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi); dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi); double mgLat = lat + dlat; double mgLng = lng + dlng; return new Coordinate(lng * 2 - mgLng, lat * 2 - mgLat); } /** * GCJ-02 转 BD-09 * * @param lng GCJ-02经度 * @param lat GCJ-02纬度 * @return */ public static Coordinate gcj02ToBd09(double lng, double lat) { double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_pi); double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi); double bd_lng = z * Math.cos(theta) + 0.0065; double bd_lat = z * Math.sin(theta) + 0.006; return new Coordinate(bd_lng, bd_lat); } /** * BD-09 转 GCJ-02 * * @param lng BD-09经度 * @param lat BD-09纬度 */ public static Coordinate bd09ToGcj02(double lng, double lat) { double x = lng - 0.0065; double y = lat - 0.006; double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi); double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi); double gg_lng = z * Math.cos(theta); double gg_lat = z * Math.sin(theta); return new Coordinate(gg_lng, gg_lat); } /** * BD-09 转 WGS84 * * @param lng BD-09经度 * @param lat BD-09纬度 * @return */ public static Coordinate bd09ToWgs84(double lng, double lat) { Coordinate gcj02 = bd09ToGcj02(lng, lat); Coordinate wgs84 = gcj02ToWgs84(gcj02.longitude, gcj02.latitude); return wgs84; } /** * WGS84 转 BD-09 * * @param lng WGS84经度 * @param lat WGS84纬度 * @return */ public static Coordinate wgs84ToBd09(double lng, double lat) { Coordinate gcj02 = wgs84ToGcj02(lng, lat); Coordinate bd09 = gcj02ToBd09(gcj02.longitude, gcj02.latitude); return bd09; } /** * 纬度转换 * * @param lng * @param lat * @return */ public static double transformlat(double lng, double lat) { double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(lat * pi) + 40.0 * Math.sin(lat / 3.0 * pi)) * 2.0 / 3.0; ret += (160.0 * Math.sin(lat / 12.0 * pi) + 320 * Math.sin(lat * pi / 30.0)) * 2.0 / 3.0; return ret; } /** * 经度转换 * * @param lng * @param lat * @return */ public static double transformlng(double lng, double lat) { double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); ret += (20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(lng * pi) + 40.0 * Math.sin(lng / 3.0 * pi)) * 2.0 / 3.0; ret += (150.0 * Math.sin(lng / 12.0 * pi) + 300.0 * Math.sin(lng / 30.0 * pi)) * 2.0 / 3.0; return ret; } /** * 判断是否在国内,不在国内不做偏移 * * @param lng * @param lat * @return */ public static boolean outOfChina(double lng, double lat) { if (lng < 72.004 || lng > 137.8347) { return true; } else if (lat < 0.8293 || lat > 55.8271) { return true; } return false; } /** * 坐标类 */ @Data public static class Coordinate { /** * 经度 */ private double longitude; /** * 维度 */ private double latitude; public Coordinate(double longitude, double latitude) { // 保留6位小数,四舍五入模式 //BigDecimal latBigDecimal = new BigDecimal(latitude).setScale(6, RoundingMode.HALF_UP); //BigDecimal lonBigDecimal = new BigDecimal(longitude).setScale(6, RoundingMode.HALF_UP); //this.longitude = lonBigDecimal.doubleValue(); //this.latitude = latBigDecimal.doubleValue(); this.longitude = longitude; this.latitude = latitude; } } // 定义CGCS2000的坐标系 private final static String CGCS2000 = "EPSG:4490"; // 定义WGS84的坐标系 final static String WGS84 = "EPSG:4326"; /** * CGCS2000 转 WGS84 * * @param lng CGCS2000经度 * @param lat CGCS2000纬度 * @return */ public static Coordinate cgcs2000ToWgs84(double lng, double lat) { CRSFactory crsFactory = new CRSFactory(); // 创建CGCS2000的坐标参考系统 CoordinateReferenceSystem sourceCRS = crsFactory.createFromName(CGCS2000); // 创建WGS84的坐标参考系统 http://www.devze.com CoordinateReferenceSystem targetCRS = crsFactory.createFromName(WGS84); // 定义坐标转换器 CoordinateTransformFactory ctFactory = new CoordinateTransformFactory(); // 创建转换器 CoordinateTransform transform = ctFactory.createTransform(sourceCRS, targetCRS); // 执行坐标转换 ProjCoordinate srcCoord = new ProjCoordinate(lng, lat); ProjCoordinate targetCoord = new ProjCoordinate(); transform.transform(srcCoord, targetCoord); // 4. 输出转换后的正常经纬度坐标 return new Coordinate(targetCoord.x, targetCoord.y); } /** * WGS84 转 CGCS2000 * * @param lng WGS84经度 * @param lat WGS84纬度 * @return */ public static Coordinate wgs84ToCgcs2000(double lng, double lat) { CRSFactory crsFactory = new CRSFactory(); // 定义源和目标投影 CoordinateReferenceSystem sourceCRS = crsFactory.createFromName(WGS84); CoordinateReferenceSystem targetCRS = crsFactory.createFromName(CGCS2000); // 定义坐标转换器 CoordinateTransformFactory ctFactory = new CoordinateTransformFactory(); // 创建转换器 CoordinateTransform transform = ctFactory.createTransform(sourceCRS, targetCRS); // 执行坐标转换 ProjCoordinate srcCoord = new ProjCoordinate(lng, lat); ProjCoordinate targetCoord = new ProjCoordinate(); transform.transform(srcCoord, targetCoord); // 输出转换后的正常经纬度坐标 return new Coordinate(targetCoord.x, targetCoord.y); } public static void main(String[] args) { double GPSLon = 108.876152; double GPSLat = 34.226685; CoordinateTransformUtil.Coordinate wgs84ToGcj02 = CoordinateTransformUtil.wgs84ToGcj02(GPSLon, GPSLat); CoordinateTransformUtil.Coordinate wgs84ToBd09 = CoordinateTransformUtil.wgs84ToBd09(GPSLon, GPSLat); log.info("GPS wgs84ToGcj02 : longitude={}, latitude={}", wgs84ToGcj02.longitude, wgs84ToGcj02.latitude); log.info("GPS wgs84ToBd09 : longitude={}, latitude={}", wgs84ToBd09.longitude, wgs84ToBd09.latitude); double aMapLon2 = 108.880753; double aMapLat2 = 34.225075; CoordinateTransformUtil.Coordinate gcj02ToWgs84 = CoordinateTransformUtil.gcj02ToWgs84(aMapLon2, aMapLat2); CoordinateTransformUtil.Coordinate gcj02ToBd09 = CoordinateTransformUtil.gcj02ToBd09(aMapLon2, aMapLat2);http://www.devze.com log.info("高德 gcj02ToWgs84 : longitude={}, latitude={}", gcj02ToWgs84.longitude, gcj02ToWgs84.latitude); log.info("高德 gcj02ToBd09 : longitude={}, latitude={}", gcj02ToBd09.longitude, gcj02ToBd09.latitude); double baiduLon3 = 108.887314; double baiduLat3 = 34.230897; CoordinateTransformUtil.Coordinate bd09ToWgs84 = CoordinateTransformUtil.bd09ToWgs84(baiduLon3, baiduLat3); CoordinateTransformUtil.Coordinate bd09ToGcj02 = CoordinateTransformUtil.bd09ToGcj02(baiduLon3, baiduLat3); log.info("百度 gcj02ToWgs84 : longitude={}, latitude={}", bd09ToWgs84.longitude, bd09ToWgs84.latitude); log.info("百度 gcj02ToBd09 : longitude={}, latitude={}", bd09ToGcj02.longitude, bd09ToGcj02.latitude); /** * CGCS2000 */ double CGCS2000Lon4 = 108.887314; double CGCS2000Lat4 = 34.230897; CoordinateTransformUtil.Coordinate CGCS2000ToWgs84 = CoordinateTransformUtil.cgcs2000ToWgs84(CGCS2000Lon4, CGCS2000Lat4); CoordinateTransformUtil.Coordinate CGCS2000ToBd09 = CoordinateTransformUtil.wgs84ToCgcs2000(CGCS2000Lon4, CGCS2000Lat4); log.info("中国2000 CGCS2000ToWgs84 : longitude={}, latitude={}", CGCS2000ToWgs84.longitude, CGCS2000ToWgs84.latitude); log.info("中国2000 CGCS2000ToBd09 : longitude={}, latitude={}", CGCS2000ToBd09.longitude, CGCS2000ToBd09.latitude); } }
三、方法补充
Java实现WGS84、百度、腾讯、高德等主流的地理坐标转换
主要是WGS84(大地坐标系)、GCJ02(国测局坐标系,如高德地图、腾讯地图、谷歌中国范围地图)、BD09(百度坐标系)三种主流坐标系之间的转换。
注意:如果经纬度8位数字的需要进行转换:例如:69857065/600000=“116.428441” 即是真实的WGS84坐标
完整代码
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 常用地图转换工具类(各个地图API采用的坐标系(WGS84坐标系:即地球坐标系,国际上通用的坐标系。谷歌地图用此坐标)) * 百度地图API 百度坐标 (BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。) * 腾讯搜搜地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。) * 阿里云地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。) * 高德MapABC地图API 火星坐标 (GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。) */ public class MapUtils { public static final double r2d = 57.2957795131; public static final double PI = 3.1415926535897932384626433832795; public static final double rearth = 6371006.84; /** * wgs84坐标转上海城市坐标 * @param lat 维度 * @param lon 经度 * @return */ public static Map<String, Double> wgs84Tosh(Double lat, Double lon) { double tolat = (31 + (14.0 + 7.55996 / 60.0) / 60.0) / r2d; double tolon = (121.0 + (28.0 + 1.80651 / 60.0) / 60) / r2d; Double frlat = lat / r2d; Double frlon = lon / r2d; Double clatt = Math.cos(frlat); Double clatf = Math.cos(tolat); Double slatt = Math.sin(frlat); Double slatf = Math.sin(tolat); Double dlon = frlon - tolon; Double cdlon = Math.cos(dlon); Double sdlon = Math.sin(dlon); Double cdist = slatf * slatt + clatf * clatt * cdlon; Double temp = (clatt * sdlon) * (clatt * sdlon) + (clatf * slatt - slatf * clatt * cdlon) * (clatf * slatt - slatf * clatt * cdlon); Double sdist = Math.sqrt(Math.abs(temp)); Double gcdist = 0.0; if ((Math.abs(sdist) > 1e-7) || (Math.abs(cdist) > 1e-7)) gcdist = Math.atan2(sdist, cdist); Double sbrg = sdlon * clatt; Double cbrg = (clatf * slatt - slatf * clatt * cdlon); if ((Math.abs(sbrg) > 1e-7) || (Math.abs(cbrg) > 1e-7)) { temp = Math.atan2(sbrg, cbrg); while (temp < 0) { temp = temp + 2 * PI; } } Double hor = gcdist * rearth; Double xx = hor * Math.sin(temp); Double yy = hor * Math.cos(temp); Map<String,Double> model = new HashMap<String,Double>(); model.put("lat", xx); model.put("lon", yy); return model; } public static final Double m_pNorthMove = -3457000.0; public static final Double m_pSHa = 6378245.0; public static final double m_pSHf = 298.3; public static final double m_pWGS84a = 6371006.84; public static final double m_pWGS84f = 298.25722356300003; /** * 上海城市坐标转WGS84坐标 * @param East 经(东部) * @param North 纬(北部) * @param InH 内部高度(默认可以用 0.0) * @return */ public static Map<String, Double> ShToWGS84(Double East, Double North, Double InH) { North = North - m_pNorthMove; List<Double> a = AntiGaussProjectionConst(m_pSHa, m_pSHf, East, North); Double rB = a.get(0); Double rl = a.get(1); Double m_pCenterL = DMSToDegree(121.0, 28.0, 0.0); Double dL = RadianToDegree(rl) + m_pCenterL; Double tB = rB; Double tL = DegreeToRadian(dL); Double tH = InH; /* Double sB = 0.0; Double sL = 0.0; Double sH = 0.0;*/ ArrayList<Double> m_pPara = new ArrayList<Double>(); m_pPara.add(-39.208938); m_pPara.add(65.046547); m_pPara.add(49.410739); m_pPara.add(SecondToRadian(6.125483)); m_pPara.add(SecondToRadian(-1.281548)); m_pPara.add(SecondToRadian(-0.861599)); m_pPara.add(2.916036 * 1e-6); List<Double> b = LBH7ParameterSelf(tL, tB, tH, m_pSHa, 1.0 / m_pSHf, m_pPara.get(0), m_pPara.get(1), m_pPara.get(2), m_pPara.get(3), m_pPara.get(4), m_pPara.get(5), m_pPara.get(6), m_pWGS84a, 1.0 / m_pWGS84f); ArrayList<Double> a1 = RadianToDMS(b.get(0)); ArrayList<Double> a2 = RadianToDMS(b.get(1)); Double b1 = a1.get(0) + a1.get(1) / 60 + a1.get(2) / 3600; Double b2 = a2.get(0) + a2.get(1) / 60 + a2.get(2) / 3600; /*百度偏移*/ /*谷歌偏移*/ b1 = b1 + 0.000935; b2 = b2 + 0.002651; Map<String,Double> model = new HashMap<String,Double>(); model.put("lat", b1); model.put("lon", b2); return model; } /** * WGS-84转GCJ坐标 * @param wgsLat * @param wgsLon * @return */ public static Map<String, Double> gcj_encrypt(Double wgsLat, Double wgsLon) { Map<String,Double> model = new HashMap<String,Double>(); if (outOfChina(wgsLat, wgsLon)) { model.put("lat", wgsLat); model.put("lon", wgsLon); return model; } Map<String, Double> d = delta(wgsLat, wgsLon); model.put("lat", wgsLat + (Double) d.get("lat")); model.put("lon", wgsLon + (Double) d.get("lon")); return model; } /** * GCJ坐标转WGS-84坐标 * @param JqabAgcjLat * @param gcjLon * @return */ public static Map<String, Double> gcj_decrypt(Double gcjLat, Double gcjLon) { Map<String, Double> model = new HashMap<String, Double>(); if (outOfChina(gcjLat, gcjLon)) { model.put("lat", gcjLat); model.put("lon", gcjLon); return model; } Map<String, Double> d = delta(gcjLat, gcjLon); model.put("lat", gcjLat - (Double) d.get("lat")); model.put("lon", gcjLon - (Double) d.get("lon")); return model; } public static final double x_pi = PI * 3000.0 / 180.0; /** * GCJ-02坐标转百度BD-09坐标 * @param gcjLat * @param gcjLon * @return */ public static Map<String, Double> bd_encrypt(Double gcjLat, Double gcjLon) { Map<String, Double> model = new HashMap<String, Double>(); Double x = gcjLon, y = gcjLat; Double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi); Double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi); Double bdLon = z * Math.cos(theta) + 0.0065; Double bdLat = z * Math.sin(theta) + 0.006; model.put("lat", bdLat); model.put("lon", bdLon); return model; } /** * 百度BD-09坐标转GCJ-02坐标 * @param bdLat * @param bdLon * @return */ public static Map<String, Double> bd_decrypt(Double bdLat, Double bdLon) { Map<String, Double> model = new HashMap<String, Double>(); Double x = bdLon - 0.0065, y = bdLat - 0.006; Double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi); Double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi); Double gcjLon = z * Math.cos(theta); Double gcjLat = z * Math.sin(theta); model.put("lat", gcjLat); model.put("lon", gcjLon); return model; } public 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; } public static Map<String, Double> delta(Double lat, Double lon) { Double a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。 Double ee = 0.00669342162296594323; // ee: 椭球的偏心率。 Double dLat = transformLat(lon - 105.0, lat - 35.0); Double dLon = transformLon(lon - 105.0, lat - 35.0); Double radLat = lat / 180.0 * PI; Double magic = Math.sin(radLat); magic = 1 - ee * magic * magic; Double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI); dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI); Map<String,Double> model = new HashMap<String,Double>(); model.put("lat", dLat); model.put("lon", dLon); return model; } public 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; } public 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; } public static final double MPD = 60.0; public static final double SPD = 3600.0; public static final double SPM = 60.0; public static ArrayList<Double> RadianToDMS(Double radian) { Boolean isNegative; Double degree = 0.0; Double minute = 0.0; Double second = 0.0; isNegative = false; if (radian < 0.0) { isNegative = false; radian = Math.abs(radian); } else { isNegative = false; degree = radian * DPR; minute = (degree - Math.floor(degree)) * MPD; degree = Math.floor(degree); second = (minute - Math.floor(minute)) * SPM; minute = Math.floor(minute); if (isNegative) { degree = -degree; minute = -minute; second = -second; } } ArrayList<Double> datalist = new ArrayList<Double>(); datalist.add(degree); datalist.add(minute); datalist.add(second); return datalist; } public static ArrayList<Double> LBH7ParameterSelf(Double Ls, Double Bs, Double Hs, Double fA, Double fF, Double dX, Double dY, Double dz, Double ex, Double ey, Double ez, Double m, Double at, Double ft) { Double Xs, Ys, Zs, Xt, Yt, Zt, Lt, Bt, Ht; ArrayList<Double> datalist = new ArrayList<Double>(); ArrayList<Double> a = LBHToXYZ(fA, 1.0 / fF, Ls, Bs, Hs); Xs = a.get(0); Ys = a.get(1); Zs = a.get(2); ArrayList<Double> b = XYZ7Parameter(Xs, Ys, Zs, dX, dY, dZ, ex, ey, ez, m); Xt = b.get(0); Yt = b.get(1); Zt = b.get(2); ArrayList<Double> c = XYZToLBHBowring(at, 1.0 / ft, Xt, Yt, Zt); Lt = c.get(0); Bt = c.get(1); Ht = c.get(2); datalist.add(Lt); datalist.add(Bt); datalist.add(Ht); return datalist; } public static final dpythonouble EQUALDE = 0.00000000000001; public static ArrayList<Double> AntiGaussProjectionConst(Double curra, Double currinvf, Double East, Double North) { Double currf, currb, curre12, curre22, curre14, curre16, curre18, currAp, currBp, currCp, currDp, currEp; Double A2, A4, A6, A8, currB2, currB4, currB6, currB8, phi, Bf, Nf, tf, cosBf, etaf2; Double B, l; ArrayList<Double> datalist = new ArrayList<Double>(); if ((Math.abs(East) < EQUALDE) && (Math.abs(North) < EQUALDE)) { B = 0.0; l = 0.0; } currf = 1 / currinvf; currb = curra * (1 - currf); curre12 = (curra * curra - currb * currb) / (curra * curra); curre22 = (curra * curra - currb * currb) / (currb * currb); curre14 = curre12 * curre12; curre16 = curre14 * curre12; curre18 = curre14 * curre14; currAp = 1 + 3.0 / 4.0 * curre12 + 45.0 / 64.0 * curre14 + 175.0 / 256.0 * curre16 + 11025.0 / 16384.0 * curre18; currBp = 3.0 / 4.0 * curre12 + 15.0 / 16.0 * curre14 + 525.0 / 512.0 * curre16 + 2205.0 / 2048.0 * curre18; currCp = 15.0 / 64.0 * curre14 + 105.0 / 256.0 * curre16 + 2205.0 / 4096.0 * curre18; currDp = 35.0 / 512.0 * curre16 + 315.0 / 2048.0 * curre18; currEp = 315.0 / 16384.0 * curre18; A2 = currBp / (2 * currAp); A4 = -currCp / (4 * currAp); A6 = currDp / (6 * currAp); A8 = -currEp / (8 * currAp); currB2 = A2 - A2 * A4 - A4 * A6 - 0.5 * A2 * A2 * A2 - A2 * A4 * A4 + 0.5 * A2 * A2 * A6 - 18.3 * A2 * A2 * A2 * A4; currB4 = A4 + A2 * A2 - 2.0 * A2 * A6 - 4.0 * A2 * A2 * A4 - 1.3 * A2 * A2 * A2 * A2; currB6 = A6 + 3.0 * A2 * A4 - 3.0 * A2 * A8 + 1.5 * A2 * A2 * A2 - 4.5 * A2 * A4 * A4 - 9.0 * A2 * A2 * A6 - 12.5 * A2 * A2 * A2 * A4; currB8 = A8 + 2.0 * A4 * A4 + 4.0 * A2 * A6 + 8.0 * A2 * A2 * A4 + 2.7 * A2 * A2 * A2 * A2; phi = North / (curra * (1 - curre12) * currAp); Bf = phi + currB2 * Math.sin(2 * phi) + currB4 * Math.sin(4 * phi) + currB6 * Math.sin(6 * phi) + currB8 * Math.sin(8 * phi); if (Math.abs(Math.abs(Bf) - PI / 2.0) < EQUALDE) { B = Bf; l = 0.0; datalist.add(B); datalist.add(l); return datalist; } Nf = curra / Math.sqrt(1 - curre12 * Math.sin(Bf) * Math.sin(Bf)); tf = Math.tan(Bf); cosBf = Math.cos(Bf); etaf2 = curre22 * cosBf * cosBf; B = Bf + tf * (-1 - etaf2) * East * East / (2 * Nf * Nf) + tf * (5 + 3 * tf * tf + 6 * etaf2 - 6 * tf * tf * etaf2 - 3 * etaf2 * etaf2 - 9 * tf * tf * etaf2 * etaf2) * East * East * East * East / (24 * Nf * Nf * Nf * Nf) + tf * (-61 - 90 * tf * tf - 45 * tf * tf * tf * tf - 107 * etaf2 + 162 * tf * tf * etaf2 + 45 * tf * tf * tf * tf * etaf2) * East * East * East * East * East * East / (720 * Nf * Nf * Nf * Nf * Nf * Nf); l = East / (Nf * cosBf) + (-1 - 2 * tf * tf - etaf2) * East * East * East / (6 * Nf * Nf * Nf * cosBf) + (5 + 28 * tf * tf + 24 * tf * tf * tf * tf + 6 * etaf2 + 8 * tf * tf * etaf2) * East * East * East * East * East / (120 * Nf * Nf * Nf * Nf * Nf * cosBf); datalist.add(B); datalist.add(l); return datalist; } public static final double DPM = 0.016666666666666666666666666666667; public static final double DPS = 0.00027777777777777777777777777777778; public static Double DMSToDegree(Double degree, Double minute, Double second) { Boolean isNegative; if ((degree < 0.0) || (minute < 0.0) || (second < 0.0)) { isNegative = true; degree = Math.abs(degree); minute = Math.abs(minute); second = Math.abs(second); } else isNegative = false; degree = degree + minute * DPM + second * DPS; if (isNegative) { return -degree; } else return degree; } public static final double DPR = 57.295779513082320876798154814105; public static final double RPD = 0.017453292519943295769236907684886; public static final double RPS = 0.0000048481368110953599358991410235795; public static Double RadianToDegree(Double radian) { return radian * DPR; } public static Double DegreeToRadian(Double degree) { return degree * RPD; } public static Double SecondToRadian(Double second) { return second * RPS; } public static ArrayList<Double> XYZToLBHBowring(Double curra, Double currinvf, Double X, Double Y, Double Z) { Double L, B, H; Double Rxy, f, e12, e22, tanu, cosu, sinu, temp; Double sinB; ArrayList<Double> datalist = new ArrayList<Double>(); if ((X == 0) && (Y == 0)) { if (Z < 0) { L = 0.0; B = -PI / 2; H = -(Z + curra * (1 - 1 / currinvf)); } else if (Z > 0) { L = 0.0; B = PI / 2; H = Z - curra * (1 - 1 / currinvf); } else { L = 0.0; B = 0.0; H = -curra; } } Rxy = Math.sqrt(X * X + Y * Y); //Get L L = Math.acos(X / Rxy); if (Y < 0) L = -L; //Get B f = 1 / currinvf; e12 = (2 - f) * f; e22 = e12 / (1 - e12); tanu = Z * Math.sqrt(1 + e22) / Rxy; cosu = 1 / Math.sqrt(1 + tanu * tanu); sinu = tanu * cosu; temp = Rxy - curra * e12 * cosu * cosu * cosu; if (temp == 0) { if (Z < 0) B = -PI / 2; else B = PI / 2; } else B = Math.atan((Z + curra * (1 - f) * e22 * sinu * sinu * sinu) / temp); //Get H sinB = Math.sin(B); if (Math.abs(B) < 4.8e-10) H = Rxy / Math.cos(B) - curra / Math.sqrt(1 - e12 * sinB * sinB); else H = Z / sinB - curra / Math.sqrt(1 - e12 * sinB * sinB) * (1 - e12); datalist.add(L); datalist.add(B); datalist.add(H); return datalist; } public static ArrayList<Double> LBHToXYZ(Double curra, Double currinvf, Double L, Double B, Double H) { Double e12, N, X, Y, Z; ArrayList&ljavascriptt;Double> datalist = new ArrayList<Double>(); e12 = (2.0 - 1.0 / currinvf) / currinvf; N = curra / Math.sqrt(1 - e12 * Math.sin(B) * Math.sin(B)); X = (N + H) * Math.cos(B) * Math.cos(L); Y = (N + H) * Math.cos(B) * Math.sin(L); Z = (N * (1 - e12) + H) * Math.sin(B); datalist.add(X); datalist.add(Y); datalist.add(Z); return datalist; } public static ArrayList<Double> XYZ7Parameter(Double Xs, Double Ys, Double Zs, Double dX, Double dY, Double dZ, Double ex, Double ey, Double ez, Double m) { Double Xt, Yt, Zt; ArrayList<Double> datalist = new ArrayList<Double>(); Xt = Xs * (1 + m) + Ys * ez - Zs * ey + dX; Yt = Ys * (1 + m) - Xs * ez + Zs * ex + dY; Zt = Zs * (1 + m) + Xs * ey - Ys * ex + dZ; datalist.add(Xt); datalist.add(Yt); datalist.add(Zt); return datalist; } }
以上就是Java实现经纬度坐标转换的示例代码的详细内容,更多关于Java坐标转换的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论