# geometry-api-net
**Repository Path**: znlgis/geometry-api-net
## Basic Information
- **Project Name**: geometry-api-net
- **Description**: No description available
- **Primary Language**: C#
- **License**: LGPL-2.1
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-09
- **Last Updated**: 2026-04-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Esri Geometry API for .NET
[Esri Geometry API for Java](https://github.com/Esri/geometry-api-java) 的 C# 移植版本,针对 .NET Standard 2.0,为空间数据分析提供全面的几何操作功能。
## 概述
本库提供了一套完整的几何类型和空间操作,与 Esri 的几何模型兼容。设计用于跨平台使用,支持 .NET Core、.NET Framework 4.6.1+、Xamarin 以及其他 .NET Standard 2.0 兼容平台。
**注意**:所有源代码注释均为中文,便于中文开发者阅读和维护。
## 功能特性
### 几何类型
- **Point(点)** - 表示具有 X、Y 坐标的点(可选 Z 和 M 值)
- **MultiPoint(多点)** - 点的集合
- **Polyline(折线)** - 一条或多条连接的路径
- **Polygon(多边形)** - 一个或多个环形成的多边形
- **Envelope(包络)** - 轴对齐的边界矩形
- **Line(线段)** - 两点之间的线段
### 空间操作符
#### 空间关系操作符(9 个操作符)
- **Contains(包含)** - 测试一个几何对象是否包含另一个
- **Intersects(相交)** - 测试几何对象是否相交
- **Distance(距离)** - 计算几何对象之间的距离
- **Equals(相等)** - 测试两个几何对象在空间上是否相等
- **Disjoint(分离)** - 测试几何对象是否不相交
- **Within(内部)** - 测试 geometry1 是否在 geometry2 内部
- **Crosses(交叉)** - 测试几何对象是否交叉
- **Touches(相接)** - 测试几何对象是否在边界处相接
- **Overlaps(重叠)** - 测试相同维度的几何对象是否重叠
#### 几何操作
- **Buffer(缓冲区)** - 在几何对象周围创建缓冲区(偏移多边形)
- **ConvexHull(凸包)** - 使用 Graham 扫描算法计算凸包
- **Area(面积)** - 计算多边形和包络的面积
- **Length(长度)** - 计算几何对象的长度/周长
#### 几何辅助方法(新增!)
- **CalculateArea2D()** - 直接计算几何对象的 2D 面积
- **CalculateLength2D()** - 直接计算几何对象的 2D 长度/周长
- **Copy()** - 创建包含所有属性的几何对象深层副本
- **IsValid()** - 检查几何对象是否有效(非 null 且非空)
- **IsPoint, IsLinear, IsArea** - 几何对象类型检查属性
#### 集合操作(4 个操作符)
- **Union(并集)** - 合并两个几何对象(任一几何对象中的所有点)
- **Intersection(交集)** - 查找公共区域(两个几何对象中的所有点)
- **Difference(差集)** - 从一个几何对象中减去另一个(geometry1 - geometry2)
- **SymmetricDifference(对称差)** - 查找排他区域((A-B) ∪ (B-A))
#### 其他操作符(6 个操作符)
- **Simplify(简化)** - 使用 Douglas-Peucker 算法简化几何对象
- **SimplifyOGC(OGC 简化)** - 根据 OGC 规范简化几何对象(新增!)
- **Centroid(质心)** - 计算几何对象的质心
- **Boundary(边界)** - 根据 OGC 规范计算边界
- **Generalize(概化)** - 删除顶点的同时保持总体形状
- **Densify(密化)** - 添加顶点以确保没有线段超过最大长度
#### 高级操作符
- **Clip(裁剪)** - 使用 Cohen-Sutherland 算法将几何对象裁剪到包络
- **GeodesicDistance(大地测量距离)** - 计算 WGS84 椭球上的大圆距离(Vincenty 公式)
- **GeodesicArea(大地测量面积)** - 使用球面过量公式计算 WGS84 椭球上的大地测量面积
- **Offset(偏移)** - 在指定距离处创建偏移曲线/多边形(垂直位移)
- **Proximity2D(2D 邻近)** - 查找几何对象上的最近坐标和顶点(GetNearestCoordinate、GetNearestVertex、GetNearestVertices)
#### 便利 API
- **GeometryEngine** - 使用便利方法包装所有操作符的简化静态 API
- **MapGeometry** - 将几何对象与空间参考捆绑(新增!)
### 导入/导出格式
- **WKT (Well-Known Text)** - 对所有几何类型的完整导入和导出支持
- **WKB (Well-Known Binary)** - 支持字节序的二进制格式导入/导出
- **GeoJSON** - 对所有几何类型的完整 GeoJSON 导入/导出
- **Esri JSON** - Esri 特定的 JSON 格式导入/导出(x/y 属性 vs GeoJSON 坐标数组)
- **JSON** - 使用 System.Text.Json 的 Point 序列化
### 空间参考系统
- 支持众所周知的 ID(WKID)
- 内置支持 WGS 84(EPSG:4326)和 Web Mercator(EPSG:3857)
### JSON 序列化
- Point 几何对象的 System.Text.Json 转换器
- 支持 X、Y、Z 和 M 坐标
## 快速开始
### 安装
#### 通过 NuGet 安装(推荐)
```bash
# 安装核心库
dotnet add package Esri.Geometry.Core
# 安装 JSON 支持
dotnet add package Esri.Geometry.Json
```
或在 .csproj 文件中添加:
```xml
```
**提示**: 将 `Version="*"` 替换为具体的版本号,如 `Version="1.0.0"`。
#### 通过项目引用安装
在项目中添加对核心库的引用:
```xml
```
对于 JSON 支持,还需引用:
```xml
```
### 基本用法
```csharp
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;
// 创建点
var point1 = new Point(10, 20);
var point2 = new Point(30, 40);
// 计算距离
var distance = point1.Distance(point2);
Console.WriteLine($"Distance: {distance}");
// 创建包络
var envelope = new Envelope(0, 0, 100, 100);
// 测试包含关系
var testPoint = new Point(50, 50);
bool contains = envelope.Contains(testPoint);
Console.WriteLine($"Contains: {contains}");
// 使用操作符
var distanceOp = DistanceOperator.Instance;
var dist = distanceOp.Execute(point1, point2);
var containsOp = ContainsOperator.Instance;
var result = containsOp.Execute(envelope, testPoint);
```
### GeometryEngine - 简化的 API
`GeometryEngine` 类为所有几何操作提供了简化的静态 API:
```csharp
using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
// 所有操作都可作为静态方法使用
var point1 = new Point(0, 0);
var point2 = new Point(3, 4);
// 空间关系
bool contains = GeometryEngine.Contains(envelope, point);
bool intersects = GeometryEngine.Intersects(geom1, geom2);
double distance = GeometryEngine.Distance(point1, point2); // 5.0
// 集合操作
var union = GeometryEngine.Union(geom1, geom2);
var intersection = GeometryEngine.Intersection(geom1, geom2);
var difference = GeometryEngine.Difference(geom1, geom2);
// 几何操作
var buffer = GeometryEngine.Buffer(point, 10.0);
var hull = GeometryEngine.ConvexHull(multiPoint);
double area = GeometryEngine.Area(polygon);
double length = GeometryEngine.Length(polyline);
// 导入/导出
string wkt = GeometryEngine.GeometryToWkt(geometry);
var geom = GeometryEngine.GeometryFromWkt(wkt);
string geoJson = GeometryEngine.GeometryToGeoJson(geometry);
var geom2 = GeometryEngine.GeometryFromGeoJson(geoJson);
// 邻近操作
var result = GeometryEngine.GetNearestCoordinate(geometry, queryPoint);
Console.WriteLine($"最近的点: ({result.Coordinate.X}, {result.Coordinate.Y})");
Console.WriteLine($"距离: {result.Distance}");
```
### 使用多边形
```csharp
var polygon = new Polygon();
var ring = new[] {
new Point(0, 0),
new Point(10, 0),
new Point(10, 10),
new Point(0, 10),
new Point(0, 0)
};
polygon.AddRing(ring);
var area = polygon.Area;
Console.WriteLine($"多边形面积: {area}");
```
### 空间参考
```csharp
using Esri.Geometry.Core.SpatialReference;
// 创建 WGS 84 空间参考
var wgs84 = SpatialReference.Wgs84();
Console.WriteLine($"WKID: {wgs84.Wkid}");
// 创建 Web Mercator 空间参考
var webMercator = SpatialReference.WebMercator();
```
### WKT 导入/导出
```csharp
using Esri.Geometry.Core.IO;
// 导出为 WKT
var point = new Point(10.5, 20.7);
var wkt = WktExportOperator.ExportToWkt(point);
// 结果: "POINT (10.5 20.7)"
// 从 WKT 导入
var geometry = WktImportOperator.ImportFromWkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
var polygon = (Polygon)geometry;
```
### 空间关系测试
```csharp
// 测试各种空间关系
var env1 = new Envelope(0, 0, 10, 10);
var env2 = new Envelope(5, 5, 15, 15);
bool intersects = IntersectsOperator.Instance.Execute(env1, env2); // true
bool overlaps = OverlapsOperator.Instance.Execute(env1, env2); // true
bool disjoint = DisjointOperator.Instance.Execute(env1, env2); // false
bool equals = EqualsOperator.Instance.Execute(env1, env1); // true
```
### 几何操作
```csharp
// 在点周围创建缓冲区
var point = new Point(10, 20);
var buffer = BufferOperator.Instance.Execute(point, 5.0);
// 计算凸包
var multiPoint = new MultiPoint();
multiPoint.Add(new Point(0, 0));
multiPoint.Add(new Point(10, 0));
multiPoint.Add(new Point(5, 10));
var hull = ConvexHullOperator.Instance.Execute(multiPoint);
// 计算面积和长度
var polygon = new Polygon();
// ... 向多边形添加环
double area = AreaOperator.Instance.Execute(polygon);
double perimeter = LengthOperator.Instance.Execute(polygon);
// 简化折线
var polyline = new Polyline();
// ... 添加路径
var simplified = SimplifyOperator.Instance.Execute(polyline, tolerance: 0.5);
// 计算质心
var centroid = CentroidOperator.Instance.Execute(polygon);
// 获取边界
var boundary = BoundaryOperator.Instance.Execute(polygon); // 返回 Polyline
// 将几何对象裁剪到包络
var clipEnvelope = new Envelope(0, 0, 100, 100);
var clipped = ClipOperator.Instance.Execute(polyline, clipEnvelope);
// 计算大地测量距离(地球上的大圆)
var newYork = new Point(-74.0060, 40.7128); // 经度,纬度
var london = new Point(-0.1278, 51.5074);
double distanceMeters = GeodesicDistanceOperator.Instance.Execute(newYork, london);
// 结果: ~5,570,000 米(5,570 公里)
// 概化 - 删除顶点的同时保持形状
var generalizedPolyline = GeneralizeOperator.Instance.Execute(polyline, maxDeviation: 0.5);
// 密化 - 添加顶点以确保没有线段超过最大长度
var densifiedPolyline = DensifyOperator.Instance.Execute(polyline, maxSegmentLength: 5.0);
```
### 集合操作
```csharp
using Esri.Geometry.Core.Operators;
// 并集 - 合并几何对象
var point1 = new Point(0, 0);
var point2 = new Point(10, 10);
var union = UnionOperator.Instance.Execute(point1, point2); // 返回 MultiPoint
var env1 = new Envelope(0, 0, 10, 10);
var env2 = new Envelope(5, 5, 15, 15);
var envUnion = UnionOperator.Instance.Execute(env1, env2); // 返回 Envelope(0, 0, 15, 15)
// 交集 - 查找公共区域
var intersection = IntersectionOperator.Instance.Execute(env1, env2); // 返回 Envelope(5, 5, 10, 10)
var testPoint = new Point(7, 7);
var ptIntersection = IntersectionOperator.Instance.Execute(testPoint, env1); // 返回 Point(7, 7)
// 差集 - 从一个几何对象中减去另一个
var mp = new MultiPoint();
mp.Add(new Point(2, 2));
mp.Add(new Point(5, 5));
mp.Add(new Point(12, 12));
var difference = DifferenceOperator.Instance.Execute(mp, env1); // 返回 Point(12, 12) - env1 外的点
// 对称差 - 任一中的点但不同时在两者中
var mp1 = new MultiPoint();
mp1.Add(new Point(0, 0));
mp1.Add(new Point(10, 10));
var mp2 = new MultiPoint();
mp2.Add(new Point(10, 10));
mp2.Add(new Point(20, 20));
var symDiff = SymmetricDifferenceOperator.Instance.Execute(mp1, mp2); // 返回包含 (0,0) 和 (20,20) 的 MultiPoint
```
### WKB 导入/导出
```csharp
using Esri.Geometry.Core.IO;
// 导出为 WKB(二进制格式)
var point = new Point(10.5, 20.7);
byte[] wkb = WkbExportOperator.ExportToWkb(point);
// 使用大端字节序导出
byte[] wkbBigEndian = WkbExportOperator.ExportToWkb(point, bigEndian: true);
// 从 WKB 导入
var geometry = WkbImportOperator.ImportFromWkb(wkb);
var parsedPoint = (Point)geometry;
```
### GeoJSON 导入/导出
```csharp
using Esri.Geometry.Core.IO;
// 导出为 GeoJSON
var point = new Point(10.5, 20.3, 30.7);
string geoJson = GeoJsonExportOperator.ExportToGeoJson(point);
// 结果: {"type":"Point","coordinates":[10.5,20.3,30.7]}
// 导出 MultiPoint
var multiPoint = new MultiPoint();
multiPoint.Add(new Point(10, 20));
multiPoint.Add(new Point(30, 40));
string mpGeoJson = GeoJsonExportOperator.ExportToGeoJson(multiPoint);
// 结果: {"type":"MultiPoint","coordinates":[[10,20],[30,40]]}
// 导出 Polyline(单路径变为 LineString)
var polyline = new Polyline();
polyline.AddPath(new List { new Point(0, 0), new Point(10, 10) });
string lineGeoJson = GeoJsonExportOperator.ExportToGeoJson(polyline);
// 结果: {"type":"LineString","coordinates":[[0,0],[10,10]]}
// 导出 Polygon
var polygon = new Polygon();
polygon.AddRing(new List
{
new Point(0, 0),
new Point(10, 0),
new Point(10, 10),
new Point(0, 10),
new Point(0, 0)
});
string polygonGeoJson = GeoJsonExportOperator.ExportToGeoJson(polygon);
// 结果: {"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}
// 从 GeoJSON 导入
var importedGeometry = GeoJsonImportOperator.ImportFromGeoJson(geoJson);
var importedPoint = (Point)importedGeometry;
```
### 邻近操作
```csharp
using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;
// 查找几何对象上最接近查询点的坐标
var polyline = new Polyline();
polyline.AddPath(new[] {
new Point(0, 0),
new Point(10, 0),
new Point(10, 10)
});
var queryPoint = new Point(5, 5);
// 使用 GeometryEngine(推荐)
var result = GeometryEngine.GetNearestCoordinate(polyline, queryPoint);
Console.WriteLine($"最近的坐标: ({result.Coordinate.X}, {result.Coordinate.Y})");
Console.WriteLine($"距离: {result.Distance}");
Console.WriteLine($"顶点索引: {result.VertexIndex}");
// 直接使用操作符
var proximity = Proximity2DOperator.Instance;
var result2 = proximity.GetNearestVertex(polyline, queryPoint);
Console.WriteLine($"最近的顶点: ({result2.Coordinate.X}, {result2.Coordinate.Y})");
// 在搜索半径内查找多个顶点
var multiPoint = new MultiPoint();
multiPoint.Add(new Point(0, 0));
multiPoint.Add(new Point(10, 10));
multiPoint.Add(new Point(20, 20));
var results = GeometryEngine.GetNearestVertices(
multiPoint,
queryPoint,
searchRadius: 15.0,
maxVertexCount: 5
);
foreach (var r in results)
{
Console.WriteLine($"点: ({r.Coordinate.X}, {r.Coordinate.Y}), 距离: {r.Distance}");
}
// 测试点是否在多边形内部
var polygon = new Polygon();
polygon.AddRing(new[] {
new Point(0, 0),
new Point(100, 0),
new Point(100, 100),
new Point(0, 100),
new Point(0, 0)
});
var testPoint = new Point(50, 50);
var nearestResult = GeometryEngine.GetNearestCoordinate(polygon, testPoint, testPolygonInterior: true);
if (nearestResult.Distance == 0)
{
Console.WriteLine("点在多边形内部");
}
```
## 项目结构
```
Esri.Geometry.Api/
├── src/
│ ├── Esri.Geometry.Core/ # 核心几何库
│ │ ├── Geometries/ # 几何类型
│ │ ├── Operators/ # 几何操作符
│ │ ├── SpatialReference/ # 空间参考系统
│ │ └── IO/ # WKT 和 WKB 导入/导出
│ └── Esri.Geometry.Json/ # JSON 序列化支持
├── tests/
│ └── Esri.Geometry.Tests/ # 单元测试(xUnit)
└── samples/
└── Esri.Geometry.Samples/ # 示例应用程序
```
## 构建项目
### 前提条件
- .NET SDK 8.0 或更高版本(用于构建)
- 该库目标为 .NET Standard 2.0 以实现最大兼容性
### 构建命令
```bash
# 还原依赖项
dotnet restore
# 构建所有项目
dotnet build
# 运行测试
dotnet test
# 运行示例应用程序
cd samples/Esri.Geometry.Samples
dotnet run
```
## 测试
项目使用 xUnit 进行单元测试。测试位于 `tests/Esri.Geometry.Tests` 目录中。
```bash
# 运行所有测试
dotnet test
# 使用详细输出运行测试
dotnet test --logger "console;verbosity=detailed"
```
## 技术栈
- **目标框架**: .NET Standard 2.0
- **语言**: C# 7.0+
- **JSON 库**: System.Text.Json 8.0.6
- **测试框架**: xUnit
- **许可证**: LGPL 2.1
## 路线图
### 已完成的功能 ✅
- [x] 全部 9 个空间关系操作符(Contains、Intersects、Distance、Equals、Disjoint、Within、Crosses、Touches、Overlaps)
- [x] WKT(Well-Known Text)对所有几何类型的导入/导出
- [x] WKB(Well-Known Binary)导入/导出,支持字节序
- [x] Buffer 操作符(简化的正方形/矩形缓冲区)
- [x] 凸包计算(Graham 扫描算法)
- [x] 面积和长度计算操作符
- [x] Simplify 操作符(Douglas-Peucker 算法)
- [x] 质心计算(质量中心)
- [x] 边界计算(OGC 规范)
- [x] Clip 操作符(Cohen-Sutherland 线段裁剪)
- [x] 大地测量距离(WGS84 椭球上的 Vincenty 公式)
- [x] 集合操作(Union、Intersection、Difference、SymmetricDifference)
- [x] Generalize 操作符(删除顶点的同时保持形状)
- [x] Densify 操作符(向线段添加顶点)
- [x] Proximity2D 操作符(查找最近的坐标和顶点)
- [x] GeometryEngine 便利类(简化的静态 API)
- [x] 使用光线投射算法的点在多边形内测试
### 测试覆盖率
- **255 个测试通过**,具有全面的覆盖率
- 28 个几何类型测试
- 14 个空间关系操作符测试
- 23 个附加操作符测试(Simplify、Centroid、Boundary、Generalize、Densify)
- 12 个几何操作测试(Buffer、ConvexHull、Area、Length)
- 20 个高级操作符测试(Clip、GeodesicDistance、GeodesicArea、Offset、Esri JSON)
- 24 个邻近和 GeometryEngine 测试
- 23 个集合操作测试(Union、Intersection、Difference、SymmetricDifference)
- 17 个 WKT 导入/导出测试
- 10 个 WKB 导入/导出测试
- 8 个 GeoJSON 导入/导出测试
- 4 个 JSON 序列化测试
- 10 个 MapGeometry 测试
- 18 个 SimplifyOGC 操作符测试
- 17 个几何辅助方法测试(新增!)
### 计划中的功能
- [ ] Cut 操作符(使用折线切割几何对象 - 需要复杂的拓扑算法)
- [ ] 投影/转换支持(需要外部投影库)
- [ ] Relate 操作符(DE-9IM 空间关系 - 需要复杂的拓扑计算)
- [ ] 使用 Span 和 Memory 的性能优化
- [ ] 圆形缓冲区生成(目前仅支持正方形/矩形)
- [ ] Union/Intersection/Difference 的完整多边形裁剪(目前对复杂多边形进行了简化)
### 最近实现的功能 ✅
- [x] Offset 操作符(创建偏移曲线/多边形)
- [x] ESRI JSON 导入/导出(Esri 专有格式)
- [x] 大地测量面积计算(WGS84 椭球)
- [x] **GeometryEngine** - 所有操作符的简化静态 API
- [x] **Proximity2D 操作符** - 查找最近的坐标和顶点
- [x] **点在多边形内测试** - Contains 操作符的光线投射算法
- [x] **SimplifyOGC 操作符** - 符合 OGC 标准的几何简化
- [x] **MapGeometry** - 将几何对象与空间参考捆绑
- [x] **几何辅助方法** - CalculateArea2D、CalculateLength2D、Copy、IsValid(新增!)
## 代码注释
本项目的所有源代码注释均已翻译为中文,包括:
- 所有几何类型的 XML 文档注释
- 所有操作符的完整注释
- 接口和辅助类的注释
- 方法参数和返回值的说明
这使得中文开发者能够更容易地理解和使用该库。
## 发布和版本管理
本项目使用 GitHub Actions 自动发布 NuGet 包。当创建新的版本标签(tag)时,会自动构建、测试并发布包到 NuGet.org。
### 自动发布流程
1. 创建新的版本标签(例如:`v1.0.0`)
2. GitHub Actions 自动触发发布工作流
3. 构建项目并运行所有测试
4. 打包两个 NuGet 包:`Esri.Geometry.Core` 和 `Esri.Geometry.Json`
5. 发布到 NuGet.org
6. 创建 GitHub Release
### 发布新版本
```bash
# 创建版本标签
git tag v1.0.0
# 推送标签到远程仓库触发自动发布
git push origin v1.0.0
```
详细的发布说明和配置,请参阅 [GitHub Actions 工作流文档](.github/workflows/README.md)。
## 贡献
欢迎贡献!请随时提交问题和拉取请求。
## 许可证
本项目采用 GNU Lesser General Public License v2.1 许可 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
## 致谢
本项目是 [Esri Geometry API for Java](https://github.com/Esri/geometry-api-java) 的 C# 移植版本,Java 版本采用 Apache 2.0 许可证。
## 相关项目
- [Esri Geometry API for Java](https://github.com/Esri/geometry-api-java) - 原始 Java 实现
- [geometry-api-cs](https://github.com/Esri/geometry-api-cs) - Esri 的另一个 .NET 实现
## 支持
如有问题、疑问或贡献,请访问 [GitHub 仓库](https://github.com/znlgis/geometry-api-net)。