使用Java实现的新版地图图幅编号计算公式(新版图幅规则(GB/T 13989—2012))

前言

最近项目需求,需要根据经纬度,计算出图幅编号。本来想着找轮子,结果找了一大圈没找到,就自己找到相关书籍,看计算公式,重复造了一个轮子。

比如根据,北纬:30°56′50″,东经:105°4′25″,计算新旧图幅编号,根据公式,我们按照1:50000比例,可以计算出,新版图幅编号为:H48E007013,旧版图幅编号为:8-48-43-A

新版本的计算公式,以及通过新版本的图幅编号,计算出旧图幅编号

  1 package com.jucheap.utils;
  2 
  3 import com.jucheap.base.CoordinateDTO;
  4 
  5 /**
  6  * <p>
  7  * 地图图幅编号计算
  8  * </p>
  9  *
 10  * @Author jucheap
 11  * @Email jucheap@jucheap.com
 12  * @Date 2020/8/22
 13  */
 14 public class MapNumberUtil {
 15 
 16     /**
 17      * 新版图幅规则(GB/T 13989—2012)
 18      * @param longitude 经度
 19      * @param latitude 纬度
 20      * @param scaleNumber 缩放比例(1000000/500000/100000/50000)
 21      * @return 图幅编号
 22      */
 23     public static String toMapNumber(CoordinateDTO longitude, CoordinateDTO latitude, Integer scaleNumber) {
 24         // 经/纬差值计算
 25         Double lngDiff = getLongitudeDiff(scaleNumber);
 26         Double latDiff = getLatitudeDiff(scaleNumber);
 27         // 度分秒转换,统一成度
 28         Double lng = longitude.toDegreeNumber();
 29         Double lat = latitude.toDegreeNumber();
 30         StringBuilder sb = new StringBuilder(512);
 31         String[] codes = toWords();
 32         Double word_row = Double.valueOf(1) + lat / 4;
 33         Double word_col = Double.valueOf(31) + lng / 6;
 34         sb.append(String.format("%s%s%s", codes[word_row.intValue() - 1], word_col.intValue(), toScaleCode(scaleNumber)));
 35         Integer number_row = Double.valueOf(4.0 / latDiff).intValue() - Double.valueOf((lat % 4.0) / latDiff).intValue();
 36         Double number_col = lng % 6.0 / lngDiff + 1;
 37         sb.append(String.format("%03d", number_row));
 38         sb.append(String.format("%03d", number_col.intValue()));
 39         return sb.toString();
 40     }
 41 
 42     /**
 43      * 生成26个大写字母
 44      * @return 26个大写字母数组
 45      */
 46     private static String[] toWords() {
 47         String[] codes = new String[26];
 48         for (int i = 1; i <= 26; i++) {
 49             codes[i - 1] = toUpperCode(i);
 50         }
 51         return codes;
 52     }
 53 
 54     /**
 55      * 转换成单个的大写字母
 56      * @param value
 57      * @return
 58      */
 59     private static String toUpperCode(Integer value) {
 60         return String.valueOf(Character.toUpperCase((char) (96 + value)));
 61     }
 62 
 63     /**
 64      * 获取缩放比例代码
 65      *
 66      * @param scaleNumber 缩放比例(如50000,代表1:50000)
 67      * @return 缩放比例代码
 68      */
 69     private static String toScaleCode(int scaleNumber) {
 70         switch (scaleNumber) {
 71             case 500000:
 72                 return "B";
 73             case 250000:
 74                 return "C";
 75             case 100000:
 76                 return "D";
 77             case 50000:
 78                 return "E";
 79             case 25000:
 80                 return "F";
 81             case 10000:
 82                 return "G";
 83             case 5000:
 84                 return "H";
 85             case 2000:
 86                 return "I";
 87             case 1000:
 88                 return "J";
 89             case 500:
 90                 return "K";
 91             default:
 92                 return "";
 93         }
 94     }
 95 
 96     /**
 97      * 获取经差值
 98      *
 99      * @param scaleNumber 缩放比例(如50000,代表1:50000)
100      * @return 经差值
101      */
102     private static Double getLongitudeDiff(int scaleNumber) {
103         switch (scaleNumber) {
104             case 1000000:
105                 return 6.0;
106             case 500000:
107                 return 3.0;
108             case 250000:
109                 return 1.5;
110             case 100000:
111                 return 0.5;
112             case 50000:
113                 return 15.0 / 60.0;
114             case 25000:
115                 return 7.0 / 60.0 + 30.0 / 3600.0;
116             case 10000:
117                 return 3.0 / 60.0 + 45.0 / 3600.0;
118             case 5000:
119                 return 1.0 / 60.0 + 52.5 / 3600.0;
120             case 2000:
121                 return 37.5 / 3600.0;
122             case 1000:
123                 return 18.75 / 3600.0;
124             case 500:
125                 return 9.375 / 3600.0;
126             default:
127                 return 0.0;
128         }
129     }
130 
131     /**
132      * 获取纬差值
133      *
134      * @param scaleNumber 缩放比例(如50000,代表1:50000)
135      * @return 纬差值
136      */
137     private static Double getLatitudeDiff(int scaleNumber) {
138         switch (scaleNumber) {
139             case 1000000:
140                 return 4.0;
141             case 500000:
142                 return 2.0;
143             case 250000:
144                 return 1.0;
145             case 100000:
146                 return 20.0 / 60.0;
147             case 50000:
148                 return 10.0 / 60.0;
149             case 25000:
150                 return 5.0 / 60.0;
151             case 10000:
152                 return 2.0 / 60.0 + 30.0 / 3600.0;
153             case 5000:
154                 return 1.0 / 60.0 + 15.0 / 3600.0;
155             case 2000:
156                 return 25.0 / 3600.0;
157             case 1000:
158                 return 12.5 / 3600.0;
159             case 500:
160                 return 6.25 / 3600.0;
161             default:
162                 return 0.0;
163         }
164     }
165 
166     /**
167      * 新的图幅编号转换成旧的图幅编号
168      * @param newMapNumber 新图幅编号
169      * @return 旧图幅编号
170      */
171     public static String toOldMapNumber(String newMapNumber) {
172         if (newMapNumber.length() != 3 && newMapNumber.length() != 10) {
173             return "";
174         }
175         char[] newMapNumberChars = newMapNumber.toCharArray();
176         String bigRowNo = String.valueOf(newMapNumberChars[0] - 'A' + 1);
177         String bigColNo = newMapNumber.substring(1, 3);
178         if (newMapNumber.length() == 3) { //100W
179             return String.format("%s-%s", bigRowNo, bigColNo);
180         } else {
181             // 新图幅号的行列代码,col_number为行代码,col_number为列代码
182             Integer row_number = Integer.valueOf(newMapNumber.substring(4, 7));
183             Integer col_number = Integer.valueOf(newMapNumber.substring(7, 10));
184             // 提取行代码和列代码,若非数字,则表示图幅号格式不正确
185             char mapScaleNumber = newMapNumberChars[3];
186             if (mapScaleNumber == 'B') {  //50W
187                 //region 50W
188                 if (row_number > 2 || col_number > 2){
189                     return "";
190                 }
191                 //旧图幅号对应的地图代码
192                 int X = (row_number - 1) * 2 + (col_number - 1) + 1;
193                 return String.format("%s-%s-%s", bigRowNo, bigColNo, toUpperCode(X));
194                 //endregion
195             } else if (mapScaleNumber == 'C') {//25W
196                 //region 25W
197                 if (row_number > 4 || col_number > 4) {
198                     return "";
199                 }
200                 //旧图幅号对应的地图代码
201                 int X = (row_number - 1) * 4 + (col_number - 1) + 1;
202                 // String code = String.format("%02d", X);
203                 String code = String.valueOf(X);
204                 return String.format("%s-%s-[%s]", bigRowNo, bigColNo, code);
205                 //endregion
206             } else if (mapScaleNumber == 'D') {//10W
207                 //region 10W
208                 if (row_number > 12 || col_number > 12){
209                     return "";
210                 }
211                 //旧图幅号对应的地图代码
212                 int X = (row_number - 1) * 12 + (col_number - 1) + 1;
213                 //String code = String.format("%03d", X);
214                 String code = String.valueOf(X);
215                 return String.format("%s-%s-%s", bigRowNo, bigColNo, code);
216                 //endregion
217             } else if (mapScaleNumber == 'E') { //5W
218                 //region 5W
219                 if (row_number > 24 || col_number > 24) {
220                     return "";
221                 }
222                 //10W地形图对应的行号
223                 int H10 = (row_number - 1) / 2 + 1;
224                 //10W地形图对应的列号
225                 int L10 = (col_number - 1) / 2 + 1;
226                 //10W旧图幅号对应的地图代码
227                 int X10 = (H10 - 1) * 12 + (L10 - 1) + 1;
228                 //String code = String.format("%03d", X10);
229                 String code = String.valueOf(X10);
230                 //旧图幅号对应的地图代码
231                 int X = (row_number - 2 * H10 + 1) * 2 + (col_number - 2 * L10 + 1) + 1;
232                 return String.format("%s-%s-%s-%s", bigRowNo, bigColNo, code, toUpperCode(X));
233                 //endregion
234             } else if (mapScaleNumber == 'F') {236                 //5W地形图对应的行号
237                 int H5 = (row_number - 1) / 2 + 1;
238                 //5W地形图对应的列号
239                 int L5 = (col_number - 1) / 2 + 1;
240 
241                 //10W地形图对应的行号
242                 int H10 = (H5 - 1) / 2 + 1;
243                 //10W地形图对应的列号
244                 int L10 = (L5 - 1) / 2 + 1;
245 
246                 Integer X2 = (row_number - 2 * H5 + 1) * 2 + (col_number - 2 * L5 + 1) + 1;
247                 Integer X5 = (H5 - 2 * H10 + 1) * 2 + (L5 -2 * L10 + 1) + 1;
248                 Integer X10 = (H10 - 1) * 12 + (L10 - 1) + 1;
249 
250                 return String.format("%s-%s-%s-%s-%s", bigRowNo, bigColNo, X10, toUpperCode(X5), X2);
251             }
252             //图幅号格式不正确
253             return "";
254         }
255     }
256 }

坐标模型类代码

 1 package com.jucheap.base;
 2 
 3 import lombok.Getter;
 4 import lombok.Setter;
 5 
 6 /**
 7  * <p>
 8  * 地图坐标对象
 9  * </p>
10  *
11  * @Author jucheap
12  * @Email jucheap@jucheap.com
13  * @Date 2020/8/22
14  */
15 
16 @Getter
17 @Setter
18 public class CoordinateDTO {
19 
20     /**
21      * ctor
22      * @param degree 度
23      * @param minute 分
24      * @param second 秒
25      */
26     public CoordinateDTO(Double degree, Double minute, Double second) {
27         this.setDegree(degree);
28         this.setMinute(minute);
29         this.setSecond(second);
30     }
31 
32     /**
33      * 转换成十进制的度数
34      *
35      * @return 十进制的度数
36      */
37     public Double toDegreeNumber() {
38         return degree + minute / 60.0 + second / 3600.0;
39     }
40 
41     /**
42      * 度
43      */
44     private Double degree;
45 
46     /**
47      * 分
48      */
49     private Double minute;
50 
51     /**
52      * 秒
53      */
54     private Double second;
55 }

以下是单元测试代码

 1 package com.jucheap;
 2 
 3 import com.jucheap.base.CoordinateDTO;
 4 import com.jucheap.utils.MapNumberUtil;
 5 import org.junit.Test;
 6 import org.junit.runner.RunWith;
 7 import org.springframework.boot.test.context.SpringBootTest;
 8 import org.springframework.test.context.junit4.SpringRunner;
 9 
10 @RunWith(SpringRunner.class)
11 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
12 public class MapNumberTest {
13 
14     /**
15      * 新版图幅规则(GB/T 13989—2012)
16      */
17     @Test
18     public void mapNumberTest() {
19         Integer scaleNumber = 50000;
20         CoordinateDTO lng = new CoordinateDTO(105.0, 4.0, 25.8);
21         CoordinateDTO lat = new CoordinateDTO(30.0, 56.0, 50.6);
22 
23         String mapNumber = MapNumberUtil.toMapNumber(lng, lat, scaleNumber);
24         String oldMapNumber = MapNumberUtil.toOldMapNumber(mapNumber);
25         System.out.println(mapNumber);
26         System.out.println(oldMapNumber);
27     }
28 }

测试结果

 

通过上面的计算公式基本实现了新旧图幅编号的计算。在实际公式编写中,也遇到了很多问题,具体的实现公式,参考如下:

https://wenku.baidu.com/view/0c0c8bc5f80f76c66137ee06eff9aef8951e485e.html

https://wenku.baidu.com/view/5deb7e1aa8114431b90dd8ed.html

https://www.jianshu.com/p/d11c7f7e6613

参考书籍

01.地理信息系统——原理、方法和应用(邬伦)  Doc下载   PDF下载
02.地理信息系统概论(黄杏元)  PDF下载
03.地理信息系统导论(陈述彭) PDF下载
04.第一部分 地图投影及其坐标转换公式   PDF下载
05.第二部分 非地图投影坐标运算公式   PDF下载
06.GIS空间分析原理与方法(刘湘楠)  PDF下载
07.地图学与地图绘制  PDF下载
08.地图学基础    PDF下载
09.地图投影    PDF下载
10.地图投影变换原理与方法    PDF下载
11.地理信息系统原理、应用与工程 (第2版)    PDF下载
12.地籍测量学   PDF下载
13.地貌学原理(第3版)    PDF下载
14.新编地图学实习教程    PDF下载
15.普通地图制图中的数学方法   PDF下载
16.景观生态学——格局、过程、尺度与等级  PDF下载
17.海洋地图学   PDF下载
18.自然地理学  第2版   PDF下载
19.自然地理学野外实习  原理、方法与实践   PDF下载
20.地图艺术设计    PDF下载

下载地址:http://bbs.3s001.com/thread-151638-1-1.html

posted @ 2020-09-23 11:12  JuCheap  阅读(1893)  评论(0)    收藏  举报