golang 2D几何建模与算法计算插件库simplefeatures的使用

Golang 2D几何建模与算法计算插件库simplefeatures的使用

Simple Features是一个2D几何库,提供了Go类型来建模几何图形以及操作它们的算法。它是OpenGIS Consortium的Simple Feature Access Specification的纯Go实现。

几何类型

类型 示例 描述
Point Point 空间中的单个位置
MultiPoint MultiPoint 空间中的点集合
LineString LineString 通过控制点线性插值定义的曲线
MultiLineString MultiLineString LineString的集合
Polygon Polygon 界定某个区域的平面表面几何图形,可能有孔
MultiPolygon MultiPolygon Polygon的集合
GeometryCollection GeometryCollection 不受约束的几何图形集合
Geometry Geometry 可以包含任何类型的几何图形
Envelope Envelope 轴对齐的边界框,通常用于描述其他几何实体的空间范围

编组与解组

Simple features支持以下外部几何表示格式:

格式 示例 描述
WKT POLYGON((0 0,0 1,1 1,1 0,0 0)) 人类可读的几何存储格式
WKB <binary> 机器可读格式,高效处理
GeoJSON {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]} 基于JSON格式,适合Web API
TWKB <binary> 压缩二进制格式,最小化序列化表示大小

几何算法

杂项算法

  • Area: 查找几何图形的面积(适用于Polygon和MultiPolygon)
  • Centroid: 查找几何图形的质心
  • ConvexHull: 查找几何图形的凸包
  • Distance: 查找两个几何图形之间的最短距离
  • Envelope: 查找包围几何图形的最小轴对齐边界框
  • ExactEquals: 确定两个几何图形在结构上是否相等
  • Length: 查找几何图形的长度(适用于LineString和MultiLineString)
  • PointOnSurface: 查找位于几何图形内部的点
  • Relate: 计算描述两个几何图形关系的DE-9IM交集
  • Simplify: 使用Ramer-Douglas-Peucker算法简化几何图形

集合操作

  • Union: 将两个几何图形的部分连接在一起
  • Intersection: 查找两个几何图形的公共部分
  • Difference: 查找一个几何图形中不属于另一个几何图形的部分
  • SymmetricDifference: 查找两个几何图形中不相同的部分

命名空间谓词

  • Equals: 确定两个几何图形在拓扑上是否相等
  • Intersects: 确定两个几何图形是否相交
  • Disjoint: 确定两个几何图形是否没有共同点
  • Contains: 确定一个几何图形是否包含另一个
  • CoveredBy: 确定一个几何图形是否被另一个覆盖
  • Covers: 确定一个几何图形是否覆盖另一个
  • Overlaps: 确定一个几何图形是否与另一个重叠
  • Touches: 确定一个几何图形是否接触另一个
  • Within: 确定一个几何图形是否在另一个内部
  • Crosses: 确定一个几何图形是否与另一个交叉

示例代码

WKT示例

// 从WKT解码
input := "POLYGON((0 0,0 1,1 1,1 0,0 0))"
g, _ := geom.UnmarshalWKT(input)

// 编码为WKT
output := g.AsText()
fmt.Println(output) // 输出: POLYGON((0 0,0 1,1 1,1 0,0 0))

WKB示例

// 编码为WKB
coords := geom.Coordinates{XY: geom.XY{1.5, 2.5}}
pt := geom.NewPoint(coords)
wkb := pt.AsBinary()
fmt.Println(wkb) // 输出: [1 1 0 0 0 0 0 0 0 0 0 248 63 0 0 0 0 0 0 4 64]

// 从WKB解码
fromWKB, _ := geom.UnmarshalWKB(wkb)
fmt.Println(fromWKB.AsText()) // 输出: POINT(1.5 2.5)

PostGIS集成示例

db, _ := sql.Open("postgres", "postgres://...")

db.Exec(`
    CREATE TABLE my_table (
        my_geom geometry(geometry, 4326),
        population double precision
    )`,
)

// 通过WKB将几何和人口数据插入PostGIS
coords := geom.Coordinates{XY: geom.XY{-74.0, 40.7}}
nyc := geom.NewPoint(coords)
db.Exec(`
    INSERT INTO my_table
    (my_geom, population)
    VALUES (ST_GeomFromWKB($1, 4326), $2)`,
    nyc, 8.4e6,
)

// 通过WKB从PostGIS获取几何和人口数据
var location geom.Geometry
var population float64
db.QueryRow(`
    SELECT ST_AsBinary(my_geom), population
    FROM my_table LIMIT 1`,
).Scan(&location, &population)
fmt.Println(location.AsText(), population) // 输出: POINT(-74 40.7) 8.4e+06

GeoJSON示例

// 从GeoJSON解码几何
raw := `{"type":"Point","coordinates":[-74.0,40.7]}`
var g geom.Geometry
json.NewDecoder(strings.NewReader(raw)).Decode(&g)
fmt.Println(g.AsText()) // 输出: POINT(-74 40.7)

// 编码回GeoJSON
enc := json.NewEncoder(os.Stdout)
enc.Encode(g) // 输出: {"type":"Point","coordinates":[-74,40.7]}

包含几何的结构体示例

type CityPopulation struct {
    Location   geom.Geometry `json:"loc"`
    Population int           `json:"pop"`
}

// 从GeoJSON解码
raw := `{"loc":{"type":"Point","coordinates":[-74.0,40.7]},"pop":8400000}`
var v CityPopulation
json.NewDecoder(strings.NewReader(raw)).Decode(&v)
fmt.Println(v.Location.AsText()) // 输出: POINT(-74 40.7)
fmt.Println(v.Population)        // 输出: 8400000

// 编码回GeoJSON
enc := json.NewEncoder(os.Stdout)
enc.Encode(v) // 输出: {"loc":{"type":"Point","coordinates":[-74,40.7]},"pop":8400000}

GEOS和PROJ包装器

Simple Features还提供了GEOS和PROJ的CGO包装器,可以访问更多功能。这些包装器在单独的包中实现,不需要额外功能的用户不需要暴露自己到CGO。


更多关于golang 2D几何建模与算法计算插件库simplefeatures的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang 2D几何建模与算法计算插件库simplefeatures的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


SimpleFeatures: Go语言的2D几何建模与计算库

SimpleFeatures是一个用于2D几何建模和空间计算的Go语言库,它提供了简单易用的API来处理点、线、多边形等几何对象,并支持各种空间关系计算和几何操作。

安装

go get github.com/peterstace/simplefeatures

基本几何类型

点(Point)

package main

import (
	"fmt"
	"github.com/peterstace/simplefeatures/geom"
)

func main() {
	// 创建一个点
	pt := geom.NewPoint(geom.XY{X: 1, Y: 2})
	
	// 获取坐标
	coords := pt.XY()
	fmt.Printf("Point coordinates: (%.1f, %.1f)\n", coords.X, coords.Y)
	
	// 检查点是否为空
	fmt.Println("Is empty:", pt.IsEmpty())
}

线(LineString)

func lineStringExample() {
	// 创建一条线
	line := geom.NewLineString(
		geom.NewSequence([]float64{0, 0, 1, 1, 2, 0}, geom.DimXY),
	)
	
	// 获取顶点数量
	fmt.Println("Number of points:", line.NumPoints())
	
	// 获取长度
	fmt.Println("Length:", line.Length())
}

多边形(Polygon)

func polygonExample() {
	// 创建一个多边形(带一个孔)
	shell := geom.NewLinearRing(
		geom.NewSequence([]float64{0, 0, 10, 0, 10, 10, 0, 10, 0, 0}, geom.DimXY),
	)
	hole := geom.NewLinearRing(
		geom.NewSequence([]float64{2, 2, 8, 2, 8, 8, 2, 8, 2, 2}, geom.DimXY),
	)
	poly := geom.NewPolygon([]geom.LinearRing{shell, hole})
	
	// 计算面积
	fmt.Println("Area:", poly.Area())
	
	// 检查多边形是否有效
	fmt.Println("Is valid:", poly.IsValid())
}

空间关系计算

包含关系(Contains)

func containsExample() {
	poly := geom.NewPolygon([]geom.LinearRing{
		geom.NewLinearRing(geom.NewSequence([]float64{0, 0, 5, 0, 5, 5, 0, 5, 0, 0}, geom.DimXY)),
	})
	
	ptInside := geom.NewPoint(geom.XY{X: 2, Y: 2})
	ptOutside := geom.NewPoint(geom.XY{X: 6, Y: 6})
	
	fmt.Println("Contains inside point:", poly.Contains(ptInside))
	fmt.Println("Contains outside point:", poly.Contains(ptOutside))
}

相交关系(Intersects)

func intersectsExample() {
	line1 := geom.NewLineString(
		geom.NewSequence([]float64{0, 0, 5, 5}, geom.DimXY),
	)
	line2 := geom.NewLineString(
		geom.NewSequence([]float64{0, 5, 5, 0}, geom.DimXY),
	)
	
	fmt.Println("Lines intersect:", line1.Intersects(line2))
}

距离计算(Distance)

func distanceExample() {
	pt := geom.NewPoint(geom.XY{X: 3, Y: 4})
	line := geom.NewLineString(
		geom.NewSequence([]float64{0, 0, 5, 0}, geom.DimXY),
	)
	
	fmt.Println("Distance:", pt.Distance(line))
}

几何操作

缓冲区(Buffer)

func bufferExample() {
	pt := geom.NewPoint(geom.XY{X: 0, Y: 0})
	buffered := pt.Buffer(2.0, 8) // 半径2.0,8个线段近似圆
	
	fmt.Println("Buffered area:", buffered.Area())
}

交集(Intersection)

func intersectionExample() {
	poly1 := geom.NewPolygon([]geom.LinearRing{
		geom.NewLinearRing(geom.NewSequence([]float64{0, 0, 5, 0, 5, 5, 0, 5, 0, 0}, geom.DimXY)),
	})
	poly2 := geom.NewPolygon([]geom.LinearRing{
		geom.NewLinearRing(geom.NewSequence([]float64{3, 0, 8, 0, 8, 5, 3, 5, 3, 0}, geom.DimXY)),
	})
	
	intersection := poly1.Intersection(poly2)
	fmt.Println("Intersection area:", intersection.Area())
}

并集(Union)

func unionExample() {
	poly1 := geom.NewPolygon([]geom.LinearRing{
		geom.NewLinearRing(geom.NewSequence([]float64{0, 0, 2, 0, 2, 2, 0, 2, 0, 0}, geom.DimXY)),
	})
	poly2 := geom.NewPolygon([]geom.LinearRing{
		geom.NewLinearRing(geom.NewSequence([]float64{1, 1, 3, 1, 3, 3, 1, 3, 1, 1}, geom.DimXY)),
	})
	
	union := poly1.Union(poly2)
	fmt.Println("Union area:", union.Area())
}

WKT/WKB支持

SimpleFeatures支持Well-Known Text(WKT)和Well-Known Binary(WKB)格式的输入输出。

func wktExample() {
	// 从WKT创建几何体
	wkt := "POLYGON((0 0,10 0,10 10,0 10,0 0),(2 2,8 2,8 8,2 8,2 2))"
	poly, err := geom.UnmarshalWKT(wkt)
	if err != nil {
		panic(err)
	}
	
	// 转换为WKT
	fmt.Println("WKT representation:", poly.AsText())
	
	// 转换为WKB
	wkb := poly.AsBinary()
	fmt.Printf("WKB representation (first 10 bytes): %v\n", wkb[:10])
}

性能考虑

SimpleFeatures在设计时考虑了性能:

  1. 几何对象是不可变的,便于并发使用
  2. 使用高效的内存布局
  3. 算法经过优化,适合大规模几何计算

适用场景

SimpleFeatures适用于:

  • GIS应用开发
  • 空间数据分析
  • 几何算法实现
  • CAD软件集成
  • 游戏开发中的2D物理引擎

这个库提供了比标准库更丰富的几何操作功能,同时保持了简单易用的API设计。对于更复杂的3D或专业GIS需求,可能需要考虑其他专门的库如GEOS或PostGIS的Go绑定。

回到顶部