golang实现GeoJSON与S2单元格互转及地图几何特性处理插件库S2 geojson的使用
Golang实现GeoJSON与S2单元格互转及地图几何特性处理插件库S2 geojson的使用
预览
概述
在地图上绘制多边形或粘贴geoJSON,探索s2.RegionCoverer如何根据最小和最大级别用S2单元格覆盖它。放置标记并检查相应的S2单元格。
- 使用区域覆盖器在leaflet地图上显示s2单元格
- 根据最小和最大级别将geojson要素转换为单元格联合(仅支持多边形和点)
- 绘制点和多边形
- 检查点与圆与geoJSON要素的交集
快速开始
go run cmd/s2-geojson/main.go
Docker
docker run -p 8080:8080 --rm lmaroulis/s2-geojson
完整示例代码
下面是一个使用s2-geojson库进行GeoJSON与S2单元格互转的完整示例:
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/golang/geo/s2"
"github.com/pantrif/s2-geojson"
)
func main() {
// 示例GeoJSON多边形
geojsonStr := `{
"type": "Polygon",
"coordinates": [
[
[13.361263, 38.115556],
[13.361263, 38.115556],
[13.364945, 38.115556],
[13.364945, 38.117057],
[13.361263, 38.117057],
[13.361263, 38.115556]
]
]
}`
// 将GeoJSON转换为S2单元格
var geojsonPolygon map[string]interface{}
if err := json.Unmarshal([]byte(geojsonStr), &geojsonPolygon); err != nil {
log.Fatal(err)
}
// 创建区域覆盖器,设置最小和最大级别
rc := &s2.RegionCoverer{
MinLevel: 10,
MaxLevel: 20,
}
// 将GeoJSON多边形转换为S2单元格联合
cellUnion, err := s2geojson.GeoJSONToCellUnion(geojsonPolygon, rc)
if err != nil {
log.Fatal(err)
}
fmt.Println("转换后的S2单元格:")
for _, cellID := range cellUnion {
fmt.Printf("CellID: %d, Token: %s\n", cellID, cellID.ToToken())
}
// 将S2单元格联合转换回GeoJSON
convertedGeoJSON := s2geojson.CellUnionToGeoJSON(cellUnion)
jsonData, err := json.MarshalIndent(convertedGeoJSON, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println("\n转换回的GeoJSON:")
fmt.Println(string(jsonData))
}
功能说明
-
GeoJSON转S2单元格:
- 使用
GeoJSONToCellUnion
函数将GeoJSON多边形或点转换为S2单元格联合 - 可以设置RegionCoverer的MinLevel和MaxLevel来控制单元格的精度
- 使用
-
S2单元格转GeoJSON:
- 使用
CellUnionToGeoJSON
函数将S2单元格联合转换回GeoJSON格式 - 生成的GeoJSON可以在地图库中直接使用
- 使用
-
几何特性处理:
- 支持点和多边形的绘制与转换
- 可以检查点与圆的交集关系
注意事项
- 目前仅支持Polygons和Points类型的GeoJSON转换
- 转换精度取决于设置的MinLevel和MaxLevel参数
- 对于复杂多边形,可能需要调整RegionCoverer参数以获得更好的覆盖效果
许可证
该项目使用MIT许可证。
更多关于golang实现GeoJSON与S2单元格互转及地图几何特性处理插件库S2 geojson的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现GeoJSON与S2单元格互转及地图几何特性处理插件库S2 geojson的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang中GeoJSON与S2单元格互转及地图处理
概述
在Golang中处理地理空间数据时,Google的S2库和GeoJSON是常用的工具组合。S2库提供了高效的球面几何计算和空间索引能力,而GeoJSON则是地理空间数据的通用交换格式。
核心库介绍
1. S2 Geometry Library
S2库提供了球面几何计算和空间索引功能,特别适合处理地理空间数据。
import (
"github.com/golang/geo/s2"
)
2. GeoJSON处理
可以使用geojson
包来处理GeoJSON数据:
import (
"github.com/paulmach/orb"
"github.com/paulmach/orb/geojson"
)
GeoJSON与S2互转实现
1. GeoJSON转S2单元格
func GeoJSONToS2Cells(geoJSONStr string, level int) ([]s2.CellID, error) {
// 解析GeoJSON
fc, err := geojson.UnmarshalFeatureCollection([]byte(geoJSONStr))
if err != nil {
return nil, err
}
var cellIDs []s2.CellID
// 遍历所有要素
for _, feature := range fc.Features {
// 根据几何类型处理
switch geom := feature.Geometry.(type) {
case orb.Point:
// 点转S2单元格
ll := s2.LatLngFromDegrees(geom.Lat(), geom.Lon())
cellID := s2.CellIDFromLatLng(ll).Parent(level)
cellIDs = append(cellIDs, cellID)
case orb.Polygon:
// 多边形转S2单元格
loops := make([]*s2.Loop, 0, len(geom))
for _, ring := range geom {
points := make([]s2.Point, 0, len(ring))
for _, coord := range ring {
points = append(points, s2.PointFromLatLng(
s2.LatLngFromDegrees(coord.Lat(), coord.Lon()),
))
}
loops = append(loops, s2.LoopFromPoints(points))
}
// 创建多边形并获取覆盖的单元格
polygon := s2.PolygonFromLoops(loops)
rc := s2.RegionCoverer{MaxLevel: level, MinLevel: level}
cellUnion := rc.Covering(polygon)
cellIDs = append(cellIDs, cellUnion...)
}
}
return cellIDs, nil
}
2. S2单元格转GeoJSON
func S2CellsToGeoJSON(cellIDs []s2.CellID) (*geojson.FeatureCollection, error) {
fc := geojson.NewFeatureCollection()
for _, cellID := range cellIDs {
cell := s2.CellFromCellID(cellID)
// 获取单元格的四个顶点坐标
var coords []orb.Point
for i := 0; i < 4; i++ {
ll := s2.LatLngFromPoint(cell.Vertex(i))
coords = append(coords, orb.Point{ll.Lng.Degrees(), ll.Lat.Degrees()})
}
// 闭合多边形
coords = append(coords, coords[0])
// 创建GeoJSON要素
polygon := orb.Polygon{coords}
feature := geojson.NewFeature(polygon)
feature.Properties["s2_cell_id"] = cellID.String()
fc.Append(feature)
}
return fc, nil
}
地图几何特性处理
1. 空间关系判断
// 判断点是否在多边形内
func PointInPolygon(point orb.Point, polygon orb.Polygon) bool {
s2Polygon := convertOrbPolygonToS2(polygon)
s2Point := s2.PointFromLatLng(s2.LatLngFromDegrees(point.Lat(), point.Lon()))
return s2Polygon.ContainsPoint(s2Point)
}
func convertOrbPolygonToS2(polygon orb.Polygon) *s2.Polygon {
loops := make([]*s2.Loop, 0, len(polygon))
for _, ring := range polygon {
points := make([]s2.Point, 0, len(ring))
for _, coord := range ring {
points = append(points, s2.PointFromLatLng(
s2.LatLngFromDegrees(coord.Lat(), coord.Lon()),
))
}
loops = append(loops, s2.LoopFromPoints(points))
}
return s2.PolygonFromLoops(loops)
}
2. 缓冲区计算
// 创建缓冲区
func CreateBuffer(geom orb.Geometry, distance float64) orb.Geometry {
// 这里可以使用Turf.js的Go实现或其他缓冲区算法
// 示例使用简单的近似方法
switch g := geom.(type) {
case orb.Point:
// 点缓冲区转换为圆形多边形
return createCircle(g, distance)
case orb.LineString:
// 线缓冲区转换为带状多边形
return createLineBuffer(g, distance)
case orb.Polygon:
// 多边形缓冲区
return createPolygonBuffer(g, distance)
default:
return nil
}
}
使用s2-geojson插件库
s2-geojson
是一个专门处理S2和GeoJSON互转的库:
import "github.com/paulmach/go.geojson/s2geojson"
// GeoJSON转S2
func GeoJSONToS2UsingLib(geoJSONStr string) ([]s2.CellID, error) {
geom, err := geojson.UnmarshalGeometry([]byte(geoJSONStr))
if err != nil {
return nil, err
}
s2Geom, err := s2geojson.ParseGeometry(geom)
if err != nil {
return nil, err
}
// 获取覆盖的S2单元格
coverer := &s2.RegionCoverer{MaxLevel: 15}
return coverer.Covering(s2Geom), nil
}
// S2转GeoJSON
func S2ToGeoJSONUsingLib(cellIDs []s2.CellID) ([]byte, error) {
features := make([]*geojson.Feature, 0, len(cellIDs))
for _, cellID := range cellIDs {
cell := s2.CellFromCellID(cellID)
geom := s2geojson.FromCell(cell)
feature := geojson.NewFeature(geom)
feature.Properties["s2_cell_id"] = cellID.String()
features = append(features, feature)
}
fc := geojson.NewFeatureCollection()
fc.Features = features
return fc.MarshalJSON()
}
性能优化建议
- 单元格级别选择:根据精度需求选择合适的S2级别,级别越高单元格越小但数量越多
- 批量处理:对于大量数据,考虑使用goroutine并行处理
- 内存优化:处理大型数据集时注意内存使用,可以分块处理
总结
通过结合S2库和GeoJSON处理库,可以在Golang中高效地处理地理空间数据。S2提供了强大的空间索引和几何计算能力,而GeoJSON则是通用的数据交换格式。根据具体需求,可以选择直接使用底层库或更高级的封装库如s2-geojson
。