h3笔记:polygon

  • h3-py使用抽象基类 H3Shape 及其具体子类 LatLngPolyLatLngMultiPoly 来表示多边形 (polygon) 和多多边形 (multipolygon)
    • 任何涉及 “H3Shape” 的引用或函数名,都同时适用于 LatLngPolyLatLngMultiPoly 对象

1 LatLngPoly

  • 通过提供一组 经纬度 (latitude/longitude) 坐标对 来创建一个简单的 LatLngPoly 对象,这些坐标描述了多边形的外边界。
import h3
import folium

outer = [
    (37.804, -122.412),
    (37.778, -122.507),
    (37.733, -122.501)
]

poly = h3.LatLngPoly(outer)
print(poly)
#<LatLngPoly: [3]>


# folium 地图
m = folium.Map(location=[37.77, -122.45], zoom_start=12, tiles="cartodbpositron")

folium.GeoJson(
    poly.__geo_interface__
).add_to(m)
m

  • 还可以选择性地在多边形中添加 “孔洞 (holes)” —— 只需再追加一些经纬度坐标列表,用来描述这些孔洞即可
hole1 = [
    (37.782, -122.449),
    (37.779, -122.465),
    (37.788, -122.454),
]

poly = h3.LatLngPoly(outer, hole1)
print(poly)
#<LatLngPoly: [3/(3,)]>

# folium 地图
m = folium.Map(location=[37.77, -122.45], zoom_start=12, tiles="cartodbpositron")

folium.GeoJson(
    poly.__geo_interface__
).add_to(m)
m

hole2 = [
    (37.771, -122.484),
    (37.761, -122.481),
    (37.758, -122.494),
    (37.769, -122.496),
]

poly = h3.LatLngPoly(outer, hole1, hole2)
print(poly)
# folium 地图
m = folium.Map(location=[37.77, -122.45], zoom_start=12, tiles="cartodbpositron")

folium.GeoJson(
    poly.__geo_interface__
).add_to(m)
m

1.1 字符串表示与属性

LatLngPoly 的字符串表示(通过它的 __repr__ 方法给出)会显示:

  • 外环(outer loop)顶点的数量;

  • 以及每个孔洞(hole)顶点的数量。

<LatLngPoly: [3/(3, 4)]>

表示一个多边形:

  • 外边界由 3 个顶点组成;

  • 内部有 2 个孔洞,第一个孔洞由 3 个顶点组成,第二个孔洞由 4 个顶点组成。

1.2 坐标访问

可以通过属性来访问构成多边形的坐标:

  • LatLngPoly.outer
    返回外环的经纬度点列表(外边界)。

  • LatLngPoly.holes

返回一个列表,其中每个元素又是一个经纬度点列表,分别描述每个孔洞。

poly = h3.LatLngPoly(outer, hole1, hole2)
poly.outer
#((37.804, -122.412), (37.778, -122.507), (37.733, -122.501))


poly.holes
'''
([(37.782, -122.449), (37.779, -122.465), (37.788, -122.454)],
 [(37.771, -122.484),
  (37.761, -122.481),
  (37.758, -122.494),
  (37.769, -122.496)])
'''

2  __geo_interface__                                                                     

  • LatLngPoly.__geo_interface__ 会返回该多边形的 GeoJSON 表示
    • LatLngPoly.__geo_interface__ 等价于对该对象调用 h3.h3shape_to_geo()
  • 需要注意以下区别:

    • 点的顺序:GeoJSON 中的点是 (lng, lat)(经度在前,纬度在后),而 LatLngPoly 构造函数需要 (lat, lng)

    • 首尾点重复:GeoJSON 中的多边形,最后一个顶点会重复第一个顶点,以闭合环路。

d = poly.__geo_interface__
d

h3.h3shape_to_geo(poly)
'''
{'type': 'Polygon',
 'coordinates': (((-122.412, 37.804),
   (-122.507, 37.778),
   (-122.501, 37.733),
   (-122.412, 37.804)),
  ((-122.449, 37.782),
   (-122.465, 37.779),
   (-122.454, 37.788),
   (-122.449, 37.782)),
  ((-122.484, 37.771),
   (-122.481, 37.761),
   (-122.494, 37.758),
   (-122.496, 37.769),
   (-122.484, 37.771)))}
'''

2.1 从 GeoJSON 创建 LatLngPoly

可以通过 h3.geo_to_h3shape() 从 GeoJSON 字典或任何实现了 __geo_interface__ 的对象来创建一个 LatLngPoly

d = poly.__geo_interface__
d
'''
{'type': 'Polygon',
 'coordinates': (((-122.412, 37.804),
   (-122.507, 37.778),
   (-122.501, 37.733),
   (-122.412, 37.804)),
  ((-122.449, 37.782),
   (-122.465, 37.779),
   (-122.454, 37.788),
   (-122.449, 37.782)),
  ((-122.484, 37.771),
   (-122.481, 37.761),
   (-122.494, 37.758),
   (-122.496, 37.769),
   (-122.484, 37.771)))}
'''

h3.geo_to_h3shape(d)
#<LatLngPoly: [3/(3, 4)]>

3 多边形转 H3 单元格

  • 可以通过 h3.h3shape_to_cells() 获取某个多边形 (LatLngPoly) 内部所有 H3 单元格(cell)
  • 具体来说,它会返回所有质心 (centroid) 落在该多边形内部的单元格索引
  • 调用时需要指定 分辨率 (resolution)
hole1 = [
    (37.782, -122.449),
    (37.779, -122.465),
    (37.788, -122.454),
]

poly = h3.LatLngPoly(outer, hole1)
print(poly)

h3.h3shape_to_cells(poly, res=7)
'''
<LatLngPoly: [3/(3,)]>
['872830958ffffff', '87283095bffffff', '87283095affffff', '872830829ffffff']
'''

from shapely.geometry import shape as shapely_shape
# folium 地图
m = folium.Map(location=[37.77, -122.45], zoom_start=12, tiles="cartodbpositron")

folium.GeoJson(
    poly.__geo_interface__
).add_to(m)

cells = h3.h3shape_to_cells(poly,9)
boundary = h3.cells_to_h3shape(cells) 
print(boundary)

folium.GeoJson(
    boundary.__geo_interface__
).add_to(m)

m

3.1 H3 多边形不要求遵循“右手法则”

  • GeoJSON Polygon 不同,LatLngPoly 对象 不需要遵循“右手法则”
  • 右手法则 的要求是:

    • 外环(outer loop)顶点必须按 逆时针 (counterclockwise) 顺序排列;

    • 孔洞(holes)顶点必须按 顺时针 (clockwise) 顺序排列。

  • h3-py 中:

    • 顶点顺序可以随意,通常都会按你期望的方式解析,例如在转换为 H3 cell 集合时。

    • 但是:h3-py 并不会自动调整顶点顺序来符合右手法则。

      • 所以如果你用 __geo_interface__ 去画图,可能出现渲染错误。

4 LatLngMultiPoly

一个 LatLngMultiPoly 可以由多个 LatLngPoly 对象创建。

它的字符串表示会显示:

  • 每个 LatLngPoly 外环的顶点数量;

  • 以及每个孔洞(如果存在)的顶点数量。

poly1 = h3.LatLngPoly([(37.804, -122.412), (37.778, -122.507), (37.733, -122.501)])
poly2 = h3.LatLngPoly(
    [(37.803, -122.408), (37.736, -122.491), (37.738, -122.380), (37.787, -122.39)],
    [(37.760, -122.441), (37.772, -122.427), (37.773, -122.404), (37.758, -122.401), (37.745, -122.428)]
)
mpoly = h3.LatLngMultiPoly(poly1, poly2)

print(poly1)
print(poly2)
print(mpoly)

'''
<LatLngPoly: [3]>
<LatLngPoly: [4/(5,)]>
<LatLngMultiPoly: [3], [4/(5,)]>
'''
m = folium.Map(location=[37.77, -122.45], zoom_start=12, tiles="cartodbpositron")

folium.GeoJson(
    mpoly.__geo_interface__
).add_to(m)
m

5 从 Cells 转换为 LatLngPolyLatLngMultiPoly

如果你手里有一组 H3 单元格 (cells) 想要可视化,有两种常用做法:

  1. 转换为 LatLngPoly / LatLngMultiPoly

    • 使用 h3.cells_to_h3shape(cells)

    • 得到的结果可以通过 __geo_interface__ 拿到 GeoJSON 表示,方便绘图(比如在 foliumgeopandas 中)。

  2. 直接获取 GeoJSON

    • 使用 h3.cells_to_geo(cells)

    • 直接返回一个 GeoJSON 风格的字典,可以立即丢给 folium.GeoJson() 使用。

6  h3shape_to_geo

把 H3Shape 转成 __geo_interface__ 风格的字典

outer = [
    (37.804, -122.412),
    (37.778, -122.507),
    (37.733, -122.501)
]

poly = h3.LatLngPoly(outer)

geo = h3.h3shape_to_geo(poly)
geo
'''
{'type': 'Polygon',
 'coordinates': (((-122.412, 37.804),
   (-122.507, 37.778),
   (-122.501, 37.733),
   (-122.412, 37.804)),)}
'''

7 geo_to_h3shape

from shapely.geometry import Polygon
from h3 import geo_to_h3shape

# 注意:Shapely 使用 (lon, lat) 顺序!与 H3 的 (lat, lon) 相反。
outer_lonlat = [(103.80, 1.305), (103.82, 1.290), (103.84, 1.295)]
hole_lonlat  = [(103.815, 1.297), (103.825, 1.296), (103.818, 1.294)]

shp = Polygon(outer_lonlat, [hole_lonlat])
h3shape = geo_to_h3shape(shp.__geo_interface__)
h3shape
#<LatLngPoly: [3/(3,)]>

8 h3shape_to_cells

在指定分辨率 res 下,返回中心点落在该多边形内的一组 H3 单元(hex 索引)

import h3

outer = [
    (37.804, -122.412),
    (37.778, -122.507),
    (37.733, -122.501)
]

poly = h3.LatLngPoly(outer)

res = 9  # 示例分辨率
cells = h3.h3shape_to_cells(poly, res)
cells
'''
['8928309594bffff',
 '89283082927ffff',
 '89283095a27ffff',
 '89283095a53ffff',
 '892830829abffff',
 '89283087493ffff',
 '89283095aabffff',
...
'''

9 cells_to_h3shape

把一组 同分辨率 的 H3 单元重建为 H3Shape(尽量贴近“真实边界”)。

tight=True:能合并成单一多边形时返回 LatLngPoly,否则 LatLngMultiPoly

tight=False:总是返回 LatLngMultiPoly(边界可能更“松”一些)

from h3 import cells_to_h3shape

shape_from_cells = cells_to_h3shape(cells, tight=True)
shape_from_cells
#<LatLngPoly: [148]>

10  h3shape_to_cells_experimental

  • 这是 h3shape_to_cells 的增强版本,用于把一个多边形区域(H3Shape,比如 LatLngPoly 或 LatLngMultiPoly)转化为一组 H3 单元格。
  • 与老版本的区别:
    • h3shape_to_cells 只支持 中心点包含 (center) 模式。
    • h3shape_to_cells_experimental 支持多种判定模式,可以更灵活地决定哪些 cell 算“在多边形里面”。
      • res:目标 H3 分辨率(0–15)

      • contain:判定方式(字符串),可选:

        • "center":cell 的中心点在多边形内(默认逻辑,旧函数的行为)

        • "full":整个 cell 完全在多边形内才算

        • "overlap":只要 cell 与多边形有部分重叠就算(最宽松)

        • "bbox_overlap":只检查 cell 的外接矩形是否与多边形重叠(更快但近似)

from h3 import LatLngPoly, h3shape_to_cells_experimental

import h3

outer = [
    (37.804, -122.412),
    (37.778, -122.507),
    (37.733, -122.501)
]

poly = h3.LatLngPoly(outer)

cells_center = h3shape_to_cells_experimental(poly, res=9, contain="center")
print("中心点包含:", len(cells_center), "个 cell")
#中心点包含: 197 个 cell



cells_full = h3shape_to_cells_experimental(poly, res=9, contain="full")
print("完全包含:", len(cells_full), "个 cell")
#完全包含: 155 个 cell


cells_overlap = h3shape_to_cells_experimental(poly, res=9, contain="overlap")
print("任意重叠:", len(cells_overlap), "个 cell")
#任意重叠: 243 个 cell



cells_bbox = h3shape_to_cells_experimental(poly, res=9, contain="bbox_overlap")
print("bbox 重叠:", len(cells_bbox), "个 cell")
#bbox 重叠: 294 个 cell

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UQI-LIUWJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值