type
Post
status
Published
date
‣
slug
tools/geosot
summary
GeoSOT 是基于2ⁿ一维整型数组的全球经纬剖分网格,其相关标准为《GB/T 40087-2021地球空间网格编码规则》。GitHub开源库catnuko/geosot的使用方法,包括经纬度与二进制/四进制编码的转换、三维编码处理及网格操作等功能。该库实现了标准文件中的编码解码规则,支持从二维到三维空间的网格编码转换,适用于地图绘制、地理信息系统(GIS)等领域的数据组织与管理。
tags
工具
category
工具分享
icon
password
GeoSOT网格编码教程
一、网格编码和GeoSOT基本概念及重要性
网格编码基础信息
网格编码是按照一定规则,对地球空间网格赋予代码标识,可实现对地理空间的数字化表达和管理。不同的网格编码系统适用于不同的应用场景,以满足多样化的地理信息处理需求。相关标准文件如《GB/T 40087 - 2021地球空间网格编码规则》规定了地球空间网格剖分要求和编码方法,适用于作为空间单元与空间信息组织的地球空间网格剖分和代码标识;《社会治理网格划分和编码规则》规定了社会治理网格的术语和定义、网格划分原则、网格编码原则、网格编码规则等内容,适用于城乡网格化服务与治理中单元网格的划分与编码。
GeoSOT基础信息
GeoSOT全称为Geographic Coordinate Subdividing Grid with One Dimension Integral Coding on 2ⁿ - Tree,即基于2ⁿ一维整型数组全球经纬剖分网格。相关标准文件《GB/T 40087 - 2021地球空间网格编码规则》基于GeoSOT地球剖分模型,将地球空间统一剖分成不同尺度的网格单元,并按统一编码规则进行标识和表达,构建了网格化的地球空间数据组织参考框架。
GeoSOT网格通过地球表面经纬度范围空间经过3次空间扩展(将地球地理空间扩展为512°、将1°扩展为64′、将1′扩展为64″),实现了整度、整分的整型四叉树剖分网格。具体包括度级剖分网格(0 - 9级)、分级剖分网格(10 - 15级)和秒级剖分网格(16 - 21级),秒以下22 - 32级网格严格按照四分方法进行剖分和编码。其具有可标识性、层次性、聚合性和关联性等特点,可实现层次之间的有机关联,为地图多尺度表达提供基础。该网格与国家标准图幅很好地聚合和关联,能够方便地与现在主要的多种类型数据进行转换,有利于多源数据的兼容以及跨部门、跨系统之间的空间数据的整合和共享。
GeoSOT网格编码采用64位编码对各级剖分网格进行标识,最长的编码位为32位四进制数值编码。第1 - 9位是度级网格编码,第10 - 15位是分级网格编码,第16 - 21位是秒级网格编码,第22 - 32位是秒以下网格编码。其编码形式为“Gddddddddd - mmmmmm - ssssss.uuuuuuuuuuu”,其中d、m、s、u取值均为0、1、2、3。具体编码规则是,距赤道和本初子午线的交点最近的剖分网格为0,最远的为3,然后按照先沿纬线方向再沿经线方向对其他两个剖分网格分别为1和2。通过这种编码方式,实现对每个GeoSOT网格单元进行编码且该编码全球唯一,同时具有准确的地理空间含义。
二、经纬度、高度与网格编码之间的编码解码规则及转换规则
(一)网格剖分规则
1. 地球表面剖分
地球空间网格剖分从经度(L)、纬度(B)两个方向逐级递归二分,形成整度、整分、整秒的等经纬度网格。网格剖分在初始空间、1°、1’所对应的第0级、第9级和第15级上有三次扩展。
- 初始扩展:将纬度从 - 90°~90°扩展为 - 256°~256°,将经度从 - 180°~180°扩展为 - 256°~256°,形成512°×512°的0级网格,0级网格用G标识。
- 1°扩展:1级网格在0级网格基础上按等经差和纬差二分,每一级网格在上级网格基础上按等经差和纬差逐级递归二分。接近地球南极、北极时纬线长度急剧收缩,南纬和北纬88°~90°范围的8级和9级网格应合并。
- 1’扩展:分网格剖分时将每一个经纬度为1°×1°(60’×60’,9级网格)的网格扩展成为64’×64’的网格。南纬和北纬0°~88°的10级至15级网格,在上级网格基础上继续剖分。
(二)编码规则
1. 编码长度和分段
编码最长为32级,分为四段,分别是9位度网格编码、6位分网格编码、6位秒网格编码和11位秒以下网格编码,形式为:
ddddddddd - mmmmmm - ssssss . uuuuuuuuuuu 9位度级编码 6位分级编码 6位秒级编码 11位秒级以下编码
2. 编码顺序
采用Z序进行,1级网格按东北、西北、东南、西南的Z序进行编码,即G0网格对应地球表面空间区域位置是东北半球、G1网格对应西北半球、G2网格对应东南半球、G3网格对应西南半球。每一级网格编码在上一级网格编码基础上采用Z序继续编码。
3. 编码示例
以地球参考椭球面经纬度坐标(39°54’37.0″N,116°18’54.8″E)求6级别编码为例:
1. 东北半球:G0
2. 1级:纬度小于256,经度小于256 -> 0
3. 2级:纬度小于128,经度小于128 -> 00
4. 3级:纬度小于64,经度大于64 -> 001
5. 4级:纬度大于32,经度大于96 -> 00013
6. 5级:纬度小于48,经度大于112 -> 00131
7. 6级:纬度小于40,经度小于120 -> 001310
补上G0(东北半球)得到编码值G0001310。
(三)解码规则
解码是编码的逆过程。给定一个GeoSOT编码,通过对编码中每一个字符进行解析,确定其对应的经纬度偏移量,最终通过累加这些偏移量,得到精确的地理位置坐标。例如,对于编码G0001310:
1. 6级
2. G0 -> 东北半球
3. 1: 0,纬度 -> [0,256] 经度 -> [0,256]
4. 2: 00,纬度 -> [0,128] 经度 -> [0,128]
5. 3: 001,纬度 -> [0,64] 经度 -> [64,128]
6. 4: 0013,纬度 -> [32,64] 经度 -> [96,128]
7. 5: 00131,纬度 -> [32,48] 经度 -> [112,128]
8. 6: 001310,纬度 -> [32,40] 经度 -> [112,120]
G0001310 -> 对应坐标在纬度3240,经度112120之间的区域。
(四)附录中的转换规则
标准文件中有相关附录对转换规则进行说明,如附录D(资料性附录)提供了地球参考椭球面经纬度坐标到网格编码转换示例等内容。这些转换规则在实际应用中具有重要的作用,例如在地理信息系统中,能够方便地将经纬度坐标转换为网格编码,便于数据的存储和管理;在地图绘制中,能够根据网格编码准确地确定地理空间的位置,提高地图的精度和准确性。
三、使用开源库实现标准文件中编码解码转换
(一)核心函数介绍
根据开源库
geosot.ts
文件的注释,以下是实现标准文件编码解码功能的核心函数:1. 经纬度转编码函数
locToBinary1D
/** * 经纬度转二进制编码 * @param lng 经度,单位是度 * @param lat 纬度,单位是度 * @param level 层级 * @returns 二进制编码 */ export function locToBinary1D(lng: number, lat: number, level: number): bigint
功能:实现标准中经纬度到二进制编码的转换,采用Z序编码方式(Morton码)
示例:
// 将经纬度转换为20级二进制编码 const binaryCode = geosot.locToBinary1D(116.3152, 39.9088, 20);
locToQuaternary
/** * 经纬度转四进制编码 * @param lng 经度,单位是度 * @param lat 纬度,单位是度 * @param level 层级 * @returns 四进制编码 */ export function locToQuaternary(lng: number, lat: number, level: number)
功能:直接生成符合标准格式的四进制编码字符串,对应标准中的”Gddddddddd-mmmmmm-ssssss.uuuuuuuuuuu”格式
示例:
// 将北京坐标转换为20级四进制编码const code = geosot.locToQuaternary(116.3152, 39.9088, 20);// 输出类似: G001234567-012345-678901.23456789012
2. 编码转经纬度函数
cornerFromCode
/** * 四进制编码转瓦片角点经纬度 * @param code 四进制编码 * @returns 瓦片的经纬度,瓦片的西南角 */ export function cornerFromCode(code: string)
功能:实现标准中的解码过程,将四进制编码转换为对应网格的西南角经纬度
示例:
// 解码四进制编码获取对应网格的西南角坐标 const corner = geosot.cornerFromCode("G001234567-012345-678901.23456789012"); // 输出: { lng: 116.3, lat: 39.9 }
bboxFromCode
/** * 四进制编码转经纬度BoundingBox * @param code 四进制编码 * @returns 瓦片的经纬度BoundingBox */ export function bboxFromCode(code: string)
功能:根据编码获取网格的边界框信息,返回{west, south, east, north}
示例:
// 获取编码对应网格的边界框 const bbox = geosot.bboxFromCode("G001234567-012345-678901.23456789012"); // 输出: { west: 116.3, south: 39.9, east: 116.4, north: 40.0 }
3. 编码与ID转换函数
toCode
/** * 将一个瓦片id转换成一个字符串编码 * @param id 瓦片id * @param level 层级 * @returns 瓦片id对应的字符串编码 */ export function toCode(id: bigint, level: number): string
功能:将二进制编码(bigint类型)转换为符合标准格式的四进制编码字符串
示例:
// 将二进制编码转换为标准格式的四进制编码字符串 const binaryCode = geosot.locToBinary1D(116.3152, 39.9088, 20); const code = geosot.toCode(binaryCode, 20);
toId
/** * 将一个字符串编码转换成一个瓦片id * @param code 瓦片id对应的字符串编码 * @returns 瓦片id对应的id和级别 */ export function toId(code: string): { id: bigint; level: number }
功能:将四进制编码字符串解析为二进制编码(bigint类型)和层级
示例:
// 将编码字符串解析为二进制ID和层级 const { id, level } = geosot.toId("G001234567-012345-678901.23456789012");
4. 辅助函数
getCellSizeInDegree
/** * 获取第i级的经纬度网格的大小 * @param i 级别 * @returns 第i级的经纬度网格的大小,单位是度 */ export function getCellSizeInDegree(i: number)
功能:根据层级获取网格大小,对应标准中的不同级别网格精度
示例:
// 获取20级网格的大小(单位:度) const size = geosot.getCellSizeInDegree(20); // 输出: 0.000277777... (约等于1秒)
(二)标准编码解码流程实现
1. 经纬度编码流程
// 1. 定义经纬度和层级const lng = 116.3152; // 经度const lat = 39.9088; // 纬度const level = 20; // 层级 // 2. 直接生成四进制编码 const code = geosot.locToQuaternary(lng, lat, level); console.log("编码结果:", code); // 或者分步实现: // a. 先转二进制编码 const binaryId = geosot.locToBinary1D(lng, lat, level); // b. 再转四进制编码字符串 const code2 = geosot.toCode(binaryId, level);
2. 编码解码流程
// 1. 定义编码字符串 const code = "G001234567-012345-678901.23456789012"; // 2. 解码获取角点坐标 const corner = geosot.cornerFromCode(code);console.log("西南角坐标:", corner); // 3. 获取边界框 const bbox = geosot.bboxFromCode(code);console.log("边界框:", bbox); // 4. 获取层级 const level = geosot.getLevel(code);console.log("层级:", level);
(三)与标准文件的对应关系
开源库函数与《GB/T 40087-2021》标准的对应关系如下:
标准内容 | 开源库实现函数 |
经纬度到网格编码转换 | locToQuaternary, locToBinary1D |
网格编码到经纬度转换 | cornerFromCode, bboxFromCode |
编码结构定义(32级四段式) | toCode, getLevel |
网格大小计算 | getCellSizeInDegree |
Z序编码规则 | locToBinary1D(基于Morton码实现) |
(四)实际应用场景
1. 地图瓦片生成
// 根据经纬度和层级计算瓦片行列号 const {x, y} = geosot.xyFromLngLat(lng, lat, level); // 根据行列号获取瓦片URL(示例) const tileUrl = `https://example.com/tiles/${level}/${x}/${y}.png`;
2. 空间索引构建
// 将大量POI点编码为GeoSOT网格 const pois = [ { id: 1, lng: 116.3, lat: 39.9 }, { id: 2, lng: 116.4, lat: 39.8 } ]; // 构建网格索引 const index = new Map(); pois.forEach(poi => { const code = geosot.locToQuaternary(poi.lng, poi.lat, 18); if (!index.has(code)) index.set(code, []); index.set(code, [...index.get(code), poi.id]); }); // 查询某个区域内的POI const bboxCode = geosot.locToQuaternary(116.35, 39.85, 16); const bbox = geosot.bboxFromCode(bboxCode); // 基于网格索引进行空间查询...
(五)额外参考资料和学习资源
- 官方文档:可以访问
geosot
开源库的GitHub仓库(https://github.com/catnuko/geosot ),查看详细的文档和代码示例。
- 标准文件:《GB/T 40087-2021地球空间网格编码规则》提供了完整的技术规范。
- 源代码注释:直接参考
src/geosot.ts
文件中的函数注释获取最准确的使用说明。
- 作者:南山无物
- 链接:http://www.supony.top//article/tools/geosot
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。