根据经纬度求算所在的地形图分幅编号

该代码实现了一个Java类`MapNumberUtil`,用于根据经纬度和不同的缩放比例计算新版图幅规则下的图幅编号。方法包括了对不同比例尺(如1:25000,1:50000等)的处理,基于GB/T13989—2012标准,通过计算经度和纬度的差值来确定图幅位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


/**
 * 根据经纬度求算所在的地形图分幅编号
 * 地球经度 180 + 180
 * 地球纬度 90 + 90
 *
 * 1:100w地图是按照经度差6度,纬度差4度 将地球分为2760份
 * 180 / 6 = 30
 * 90 / 4 = 23
 * 所以 ,100w比例的地图是将全球分成了 60 * 46 = 2760 份,按照100w的比例可以将全球分成2760份,每份大概面积18.5w平方公里
 * 1:50w地图是将一副1:100w的地图四等分,2760 * 4 = 11040 份,每份大概面积4.5w平方公里
 * 同理,1:25w地图是将一副1:100w的地图16等分,将全球分为 2760 * 16 = 44160 份,每份大概面积1.15w平方公里
 * 1:10w地图是将一副1:100w的地图144等分,将全球分为 2760 * 144 = 397440 份,每份大概面积1283平方公里
 * 1:5w地图是将一副1:10w的地图4等分,将全球分为 2760 * 144 * 4 = 1589760 份,每份大概面积320平方公里
 * 1:2w5地图是将一副1:5w的地图4等分,将全球分为 2760 * 144 * 4 * 4 = 6359040 份,每份大概面积80平方公里
 */
public class MapNumberUtil {

    /**
     * 新版图幅规则(GB/T 13989—2012)
     * 缩放比例为25000
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 图幅编号
     */
    public static String toMapNumber2W5(double longitude, double latitude) {
        return toMapNumber(longitude, latitude, 25000);
    }

    /**
     * 新版图幅规则(GB/T 13989—2012)
     * 缩放比例为25000
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 图幅编号
     */
    public static String toMapNumber2W5(CoordinateDTO longitude, CoordinateDTO latitude) {
        return toMapNumber(longitude, latitude, 25000);
    }

    /**
     * 新版图幅规则(GB/T 13989—2012)
     * 缩放比例为50000
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 图幅编号
     */
    public static String toMapNumber5W(double longitude, double latitude) {
        return toMapNumber(longitude, latitude, 50000);
    }

    /**
     * 新版图幅规则(GB/T 13989—2012)
     * 缩放比例为50000
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 图幅编号
     */
    public static String toMapNumber5W(CoordinateDTO longitude, CoordinateDTO latitude) {
        return toMapNumber(longitude, latitude, 50000);
    }

    /**
     * 新版图幅规则(GB/T 13989—2012)
     *
     * @param longitude   经度
     * @param latitude    纬度
     * @param scaleNumber 缩放比例(1000000/500000/100000/50000),
     *                    推荐2w5,1:5w的比例纬度差为5分,纬度1分约等于1.85km,5分约等于9.25km
     *                    推荐5w,1:5w的比例纬度差为10分,纬度1分约等于1.85km,10分约等于18.5km
     * @return 图幅编号
     */
    public static String toMapNumber(double longitude, double latitude, Integer scaleNumber) {
        return toMapNumber(toCoordinateDTO(longitude), toCoordinateDTO(latitude), scaleNumber);
    }

    /**
     * 新版图幅规则(GB/T 13989—2012)
     * 计算方法参考:https://blog.youkuaiyun.com/weixin_39716160/article/details/111815576
     *
     * @param longitude   经度
     * @param latitude    纬度
     * @param scaleNumber 缩放比例(1000000/500000/100000/50000),
     *                    推荐2w5,1:5w的比例纬度差为5分,纬度1分约等于1.85km,5分约等于9.25km
     *                    推荐5w,1:5w的比例纬度差为10分,纬度1分约等于1.85km,10分约等于18.5km
     * @return 图幅编号
     */
    public static String toMapNumber(CoordinateDTO longitude, CoordinateDTO latitude, Integer scaleNumber) {
        // 经/纬差值计算
        Double lngDiff = getLongitudeDiff(scaleNumber);
        Double latDiff = getLatitudeDiff(scaleNumber);
        // 度分秒转换,统一成度
        Double lng = longitude.toDegreeNumber();
        Double lat = latitude.toDegreeNumber();
        StringBuilder sb = new StringBuilder(512);
        String[] codes = toWords();
        Double word_row = Double.valueOf(1) + lat / 4;
        Double word_col = Double.valueOf(31) + lng / 6;
        sb.append(String.format("%s%s%s", codes[word_row.intValue() - 1], word_col.intValue(), toScaleCode(scaleNumber)));
        Integer number_row = Double.valueOf(4.0 / latDiff).intValue() - Double.valueOf((lat % 4.0) / latDiff).intValue();
        Double number_col = lng % 6.0 / lngDiff + 1;
        sb.append(String.format("%03d", number_row));
        sb.append(String.format("%03d", number_col.intValue()));
        return sb.toString();
    }

    /**
     * 生成26个大写字母
     *
     * @return 26个大写字母数组
     */
    private static String[] toWords() {
        String[] codes = new String[26];
        for (int i = 1; i <= 26; i++) {
            codes[i - 1] = toUpperCode(i);
        }
        return codes;
    }

    /**
     * 转换成单个的大写字母
     *
     * @param value
     * @return
     */
    private static String toUpperCode(Integer value) {
        return String.valueOf(Character.toUpperCase((char) (96 + value)));
    }

    /**
     * 获取缩放比例代码
     *
     * @param scaleNumber 缩放比例(如50000,代表1:50000)
     * @return 缩放比例代码
     */
    private static String toScaleCode(int scaleNumber) {
        switch (scaleNumber) {
            case 1000000:
                return "A";
            case 500000:
                return "B";
            case 250000:
                return "C";
            case 100000:
                return "D";
            case 50000:
                return "E";
            case 25000:
                return "F";
            case 10000:
                return "G";
            case 5000:
                return "H";
            case 2000:
                return "I";
            case 1000:
                return "J";
            case 500:
                return "K";
            default:
                return "";
        }
    }

    /**
     * 获取经差值
     *
     * @param scaleNumber 缩放比例(如50000,代表1:50000)
     * @return 经差值
     */
    private static Double getLongitudeDiff(int scaleNumber) {
        switch (scaleNumber) {
            case 1000000:
                return 6.0;
            case 500000:
                return 3.0;
            case 250000:
                return 1.5;
            case 100000:
                return 0.5;
            case 50000:
                return 15.0 / 60.0;
            case 25000:
                return 7.0 / 60.0 + 30.0 / 3600.0;
            case 10000:
                return 3.0 / 60.0 + 45.0 / 3600.0;
            case 5000:
                return 1.0 / 60.0 + 52.5 / 3600.0;
            case 2000:
                return 37.5 / 3600.0;
            case 1000:
                return 18.75 / 3600.0;
            case 500:
                return 9.375 / 3600.0;
            default:
                return 0.0;
        }
    }

    /**
     * 获取纬差值
     *
     * @param scaleNumber 缩放比例(如50000,代表1:50000)
     * @return 纬差值
     */
    private static Double getLatitudeDiff(int scaleNumber) {
        switch (scaleNumber) {
            case 1000000:
                return 4.0;
            case 500000:
                return 2.0;
            case 250000:
                return 1.0;
            case 100000:
                return 20.0 / 60.0;
            case 50000:
                return 10.0 / 60.0;
            case 25000:
                return 5.0 / 60.0;
            case 10000:
                return 2.0 / 60.0 + 30.0 / 3600.0;
            case 5000:
                return 1.0 / 60.0 + 15.0 / 3600.0;
            case 2000:
                return 25.0 / 3600.0;
            case 1000:
                return 12.5 / 3600.0;
            case 500:
                return 6.25 / 3600.0;
            default:
                return 0.0;
        }
    }

    /**
     * 经纬度转换成度分秒
     *
     * @param longitudeOrLatitude 经纬度
     * @return 度分秒
     */
    public static CoordinateDTO toCoordinateDTO(double longitudeOrLatitude) {
        int d = (int) longitudeOrLatitude;
        int m = (int) ((longitudeOrLatitude - d) * 60);
        Double degree = (double) d;
        Double minute = (double) m;
        Double second = ((longitudeOrLatitude - d) * 60 - m) * 60;
        return new CoordinateDTO(degree, minute, second);
    }

    public static void main(String[] args) {
        /**
         * 新版图幅规则(GB/T 13989—2012)
         */
        CoordinateDTO lng = toCoordinateDTO(118.32644);
        CoordinateDTO lat = toCoordinateDTO(35.12542);

        //    经度      纬度   缩放比例5w  缩放比例2w5
        // 118.31532 35.18246 I50E005018 I50F010035
        // 118.30771 35.21735 I50E005018 I50F010035
        // 118.31005 35.20489 I50E005018 I50F010035
        // 118.31936 35.17056 I50E005018 I50F010035
        // 118.32578 35.13390 I50E006018 I50F011035
        // 118.33317 35.10355 I50E006018 I50F011035
        // 118.34441 35.05687 I50E006018 I50F012035
        // 118.30523 35.05776 I50E006018 I50F012035
        // 118.31676 35.03584 I50E006018 I50F012035

        String mapNumber = MapNumberUtil.toMapNumber(lng, lat, 25000);
        System.out.println(mapNumber);
    }

}


import lombok.Data;

/**
 * 坐标,度分秒格式
 */
@Data
public class CoordinateDTO {

    /**
     * ctor
     *
     * @param degree 度
     * @param minute 分
     * @param second 秒
     */
    public CoordinateDTO(Double degree, Double minute, Double second) {
        this.setDegree(degree);
        this.setMinute(minute);
        this.setSecond(second);
    }

    /**
     * 转换成十进制的度数
     *
     * @return 十进制的度数
     */
    public Double toDegreeNumber() {
        return degree + minute / 60.0 + second / 3600.0;
    }

    /**
     * 度
     */
    private Double degree;

    /**
     * 分
     */
    private Double minute;

    /**
     * 秒
     */
    private Double second;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值