界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
数据与研究 · SKILL.md

nettopologysuite

nettopologysuite

【数据与研究】Use when performing 2D computational geometry in .NET — spatial predicates, overlay operations, buffering, WKT/WKB I/O. NetTopologySuite: the .NET port of JTS, available via NuGet for spatial analysis in C# applications.

独立 GitHub 快照 · 自动分类 · 以原作者文档为准

技能说明

GitHub

name: nettopologysuite description: "Use when performing 2D computational geometry in .NET — spatial predicates, overlay operations, buffering, WKT/WKB I/O. NetTopologySuite: the .NET port of JTS, available via NuGet for spatial analysis in C# applications." tags:

  • dotnet
  • csharp
  • geometry
  • spatial
  • wkt
  • wkb
  • geojson
  • ef-core
  • npgsql

项目地址: https://github.com/NetTopologySuite/NetTopologySuite

NuGet: NetTopologySuite(最新稳定版 2.6.0,截至2026年)

官方文档: https://nettopologysuite.github.io/NetTopologySuite/

许可证: BSD-3-Clause

概述

NTS 与 JTS API 几乎一一对应(C# 命名风格):

  • 几何模型:Point/LineString/Polygon/Multi*/GeometryCollection
  • 空间关系:Equals/Contains/Within/Intersects/Touches/Crosses/Overlaps/Disjoint/Relate
  • 集合运算:Intersection/Union/Difference/SymmetricDifference/Buffer
  • 几何分析:ConvexHull/Centroid/Area/Length/Distance/IsValid/Simplify
  • 空间索引:STRtree/Quadtree
  • 格式读写:WKT、WKB、GeoJSON、Shapefile(独立 NuGet)
  • EF Core 集成:SqlServer 与 PostgreSQL 自动翻译为空间 SQL

环境准备

dotnet add package NetTopologySuite
dotnet add package NetTopologySuite.IO.GeoJSON
dotnet add package NetTopologySuite.IO.ShapeFile
dotnet add package ProjNet                          # 坐标变换(可选)

.NET 6+ 推荐。


几何工厂

using NetTopologySuite.Geometries;

var gf = new GeometryFactory(new PrecisionModel(), 4326);

var p  = gf.CreatePoint(new Coordinate(116.397, 39.908));
var ls = gf.CreateLineString(new[] {
    new Coordinate(116, 39), new Coordinate(117, 40)
});
var poly = gf.CreatePolygon(new[] {
    new Coordinate(0,0), new Coordinate(10,0),
    new Coordinate(10,10), new Coordinate(0,10), new Coordinate(0,0)
});

空间关系与运算

bool b   = polyA.Intersects(polyB);
var inter = polyA.Intersection(polyB);
var union = polyA.Union(polyB);
var diff  = polyA.Difference(polyB);

var buf  = p.Buffer(100);
var hull = mp.ConvexHull();
double area = poly.Area;
double len  = ls.Length;
double dist = polyA.Distance(polyB);

string rel = polyA.Relate(polyB).ToString();
bool ok    = polyA.Relate(polyB, "T*F**F***");

WKT / WKB / GeoJSON

using NetTopologySuite.IO;

var rdr = new WKTReader();
var g = rdr.Read("POINT (116.4 39.9)");

string wkt = new WKTWriter().Write(g);
byte[] wkb = new WKBWriter().Write(g);

using NetTopologySuite.IO.Converters;
using System.Text.Json;
var opts = new JsonSerializerOptions();
opts.Converters.Add(new GeoJsonConverterFactory());
string json = JsonSerializer.Serialize(g, opts);
var g2 = JsonSerializer.Deserialize<Geometry>(json, opts);

Shapefile

using NetTopologySuite.IO.Esri;
foreach (var f in Shapefile.ReadAllFeatures("input.shp"))
    Console.WriteLine(quot;{f.Geometry} {f.Attributes["NAME"]}");

Shapefile.WriteAllFeatures(features, "output.shp");

空间索引

using NetTopologySuite.Index.Strtree;

var tree = new STRtree<Geometry>();
foreach (var g in geometries)
    tree.Insert(g.EnvelopeInternal, g);
tree.Build();

var hits   = tree.Query(queryEnv);
var nearby = tree.NearestNeighbour(p.EnvelopeInternal, p, new GeometryItemDistance());

几何修复与简化

using NetTopologySuite.Operation.Valid;
using NetTopologySuite.Simplify;
using NetTopologySuite.Geometries.Utilities;

if (!poly.IsValid)
    poly = (Polygon)GeometryFixer.Fix(poly);

var simp = TopologyPreservingSimplifier.Simplify(poly, 0.001);

EF Core + SQL Server / PostgreSQL

dotnet add package Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
# 或
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite
public class City {
    public int Id { get; set; }
    public string Name { get; set; }
    public Point Location { get; set; }
    public Geometry Boundary { get; set; }
}

services.AddDbContext<AppDb>(o =>
    o.UseSqlServer(conn, x => x.UseNetTopologySuite()));

var nearby = db.Cities
    .Where(c => c.Location.Distance(target) < 5000)
    .OrderBy(c => c.Location.Distance(target))
    .Take(10)
    .ToList();   // 自动翻译为空间 SQL

坐标系转换(ProjNet)

using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;

var src = GeographicCoordinateSystem.WGS84;
var tgt = ProjectedCoordinateSystem.WebMercator;
var ct  = new CoordinateTransformationFactory()
            .CreateFromCoordinateSystems(src, tgt);
double[] xy = ct.MathTransform.Transform(new[] { 116.397, 39.908 });

性能优化

  1. 共享 GeometryFactory,固定 SRID
  2. 大批量空间查询用 STRtree
  3. WKB 比 WKT 更快更紧凑
  4. 多次空间关系判断使用 PreparedGeometry:
using NetTopologySuite.Geometries.Prepared;
var prep = PreparedGeometryFactory.Prepare(largePoly);
foreach (var p in points) if (prep.Contains(p)) ...

常见问题

问题解决
TopologyExceptionGeometryFixer.Fix 修复无效几何
EF Core 类型冲突用 UseNetTopologySuite() 而非 Microsoft.SqlServer.Types
Z/M 坐标丢失配置 WKBWriter 的 HandleOrdinates
Buffer 慢减小 quadrantSegments、并行处理

AI 使用建议

推荐工作流

  1. 创建几何工厂:使用 new GeometryFactory(new PrecisionModel(), 4326) 创建工厂,SRID 指定坐标系
  2. 创建几何对象:通过工厂方法 CreatePoint()、CreateLineString()、CreatePolygon() 创建几何
  3. 空间运算:直接调用几何对象方法 Intersects()、Intersection()、Buffer() 等
  4. 格式读写:使用 WKTReader/WKTWriter、GeoJsonConverterFactory 进行序列化
  5. EF Core 集成:UseNetTopologySuite() 启用空间查询翻译为 SQL

关键注意事项

  • GeometryFactory 共享:固定 SRID,复用 GeometryFactory 实例
  • 拓扑异常修复:无效几何使用 GeometryFixer.Fix() 修复
  • PreparedGeometry:重复空间关系判断时使用 PreparedGeometryFactory.Prepare() 大幅提速
  • STRtree 批量查询:先 Build() 再 Query(),大数据量场景优于逐几何判断
  • WKB vs WKT:WKB 比 WKT 更快更紧凑,数据库交互优先使用 WKB
  • Z/M 坐标:WKBWriter 需配置 HandleOrdinates 保留 Z/M 坐标

相关技能

参考资源

我的收藏