golang 2D几何建模与算法计算插件库simplefeatures的使用
Golang 2D几何建模与算法计算插件库simplefeatures的使用
Simple Features是一个2D几何库,提供了Go类型来建模几何图形以及操作它们的算法。它是OpenGIS Consortium的Simple Feature Access Specification的纯Go实现。
几何类型
类型 | 示例 | 描述 |
---|---|---|
Point | 空间中的单个位置 | |
MultiPoint | 空间中的点集合 | |
LineString | 通过控制点线性插值定义的曲线 | |
MultiLineString | LineString的集合 | |
Polygon | 界定某个区域的平面表面几何图形,可能有孔 | |
MultiPolygon | Polygon的集合 | |
GeometryCollection | 不受约束的几何图形集合 | |
Geometry | 可以包含任何类型的几何图形 | |
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
更多关于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在设计时考虑了性能:
- 几何对象是不可变的,便于并发使用
- 使用高效的内存布局
- 算法经过优化,适合大规模几何计算
适用场景
SimpleFeatures适用于:
- GIS应用开发
- 空间数据分析
- 几何算法实现
- CAD软件集成
- 游戏开发中的2D物理引擎
这个库提供了比标准库更丰富的几何操作功能,同时保持了简单易用的API设计。对于更复杂的3D或专业GIS需求,可能需要考虑其他专门的库如GEOS或PostGIS的Go绑定。