H3 坐标系完全指南:IJK、FaceIJK、Hex2d 与 Local IJ 坐标系的内部原理与实战运用 GIS【免费下载链接】h3Hexagonal hierarchical geospatial indexing system项目地址https://gitcode.com/gh_mirrors/h3/h3点击查看免费下载H3 是一个分层六边形地理空间索引系统其核心库在内部维护着一套彼此关联的坐标系用于在球面上的经纬度点与六边形网格单元之间完成数学转换。本文以官方文档《Coordinate systems》为骨架结合本仓库源码完整讲解 IJK、FaceIJK、Hex2d、Local IJ 四种坐标系的定义、彼此间的换算关系、在源码中的落地实现以及围绕 Local IJ 坐标系的cellToLocalIj/localIjToCell实践方法与注意事项。读完本文你将能看懂 H3 内部索引的编码路径并能在自己的算法中正确使用以某个 H3 索引为原点的局部网格坐标。总览H3 为什么需要多套坐标系H3 索引最终要被编码为一个 64 位整数但球面上的位置计算经纬度到六边形单元的映射无法直接在整数位域上进行。因此 H3 核心库在内部引入了一条经纬度 → 3D 向量 → 正二十面体面内坐标 → 平面六边形网格坐标的换算链路这条链路中的每个中间表示都对应一套坐标系坐标系载体结构维度用途IJKCoordIJK3120° 夹角三轴六边形平面网格的轴向寻址与邻接运算FaceIJKFaceIJK面号 IJK在正二十面体某个面上的局部网格坐标Hex2dVec2d2笛卡尔直角面内连续坐标用于经纬度与网格之间的桥接Local IJCoordIJ2120° 夹角双轴以某个 H3 索引为原点、跨基础单元连续的局部网格坐标下面的小节依次展开每种坐标系的定义与实现。IJK 坐标系120° 夹角的三轴寻址定义与结构离散六边形平面网格天然具有三条相隔 120° 的坐标轴。H3 以i、j、k命名这三条轴一个ijk坐标三元组用CoordIJK结构表示。其定义位于 src/h3lib/include/coordijk.htypedef struct { int i; /// i component int j; /// j component int k; /// k component } CoordIJK;下面这张来自 H3 文档的示意图直观展示了六边形网格上(i, j, k)三轴坐标的排列方式每个六边形单元都对应一组形如(0,0,1)、(1,0,0)的三元组原点为(0, 0, 0)。归一化_ijkNormalize由于三条轴夹角 120° 且互相冗余任意两轴可表示第三轴方向同一个六边形单元在ijk系统中会对应多个不同的坐标三元组。为此库提供归一化函数_ijkNormalizecoordijk.h 实现它先将负分量逐轴借用到其余两轴上例如i 0时执行j - i; k - i; i 0随后取出最小正值并整体减去最终得到由最小非负分量构成的唯一地址。归一化后的ijk地址最多只有两个非零分量这一性质极大简化了后续的网格距离与邻接运算。注意该函数就地修改works in place传入的坐标且要求调用方保证减法运算不发生有符号整数溢出头文件中专门提供了_ijkNormalizeCouldOverflow用于溢出预检coordijk.h。IJK 上的核心运算coordijk.h是 header-only 实现围绕CoordIJK提供了一整套内联运算它们构成 H3 索引层级parent/child与邻接neighbor逻辑的底层基础加减与缩放_ijkAdd、_ijkSub、_ijkScalecoordijk.h邻接_neighbor在给定方向上加上UNIT_VECS[digit]单位向量并归一化coordijk.h旋转_ijkRotate60ccw/_ijkRotate60cw以 60° 为步长旋转坐标coordijk.h层级升降_downAp7/_downAp7r孔径 7 细分、_downAp3/_downAp3r孔径 3 细分与_upAp7/_upAp7r向父级回溯coordijk.h距离ijkDistance先做差、归一化、取绝对值后返回最大分量即两单元间的网格步数coordijk.h。此外头文件用UNIT_VECS[7]将 7 个 H3 索引数字digit方向 0 为中心、1~6 对应六方向映射为CoordIJK单位向量coordijk.h并提供了_unitIjkToDigit做反向映射——这正是 H3 64 位索引中每 3 位方向数字与平面坐标互译的关键桥梁。FaceIJK 坐标系把网格铺在正二十面体每个面上定义与结构H3 的地球模型是正二十面体icosahedron其每个三角面都承载一套以面中心为原点的ijk坐标系。FaceIJK结构 面编号 该面上的CoordIJK坐标定义于 src/h3lib/include/faceijk.htypedef struct { int face; /// face number CoordIJK coord; /// ijk coordinates on that face } FaceIJK;同一文件还定义了FaceOrientIJK记录从一个面变换到相邻面时所需的平移向量与 60° 旋转次数faceijk.h并定义了Overage枚举NO_OVERAGE未越界、FACE_EDGE落在面边缘、NEW_FACE越界到新面内部用于处理网格跨面时的边界情形faceijk.h。Class II 与 Class III相邻分辨率的 ~19.1° 旋转面内的网格不能简单地逐级放大每个网格分辨率都相对其下一级粗糙分辨率旋转约 19.1°旋转方向在每一级之间交替——逆时针、顺时针交替出现从而每个分辨率只会呈现两种朝向之一Class II偶数分辨率六边形顶点朝上尖顶向上Class III奇数分辨率六边形边朝上平边向上。这一术语源自 R. Buckminster Fuller。分辨率 0 的基础单元base cells属于 Class II。19.1° 这个数值并非经验值而是由孔径 7aperture 7细分的几何关系推导出的精确常量。在 src/h3lib/include/constants.h 中/** rotation angle between Class II and Class III resolution axes * (asin(sqrt(3.0 / 28.0))) */ #define M_AP7_ROT_RADS 0.333473172251832115336090755351601070065900389换算成角度约为asin(sqrt(3/28)) ≈ 19.1066°即文档所说的 ~19.1°。该常量在面坐标与经纬度的双向换算中被直接使用_vec3ToHex2d在 Class III 分辨率下对角度执行theta - M_AP7_ROT_RADSfaceijk.c反向的_hex2dToVec3则执行theta M_AP7_ROT_RADSfaceijk.c。从经纬度到 FaceIJK 的调用链FaceIJK位于球面 ↔ 平面换算的中心位置核心转换函数声明在 faceijk.h_vec3ToFaceIjk3D 向量 → FaceIJK、_faceIjkToVec3FaceIJK → 3D 向量、_faceIjkToCellBoundaryFaceIJK → 单元边界坐标等。整条链路为latLngToCell等公共 API 将经纬度转为单位球上的 3D 向量Vec3d_vec3ToFaceIjk先经_vec3ToClosestFace确定最近的二十面体面再做 gnomonic 投影、按分辨率缩放落到该面的ijk网格上最终faceIjkToH3把FaceIJK逐位编码进 64 位 H3 索引。越界调整overage由_adjustOverageClassII等函数处理faceijk.h保证跨面网格在相邻面上的坐标可被正确折算。Hex2d 坐标系面内连续直角坐标Hex2d是与特定ijk坐标系绑定的平面笛卡尔直角坐标系满足三个约束原点位于ijk系统的原点单元中心正x轴与i轴对齐单位距离 1.0 等于ijk坐标系中相邻单元中心之间的距离。即 Hex2d 是把六边形中心点摊平到直角坐标的表示用Vec2d结构承载src/h3lib/include/vec2d.htypedef struct { double x; /// x component double y; /// y component } Vec2d;vec2d.h同时提供_v2dMag模长、_v2dIntersect线段求交、_v2dAlmostEquals近似相等判断等几何工具vec2d.h。IJK ↔ Hex2d 的互转在 coordijk.h 中_ijkToHex2d先把ijk坐标折算成双轴形式i h-i - h-k; j h-j - h-k再做斜坐标到直角的投影v-x i - 0.5 * j; v-y j * M_SQRT3_2; // sqrt(3)/2M_SQRT3_2 0.8660254037844386...是六边形几何的基本常量constants.h。反向的_hex2dToCoordIJKcoordijk.h则先将直角坐标投影回斜坐标系、量化取整到最近六边形中心含奇偶行的折叠处理最后调用_ijkNormalize得到规一化地址。这段量化取整逻辑沿袭自 DGGRID 的 hex 判定方法。Hex2d 与分辨率缩放_vec3ToHex2dfaceijk.c在确定面后以面中心为原点计算方位角 theta做 gnomonic 缩放r tan(r)再按分辨率逐级放大每级分辨率乘M_SQRT7孔径 7 的线性缩放因子。反向_hex2dToVec3执行对称的逆运算faceijk.c。因此 Hex2d 是一套以当前分辨率的单元间距为 1.0 单位的坐标系——同一面中心在不同分辨率下的 Hex2d 数值天然随分辨率缩放这也是它能同时服务坐标换算与网格几何运算的原因。Local IJ 坐标系以任意索引为原点的局部网格前三种坐标系都受限于面或基础单元的边界——跨基础单元时坐标会跳变。而许多网格算法如环状遍历、路径查找希望得到一套不被基础单元和面中断的连续网格坐标这就是 Local IJ 坐标系。定义与限制Local IJ 有两条相隔 120° 的坐标轴且坐标由一个originH3 索引锚定。坐标用CoordIJ结构承载src/h3lib/include/h3api.h.intypedef struct { int i; /// i component int j; /// j component } CoordIJ;同时Local IJ 具有以下重要性质与限制与文档一致同源可比不同来源的 local 坐标只有拥有相同origin索引时才可比较局部有效local 坐标只在origin附近有效实践中通常限定在同一个基础单元或相邻基础单元内五边形pentagon除外存在形变由于五边形畸变坐标空间可能包含删除或扭曲warped的区域一码多址同一个索引相对于同一个origin可能对应多个坐标原点偏移origin本身在局部坐标空间中不一定位于(0, 0)。源码实现与错误处理Local IJ 的全部逻辑位于 src/h3lib/lib/localij.c。核心函数cellToLocalIjklocalij.c完成索引 → 锚定坐标它要求 origin 与目标索引分辨率一致否则返回E_RES_MISMATCH通过_getBaseCellDirection判断基础单元方向必要时对五边形做_ijkRotate60cw旋转展开再按分辨率逐级缩放平移量最终产出规一化的ijk坐标反向的localIjkToCelllocalij.c执行对称过程。受五边形畸变影响两个方向都可能返回错误码E_FAILED索引距 origin 过远、跨五边形展开方向被禁止等。文件开头的PENTAGON_ROTATIONS、PENTAGON_ROTATIONS_REVERSE系列 7×7 旋转查找表与FAILED_DIRECTIONS禁止方向表localij.c就是为处理这些畸变而精心设计的。公共 API 实践cellToLocalIj 与 localIjToCell面向使用者的 Local IJ 能力通过两个公开 API 暴露声明于 src/h3lib/include/h3api.h.inDECLSPEC H3Error H3_EXPORT(cellToLocalIj)(H3Index origin, H3Index h3, uint32_t mode, CoordIJ *out); DECLSPEC H3Error H3_EXPORT(localIjToCell)(H3Index origin, const CoordIJ *ij, uint32_t mode, H3Index *out);其中mode参数用于控制行为0标准模式任何已知或预期的错误如跨五边形、超出有效范围都会返回错误码1尝试在错误发生时仍返回结果例如localIjToCell遇到无效输入时可能返回E_FAILED或尽力推算2关闭若干检查换取更快的执行速度代价是结果可能在畸形区域失真。实际调用形态可参考命令行的cellToLocalIj与localIjToCell过滤实现例如 src/apps/filters/cellToLocalIj.c 与 src/apps/filters/localIjToCell.c它们直接调用上述 API 并打印结果或错误码。仓库测试 src/apps/testapps/testCellToLocalIj.c 与 src/apps/testapps/testCellToLocalIjExhaustive.c 则系统地验证了各种 origin/目标组合下的正确性与失败路径。使用 Local IJ 的实用建议结合文档限制与源码行为实践中有如下建议固定 origin所有相互比较的 local 坐标必须来自同一个 origin 索引跨 origin 的坐标相加、相减没有意义控制距离将运算范围控制在 origin 所在基础单元及其直接相邻基础单元内远离五边形区域否则应接受并处理E_FAILED等错误码验证返回值调用cellToLocalIj/localIjToCell后务必检查H3Error而不是假定必然成功慎用快速模式mode2只适合对性能敏感且能容忍近似结果的场景。总结四套坐标系的协作关系可以把 H3 的坐标体系理解为一条流水线经纬度 (lat/lng) → Vec3d单位球 3D 向量 → FaceIJK正二十面体面号 面内 IJK → Hex2d / Vec2d面内直角坐标用于 gnomonic 投影与分辨率缩放 → CoordIJK规一化的平面六边形坐标 → 64 位 H3 索引逐级 digit 编码其中 IJK 负责面内网格的代数运算FaceIJK 负责网格落在哪个面Hex2d 负责球面到平面的投影桥接Local IJ 则提供一个以任意索引为原点、跨基础单元连续的应用层坐标空间。理解这四套坐标系及其互转关系是深入阅读 H3 源码src/h3lib/lib/faceijk.c、src/h3lib/lib/localij.c与正确使用 Local IJ 类 API 的前提。赞分享GIS【免费下载链接】h3Hexagonal hierarchical geospatial indexing system项目地址https://gitcode.com/gh_mirrors/h3/h3点击查看免费下载相关推荐mp4parser4cj编译部署完整指南从零搭建FFmpeg仓颉环境Linux/Windows/鸿蒙全平台支持mp4parser4cj编译部署完整指南从零搭建FFmpeg仓颉环境Linux/Windows/鸿蒙全平台支持 mp4parser4cj 是一个用仓颉语言GISX6 坐标系完全指南local / graph / client / page 四种坐标系的转换原理与实战X6 坐标系完全指南local / graph / client / page 四种坐标系的转换原理与实战 本篇技术指南以 X6基于 SVG 与 HTML前端图形学Skia 坐标系完全指南Device、Local 与 Shader 坐标空间的变换原理Skia 坐标系完全指南Device、Local 与 Shader 坐标空间的变换原理 本篇指南围绕 Skia 官方文档 site/docs/user/coo图形学上一篇Redis 3.0集群负载均衡算法从源码注释看请求分发下一篇怎样3步搞定流媒体服务器部署专业实战方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考