二维北斗网格码将地球表面划分为多层网格用 20 个字符就能精确到 0.24 米。但在无人机航路规划、空域管理等场景中仅有平面定位是不够的——还需要高度维度。北斗三维网格位置码在二维编码的基础上增加了一组高程编码形成[二维网格码] [高程码]交替穿插的结构总共约 46 个字符可精确描述三维空间中的一个网格单元。二维编码原理见前文经纬度转北斗网格位置码非极地区域编码篇-CSDN博客规范参考北斗网格位置码一、三维编码结构总览北斗三维网格码 二维网格码 高程码两者逐级交替拼接二维部分已在上一篇文章中详细讲解本文重点介绍高程编码。二、高程编码规则2.1 高程码结构高程码共 12 位码元嵌入到各级二维网格码之间码元位置对应级别取值范围进制二进制位段第1位—0地上/ 1地下二进制bit[0]第2~3位第1级00~63十进制bit[1,7)第4位第2级0~7八进制bit[7,10)第5位第3级0~1二进制bit[10,11)第6位第4级0~9, A~E十六进制bit[11,15)第7位第5级0~9, A~E十六进制bit[15,19)第8位第6级0~1二进制bit[19,20)第9位第7级0~7八进制bit[20,23)第10位第8级0~7八进制bit[23,26)第11位第9级0~7八进制bit[26,29)第12位第10级0~7八进制bit[29,32)2.2 高程计算原理高程编码的核心思想将海拔高度映射为一个 32 位二进制整数然后按位段截取并转换进制。计算公式来自规范 C.12 和 C.142.3 举例以海拔 100m 为例n ≈ 7229440 32位二进制: 00000000011011100101000000000000 ─┬─────┬──┬─┬────┬────┬─┬───┬───┬───┬─── │ │ │ │ │ │ │ │ │ │ 地上/下 1级 2级 3级 4级 5级 6级 7级 8级 9级 10级按位段截取并转进制位段二进制值转进制高程码bit[0]0—0地上bit[1,7)000000十进制00bit[7,10)011八进制3bit[10,11)0二进制0............三、完整实现常量定义// 各级经度步长秒 private static final double[] COL_STEP { 0, 21600, 1800, 900, 60, 4, 2, 0.25, 1.0/32, 1.0/256, 1.0/2048 }; // 各级纬度步长秒 private static final double[] ROW_STEP { 0, 14400, 1800, 600, 60, 4, 2, 0.25, 1.0/32, 1.0/256, 1.0/2048 }; // 各级子网格列数 private static final int[] COL_NUM { 0, 60, 12, 2, 15, 15, 2, 8, 8, 8, 8 }; // 是否使用Z字形编码 private static final boolean[] ZIGZAG { false, false, false, true, false, false, true, false, false, false, false }; // 高程编码常量 private static final double EARTH_RADIUS 6378137.0; private static final double THETA_0 Math.PI / 180.0; private static final double LOG_THETA Math.log(1.0 THETA_0); private static final double HEIGHT_GRID_STEP 1.0 / (2048.0 * 3600.0); // 各级高程码在32位二进制中的起止位置 private static final int[] H_START {0, 0, 7, 10, 11, 15, 19, 20, 23, 26, 29}; private static final int[] H_END {0, 7, 10, 11, 15, 19, 20, 23, 26, 29, 32}; // 各级高程码的进制 private static final int[] H_RADIX {0, 0, 8, 2, 16, 16, 2, 8, 8, 8, 8};代码实现逻辑/** * 将经纬度和高程编码为三维北斗网格码 * * param lon 经度度 * param lat 纬度度 * param alt 高程米 * param level 编码级别1-10 * return 三维北斗网格编码 */ public String encode(double lon, double lat, double alt, int level) { if (lon -180.0 || lon 180.0) { throw new BeidouGridException(经度超出范围: lon); } if (lat -88.0 || lat 88.0) { throw new BeidouGridException(纬度超出范围: lat); } if (alt -6302106.722602182 || alt 528680171.1252437) { throw new BeidouGridException(高程超出范围: alt); } if (level 1 || level 10) { throw new BeidouGridException(编码级别超出范围: level); } String hBits calcHeightBits(alt); StringBuilder buf new StringBuilder(40); buf.append(lat 0.0 ? N : S); double absLon Math.abs(lon) * 3600; double absLat Math.abs(lat) * 3600; double refLon 0, refLat 0; for (int lv 1; lv level; lv) { double cellW COL_STEP[lv]; double cellH ROW_STEP[lv]; int col (int) ((absLon - refLon) / cellW); int row (int) ((absLat - refLat) / cellH); refLon col * cellW; refLat row * cellH; String layer extractLayer(hBits, lv); if (lv 1) { int num lon 0 ? (COL_NUM[1] 1) - col : (COL_NUM[1] 1) col 1; buf.append(layer.charAt(0)); if (num 10) buf.append(0); buf.append(num).append((char) (A row)); buf.append(layer.substring(1)); } else if (ZIGZAG[lv]) { buf.append(col row * COL_NUM[lv]); buf.append(layer); } else { buf.append(Integer.toHexString(col).toUpperCase()) .append(Integer.toHexString(row).toUpperCase()); buf.append(layer); } } return buf.toString(); } /** * 根据高程计算32位二进制编码 */ private String calcHeightBits(double alt) { double n (1.0 / HEIGHT_GRID_STEP) * (Math.log((EARTH_RADIUS alt) / EARTH_RADIUS) / LOG_THETA); long val (long) n; String binary Long.toBinaryString(val); if (binary.length() 32) { binary binary.substring(binary.length() - 32); } StringBuilder sb new StringBuilder(32); for (int i binary.length(); i 32; i) { sb.append(0); } sb.append(binary); return sb.toString(); } /** * 从32位二进制串中提取指定级别的高程码 */ private String extractLayer(String bits, int lv) { if (lv 1) { String flag bits.substring(0, 1); long layer Long.parseLong(bits.substring(1, 7), 2); String layerStr Long.toString(layer); if (layerStr.length() 2) layerStr 0 layerStr; return flag layerStr; } String sub bits.substring(H_START[lv], H_END[lv]); long val Long.parseLong(sub, 2); switch (H_RADIX[lv]) { case 8: return Long.toOctalString(val); case 16: return Long.toHexString(val); default: return Long.toString(val); } }异常类定义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); } }