第一章:geometry-api-net 项目概述与框架理念

1.1 项目简介

geometry-api-net 是一个面向 .NET 平台的高性能几何计算库,是 Esri Geometry API for Java 的 C# 移植版本。该库提供了完整的几何对象模型、空间关系测试、几何运算、数据格式转换等核心功能,是开发 GIS 应用程序的基础工具库。

1.1.1 项目背景

在地理信息系统(GIS)开发领域,几何计算是最基础也是最核心的功能之一。无论是简单的点线面绘制,还是复杂的空间分析,都离不开强大的几何计算引擎。Esri 作为全球领先的 GIS 软件厂商,开源了其 Java 版本的几何 API,geometry-api-net 正是基于该项目的设计理念和算法实现,为 .NET 生态系统提供了同等级别的几何计算能力。

1.1.2 技术规格

技术项 说明
目标框架 .NET Standard 2.0
开发语言 C# 7.0+
JSON 支持 System.Text.Json 8.0.6
测试框架 xUnit
开源协议 LGPL 2.1

选择 .NET Standard 2.0 作为目标框架,可以确保库在各种 .NET 运行时环境中的兼容性:

  • .NET Framework 4.6.1+
  • .NET Core 2.0+
  • .NET 5/6/7/8+
  • Xamarin
  • Unity

1.2 核心设计理念

1.2.1 单例模式的操作符设计

geometry-api-net 采用了操作符单例模式(Operator Singleton Pattern)作为核心设计范式。这种设计模式的核心思想是:将几何运算封装为独立的操作符类,每个操作符类都是单例的,通过 Instance 属性获取唯一实例。

// 操作符接口定义
public interface IGeometryOperator<TResult>
{
    TResult Execute(Geometry geometry, SpatialReference? spatialRef = null);
}

public interface IBinaryGeometryOperator<TResult>
{
    TResult Execute(Geometry geometry1, Geometry geometry2, 
                    SpatialReference? spatialRef = null);
}

这种设计带来了几个重要优势:

  1. 内存效率:操作符实例在整个应用生命周期内只创建一次,避免了频繁创建对象的开销
  2. 线程安全:使用 Lazy<T> 实现延迟初始化,确保线程安全
  3. 一致的 API:所有操作符都遵循统一的接口规范,学习一个就能掌握全部
  4. 可扩展性:新增操作符只需实现相应接口,无需修改现有代码
// 典型的操作符实现
public class BufferOperator : IGeometryOperator<Polygon>
{
    private static readonly Lazy<BufferOperator> _instance = 
        new(() => new BufferOperator());
    
    private BufferOperator() { }
    
    public static BufferOperator Instance => _instance.Value;
    
    public Polygon Execute(Geometry geometry, SpatialReference? spatialRef = null)
    {
        // 实现逻辑
    }
}

1.2.2 几何类型层次结构

框架采用了清晰的类型层次结构设计,所有几何类型都继承自抽象基类 Geometry:

Geometry (抽象基类)
├── Point (点)
├── MultiPoint (多点)
├── Line (线段)
├── Polyline (折线)
├── Polygon (多边形)
└── Envelope (包络矩形)

基类定义了所有几何对象的公共属性和行为:

public abstract class Geometry
{
    // 几何类型标识
    public abstract GeometryType Type { get; }
    
    // 是否为空
    public abstract bool IsEmpty { get; }
    
    // 几何维度:点=0, 线=1, 面=2
    public abstract int Dimension { get; }
    
    // 获取边界矩形
    public abstract Envelope GetEnvelope();
    
    // 类型判断便捷属性
    public bool IsPoint => Type == GeometryType.Point || Type == GeometryType.MultiPoint;
    public bool IsLinear => Type == GeometryType.Line || Type == GeometryType.Polyline;
    public bool IsArea => Type == GeometryType.Polygon || Type == GeometryType.Envelope;
    
    // 几何计算方法
    public virtual double CalculateArea2D() { ... }
    public virtual double CalculateLength2D() { ... }
    public virtual Geometry Copy() { ... }
    public virtual bool IsValid() { ... }
}

这种设计体现了开放封闭原则(OCP):对扩展开放,对修改封闭。添加新的几何类型只需继承 Geometry 基类,无需修改现有代码。

1.2.3 关注点分离

框架将功能清晰地划分为不同的命名空间,实现了良好的关注点分离:

OpenGIS.Esri.Geometry.Core
├── Geometries/          # 几何类型定义
│   ├── Geometry.cs      # 抽象基类
│   ├── Point.cs         # 点
│   ├── MultiPoint.cs    # 多点
│   ├── Line.cs          # 线段
│   ├── Polyline.cs      # 折线
│   ├── Polygon.cs       # 多边形
│   └── Envelope.cs      # 包络矩形
├── Operators/           # 几何操作符
│   ├── 空间关系操作符
│   ├── 几何运算操作符
│   └── 集合操作符
├── SpatialReference/    # 空间参考系统
└── IO/                  # 数据格式导入导出
    ├── WKT 处理
    ├── WKB 处理
    ├── GeoJSON 处理
    └── Esri JSON 处理

1.2.4 不可变性与数据封装

框架在数据封装方面采用了保守策略,内部集合对象通过 AsReadOnly() 方法返回只读视图:

public class Polygon : Geometry
{
    private readonly List<List<Point>> _rings;
    
    // 返回只读列表,防止外部修改
    public IReadOnlyList<Point> GetRing(int index)
    {
        return _rings[index].AsReadOnly();
    }
    
    public IEnumerable<IReadOnlyList<Point>> GetRings()
    {
        return _rings.Select(r => r.AsReadOnly());
    }
}

1.3 项目架构

1.3.1 整体架构图

┌─────────────────────────────────────────────────────────────────┐
│                        Application Layer                         │
│                    (用户应用程序 / GIS 系统)                        │
├─────────────────────────────────────────────────────────────────┤
│                       GeometryEngine                             │
│              (简化的静态 API,统一入口)                              │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │   Operators  │  │     I/O      │  │   Spatial    │          │
│  │   操作符层    │  │  数据格式层   │  │  Reference   │          │
│  ├──────────────┤  ├──────────────┤  │   空间参考层  │          │
│  │ Contains     │  │ WKT Export   │  ├──────────────┤          │
│  │ Intersects   │  │ WKT Import   │  │ WGS84        │          │
│  │ Buffer       │  │ WKB Export   │  │ WebMercator  │          │
│  │ Union        │  │ WKB Import   │  │ Custom WKID  │          │
│  │ Simplify     │  │ GeoJSON      │  │              │          │
│  │ ...          │  │ EsriJSON     │  │              │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
├─────────────────────────────────────────────────────────────────┤
│                       Geometry Layer                             │
│                        几何对象层                                  │
│  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐        │
│  │ Point  │ │Polyline│ │Polygon │ │Envelope│ │  Line  │        │
│  └────────┘ └────────┘ └────────┘ └────────┘ └────────┘        │
│              ┌────────────┐  ┌────────────┐                     │
│              │ MultiPoint │  │MapGeometry │                     │
│              └────────────┘  └────────────┘                     │
├─────────────────────────────────────────────────────────────────┤
│                       Foundation Layer                           │
│                          基础层                                   │
│  ┌──────────────────┐  ┌──────────────────┐                     │
│  │GeometryConstants │  │  GeometryType    │                     │
│  │    常量定义       │  │    类型枚举       │                     │
│  └──────────────────┘  └──────────────────┘                     │
└─────────────────────────────────────────────────────────────────┘

1.3.2 GeometryEngine - 统一入口

GeometryEngine 是框架提供的简化 API,它将所有操作符封装为静态方法,使得日常使用更加便捷:

public static class GeometryEngine
{
    // 空间关系测试
    public static bool Contains(Geometry g1, Geometry g2);
    public static bool Intersects(Geometry g1, Geometry g2);
    public static double Distance(Geometry g1, Geometry g2);
    
    // 几何运算
    public static Geometry Buffer(Geometry g, double distance);
    public static Geometry ConvexHull(Geometry g);
    public static Point Centroid(Geometry g);
    
    // 集合运算
    public static Geometry Union(Geometry g1, Geometry g2);
    public static Geometry Intersection(Geometry g1, Geometry g2);
    public static Geometry Difference(Geometry g1, Geometry g2);
    
    // 数据导入导出
    public static string GeometryToWkt(Geometry g);
    public static Geometry GeometryFromWkt(string wkt);
    public static string GeometryToGeoJson(Geometry g);
    public static Geometry GeometryFromGeoJson(string json);
}

选择使用 GeometryEngine 还是直接使用操作符类,取决于具体场景:

  • 日常使用:推荐 GeometryEngine,代码更简洁
  • 批量处理:推荐直接使用操作符,避免方法调用开销
  • 需要自定义行为:必须使用操作符类

1.4 功能清单

1.4.1 几何类型

类型 类名 维度 说明
点 Point 0 二维或三维点,支持 M 值
多点 MultiPoint 0 点的集合
线段 Line 1 由两个点定义的线段
折线 Polyline 1 由一条或多条路径组成
多边形 Polygon 2 由一个或多个环组成
包络矩形 Envelope 2 轴对齐的边界矩形

1.4.2 空间关系操作符

操作符 类名 说明
包含 ContainsOperator 测试 A 是否包含 B
相交 IntersectsOperator 测试 A 和 B 是否相交
距离 DistanceOperator 计算 A 和 B 之间的距离
相等 EqualsOperator 测试 A 和 B 是否空间相等
分离 DisjointOperator 测试 A 和 B 是否分离
在内部 WithinOperator 测试 A 是否在 B 内部
穿过 CrossesOperator 测试 A 是否穿过 B
接触 TouchesOperator 测试 A 和 B 是否接触
重叠 OverlapsOperator 测试 A 和 B 是否重叠

上述 9 个谓词(外加 IsSimpleOGC)均由内部的 DE-9IM 九交矩阵引擎(RelateEngine / RelateOps)统一驱动,已对 OGC-SF 语料与 PostGIS 逐条验证,对任意几何类型组合给出精确结果,而非仅包络判断。

1.4.3 几何运算操作符

操作符 类名 说明
缓冲区 BufferOperator 真圆缓冲区(Minkowski 圆盘近似,可配 circleSegments;负距离内缩;复杂多边形稳健叠加)
凸包 ConvexHullOperator 计算凸包
面积 AreaOperator 计算面积
长度 LengthOperator 计算长度或周长
简化 SimplifyOperator 使用 Douglas-Peucker 算法简化
质心 CentroidOperator 计算质心
边界 BoundaryOperator 计算边界
裁剪 ClipOperator 裁剪到包络范围
概化 GeneralizeOperator 概化几何对象
密化 DensifyOperator 密化几何对象
偏移 OffsetOperator 创建偏移曲线
简化(OGC) SimplifyOGCOperator 按 OGC 规范简化
邻近分析 Proximity2DOperator 最近坐标/顶点查询(GetNearestCoordinate、GetNearestVertex、GetNearestVertices)

1.4.4 集合操作符

操作符 类名 说明
并集 UnionOperator 计算两个几何对象的并集
交集 IntersectionOperator 计算两个几何对象的交集
差集 DifferenceOperator 计算两个几何对象的差集
对称差 SymmetricDifferenceOperator 计算对称差

集合操作由内部 SetOpsCore + 稳健绕数裁剪器 PolygonClipper 统一驱动:面×面为真布尔结果,支持带洞与多部件,已与 PostGIS 对拍;不再退化为包络近似。

1.4.5 大地测量操作符

操作符 类名 说明
大地测量距离 GeodesicDistanceOperator 计算椭球面上的距离
大地测量面积 GeodesicAreaOperator 计算椭球面上的面积

1.4.6 数据格式支持

格式 导入 导出 说明
WKT / EWKT ✅ ✅ Well-Known Text;EWKT 带 SRID=…; 前缀
WKB / EWKB ✅ ✅ Well-Known Binary;EWKB 覆盖 PostGIS Z/M/SRID 高位标志
GeoJSON ✅ ✅ GeoJSON 格式
Esri JSON ✅ ✅ Esri 专有 JSON 格式

1.5 与其他库的比较

1.5.1 与 NetTopologySuite (NTS) 比较

特性 geometry-api-net NetTopologySuite
设计理念 操作符单例模式 JTS 移植
API 风格 静态方法 + 操作符 实例方法
性能重点 轻量级、快速 功能完整
依赖 最小化 较多
适用场景 嵌入式、轻量级应用 企业级 GIS

1.5.2 选择建议

选择 geometry-api-net 的场景:

  • 需要轻量级几何计算库
  • 对启动时间和内存占用敏感
  • 与 Esri 产品集成
  • 学习 GIS 几何算法

选择 NetTopologySuite 的场景:

  • 需要完整的 JTS 功能
  • 与 Entity Framework 集成
  • 需要高级拓扑操作
  • 处理复杂的空间查询

1.6 测试覆盖

项目具有全面的测试覆盖,共计 255+ 个测试用例:

  • 28 个几何类型测试
  • 14 个空间关系操作符测试
  • 23 个附加操作符测试
  • 12 个几何操作测试
  • 20 个高级操作符测试
  • 24 个邻近和 GeometryEngine 测试
  • 23 个集合操作测试
  • 17 个 WKT 导入/导出测试
  • 10 个 WKB 导入/导出测试
  • 8 个 GeoJSON 导入/导出测试
  • 18 个 SimplifyOGC 操作符测试
  • 17 个几何辅助方法测试

1.7 小结

geometry-api-net 是一个设计精良、功能完备的 .NET 几何计算库。其核心设计理念包括:

  1. 操作符单例模式:提供一致的 API 和良好的性能
  2. 清晰的类型层次:符合 OGC 标准的几何模型
  3. 关注点分离:功能模块化,易于理解和维护
  4. 多格式支持:WKT、WKB、GeoJSON、Esri JSON
  5. 全面的测试:255+ 个测试用例确保代码质量

在接下来的章节中,我们将深入学习每个功能模块的使用方法和实现原理。