golang实现H3索引与GeoJSON格式相互转换插件库H3 GeoJSON的使用
Golang实现H3索引与GeoJSON格式相互转换插件库H3 GeoJSON的使用
概述
go-geojson2h3
库提供了一系列实用工具,用于在GeoJSON对象和H3六边形索引之间进行转换。它支持以下GeoJSON对象类型:
- Point, MultiPoint
- LineString, MultiLineString
- Polygon, MultiPolygon
- GeometryCollection
- Feature, FeatureCollection
- Circle
安装
$ go get github.com/mmadfox/go-geojson2h3
API
// ToH3将GeoJSON对象转换为指定分辨率的六边形索引列表
ToH3(resolution int, o geojson.Object) (indexes []h3.H3Index, err error)
// ToFeatureCollection将一组六边形索引转换为GeoJSON FeatureCollection
// 包含集合的轮廓。特征的几何类型将是Polygon
ToFeatureCollection(indexes []h3.H3Index) (*geojson.FeatureCollection, error)
使用示例
完整示例代码
package main
import (
"fmt"
"github.com/mmadfox/go-geojson2h3"
"github.com/tidwall/geojson"
"github.com/uber/h3-go/v3"
)
func main() {
// 设置H3分辨率
resolution := 9
// 解析GeoJSON字符串
object, err := geojson.Parse(`{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"shape":"Polygon","name":"Unnamed Layer","category":"default"},"geometry":{"type":"Polygon","coordinates":[[[-73.901303,40.756892],[-73.893924,40.743755],[-73.871476,40.756278],[-73.863378,40.764175],[-73.871444,40.768467],[-73.879852,40.760014],[-73.885515,40.764045],[-73.891522,40.761054],[-73.901303,40.756892]]]},"id":"a6ca1b7e-9ddf-4425-ad07-8a895f7d6ccf"}]}`, nil)
if err != nil {
panic(err)
}
// 将GeoJSON转换为H3索引
indexes, err := geojson2h3.ToH3(resolution, object)
if err != nil {
panic(err)
}
// 打印所有H3索引
for _, index := range indexes {
fmt.Printf("h3index: %s\n", h3.ToString(index))
}
// 将H3索引转换回GeoJSON FeatureCollection
featureCollection, err := geojson2h3.ToFeatureCollection(indexes)
if err != nil {
panic(err)
}
// 打印生成的GeoJSON
fmt.Println("Polyfill:")
fmt.Println(featureCollection.JSON())
}
示例说明
-
设置分辨率:H3索引的分辨率决定了六边形的大小,范围从0(最大)到15(最小)
-
解析GeoJSON:使用
geojson.Parse
函数解析GeoJSON字符串 -
转换为H3索引:使用
geojson2h3.ToH3
函数将GeoJSON对象转换为H3索引列表 -
转换回GeoJSON:使用
geojson2h3.ToFeatureCollection
函数将H3索引列表转换回GeoJSON FeatureCollection -
输出结果:打印所有H3索引和生成的GeoJSON字符串
贡献
欢迎提交Pull Request和问题报告。请为新功能添加测试,并保持库的测试覆盖率在90-100%之间。
更多关于golang实现H3索引与GeoJSON格式相互转换插件库H3 GeoJSON的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现H3索引与GeoJSON格式相互转换插件库H3 GeoJSON的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
H3与GeoJSON相互转换的Golang实现
H3是Uber开源的六边形地理空间索引系统,GeoJSON是一种常用的地理数据格式。下面我将介绍如何使用Golang实现两者之间的相互转换。
安装依赖
首先需要安装H3的Golang绑定:
go get github.com/uber/h3-go/v3
基本转换功能实现
1. H3索引转GeoJSON
package h3geojson
import (
"encoding/json"
"github.com/uber/h3-go/v3"
)
// H3ToGeoJSON 将H3索引转换为GeoJSON多边形
func H3ToGeoJSON(h3Index h3.H3Index) ([]byte, error) {
// 获取H3六边形的边界坐标
boundary := h3.ToGeoBoundary(h3Index)
// 构建GeoJSON多边形坐标
coordinates := make([][][]float64, 1)
coordinates[0] = make([][]float64, len(boundary)+1) // +1是为了闭合多边形
for i, vertex := range boundary {
coordinates[0][i] = []float64{vertex.Longitude, vertex.Latitude}
}
// 闭合多边形
coordinates[0][len(boundary)] = []float64{boundary[0].Longitude, boundary[0].Latitude}
// 构建GeoJSON Feature
feature := map[string]interface{}{
"type": "Feature",
"properties": map[string]interface{}{
"h3_index": h3.ToString(h3Index),
},
"geometry": map[string]interface{}{
"type": "Polygon",
"coordinates": coordinates,
},
}
return json.Marshal(feature)
}
2. GeoJSON转H3索引
// GeoJSONToH3 将GeoJSON点转换为H3索引
func GeoJSONToH3(geojson []byte, resolution int) (h3.H3Index, error) {
// 解析GeoJSON
var feature map[string]interface{}
if err := json.Unmarshal(geojson, &feature); err != nil {
return 0, err
}
geometry, ok := feature["geometry"].(map[string]interface{})
if !ok {
return 0, fmt.Errorf("invalid GeoJSON: geometry not found")
}
// 只处理点类型
if geometry["type"].(string) != "Point" {
return 0, fmt.Errorf("only Point type is supported for GeoJSON to H3 conversion")
}
coordinates := geometry["coordinates"].([]interface{})
if len(coordinates) < 2 {
return 0, fmt.Errorf("invalid coordinates")
}
lat := coordinates[1].(float64)
lng := coordinates[0].(float64)
// 将经纬度转换为H3索引
geoCoord := h3.GeoCoord{
Latitude: lat,
Longitude: lng,
}
return h3.FromGeo(geoCoord, resolution), nil
}
高级功能实现
1. 多分辨率H3网格填充GeoJSON多边形
// PolygonToH3 将GeoJSON多边形填充为H3网格
func PolygonToH3(geojson []byte, resolutions []int) (map[int][]h3.H3Index, error) {
var feature map[string]interface{}
if err := json.Unmarshal(geojson, &feature); err != nil {
return nil, err
}
geometry, ok := feature["geometry"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid GeoJSON: geometry not found")
}
if geometry["type"].(string) != "Polygon" {
return nil, fmt.Errorf("only Polygon type is supported")
}
// 解析多边形坐标
coords := geometry["coordinates"].([]interface{})[0].([]interface{})
polygon := make([]h3.GeoCoord, len(coords))
for i, coord := range coords {
point := coord.([]interface{})
polygon[i] = h3.GeoCoord{
Longitude: point[0].(float64),
Latitude: point[1].(float64),
}
}
result := make(map[int][]h3.H3Index)
for _, res := range resolutions {
// 使用H3的多边形填充功能
indexes, err := h3.PolygonToCells(polygon, res)
if err != nil {
return nil, err
}
result[res] = indexes
}
return result, nil
}
2. H3网格集合转GeoJSON MultiPolygon
// H3SetToGeoJSON 将一组H3索引转换为GeoJSON MultiPolygon
func H3SetToGeoJSON(indexes []h3.H3Index) ([]byte, error) {
coordinates := make([][][][]float64, len(indexes))
for i, index := range indexes {
boundary := h3.ToGeoBoundary(index)
polygon := make([][][]float64, 1)
polygon[0] = make([][]float64, len(boundary)+1)
for j, vertex := range boundary {
polygon[0][j] = []float64{vertex.Longitude, vertex.Latitude}
}
// 闭合多边形
polygon[0][len(boundary)] = []float64{boundary[0].Longitude, boundary[0].Latitude}
coordinates[i] = polygon
}
feature := map[string]interface{}{
"type": "Feature",
"properties": map[string]interface{}{
"h3_count": len(indexes),
},
"geometry": map[string]interface{}{
"type": "MultiPolygon",
"coordinates": coordinates,
},
}
return json.Marshal(feature)
}
使用示例
package main
import (
"fmt"
"log"
"github.com/yourusername/h3geojson"
"github.com/uber/h3-go/v3"
)
func main() {
// 示例1: 点转H3
pointGeoJSON := []byte(`{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.404, 39.915]
}
}`)
h3Index, err := h3geojson.GeoJSONToH3(pointGeoJSON, 9)
if err != nil {
log.Fatal(err)
}
fmt.Printf("H3 index: %s\n", h3.ToString(h3Index))
// 示例2: H3转GeoJSON
geojson, err := h3geojson.H3ToGeoJSON(h3Index)
if err != nil {
log.Fatal(err)
}
fmt.Printf("GeoJSON: %s\n", string(geojson))
// 示例3: 多边形填充H3网格
polygonGeoJSON := []byte(`{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[116.404, 39.915],
[116.414, 39.915],
[116.414, 39.925],
[116.404, 39.925],
[116.404, 39.915]
]]
}
}`)
resolutions := []int{8, 9}
h3Indexes, err := h3geojson.PolygonToH3(polygonGeoJSON, resolutions)
if err != nil {
log.Fatal(err)
}
for res, indexes := range h3Indexes {
fmt.Printf("Resolution %d has %d hexagons\n", res, len(indexes))
}
}
性能优化建议
- 批量处理:对于大量H3索引转换,考虑使用goroutine并行处理
- 内存复用:对于频繁转换的场景,可以复用内存缓冲区
- 精度选择:根据需求选择合适的分辨率,避免不必要的计算
- 缓存结果:对于静态地理数据,可以缓存转换结果
这个实现提供了H3与GeoJSON之间基本的转换功能,可以根据实际需求进一步扩展,比如支持MultiPoint、LineString等其他GeoJSON类型,或者添加更多的H3高级功能。