java把百度经纬度转换为天地图坐标系WGS-84

可以使用,百度地图坐标拾取器:https://lbs.baidu.com/maptool/getpoint

天地图:http://lbs.tianditu.gov.cn/api/js4.0/examples.html 在添加覆盖物,添加标注里面

测试类

package org.springblade.modules.api.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springblade.common.config.BladeRemoteConfig;
import org.springblade.common.utils.CommonUtil;
import org.springblade.core.http.util.HttpUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.modules.api.entity.SimpleAuthentication;
import org.springblade.modules.api.service.IClueService;
import org.springblade.modules.api.vo.TestVo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@AllArgsConstructor
@RequestMapping("/change")
@Api(value = "", tags = "接口")
public class TestController {

    private final IClueService clueService;


   

    /**
     * @param longitude 经度
     * @param latitude  纬度
     * @return
     */
    public static String changeItudeOne(String longitude, String latitude) {
        //源坐标类型      from=5 bd09ll(百度经纬度坐标)
        //目的坐标类型    to=3  google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标
        String url = "https://api.map.baidu.com" + "/geoconv/v1/?coords=" + longitude + "," + latitude + "&from=5&to=3&ak=写自己的ak";

        Map header = new HashMap();
        String s = HttpUtil.get(url, header, null);
        //请求结果不为空并且不包含html(有html可能访问路径不对)
        if (Func.isNotEmpty(s) && !s.contains("html")) {
            Map<String, Object> baiDuMap = JsonUtil.toMap(s);
            //如果包含status代表请求成功
            if (baiDuMap.containsKey("status")) {
                int status = Func.toInt(baiDuMap.get("status"));
                //非0的状态码都是失败
                if (status != 0) {
                    throw new ServiceException(Func.toStr(baiDuMap.get("message")));
                }
                List<Map> mapList = (List<Map>) baiDuMap.get("result");
                List<String> list = new ArrayList();
                mapList.forEach(a -> {
                    String x = Func.toStr(a.get("x"));
                    String y = Func.toStr(a.get("y"));
                    String str = (x.length() >= 10 ? x.substring(0, 10) : x) + "," + (y.length() >= 10 ? y.substring(0, 10) : y);
                    list.add(str);
                });
                return list.stream().map(String::valueOf).collect(Collectors.joining(";"));

            }
        }
        throw new ServiceException("操作失败,坐标转换出现异常");
    }

    /**
     * 转换多个如:120.00,31.00;120.01,31.01
     *
     * @param geometry
     */
    public static String changeItudeMany(String geometry) {
        if (Func.isNotEmpty(geometry) && !geometry.contains("[]")) {
            if (geometry.endsWith(";")) {
                geometry = geometry.substring(0, geometry.length() - 1);
            }
            if (geometry.contains(";")) {
                String[] split = geometry.split(";");
                System.err.println("多条经纬度 = " + split.length);
                List<String> list = new ArrayList();
                for (int i = 0; i < split.length; i++) {
                    System.err.println("第" + (i + 1) + "条," + split[i]);
                    //源坐标类型      from=3 google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标
                    //目的坐标类型    to=5 bd09ll(百度经纬度坐标)
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    }
                    String url = "https://api.map.baidu.com" + "/geoconv/v1/?coords=" + split[i] + "&from=5&to=3&ak=自己的ak";
                    Map header = new HashMap();
                    String s = HttpUtil.get(url, header, null);
                    //请求结果不为空并且不包含html(有html可能访问路径不对)
                    if (Func.isNotEmpty(s) && !s.contains("html")) {
                        Map<String, Object> baiDuMap = JsonUtil.toMap(s);
                        //如果包含status代表请求成功
                        if (baiDuMap.containsKey("status")) {
                            int status = Func.toInt(baiDuMap.get("status"));
                            //非0的状态码都是失败
                            if (status != 0) {
                                throw new ServiceException(Func.toStr(baiDuMap.get("message")));
                            }
                            List<Map> mapList = (List<Map>) baiDuMap.get("result");

                            mapList.forEach(a -> {
                                String x = Func.toStr(a.get("x"));
                                String y = Func.toStr(a.get("y"));
                                String str = (x.length() >= 10 ? x.substring(0, 10) : x) + "," + (y.length() >= 10 ? y.substring(0, 10) : y);
                                list.add(str);
                            });
                        }
                    }
                }
                return list.stream().map(String::valueOf).collect(Collectors.joining(";"));
            }
            throw new ServiceException("操作失败,坐标转换出现异常");
        }
        return null;

    }

    /**
     * 验证所传参数是否是经纬度
     */
    private boolean checkItude(BigDecimal longitude, BigDecimal latitude) {
        boolean flag = true;
        //不为空的情况下,判断经度是否符合要求
        if (!Func.isEmpty(longitude)) {
            BigDecimal maxLongitude = new BigDecimal("180");
            BigDecimal minLongitude = new BigDecimal("-180");
            if (longitude.compareTo(maxLongitude) > 0 || longitude.compareTo(minLongitude) < 0) {
                flag = false;
            }
        }
        //不为空的情况下,判断纬度是否符合要求
        if (!Func.isEmpty(latitude)) {
            BigDecimal maxLatitude = new BigDecimal("90");
            BigDecimal minLatitude = new BigDecimal("-90");
            if (latitude.compareTo(maxLatitude) > 0 || latitude.compareTo(minLatitude) < 0) {
                flag = false;
            }
        }
        return flag;
    }


    public static void main(String[] args) {
	    //***********转换单条***********
	    //1、先把百度地图经纬度转为GCJ-02,天安门广场百度地图坐标
        String s = changeItudeOne("116.403944","39.914780");
        //得到GCJ-02:116.3975710494649,39.90843680810011
        System.out.println("百度转GCJ-02坐标系:" + s);
        String[] split = s.split(",");
        //2、再把得到的GCJ-02坐标系转为天地图坐标系WGS-84坐标
        String[] strings = GcjToWgs.gcj02ToWgs84(Func.toDouble(split[0]), Func.toDouble(split[1]));
        System.out.println("GCJ-02坐标系转WGS-84坐标:" + strings[0] + "," + strings[1]);

		//***********转换多条***********
        String geometry = "119.63143, 32.227513;119.627368, 32.22366;119.626473, 32.251232;119.61682, 32.259295;119.605639, 32.257454;119.60443, 32.240967;119.594065, 32.237473;";
        geometry = geometry.replaceAll("\\s", "");
        //1、先把百度地图经纬度转为GCJ-02
        String s1 = changeItudeMany(geometry);
        //2、再把得到的GCJ-02坐标系转为天地图坐标系WGS-84坐标,保持原结构
        String s2 = GcjToWgs.changeMany(s1);
        System.out.println(s2);
    }

}

工具类:将GCJ-02坐标转换为WGS-84坐标

package org.springblade.modules.api.controller;

import org.springblade.core.tool.utils.Func;

import java.util.ArrayList;
import java.util.List;

public class GcjToWgs {

    private static final double PI = 3.1415926535897932384626;
    private static final double EE = 0.00669342162296594323;  // 偏心率平方
    private static final double EARTH_RADIUS = 6378137;      // 地球长半轴

    /**
     * 将GCJ-02坐标转换为WGS-84坐标
     *
     * @param lon 经度(GCJ-02)
     * @param lat 纬度(GCJ-02)
     * @return 包含WGS-84经度和纬度的数组
     */
    public static String[] gcj02ToWgs84(double lon, double lat) {
        // 创建初始点(假设初始为GCJ-02点)
        double initLon = lon;
        double initLat = lat;

        // 计算初始点与WGS-84的偏差
        double[] delta = delta(initLon, initLat);
        double dLon = initLon - delta[0];
        double dLat = initLat - delta[1];

        // 迭代计算更精确的坐标
        double threshold = 1e-6; // 精度阈值
        for (int i = 0; i < 10000; i++) {
            // 计算当前偏移量
            double[] currentDelta = delta(dLon, dLat);
            double curLon = initLon - currentDelta[0];
            double curLat = initLat - currentDelta[1];

            // 判断是否达到精度要求
            if (Math.max(Math.abs(curLon - dLon), Math.abs(curLat - dLat)) < threshold) {
                return new String[]{Func.toStr(curLon).substring(0, 10), Func.toStr(curLat).substring(0, 9)};
            }

            dLon = curLon;
            dLat = curLat;
        }
        return new String[]{Func.toStr(dLon).substring(0, 10), Func.toStr(dLat).substring(0, 9)};
    }

    /**
     * 计算坐标偏移量(WGS-84 -> GCJ-02)
     *
     * @param lon 经度
     * @param lat 纬度
     * @return 包含x方向偏移和y方向偏移的数组
     */
    private static double[] delta(double lon, double lat) {
        double[] result = new double[2];
        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);
        result[0] = (dLon * 180.0) / (EARTH_RADIUS / sqrtMagic * Math.cos(radLat) * PI);
        result[1] = (dLat * 180.0) / ((EARTH_RADIUS * (1 - EE)) / (magic * sqrtMagic) * PI);
        return result;
    }

    // 纬度变换公式
    private 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;
    }

    // 经度变换公式
    private 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 String changeMany(String geometry) {
        if (Func.isNotEmpty(geometry)) {
            if (geometry.endsWith(";")) {
                geometry = geometry.substring(0, geometry.length() - 1);
            }
            List<String> list = new ArrayList<>();
            if (geometry.contains(";")) {
                String[] split = geometry.split(";");
                for (String s : split) {
                    if (s.contains(",")) {
                        String[] strings = s.split(",");
                        String[] wgs84 = gcj02ToWgs84(Func.toDouble(strings[0]), Func.toDouble(strings[1]));
                        list.add(Func.toStr(wgs84[0]) + "," + Func.toStr(wgs84[1]));
                    }
                }
            }
            return Func.toStr(Func.join(list, ";"));
        }
        return null;
    }

    // 测试
    public static void main(String[] args) {
        // 示例:天安门广场的GCJ-02坐标
        String[] wgs = gcj02ToWgs84(119.62499962917197, 32.221260580618359);
        System.out.println("WGS-84经度: " + wgs[0]); // 约116.3975
        System.out.println("WGS-84纬度: " + wgs[1]); // 约39.9087

//        System.out.println(changeMany("119.637835,32.2338343;119.633788,32.2299422;119.632880,32.2574993;119.623269,32.2654158;119.612143,32.2633679;"));
    }
}

可以看出来两个点差不多
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值