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

该库基于H3-GOGeoJSON实现。

安装

$ 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())
}

示例说明

  1. 设置分辨率:H3索引的分辨率决定了六边形的大小,范围从0(最大)到15(最小)

  2. 解析GeoJSON:使用geojson.Parse函数解析GeoJSON字符串

  3. 转换为H3索引:使用geojson2h3.ToH3函数将GeoJSON对象转换为H3索引列表

  4. 转换回GeoJSON:使用geojson2h3.ToFeatureCollection函数将H3索引列表转换回GeoJSON FeatureCollection

  5. 输出结果:打印所有H3索引和生成的GeoJSON字符串

贡献

欢迎提交Pull Request和问题报告。请为新功能添加测试,并保持库的测试覆盖率在90-100%之间。


更多关于golang实现H3索引与GeoJSON格式相互转换插件库H3 GeoJSON的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于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))
	}
}

性能优化建议

  1. 批量处理:对于大量H3索引转换,考虑使用goroutine并行处理
  2. 内存复用:对于频繁转换的场景,可以复用内存缓冲区
  3. 精度选择:根据需求选择合适的分辨率,避免不必要的计算
  4. 缓存结果:对于静态地理数据,可以缓存转换结果

这个实现提供了H3与GeoJSON之间基本的转换功能,可以根据实际需求进一步扩展,比如支持MultiPoint、LineString等其他GeoJSON类型,或者添加更多的H3高级功能。

回到顶部