当前位置: 首页 > news >正文

北斗网格位置码详解:经纬度到二维网格码的转换(非极地)

在全球定位系统(GPS)和北斗卫星导航系统(BDS)的发展下,经纬度坐标已经成为描述地球表面位置的标准方式。然而,在某些特定的应用场景中,如城市交通管理、物流配送、无人机路径规划等,直接使用经纬度坐标存在一些局限性,例如数据量大、查询效率低等问题。
北斗网格码是一种基于地理位置的编码系统,它将地球表面划分为多个层级的网格,并为每个网格分配唯一的编码。这种编码方式可以有效地压缩地理数据,提高空间索引的效率,便于大规模地理数据的管理和分析。

规范见百度百科内容范围章节图片:北斗网格位置码_百度百科

1. 北斗网格位置码介绍

北斗网格位置码是利用北斗卫星导航系统的定位能力,对地球表面进行分层划分的一种网格编码方式。每个网格都有一个唯一的标识符,该标识符可以表示一定范围内的地理位置信息。其主要特点包括:

  1. 唯一性:每个网格编码在整个地球上是唯一的。
  2. 层级性:网格可以按照精度需求进行多级细分,例如从大区域到小区域逐步细化。
  3. 高效性:通过网格编码,可以快速检索和管理地理数据,提升查询效率。

2. 经纬度与北斗网格编码的关系

经纬度是以地球的经线和纬线为基础的坐标系统,用于描述地球上的任意一点。而北斗网格编码则是将这些点映射到特定的网格中,从而实现更高效的管理和计算。其转换原理为:

  1. 定义网格大小:根据应用需求,定义不同级别的网格大小。
  2. 划分网格:将经纬度范围按照预设的网格大小划分为若干个矩形或正方形网格。
  3. 生成编码:为每个网格分配一个唯一的编码。编码规则可以根据需要设计,例如使用二进制编码、十进制编码或其他自定义编码格式。
  4. 转换算法:根据给定的经纬度,确定其所在的网格,并返回对应的编码。

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;if (latitude.compareTo(BigDecimal.ZERO) < 0) {// 南半球使用倒序映射rowChar = rowChars[rowChars.length - row];} else {// 北半球使用正常映射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(),rowChars[column - 1], columnChars[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))));// 设置当前网格粒度级别为3gridInfo.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)))));// 设置当前网格粒度级别为4gridInfo.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(), rowChars[column - 1], columnChars[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)))));// 设置当前网格粒度级别为5gridInfo.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(), rowChars[column - 1], columnChars[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)))));// 更新网格粒度级别为6gridInfo.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))));// 设置当前网格粒度级别为7gridInfo.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(), rowChars[column - 1], columnChars[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))));// 更新网格粒度级别为8gridInfo.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(), rowChars[column - 1], columnChars[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))));// 更新网格粒度级别为9gridInfo.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(), rowChars[column - 1], columnChars[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))));// 设置当前网格粒度级别为10gridInfo.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(), rowChars[column - 1], columnChars[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;if (latitude.compareTo(BigDecimal.ZERO) < 0) {// 南半球使用倒序映射rowChar = rowChars[rowChars.length - row];} else {// 北半球使用正常映射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(),rowChars[column - 1], columnChars[row - 1]));}/*** 计算第三级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DThirdLevelCode(GridInfo gridInfo) {BigDecimal longitude = gridInfo.getBaseLon();BigDecimal latitude = gridInfo.getBaseLat();// 构建Z序编码矩阵(3列×2行),用于空间填充曲线编码int[][] zOrderMatrix = {{0, 2, 4},{1, 3, 5}};// 计算当前网格的基准经纬度 λ₁, φ₁// λ₁ = 左下角经度 + (二级网格列号 - 1) * 二级网格粒度经度 * 符号BigDecimal baseLongitude = gridInfo.getCurrentLon().add(new BigDecimal(gridInfo.getColumn() - 1).multiply(gridInfo.getGridStepLon()).multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO))));// φ₁ = 左下角纬度 + (二级网格行号 - 1) * 二级网格粒度纬度 * 符号BigDecimal baseLatitude = gridInfo.getCurrentLat().add(new BigDecimal(gridInfo.getRow() - 1).multiply(gridInfo.getGridStepLat()).multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO))));// 设置当前网格粒度级别为3gridInfo.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]));}/*** 计算第四级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DForthLevelCode(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)))));// 设置当前网格粒度级别为4gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}/*** 计算第五级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DFifthLevelCode(GridInfo gridInfo) {BigDecimal longitude = gridInfo.getBaseLon();BigDecimal latitude = gridInfo.getBaseLat();// 定义编码字符集(十六进制)char[] columnChars = "0123456789ABCDE".toCharArray();char[] rowChars = "0123456789ABCDE".toCharArray();// 计算当前网格的基准经纬度 λ₁, φ₁// λ₁ = 左下角经度 + (当前列号 - 1) * 当前网格粒度经度BigDecimal baseLongitude = gridInfo.getCurrentLon().add(new BigDecimal(gridInfo.getColumn() - 1).multiply(gridInfo.getGridStepLon().multiply(BigDecimal.valueOf(longitude.compareTo(BigDecimal.ZERO)))));// φ₁ = 左下角纬度 + (当前行号 - 1) * 当前网格粒度纬度 * 符号BigDecimal baseLatitude = gridInfo.getCurrentLat().add(new BigDecimal(gridInfo.getRow() - 1).multiply(gridInfo.getGridStepLat().multiply(BigDecimal.valueOf(latitude.compareTo(BigDecimal.ZERO)))));// 设置当前网格粒度级别为5gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}/*** 计算第六级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DSixthLevelCode(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)))));// 更新网格粒度级别为6gridInfo.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]));}/*** 计算第七级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DSeventhLevelCode(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))));// 设置当前网格粒度级别为7gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}/*** 计算第八级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DEighthLevelCode(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))));// 更新网格粒度级别为8gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}/*** 计算第九级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DNinthLevelCode(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))));// 更新网格粒度级别为9gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}/*** 计算第十级北斗网格编码(二维)** @param gridInfo 网格信息对象* @return 包含计算结果的网格信息对象*/private GridInfo calculate2DTenthLevelCode(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))));// 设置当前网格粒度级别为10gridInfo.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(), rowChars[column - 1], columnChars[row - 1]));}
http://www.dtcms.com/a/286938.html

相关文章:

  • 针对BERT模型的理解
  • 04-三思而后行:解锁AI的“内心戏”
  • VMware安装Win10教程(附安装包)虚拟机下载详细安装图文教程
  • chainlink VRF中文教程(含mock),解决error: Arithmetic Underflow in createSubscription
  • bmp图像操作:bmp图像保存及raw与bmp转换
  • 二分答案之第 K 小/大
  • CMake指令:常见内置命令行工具( CMake -E )
  • 乙烯丙烯酸酯橡胶市场报告:性能优势、行业现状与发展前景​
  • selenium后续!!
  • 【数据集】1970-2023年全球温室气体排放 GHG 数据集 EDGAR
  • 语音直播和视频直播的测试要点
  • 【ROS1】06-ROS通信机制——话题通信
  • OOA、OOD 与 OOP:面向对象范式的核心支柱详解
  • 接口测试的原则、用例与流程详解
  • ModelSim 配合 Makefile 搭建 Verilog 仿真工程
  • Docker-下载和安装
  • ADVB协议内容分析
  • LeetCode Hot100【6. Z 字形变换】
  • GI6E 加密GRID電碼通信SHELLCODE載入
  • CCF编程能力等级认证GESP—C++3级—20250628
  • 操作系统-处理机调度和死锁进程同步
  • 基于Qwen2.5-3B-Instruct的LoRA微调与推理实战指南
  • 多线程-3-线程同步
  • HTTPie: 开发者友好的http客户端工具
  • 数据排序
  • 特种作业操作证(制冷空调)的考试科目有哪些?
  • Xilinx Zynq:一款适用于软件定义无线电的现代片上系统
  • 使用 C# 实现移动加权平均(Weighted Moving Average)算法
  • java基础-5 : 面向对象
  • python网络爬虫(第三章/共三章:驱动浏览器窗口界面,网页元素定位,模拟用户交互(输入操作、点击操作、文件上传),浏览器窗口切换,循环爬取存储)