在全球定位系统(GPS)和北斗卫星导航系统(BDS)的发展下,经纬度坐标已经成为描述地球表面位置的标准方式。然而,在某些特定的应用场景中,如城市交通管理、物流配送、无人机路径规划等,直接使用经纬度坐标存在一些局限性,例如数据量大、查询效率低等问题。
北斗网格码是一种基于地理位置的编码系统,它将地球表面划分为多个层级的网格,并为每个网格分配唯一的编码。这种编码方式可以有效地压缩地理数据,提高空间索引的效率,便于大规模地理数据的管理和分析。
规范见百度百科内容范围章节图片:北斗网格位置码_百度百科
1. 北斗网格位置码介绍
北斗网格位置码是利用北斗卫星导航系统的定位能力,对地球表面进行分层划分的一种网格编码方式。每个网格都有一个唯一的标识符,该标识符可以表示一定范围内的地理位置信息。其主要特点包括:
- 唯一性:每个网格编码在整个地球上是唯一的。
- 层级性:网格可以按照精度需求进行多级细分,例如从大区域到小区域逐步细化。
- 高效性:通过网格编码,可以快速检索和管理地理数据,提升查询效率。
2. 经纬度与北斗网格编码的关系
经纬度是以地球的经线和纬线为基础的坐标系统,用于描述地球上的任意一点。而北斗网格编码则是将这些点映射到特定的网格中,从而实现更高效的管理和计算。其转换原理为:
- 定义网格大小:根据应用需求,定义不同级别的网格大小。
- 划分网格:将经纬度范围按照预设的网格大小划分为若干个矩形或正方形网格。
- 生成编码:为每个网格分配一个唯一的编码。编码规则可以根据需要设计,例如使用二进制编码、十进制编码或其他自定义编码格式。
- 转换算法:根据给定的经纬度,确定其所在的网格,并返回对应的编码。
3. 经纬度转北斗网格编码的实现步骤
北斗二维网格位置码编码规则由最多不超过20个码元组成,按照从左到右的顺序分成十一段,分别对应地球表面南北半球以及第一级至第十级网格,北斗二维网格位置码编码结构与代码取值如下图所示:
下面,我在四个半球各取一个点,分别以西北半球 116°18'45.37"W,39°59'35.38"N ,东北半球 116°18'45.37"E,39°59'35.38"N,西南半球 116°18'45.37"W,39°59'35.38"S,东南半球 116°18'45.37"E,39°59'35.38"S 为例,逐级网格实现。
3.1 第一级网格实现
3.1.1 规范解析
地球表面北斗二维网格的划分原点在赤道面与本初子午面的交点处,地球表面非两极区域(南纬 88° ~ 北纬 88°) 第一级网格根据 GB/T13989-2012 中 1:100 万图幅进行划分,单元大小是 6° × 4°。其对应 4 位码元:
- 第一位码元,取值 N 或者 S,分别代表地球表面北半球、南半球。
- 第二位~第四位码元,标识第一级网格。其中,第二位、第三位码元,标识经度方向网格,用01~60编码;第四位码元,标识纬度方向网格,纬分南北半球按照A~V编码,第一级网格码元编码方向如图所示。

因此, 第一位码元可以根据纬度的正负判断。第二、三位码元按经度(0° ~ 360°)按每6°为一个单元,全球划分为60个经度带(01~60),计算公式:经度带编号 = (经度° + 180°) / 6° + 1。第四位码元按纬度每4°为一个单元,南北半球各划分为22个纬度带(A~V),计算公式:纬度带索引 = (纬度绝对值°) / 4°。


3.1.2 代码实现
说明:
后续代码以秒为单位计算,为防止传入 Bigdecimal(double) 导致的精度损失问题。该示例中,直接使用 double 类型直接运算也可以算出同样的结果。
1. 创建网格信息实体类:
import com.zjp.exceptions.BeidouGridException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.math.MathContext;
@Data
@Builder
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class GridInfo {
// 常量定义(1度=3600秒)
private static final BigDecimal SECONDS_PER_DEGREE = new BigDecimal("3600");
private static final BigDecimal SECONDS_PER_MINUTE = new BigDecimal("60");
// 纬度步长常量定义(单位:秒)
private static final BigDecimal[] LON_STEPS = {
// level 1: 6°=6*3600=21600秒
new BigDecimal("6").multiply(SECONDS_PER_DEGREE),
// level 2: 30'=30*60=1800秒
new BigDecimal("30").multiply(SECONDS_PER_MINUTE),
// level 3: 15'=15*60=900秒
new BigDecimal("15").multiply(SECONDS_PER_MINUTE),
// level 4: 1'=1*60=60秒
SECONDS_PER_MINUTE,
// level 5: 4秒
new BigDecimal("4"),
// level 6: 2秒
new BigDecimal("2"),
// level 7: 0.25秒
new BigDecimal("0.25"),
// level 8: 1/32秒=0.03125秒
new BigDecimal("1").divide(new BigDecimal("32"), MathContext.DECIMAL128),
// level 9: 1/256秒=0.00390625秒
new BigDecimal("1").divide(new BigDecimal("256"), MathContext.DECIMAL128),
// level 10: 1/2048秒=0.00048828125秒
new BigDecimal("1").divide(new BigDecimal("2048"), MathContext.DECIMAL128)
};
// 经度步长常量定义(单位:秒)
private static final BigDecimal[] LAT_STEPS = {
// level 1: 4°=4*3600=14400秒
new BigDecimal("4").multiply(SECONDS_PER_DEGREE),
// level 2: 30'=30*60=1800秒
new BigDecimal("30").multiply(SECONDS_PER_MINUTE),
// level 3: 10'=10*60=600秒
new BigDecimal("10").multiply(SECONDS_PER_MINUTE),
// level 4: 1'=60秒
SECONDS_PER_MINUTE,
// level 5: 4秒
new BigDecimal("4"),
// level 6: 2秒
new BigDecimal("2"),
// level 7: 0.25秒
new BigDecimal("0.25"),
// level 8: 1/32秒=0.03125秒
new BigDecimal("1").divide(new BigDecimal("32"), MathContext.DECIMAL128),
// level 9: 1/256秒=0.00390625秒
new BigDecimal("1").divide(new BigDecimal("256"), MathContext.DECIMAL128),
// level 10: 1/2048秒=0.00048828125秒
new BigDecimal("1").divide(new BigDecimal("2048"), MathContext.DECIMAL128)
};
/**
* 初始经度
*/
private BigDecimal baseLon;
/**
* 初始纬度
*/
private BigDecimal baseLat;
/**
* 左下角经度
*/
private BigDecimal currentLon;
/**
* 左下角纬度
*/
private BigDecimal currentLat;
/**
* 当前列号
*/
private int column;
/**
* 当前行号
*/
private int row;
/**
* 网格粒度经度
*/
private BigDecimal gridStepLon;
/**
* 网格粒度纬度
*/
private BigDecimal gridStepLat;
/**
* 网格粒度
*/
private int gridStep = 1;
/**
* 网格编码
*/
private String gridCode;
public BigDecimal getGridStepLon() {
if (gridStep < 1 || gridStep > LON_STEPS.length) {
throw new BeidouGridException("编码级别超出范围: " + gridStep);
}
return LON_STEPS[gridStep - 1];
}
public BigDecimal getGridStepLat() {
if (gridStep < 1 || gridStep > LON_STEPS.length) {
throw new BeidouGridException("编码级别超出范围: " + gridStep);
}
return LAT_STEPS[gridStep - 1];
}
}
2. 计算第一级网格
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
/**
* 计算第一级北斗网格编码
*
* @param longitude 经度(单位:秒)
* @param latitude 纬度(单位:秒)
* @param level 编码级别(1-10)
* @return 网格信息对象
*/
public static GridInfo calculateFirstLevelCode(BigDecimal longitude, BigDecimal latitude) {
// 校验经纬度是否在有效范围内(经度:-180°~180°,纬度:-88°~88°),非两级区域
if (longitude.doubleValue() < -180 * 3600 || longitude.doubleValue() > 180 * 3600 ||
latitude.doubleValue() < -88 * 3600 || latitude.doubleValue() > 88 * 3600) {
throw new BeidouGridException("经纬度超出范围");
}
// 创建初始网格信息对象
GridInfo gridInfo = GridInfo.builder()
.baseLon(longitude)
.baseLat(latitude)
.currentLon(longitude)
.currentLat(latitude)
.gridStep(1)
.build();
// 北斗网格编码使用的32进制字符集
char[] rowChars = "ABCDEFGHIJKLMNOPQRSTUV".toCharArray();
// 计算第一级码元
char hemisphere = latitude.compareTo(BigDecimal.ZERO) >= 0 ? 'N' : 'S';
// 计算经度方向编号(列号,第二位码元)
int column = longitude
.add(BigDecimal.valueOf(180 * 3600)) // 加上东经180°的偏移量
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.add(BigDecimal.ONE)
.intValue();
// 计算纬度方向编号(行号)
int row = latitude.abs()
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.add(BigDecimal.ONE)
.intValue();
// 将纬度编号映射到对应的字母(第三位码元)
char rowChar;
rowChar = rowChars[row - 1];
// 返回更新后的网格信息
return gridInfo.setColumn(column)
.setRow(row)
.setGridCode(String.format("%c%02d%c", hemisphere, column, rowChar));
}
3.2 第二级网格实现
3.2.1 规范解析
第二级网格是将第一级 6° x 4° 网格,按照经纬度等分,分成 12 x 8 个第二级网格,对应于 30' x 30' 网格,约等于地球赤道处 55.66 km x 55.66 km 网格。其对应第五、六位码元。其中,第五位码元标识经度方向网格,用0~B编码;第六位码元标识纬度方向网格,用0~7编码。

因此,先求出第一级网格码定位角的位置,即经度为第二、三位码元(东半球则减一) × 6°,纬度为(第四位码元(映射到数字)- 1)× 4°,由此得出一级网格码位置为:西北半球(-114°, 36°),东北半球(114°, 36°),西南半球(-114°, -36°),东南半球(114°, -36°)。再将一级网格码分成 12 x 8 个第二级网格,则他们所在二级网格码的位置如图所示:




最后再用经(纬)度减去第一级网格码的定位角经(纬)度的差,除以网格步长(30' x 30'),加一,则得出最终的行列号。
3.2.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第二级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateSecondLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789AB".toCharArray();
char[] rowChars = "01234567".toCharArray();
// 计算第一级网格码定位角的坐标
BigDecimal baseLongitude = (longitude.compareTo(BigDecimal.ZERO) < 0 ?
new BigDecimal(gridInfo.getColumn()) :
new BigDecimal(gridInfo.getColumn() - 1))
.multiply(gridInfo.getGridStepLon())
.subtract(new BigDecimal(180 * 3600));
BigDecimal baseLatitude = new BigDecimal(gridInfo.getRow())
.subtract(BigDecimal.ONE)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)));
// 更新网格粒度级别
gridInfo.setGridStep(2);
// 计算第二级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(),
columnChars[column - 1], rowChars[row - 1]));
}
3.3 第三级网格实现
3.3.1 规范解析
第三级网格是将第二级网格按照经纬度等分,分成2x3个第三级网格,对应于 1:5 万地图图幅 15'x10' 网格,约等于地球赤道处 27.83 km x 18.55 km 网格。其对应第七位码元,编码顺序按照Z序采用0~5编码,Z编码方向与第三级网格所在半球相关,详见下图:

因此,先求出第二级网格码定位角的位置,即用二级网格列(行)号减一的差,乘二级网格粒度(根据所在的半球取正负),最后再加上第一级网格码定位角经(纬)度。下一步将经(纬)度与第二级网格码定位角的经(纬)度作差,再除以第三级网格粒度得出最终的行列号。




3.3.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第三级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateThirdLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 构建Z序编码矩阵(3列×2行),用于空间填充曲线编码
int[][] zOrderMatrix = {
{0, 2, 4},
{1, 3, 5}
};
// 计算第二级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 设置当前网格粒度级别为3
gridInfo.setGridStep(3);
// 计算第三级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%d", gridInfo.getGridCode(), zOrderMatrix[column][row]));
}
3.4 第四级网格实现
3.4.1 规范解析
第四级网格是将第三级网格按照经纬度等分,划分成 15 × 10 个第四级网格,约等于地球赤道处 1.85 km × 1.85 km 网格,其对应第八、九级码元。其中,第八位码元标识经度方向网格,用0~E编码;第九位码元标识纬度方向网格,用 0 ~ 9 编码。第四级网格码元编码方向与该网格所在半球相关,如图所示:

因此,先求出第三级网格码定位角的位置,思路同第三级网格。下一步将经(纬)度与第二级网格码定位角的经(纬)度作差,再除以第三级网格粒度得出最终的行列号。




3.4.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第四级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateForthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789".toCharArray();
// 计算第三级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn())
.multiply(gridInfo.getGridStepLon()
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO)))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow())
.multiply(gridInfo.getGridStepLat()
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)))));
// 设置当前网格粒度级别为4
gridInfo.setGridStep(4);
// 计算第四级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
3.5 第五级网格实现
3.5.1 规范解析
第五级网格是将第四级网格按照经纬度等分,划分成 15 × 15 个第五级网格,约等于地球赤道处 123.69 m × 123.69 m 网格,其对应第十、十一位码元,均用 0 ~ E 编码,编码方向同第四级网格。
因此,代码实现思路同第四级网格。




3.5.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第五级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateFifthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789ABCDE".toCharArray();
// 计算第四级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon()
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO)))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat()
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)))));
// 设置当前网格粒度级别为5
gridInfo.setGridStep(5);
// 计算第五级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
3.6 第六级网格实现
3.6.1 规范解析
第六级网格是将第五级网格按照经纬度等分,划分成 2 × 2 个第六级网格,约等于地球赤道处 61.84 m × 61.84 m 网格,其对应第十二位码元。编码顺序按照 Z 序采用 0 ~ 3 编码,Z 编码方向与第六级网格所在半球相关,如下图所示:

因此,代码实现思路同第三级网格。




3.6.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第六级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateSixthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 构建 2x2 Z序编码矩阵
int[][] zOrderMatrix = {
{0, 2},
{1, 3}
};
// 计算第五级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon()
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO)))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat()
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)))));
// 更新网格粒度级别为6
gridInfo.setGridStep(6);
// 计算第六级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs().intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs().intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%d", gridInfo.getGridCode(), zOrderMatrix[column][row]));
}
3.7 第七级网格实现
3.7.1 规范解析
第六级网格是将第五级网格按照经纬度等分,划分成 8 × 8 个第七级网格,约等于地球赤道处 7.73 m × 7.73 m网格,其对应第十三、十四位码元,均用 0 ~ 7 编码,编码方向与该网格所在半球相关,如下图所示:

因此,代码实现思路同第四级网格。



3.7.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第七级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
public static GridInfo calculateSeventhLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789ABCDE".toCharArray();
// 计算第六级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn())
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow())
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 设置当前网格粒度级别为7
gridInfo.setGridStep(7);
// 计算第七级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
3.8 第八 ~ 十级网格实现
3.8.1 规范解析
均基于上一级网格,按照经纬度等分,划分成 8 × 8 个网格,各级各占两个码元。
因此,代码实现思路同第五级网格。
3.8.2 代码实现
import com.zjp.entity.GridInfo;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 计算第八级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
private static GridInfo calculateEighthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789ABCDE".toCharArray();
// 计算第七级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 更新网格粒度级别为8
gridInfo.setGridStep(8);
// 计算第八级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
/**
* 计算第九级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
private static GridInfo calculateNinthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789ABCDE".toCharArray();
// 计算第八级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 更新网格粒度级别为9
gridInfo.setGridStep(9);
// 计算第九级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
/**
* 计算第十级北斗网格编码
*
* @param gridInfo 网格信息对象
* @return 网格信息对象
*/
private static GridInfo calculateTenthLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789ABCDE".toCharArray();
char[] rowChars = "0123456789ABCDE".toCharArray();
// 计算第九级网格码定位角的坐标
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 设置当前网格粒度级别为10
gridInfo.setGridStep(10);
// 计算第十级网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(), columnChars[column - 1], rowChars[row - 1]));
}
3.9 代码汇总
1. 创建异常类:
public class BeidouGridException extends RuntimeException{
private static final long serialVersionUID = 1L;
public BeidouGridException() {
}
public BeidouGridException(String message) {
super(message);
}
public BeidouGridException(String message, Throwable cause) {
super(message, cause);
}
public BeidouGridException(Throwable cause) {
super(cause);
}
public BeidouGridException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2. 创建网格信息实体类:
import com.zjp.exceptions.BeidouGridException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.math.MathContext;
@Data
@Builder
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class GridInfo {
// 常量定义(1度=3600秒)
private static final BigDecimal SECONDS_PER_DEGREE = new BigDecimal("3600");
private static final BigDecimal SECONDS_PER_MINUTE = new BigDecimal("60");
// 纬度步长常量定义(单位:秒)
private static final BigDecimal[] LON_STEPS = {
// level 1: 6°=6*3600=21600秒
new BigDecimal("6").multiply(SECONDS_PER_DEGREE),
// level 2: 30'=30*60=1800秒
new BigDecimal("30").multiply(SECONDS_PER_MINUTE),
// level 3: 15'=15*60=900秒
new BigDecimal("15").multiply(SECONDS_PER_MINUTE),
// level 4: 1'=1*60=60秒
SECONDS_PER_MINUTE,
// level 5: 4秒
new BigDecimal("4"),
// level 6: 2秒
new BigDecimal("2"),
// level 7: 0.25秒
new BigDecimal("0.25"),
// level 8: 1/32秒=0.03125秒
new BigDecimal("1").divide(new BigDecimal("32"), MathContext.DECIMAL128),
// level 9: 1/256秒=0.00390625秒
new BigDecimal("1").divide(new BigDecimal("256"), MathContext.DECIMAL128),
// level 10: 1/2048秒=0.00048828125秒
new BigDecimal("1").divide(new BigDecimal("2048"), MathContext.DECIMAL128)
};
// 经度步长常量定义(单位:秒)
private static final BigDecimal[] LAT_STEPS = {
// level 1: 4°=4*3600=14400秒
new BigDecimal("4").multiply(SECONDS_PER_DEGREE),
// level 2: 30'=30*60=1800秒
new BigDecimal("30").multiply(SECONDS_PER_MINUTE),
// level 3: 10'=10*60=600秒
new BigDecimal("10").multiply(SECONDS_PER_MINUTE),
// level 4: 1'=60秒
SECONDS_PER_MINUTE,
// level 5: 4秒
new BigDecimal("4"),
// level 6: 2秒
new BigDecimal("2"),
// level 7: 0.25秒
new BigDecimal("0.25"),
// level 8: 1/32秒=0.03125秒
new BigDecimal("1").divide(new BigDecimal("32"), MathContext.DECIMAL128),
// level 9: 1/256秒=0.00390625秒
new BigDecimal("1").divide(new BigDecimal("256"), MathContext.DECIMAL128),
// level 10: 1/2048秒=0.00048828125秒
new BigDecimal("1").divide(new BigDecimal("2048"), MathContext.DECIMAL128)
};
/**
* 初始经度
*/
private BigDecimal baseLon;
/**
* 初始纬度
*/
private BigDecimal baseLat;
/**
* 左下角经度
*/
private BigDecimal currentLon;
/**
* 左下角纬度
*/
private BigDecimal currentLat;
/**
* 当前列号
*/
private int column;
/**
* 当前行号
*/
private int row;
/**
* 网格粒度经度
*/
private BigDecimal gridStepLon;
/**
* 网格粒度纬度
*/
private BigDecimal gridStepLat;
/**
* 网格粒度
*/
private int gridStep = 1;
/**
* 网格编码
*/
private String gridCode;
public BigDecimal getGridStepLon() {
if (gridStep < 1 || gridStep > LON_STEPS.length) {
throw new BeidouGridException("编码级别超出范围: " + gridStep);
}
return LON_STEPS[gridStep - 1];
}
public BigDecimal getGridStepLat() {
if (gridStep < 1 || gridStep > LON_STEPS.length) {
throw new BeidouGridException("编码级别超出范围: " + gridStep);
}
return LAT_STEPS[gridStep - 1];
}
}
3. 创建工具类:
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class GridEncoder<T> {
private final Map<Integer, Function<T, T>> encoders = new HashMap<>();
public void register(int level, Function<T, T> encoder) {
encoders.put(level, encoder);
}
public Function<T, T> get(int level) {
return encoders.get(level);
}
}
4. 北斗网格位置码工具类:
import cn.hutool.core.lang.Assert;
import com.zjp.exceptions.BeidouGridException;
import com.zjp.pojo.GridInfo;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.function.Function;
@Slf4j
@UtilityClass
public class BeidouGridUtil {
// 2D编码策略
private static final GridEncoder<GridInfo> GRID_ENCODER_2D = new GridEncoder<>();
static {
// 注册2D编码器
register2DEncoders();
}
/**
* 注册所有2D编码器
*/
private void register2DEncoders() {
GRID_ENCODER_2D.register(1, BeidouGridUtil::calculate2DFirstLevelCode);
GRID_ENCODER_2D.register(2, BeidouGridUtil::calculate2DSecondLevelCode);
GRID_ENCODER_2D.register(3, BeidouGridUtil::calculate2DThirdLevelCode);
GRID_ENCODER_2D.register(4, BeidouGridUtil::calculate2DForthLevelCode);
GRID_ENCODER_2D.register(5, BeidouGridUtil::calculate2DFifthLevelCode);
GRID_ENCODER_2D.register(6, BeidouGridUtil::calculate2DSixthLevelCode);
GRID_ENCODER_2D.register(7, BeidouGridUtil::calculate2DSeventhLevelCode);
GRID_ENCODER_2D.register(8, BeidouGridUtil::calculate2DEighthLevelCode);
GRID_ENCODER_2D.register(9, BeidouGridUtil::calculate2DNinthLevelCode);
GRID_ENCODER_2D.register(10, BeidouGridUtil::calculate2DTenthLevelCode);
}
/**
* 生成二维北斗网格码
*
* @param longitude 经度(单位:秒)
* @param latitude 纬度(单位:秒)
* @param level 编码级别(1-10)
* @return 北斗网格编码
*/
public String generate2DGridCode(BigDecimal longitude, BigDecimal latitude, int level) {
validateCoordinates(longitude.doubleValue(), latitude.doubleValue());
validateLevel(level);
GridInfo gridInfo = createInitialGridInfo(longitude, latitude);
for (int i = 1; i <= level; i++) {
Function<GridInfo, GridInfo> encoder = GRID_ENCODER_2D.get(i);
if (encoder == null) {
throw new BeidouGridException("不支持的编码级别: " + i);
}
gridInfo = encoder.apply(gridInfo);
}
return gridInfo.getGridCode();
}
/**
* 校验经纬度是否在有效范围内(经度:-180°~180°,纬度:-88°~88°),不包含极地
*
* @param longitude 经度(单位:秒)
* @param latitude 纬度(单位:秒)
*/
private void validateCoordinates(double longitude, double latitude) {
if (longitude < -180 * 3600 || longitude > 180 * 3600 ||
latitude < -88 * 3600 || latitude > 88 * 3600) {
throw new BeidouGridException("经纬度超出范围");
}
}
/**
* 校验编码级别是否在有效范围内(1-10)
*
* @param level 编码级别
*/
private void validateLevel(int level) {
if (level < 1 || level > 10) {
throw new BeidouGridException("编码级别超出范围: " + level);
}
}
/**
* 创建初始网格信息对象(用于二维编码)
*
* @param longitude 初始经度(单位:秒)
* @param latitude 初始纬度(单位:秒)
* @return 初始化后的 GridInfo 对象
*/
private GridInfo createInitialGridInfo(BigDecimal longitude, BigDecimal latitude) {
return GridInfo.builder()
.baseLon(longitude)
.baseLat(latitude)
.currentLon(longitude)
.currentLat(latitude)
.gridStep(1)
.build();
}
/**
* 计算第一级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DFirstLevelCode(GridInfo gridInfo) {
// 获取基础经纬度(单位:秒)
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 北斗网格编码使用的32进制字符集
char[] rowChars = "ABCDEFGHIJKLMNOPQRSTUV".toCharArray();
// 判断半球并计算绝对纬度值
char hemisphere = latitude.compareTo(BigDecimal.ZERO) >= 0 ? 'N' : 'S';
// 计算经度方向编号(列号)
int column = longitude
.add(BigDecimal.valueOf(180 * 3600)) // 加上东经180°的偏移量
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.add(BigDecimal.ONE)
.intValue();
// 计算纬度方向编号(行号)
int row = latitude.abs()
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.add(BigDecimal.ONE)
.intValue();
// 将纬度编号映射到对应的字母(1->A, 2->B,...)
char rowChar;
rowChar = rowChars[row - 1];
// 返回更新后的网格信息
return gridInfo.setColumn(column)
.setRow(row)
.setGridCode(String.format("%c%02d%c", hemisphere, column, rowChar));
}
/**
* 计算第二级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DSecondLevelCode(GridInfo gridInfo) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 定义编码字符集
char[] columnChars = "0123456789AB".toCharArray();
char[] rowChars = "01234567".toCharArray();
// 计算基准经度λ₁和纬度φ₁
BigDecimal baseLongitude = (longitude.compareTo(BigDecimal.ZERO) < 0 ?
new BigDecimal(gridInfo.getColumn()) :
new BigDecimal(gridInfo.getColumn() - 1))
.multiply(gridInfo.getGridStepLon())
.subtract(new BigDecimal(180 * 3600));
BigDecimal baseLatitude = new BigDecimal(gridInfo.getRow())
.subtract(BigDecimal.ONE)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)));
// 更新网格粒度级别
gridInfo.setGridStep(2);
// 计算子网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE).intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.add(BigDecimal.ONE)
.intValue();
// 更新网格信息
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c", gridInfo.getGridCode(),
columnChars[column - 1], rowChars[row - 1]));
}
/**
* 计算第三级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DThirdLevelCode(GridInfo gridInfo) {
int[][] zOrderMatrix = {
{0, 2, 4},
{1, 3, 5}
};
return calculate2DLevelCode(gridInfo, 3, zOrderMatrix);
}
/**
* 计算第四级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DForthLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 4, false, false, true,
"0123456789ABCDE".toCharArray(),
"0123456789".toCharArray());
}
/**
* 计算第五级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DFifthLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 5, true, true, true,
"0123456789ABCDE".toCharArray(),
"0123456789ABCDE".toCharArray());
}
/**
* 计算第六级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DSixthLevelCode(GridInfo gridInfo) {
int[][] zOrderMatrix = {
{0, 2},
{1, 3}
};
return calculate2DLevelCode(gridInfo, 6, zOrderMatrix);
}
/**
* 计算第七级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DSeventhLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 7, false, false, true,
"0123456789ABCDE".toCharArray(),
"0123456789ABCDE".toCharArray());
}
/**
* 计算第八级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DEighthLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 8, true, true, true,
"0123456789ABCDE".toCharArray(),
"0123456789ABCDE".toCharArray());
}
/**
* 计算第九级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DNinthLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 9, true, true, true,
"0123456789ABCDE".toCharArray(),
"0123456789ABCDE".toCharArray());
}
/**
* 计算第十级北斗网格编码(二维)
*
* @param gridInfo 网格信息对象
* @return 包含计算结果的网格信息对象
*/
private GridInfo calculate2DTenthLevelCode(GridInfo gridInfo) {
return calculate2DLevelCode(gridInfo, 10, true, true, true,
"0123456789ABCDE".toCharArray(),
"0123456789ABCDE".toCharArray());
}
/**
* 通用的二维北斗网格编码计算方法
*
* @param gridInfo 网格信息对象,包含网格的基本信息和当前状态
* @param level 粒度级别,用于确定网格的细分程度
* @param zOrderMatrix Z字形矩阵,用于确定网格在二维平面上的编码
* @return 返回更新后的网格信息对象
*/
private GridInfo calculate2DLevelCode(GridInfo gridInfo, int level, int[][] zOrderMatrix) {
// 获取网格基本信息
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 计算当前粒度级别的基准经纬度 λ₁, φ₁
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(gridInfo.getColumn() - 1)
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(gridInfo.getRow() - 1)
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 设置当前网格粒度级别
gridInfo.setGridStep(level);
// 计算子网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.intValue();
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%d",
gridInfo.getGridCode(),
zOrderMatrix[column][row]));
}
/**
* 通用的二维北斗网格编码计算方法
*
* @param gridInfo 网格信息对象
* @param level 当前网格粒度级别
* @param useMinusOneForColumn 是否使用 column - 1 计算基准经度
* @param useMinusOneForRow 是否使用 row - 1 计算基准纬度
* @param addOneForSubGridCalc 是否在子网格列号和行号计算时加 1
* @param columnChars 列号字符集
* @param rowChars 行号字符集
* @return 更新后的 GridInfo 对象
*/
private GridInfo calculate2DLevelCode(GridInfo gridInfo,
int level,
boolean useMinusOneForColumn,
boolean useMinusOneForRow,
boolean addOneForSubGridCalc,
char[] columnChars,
char[] rowChars) {
BigDecimal longitude = gridInfo.getBaseLon();
BigDecimal latitude = gridInfo.getBaseLat();
// 计算当前粒度级别的基准经纬度 λ₁, φ₁
BigDecimal baseLongitude = gridInfo.getCurrentLon()
.add(new BigDecimal(useMinusOneForColumn ? gridInfo.getColumn() - 1 : gridInfo.getColumn())
.multiply(gridInfo.getGridStepLon())
.multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));
BigDecimal baseLatitude = gridInfo.getCurrentLat()
.add(new BigDecimal(useMinusOneForRow ? gridInfo.getRow() - 1 : gridInfo.getRow())
.multiply(gridInfo.getGridStepLat())
.multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));
// 设置当前网格粒度级别
gridInfo.setGridStep(level);
// 计算子网格列号和行号
int column = longitude
.subtract(baseLongitude)
.divide(gridInfo.getGridStepLon(), 0, RoundingMode.DOWN)
.abs()
.intValue();
int row = latitude
.subtract(baseLatitude)
.divide(gridInfo.getGridStepLat(), 0, RoundingMode.DOWN)
.abs()
.intValue();
// 是否加 1
if (addOneForSubGridCalc) {
column = column + 1;
row = row + 1;
}
// 更新网格信息并返回
return gridInfo.setCurrentLon(baseLongitude)
.setCurrentLat(baseLatitude)
.setColumn(column)
.setRow(row)
.setGridCode(String.format("%s%c%c",
gridInfo.getGridCode(),
columnChars[column - 1],
rowChars[row - 1]));
}


3485

被折叠的 条评论
为什么被折叠?



